uint16_t _cpri__StartHash(TPM_ALG_ID alg, BOOL sequence, CPRI_HASH_STATE *state) { struct HASH_CTX *ctx = (struct HASH_CTX *) state->state; uint16_t result; switch (alg) { case TPM_ALG_SHA1: DCRYPTO_SHA1_init(ctx, sequence); result = HASH_size(ctx); break; case TPM_ALG_SHA256: DCRYPTO_SHA256_init(ctx, sequence); result = HASH_size(ctx); break; /* TODO: add support for SHA384 and SHA512 * case TPM_ALG_SHA384: * DCRYPTO_SHA384_init(in, in_len, p); * break; * case TPM_ALG_SHA512: * DCRYPTO_SHA512_init(in, in_len, p); * break; */ default: result = 0; break; } if (result > 0) state->hashAlg = alg; return result; }
static void MGF1_xor(uint8_t *dst, uint32_t dst_len, const uint8_t *seed, uint32_t seed_len, enum hashing_mode hashing) { struct HASH_CTX ctx; struct { uint8_t b3; uint8_t b2; uint8_t b1; uint8_t b0; } cnt; const uint8_t *digest; const size_t hash_size = (hashing == HASH_SHA1) ? SHA1_DIGEST_BYTES : SHA256_DIGEST_BYTES; cnt.b0 = cnt.b1 = cnt.b2 = cnt.b3 = 0; while (dst_len) { int i; if (hashing == HASH_SHA1) DCRYPTO_SHA1_init(&ctx, 0); else DCRYPTO_SHA256_init(&ctx, 0); DCRYPTO_HASH_update(&ctx, seed, seed_len); DCRYPTO_HASH_update(&ctx, (uint8_t *) &cnt, sizeof(cnt)); digest = DCRYPTO_HASH_final(&ctx); for (i = 0; i < dst_len && i < hash_size; ++i) *dst++ ^= *digest++; dst_len -= i; if (!++cnt.b0) ++cnt.b1; } }
/* TODO(ngm): constant time. */ static int check_oaep_pad(uint8_t *out, uint32_t *out_len, uint8_t *padded, uint32_t padded_len, enum hashing_mode hashing, const char *label) { const size_t hash_size = (hashing == HASH_SHA1) ? SHA1_DIGEST_BYTES : SHA256_DIGEST_BYTES; uint8_t *seed = padded + 1; uint8_t *phash = seed + hash_size; uint8_t *PS = phash + hash_size; const uint32_t max_msg_len = padded_len - 2 - 2 * hash_size; struct HASH_CTX ctx; int one_index = -1; int bad; int i; if (padded_len < 2 + 2 * hash_size) return 0; /* Invalid input size. */ /* Recover seed. */ MGF1_xor(seed, hash_size, phash, hash_size + 1 + max_msg_len, hashing); /* Recover db. */ MGF1_xor(phash, hash_size + 1 + max_msg_len, seed, hash_size, hashing); if (hashing == HASH_SHA1) DCRYPTO_SHA1_init(&ctx, 0); else DCRYPTO_SHA256_init(&ctx, 0); DCRYPTO_HASH_update(&ctx, label, label ? strlen(label) : 0); bad = memcmp(phash, DCRYPTO_HASH_final(&ctx), hash_size); bad |= padded[0]; for (i = PS - padded; i < padded_len; i++) { if (padded[i] == 1) { one_index = i; break; } else if (padded[i] != 0) { bad = 1; break; } } if (one_index < 0 || bad) return 0; one_index++; if (*out_len < padded_len - one_index) return 0; memcpy(out, padded + one_index, padded_len - one_index); *out_len = padded_len - one_index; return 1; }
/* encrypt */ static int oaep_pad(uint8_t *output, uint32_t output_len, const uint8_t *msg, uint32_t msg_len, enum hashing_mode hashing, const char *label) { int i; const size_t hash_size = (hashing == HASH_SHA1) ? SHA1_DIGEST_BYTES : SHA256_DIGEST_BYTES; uint8_t *const seed = output + 1; uint8_t *const phash = seed + hash_size; uint8_t *const PS = phash + hash_size; const uint32_t max_msg_len = output_len - 2 - 2 * hash_size; const uint32_t ps_len = max_msg_len - msg_len; uint8_t *const one = PS + ps_len; struct HASH_CTX ctx; if (output_len < 2 + 2 * hash_size) return 0; /* Key size too small for chosen hash. */ if (msg_len > output_len - 2 - 2 * hash_size) return 0; /* Input message too large for key size. */ dcrypto_memset(output, 0, output_len); for (i = 0; i < hash_size;) { uint32_t r = rand(); seed[i++] = r >> 0; seed[i++] = r >> 8; seed[i++] = r >> 16; seed[i++] = r >> 24; } if (hashing == HASH_SHA1) DCRYPTO_SHA1_init(&ctx, 0); else DCRYPTO_SHA256_init(&ctx, 0); DCRYPTO_HASH_update(&ctx, label, label ? strlen(label) : 0); memcpy(phash, DCRYPTO_HASH_final(&ctx), hash_size); *one = 1; memcpy(one + 1, msg, msg_len); MGF1_xor(phash, hash_size + 1 + max_msg_len, seed, hash_size, hashing); MGF1_xor(seed, hash_size, phash, hash_size + 1 + max_msg_len, hashing); return 1; }