blob: e5b9ae224d673f8b4ac9da00e9a50feea22f7231 [file] [log] [blame]
/*
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
*/
/*
* @file hmac.c
*
* @author Alexandre Adomnicai <alexandre.adomnicai@qredo.com>
*
* @brief Implementation of the Keyed-Hash Message Authentication Code (HMAC)
* with SHA-256 according to FIPS 198-1 and RFC 2104.
*/
#include "arch.h"
#include "amcl.h"
int HMAC_SHA256_init(hmac_sha256 *ctx, const char* key, int keylen)
{
if (ctx == NULL || key == NULL)
return ERR_NULLPOINTER_HMAC;
if (keylen < SHA256_HASH_SIZE)
return ERR_KEYSIZE_HMAC;
int i;
char ipad = 0x36;
// Initialize the underlying SHA256 instance
HASH256_init(&(ctx->sha256_ctx));
// Fill k0 with 0s for future padding
for(i = 0; i < SHA256_BLOCK_SIZE; i++)
ctx->k0[i] = 0x00;
// If the key size is larger than the block size, then hash it
if (keylen > SHA256_BLOCK_SIZE) {
for(i = 0; i < keylen; i++)
HASH256_process(&(ctx->sha256_ctx), key[i]);
HASH256_hash(&(ctx->sha256_ctx), ctx->k0);
}
// Otherwise the key is simply padded with 0s into k0
else {
for(i = 0; i < keylen; i++)
ctx->k0[i] = key[i];
}
// Update the HMAC instance to process k0 ^ ipad
for(i = 0; i < SHA256_BLOCK_SIZE; i++)
HASH256_process(&(ctx->sha256_ctx), (ctx->k0)[i] ^ ipad);
return SUCCESS;
}
int HMAC_SHA256_update(hash256 *ctx, const char* in, int inlen)
{
if (ctx == NULL)
return ERR_NULLPOINTER_HMAC;
if (inlen > 0 && in == NULL)
return ERR_NULLPOINTER_HMAC;
if (inlen < 0)
return ERR_BADARGLEN_HMAC;
// Update the HMAC instance to process in
for(int i = 0; i < inlen; i++)
HASH256_process(ctx, in[i]);
return SUCCESS;
}
int HMAC_SHA256_final(hmac_sha256 *ctx, char* out, int outlen)
{
if (ctx == NULL || out == NULL)
return ERR_NULLPOINTER_HMAC;
if (outlen <= 0 || outlen > SHA256_HASH_SIZE)
return ERR_BADARGLEN_HMAC;
int i;
char opad = 0x5c;
char digest[SHA256_HASH_SIZE];
// Compute H((k0 ^ ipad) || in)
HASH256_hash(&(ctx->sha256_ctx), digest);
// Compute `H((K0 ^ opad ) || H((K0 ^ ipad) || in))`
for(i = 0; i < SHA256_BLOCK_SIZE; i++)
HASH256_process(&(ctx->sha256_ctx), (ctx->k0)[i] ^ opad);
for(i = 0; i < SHA256_HASH_SIZE; i++)
HASH256_process(&(ctx->sha256_ctx), digest[i]);
HASH256_hash(&(ctx->sha256_ctx), digest);
// Erase the secret key as it is not needed anymore
for(i = 0; i < SHA256_BLOCK_SIZE; i++)
ctx->k0[i] = 0x00;
for(i = 0; i < outlen; i++)
out[i] = digest[i];
return SUCCESS;
}
int HMAC_SHA256_oneshot(char* out, int outlen,
const char* key, int keylen,
const char* in, int inlen)
{
if (out == NULL || key == NULL || in == NULL)
return ERR_NULLPOINTER_HMAC;
if (keylen < SHA256_HASH_SIZE)
return ERR_KEYSIZE_HMAC;
if (outlen <= 0 || outlen > SHA256_HASH_SIZE || inlen < 0)
return ERR_BADARGLEN_HMAC;
int i;
hash256 sha256;
char ipad = 0x36;
char opad = 0x5c;
char k0[SHA256_BLOCK_SIZE];
char digest[SHA256_HASH_SIZE];
HASH256_init(&sha256);
// Fill k0 with 0s for future padding
for(i = 0; i < SHA256_BLOCK_SIZE; i++)
k0[i] = 0x00;
// If the key size is larger than the block size, then hash it
if (keylen > SHA256_BLOCK_SIZE) {
for(i = 0; i < keylen; i++)
HASH256_process(&sha256, key[i]);
HASH256_hash(&sha256, k0);
}
// Otherwise the key is simply padded with 0s into k0
else {
for(i = 0; i < keylen; i++)
k0[i] = key[i];
}
// Compute H((k0 ^ ipad) || in)
for(i = 0; i < SHA256_BLOCK_SIZE; i++)
HASH256_process(&sha256, k0[i] ^ ipad);
for(i = 0; i < inlen; i++)
HASH256_process(&sha256, in[i]);
HASH256_hash(&sha256, digest);
// Compute `H((k0 ^ opad ) || H((k0 ^ ipad) || in))`
for(i = 0; i < SHA256_BLOCK_SIZE; i++)
HASH256_process(&sha256, k0[i] ^ opad);
for(i = 0; i < SHA256_HASH_SIZE; i++)
HASH256_process(&sha256, digest[i]);
HASH256_hash(&sha256, digest);
// Erase the secret key as it is not needed anymore
for(i = 0; i < SHA256_BLOCK_SIZE; i++)
k0[i] = 0x00;
for(i = 0; i < outlen; i++)
out[i] = digest[i];
return SUCCESS;
}