/*
* Refer to https://csrc.nist.gov/publications/detail/sp/800-56c/rev-1/final
* Section 4. One-Step Key Derivation using H(x) = hash(x)
+ * Note: X9.63 also uses this code with the only difference being that the
+ * counter is appended to the secret 'z'.
+ * i.e.
+ * result[i] = Hash(counter || z || info) for One Step OR
+ * result[i] = Hash(z || counter || info) for X9.63.
*/
static int SSKDF_hash_kdm(const EVP_MD *kdf_md,
const unsigned char *z, size_t z_len,
const unsigned char *info, size_t info_len,
+ unsigned int append_ctr,
unsigned char *derived_key, size_t derived_key_len)
{
int ret = 0, hlen;
c[3] = (unsigned char)(counter & 0xff);
if (!(EVP_MD_CTX_copy_ex(ctx, ctx_init)
- && EVP_DigestUpdate(ctx, c, sizeof(c))
+ && (append_ctr || EVP_DigestUpdate(ctx, c, sizeof(c)))
&& EVP_DigestUpdate(ctx, z, z_len)
+ && (!append_ctr || EVP_DigestUpdate(ctx, c, sizeof(c)))
&& EVP_DigestUpdate(ctx, info, info_len)))
goto end;
if (len >= out_len) {
|| derived_key_len == 0)
return 0;
- ctx = EVP_MAC_CTX_new(kdf_mac);
ctx_init = EVP_MAC_CTX_new(kdf_mac);
- if (ctx == NULL || ctx_init == NULL)
+ if (ctx_init == NULL)
goto end;
if (hmac_md != NULL &&
EVP_MAC_ctrl(ctx_init, EVP_MAC_CTRL_SET_MD, hmac_md) <= 0)
c[2] = (unsigned char)((counter >> 8) & 0xff);
c[3] = (unsigned char)(counter & 0xff);
- if (!(EVP_MAC_CTX_copy(ctx, ctx_init)
+ ctx = EVP_MAC_CTX_dup(ctx_init);
+ if (!(ctx != NULL
&& EVP_MAC_update(ctx, c, sizeof(c))
&& EVP_MAC_update(ctx, z, z_len)
&& EVP_MAC_update(ctx, info, info_len)))
memcpy(out, mac, len);
break;
}
+ EVP_MAC_CTX_free(ctx);
+ ctx = NULL;
}
ret = 1;
end:
return 0;
}
return SSKDF_hash_kdm(impl->md, impl->secret, impl->secret_len,
- impl->info, impl->info_len, key, keylen);
+ impl->info, impl->info_len, 0, key, keylen);
+ }
+}
+
+static int x963kdf_derive(EVP_KDF_IMPL *impl, unsigned char *key, size_t keylen)
+{
+ if (impl->secret == NULL) {
+ KDFerr(KDF_F_X963KDF_DERIVE, KDF_R_MISSING_SECRET);
+ return 0;
+ }
+
+ if (impl->mac != NULL) {
+ KDFerr(KDF_F_X963KDF_DERIVE, KDF_R_NOT_SUPPORTED);
+ return 0;
+ } else {
+ /* H(x) = hash */
+ if (impl->md == NULL) {
+ KDFerr(KDF_F_X963KDF_DERIVE, KDF_R_MISSING_MESSAGE_DIGEST);
+ return 0;
+ }
+ return SSKDF_hash_kdm(impl->md, impl->secret, impl->secret_len,
+ impl->info, impl->info_len, 1, key, keylen);
}
}
sskdf_size,
sskdf_derive
};
+
+const EVP_KDF x963_kdf_meth = {
+ EVP_KDF_X963,
+ sskdf_new,
+ sskdf_free,
+ sskdf_reset,
+ sskdf_ctrl,
+ sskdf_ctrl_str,
+ sskdf_size,
+ x963kdf_derive
+};