/** * Initialize the HMAC context * @param ctx the HMAC context * @param key the key * @param keyLen the length of the key * @return * - AJ_OK if successful * - AJ_ERR_INVALID if the length is negative */ static AJ_Status AJ_HMAC_SHA256_Init(AJ_HMAC_SHA256_CTX* ctx, const uint8_t* key, size_t keyLen) { int cnt; memset(ctx->ipad, 0, HMAC_SHA256_BLOCK_LENGTH); memset(ctx->opad, 0, HMAC_SHA256_BLOCK_LENGTH); /* if keyLen > 64, hash it and use it as key */ if (keyLen > HMAC_SHA256_BLOCK_LENGTH) { uint8_t digest[AJ_SHA256_DIGEST_LENGTH]; AJ_Status status; ctx->hashCtx = AJ_SHA256_Init(); if (!ctx->hashCtx) { return AJ_ERR_RESOURCES; } AJ_SHA256_Update(ctx->hashCtx, key, keyLen); status = AJ_SHA256_Final(ctx->hashCtx, digest); if (status != AJ_OK) { return status; } keyLen = AJ_SHA256_DIGEST_LENGTH; memcpy(ctx->ipad, digest, AJ_SHA256_DIGEST_LENGTH); memcpy(ctx->opad, digest, AJ_SHA256_DIGEST_LENGTH); } else { memcpy(ctx->ipad, key, keyLen); memcpy(ctx->opad, key, keyLen); } /* * the HMAC_SHA256 process * * SHA256(K XOR opad, SHA256(K XOR ipad, msg)) * * K is the key * ipad is filled with 0x36 * opad is filled with 0x5c * msg is the message */ /* * prepare inner hash SHA256(K XOR ipad, msg) * K XOR ipad */ for (cnt = 0; cnt < HMAC_SHA256_BLOCK_LENGTH; cnt++) { ctx->ipad[cnt] ^= 0x36; } ctx->hashCtx = AJ_SHA256_Init(); if (!ctx->hashCtx) { return AJ_ERR_RESOURCES; } AJ_SHA256_Update(ctx->hashCtx, ctx->ipad, HMAC_SHA256_BLOCK_LENGTH); return AJ_OK; }
/** * Retrieve the final digest for the HMAC * @param ctx the HMAC context * @param digest the buffer to hold the digest. Must be of size AJ_SHA256_DIGEST_LENGTH */ static AJ_Status AJ_HMAC_SHA256_Final(AJ_HMAC_SHA256_CTX* ctx, uint8_t* digest) { int cnt; AJ_Status status; /* complete inner hash SHA256(K XOR ipad, msg) */ status = AJ_SHA256_Final(ctx->hashCtx, digest); if (status != AJ_OK) { return status; } /* * perform outer hash SHA256(K XOR opad, SHA256(K XOR ipad, msg)) */ for (cnt = 0; cnt < HMAC_SHA256_BLOCK_LENGTH; cnt++) { ctx->opad[cnt] ^= 0x5c; } ctx->hashCtx = AJ_SHA256_Init(); if (!ctx->hashCtx) { return AJ_ERR_RESOURCES; } AJ_SHA256_Update(ctx->hashCtx, ctx->opad, HMAC_SHA256_BLOCK_LENGTH); AJ_SHA256_Update(ctx->hashCtx, digest, AJ_SHA256_DIGEST_LENGTH); status = AJ_SHA256_Final(ctx->hashCtx, digest); return status; }
static void ManifestDigest(uint8_t* manifest, size_t* len, uint8_t* digest) { AJ_SHA256_Context sha; AJ_SHA256_Init(&sha); AJ_SHA256_Update(&sha, (const uint8_t*) manifest, *len); AJ_SHA256_Final(&sha, digest); }
static AJ_Status CertificateDigest(AJ_Certificate* certificate, uint8_t* digest) { AJ_SHA256_Context ctx; uint8_t buf[sizeof (AJ_Certificate)]; AJ_BigEndianEncodeCertificate(certificate, buf, sizeof (buf)); AJ_SHA256_Init(&ctx); AJ_SHA256_Update(&ctx, buf, certificate->size - sizeof (ecc_signature)); AJ_SHA256_Final(&ctx, digest); return AJ_OK; }