summaryrefslogtreecommitdiffstats
path: root/crypto/kdf
diff options
context:
space:
mode:
authorDavid Makepeace <david.p.makepeace@oracle.com>2018-06-22 07:16:18 +1000
committerRichard Levitte <levitte@openssl.org>2019-02-13 12:11:49 +0100
commit5a285addbf39f91d567f95f04b2b41764127950d (patch)
tree4cdf512d4217da5b6b959552a20a33b6a23a9aaa /crypto/kdf
parente0ae0585bee898184cbbe8144d2fa8ce25e8ca72 (diff)
Added new EVP/KDF API.
Changed PKEY/KDF API to call the new API. Added wrappers for PKCS5_PBKDF2_HMAC() and EVP_PBE_scrypt() to call the new EVP KDF APIs. Documentation updated. Reviewed-by: Paul Dale <paul.dale@oracle.com> Reviewed-by: Richard Levitte <levitte@openssl.org> (Merged from https://github.com/openssl/openssl/pull/6674)
Diffstat (limited to 'crypto/kdf')
-rw-r--r--crypto/kdf/build.info2
-rw-r--r--crypto/kdf/hkdf.c324
-rw-r--r--crypto/kdf/kdf_err.c28
-rw-r--r--crypto/kdf/kdf_local.h22
-rw-r--r--crypto/kdf/kdf_util.c73
-rw-r--r--crypto/kdf/pbkdf2.c264
-rw-r--r--crypto/kdf/scrypt.c466
-rw-r--r--crypto/kdf/tls1_prf.c193
8 files changed, 983 insertions, 389 deletions
diff --git a/crypto/kdf/build.info b/crypto/kdf/build.info
index c166399d0c..dce960e9e1 100644
--- a/crypto/kdf/build.info
+++ b/crypto/kdf/build.info
@@ -1,3 +1,3 @@
LIBS=../../libcrypto
SOURCE[../../libcrypto]=\
- tls1_prf.c kdf_err.c hkdf.c scrypt.c
+ tls1_prf.c kdf_err.c kdf_util.c hkdf.c scrypt.c pbkdf2.c
diff --git a/crypto/kdf/hkdf.c b/crypto/kdf/hkdf.c
index dc2ead66b1..5540da35fe 100644
--- a/crypto/kdf/hkdf.c
+++ b/crypto/kdf/hkdf.c
@@ -8,32 +8,33 @@
*/
#include <stdlib.h>
+#include <stdarg.h>
#include <string.h>
#include <openssl/hmac.h>
-#include <openssl/kdf.h>
#include <openssl/evp.h>
+#include <openssl/kdf.h>
#include "internal/cryptlib.h"
#include "internal/evp_int.h"
+#include "kdf_local.h"
#define HKDF_MAXBUF 1024
-static unsigned char *HKDF(const EVP_MD *evp_md,
- const unsigned char *salt, size_t salt_len,
- const unsigned char *key, size_t key_len,
- const unsigned char *info, size_t info_len,
- unsigned char *okm, size_t okm_len);
-
-static unsigned char *HKDF_Extract(const EVP_MD *evp_md,
- const unsigned char *salt, size_t salt_len,
- const unsigned char *key, size_t key_len,
- unsigned char *prk, size_t *prk_len);
-
-static unsigned char *HKDF_Expand(const EVP_MD *evp_md,
- const unsigned char *prk, size_t prk_len,
- const unsigned char *info, size_t info_len,
- unsigned char *okm, size_t okm_len);
-
-typedef struct {
+static void kdf_hkdf_reset(EVP_KDF_IMPL *impl);
+static int HKDF(const EVP_MD *evp_md,
+ const unsigned char *salt, size_t salt_len,
+ const unsigned char *key, size_t key_len,
+ const unsigned char *info, size_t info_len,
+ unsigned char *okm, size_t okm_len);
+static int HKDF_Extract(const EVP_MD *evp_md,
+ const unsigned char *salt, size_t salt_len,
+ const unsigned char *key, size_t key_len,
+ unsigned char *prk, size_t prk_len);
+static int HKDF_Expand(const EVP_MD *evp_md,
+ const unsigned char *prk, size_t prk_len,
+ const unsigned char *info, size_t info_len,
+ unsigned char *okm, size_t okm_len);
+
+struct evp_kdf_impl_st {
int mode;
const EVP_MD *md;
unsigned char *salt;
@@ -42,230 +43,208 @@ typedef struct {
size_t key_len;
unsigned char info[HKDF_MAXBUF];
size_t info_len;
-} HKDF_PKEY_CTX;
+};
-static int pkey_hkdf_init(EVP_PKEY_CTX *ctx)
+static EVP_KDF_IMPL *kdf_hkdf_new(void)
{
- HKDF_PKEY_CTX *kctx;
+ EVP_KDF_IMPL *impl;
- if ((kctx = OPENSSL_zalloc(sizeof(*kctx))) == NULL) {
- KDFerr(KDF_F_PKEY_HKDF_INIT, ERR_R_MALLOC_FAILURE);
- return 0;
- }
-
- ctx->data = kctx;
+ if ((impl = OPENSSL_zalloc(sizeof(*impl))) == NULL)
+ KDFerr(KDF_F_KDF_HKDF_NEW, ERR_R_MALLOC_FAILURE);
+ return impl;
+}
- return 1;
+static void kdf_hkdf_free(EVP_KDF_IMPL *impl)
+{
+ kdf_hkdf_reset(impl);
+ OPENSSL_free(impl);
}
-static void pkey_hkdf_cleanup(EVP_PKEY_CTX *ctx)
+static void kdf_hkdf_reset(EVP_KDF_IMPL *impl)
{
- HKDF_PKEY_CTX *kctx = ctx->data;
- OPENSSL_clear_free(kctx->salt, kctx->salt_len);
- OPENSSL_clear_free(kctx->key, kctx->key_len);
- OPENSSL_cleanse(kctx->info, kctx->info_len);
- OPENSSL_free(kctx);
+ OPENSSL_free(impl->salt);
+ OPENSSL_clear_free(impl->key, impl->key_len);
+ OPENSSL_cleanse(impl->info, impl->info_len);
+ memset(impl, 0, sizeof(*impl));
}
-static int pkey_hkdf_ctrl(EVP_PKEY_CTX *ctx, int type, int p1, void *p2)
+static int kdf_hkdf_ctrl(EVP_KDF_IMPL *impl, int cmd, va_list args)
{
- HKDF_PKEY_CTX *kctx = ctx->data;
+ const unsigned char *p;
+ size_t len;
+ const EVP_MD *md;
- switch (type) {
- case EVP_PKEY_CTRL_HKDF_MD:
- if (p2 == NULL)
+ switch (cmd) {
+ case EVP_KDF_CTRL_SET_MD:
+ md = va_arg(args, const EVP_MD *);
+ if (md == NULL)
return 0;
- kctx->md = p2;
+ impl->md = md;
return 1;
- case EVP_PKEY_CTRL_HKDF_MODE:
- kctx->mode = p1;
+ case EVP_KDF_CTRL_SET_HKDF_MODE:
+ impl->mode = va_arg(args, int);
return 1;
- case EVP_PKEY_CTRL_HKDF_SALT:
- if (p1 == 0 || p2 == NULL)
+ case EVP_KDF_CTRL_SET_SALT:
+ p = va_arg(args, const unsigned char *);
+ len = va_arg(args, size_t);
+ if (len == 0 || p == NULL)
return 1;
- if (p1 < 0)
+ OPENSSL_free(impl->salt);
+ impl->salt = OPENSSL_memdup(p, len);
+ if (impl->salt == NULL)
return 0;
- if (kctx->salt != NULL)
- OPENSSL_clear_free(kctx->salt, kctx->salt_len);
-
- kctx->salt = OPENSSL_memdup(p2, p1);
- if (kctx->salt == NULL)
- return 0;
-
- kctx->salt_len = p1;
+ impl->salt_len = len;
return 1;
- case EVP_PKEY_CTRL_HKDF_KEY:
- if (p1 < 0)
+ case EVP_KDF_CTRL_SET_KEY:
+ p = va_arg(args, const unsigned char *);
+ len = va_arg(args, size_t);
+ OPENSSL_clear_free(impl->key, impl->key_len);
+ impl->key = OPENSSL_memdup(p, len);
+ if (impl->key == NULL)
return 0;
- if (kctx->key != NULL)
- OPENSSL_clear_free(kctx->key, kctx->key_len);
-
- kctx->key = OPENSSL_memdup(p2, p1);
- if (kctx->key == NULL)
- return 0;
+ impl->key_len = len;
+ return 1;
- kctx->key_len = p1;
+ case EVP_KDF_CTRL_RESET_HKDF_INFO:
+ OPENSSL_cleanse(impl->info, impl->info_len);
+ impl->info_len = 0;
return 1;
- case EVP_PKEY_CTRL_HKDF_INFO:
- if (p1 == 0 || p2 == NULL)
+ case EVP_KDF_CTRL_ADD_HKDF_INFO:
+ p = va_arg(args, const unsigned char *);
+ len = va_arg(args, size_t);
+ if (len == 0 || p == NULL)
return 1;
- if (p1 < 0 || p1 > (int)(HKDF_MAXBUF - kctx->info_len))
+ if (len > (HKDF_MAXBUF - impl->info_len))
return 0;
- memcpy(kctx->info + kctx->info_len, p2, p1);
- kctx->info_len += p1;
+ memcpy(impl->info + impl->info_len, p, len);
+ impl->info_len += len;
return 1;
default:
return -2;
-
}
}
-static int pkey_hkdf_ctrl_str(EVP_PKEY_CTX *ctx, const char *type,
- const char *value)
+static int kdf_hkdf_ctrl_str(EVP_KDF_IMPL *impl, const char *type,
+ const char *value)
{
if (strcmp(type, "mode") == 0) {
int mode;
if (strcmp(value, "EXTRACT_AND_EXPAND") == 0)
- mode = EVP_PKEY_HKDEF_MODE_EXTRACT_AND_EXPAND;
+ mode = EVP_KDF_HKDF_MODE_EXTRACT_AND_EXPAND;
else if (strcmp(value, "EXTRACT_ONLY") == 0)
- mode = EVP_PKEY_HKDEF_MODE_EXTRACT_ONLY;
+ mode = EVP_KDF_HKDF_MODE_EXTRACT_ONLY;
else if (strcmp(value, "EXPAND_ONLY") == 0)
- mode = EVP_PKEY_HKDEF_MODE_EXPAND_ONLY;
+ mode = EVP_KDF_HKDF_MODE_EXPAND_ONLY;
else
return 0;
- return EVP_PKEY_CTX_hkdf_mode(ctx, mode);
+ return call_ctrl(kdf_hkdf_ctrl, impl, EVP_KDF_CTRL_SET_HKDF_MODE, mode);
}
- if (strcmp(type, "md") == 0)
- return EVP_PKEY_CTX_md(ctx, EVP_PKEY_OP_DERIVE,
- EVP_PKEY_CTRL_HKDF_MD, value);
+ if (strcmp(type, "digest") == 0)
+ return kdf_md2ctrl(impl, kdf_hkdf_ctrl, EVP_KDF_CTRL_SET_MD, value);
if (strcmp(type, "salt") == 0)
- return EVP_PKEY_CTX_str2ctrl(ctx, EVP_PKEY_CTRL_HKDF_SALT, value);
+ return kdf_str2ctrl(impl, kdf_hkdf_ctrl, EVP_KDF_CTRL_SET_SALT, value);
if (strcmp(type, "hexsalt") == 0)
- return EVP_PKEY_CTX_hex2ctrl(ctx, EVP_PKEY_CTRL_HKDF_SALT, value);
+ return kdf_hex2ctrl(impl, kdf_hkdf_ctrl, EVP_KDF_CTRL_SET_SALT, value);
if (strcmp(type, "key") == 0)
- return EVP_PKEY_CTX_str2ctrl(ctx, EVP_PKEY_CTRL_HKDF_KEY, value);
+ return kdf_str2ctrl(impl, kdf_hkdf_ctrl, EVP_KDF_CTRL_SET_KEY, value);
if (strcmp(type, "hexkey") == 0)
- return EVP_PKEY_CTX_hex2ctrl(ctx, EVP_PKEY_CTRL_HKDF_KEY, value);
+ return kdf_hex2ctrl(impl, kdf_hkdf_ctrl, EVP_KDF_CTRL_SET_KEY, value);
if (strcmp(type, "info") == 0)
- return EVP_PKEY_CTX_str2ctrl(ctx, EVP_PKEY_CTRL_HKDF_INFO, value);
+ return kdf_str2ctrl(impl, kdf_hkdf_ctrl, EVP_KDF_CTRL_ADD_HKDF_INFO,
+ value);
if (strcmp(type, "hexinfo") == 0)
- return EVP_PKEY_CTX_hex2ctrl(ctx, EVP_PKEY_CTRL_HKDF_INFO, value);
+ return kdf_hex2ctrl(impl, kdf_hkdf_ctrl, EVP_KDF_CTRL_ADD_HKDF_INFO,
+ value);
- KDFerr(KDF_F_PKEY_HKDF_CTRL_STR, KDF_R_UNKNOWN_PARAMETER_TYPE);
return -2;
}
-static int pkey_hkdf_derive_init(EVP_PKEY_CTX *ctx)
+static size_t kdf_hkdf_size(EVP_KDF_IMPL *impl)
{
- HKDF_PKEY_CTX *kctx = ctx->data;
-
- OPENSSL_clear_free(kctx->key, kctx->key_len);
- OPENSSL_clear_free(kctx->salt, kctx->salt_len);
- OPENSSL_cleanse(kctx->info, kctx->info_len);
- memset(kctx, 0, sizeof(*kctx));
+ if (impl->mode != EVP_KDF_HKDF_MODE_EXTRACT_ONLY)
+ return SIZE_MAX;
- return 1;
+ if (impl->md == NULL) {
+ KDFerr(KDF_F_KDF_HKDF_SIZE, KDF_R_MISSING_MESSAGE_DIGEST);
+ return 0;
+ }
+ return EVP_MD_size(impl->md);
}
-static int pkey_hkdf_derive(EVP_PKEY_CTX *ctx, unsigned char *key,
- size_t *keylen)
+static int kdf_hkdf_derive(EVP_KDF_IMPL *impl, unsigned char *key,
+ size_t keylen)
{
- HKDF_PKEY_CTX *kctx = ctx->data;
-
- if (kctx->md == NULL) {
- KDFerr(KDF_F_PKEY_HKDF_DERIVE, KDF_R_MISSING_MESSAGE_DIGEST);
+ if (impl->md == NULL) {
+ KDFerr(KDF_F_KDF_HKDF_DERIVE, KDF_R_MISSING_MESSAGE_DIGEST);
return 0;
}
- if (kctx->key == NULL) {
- KDFerr(KDF_F_PKEY_HKDF_DERIVE, KDF_R_MISSING_KEY);
+ if (impl->key == NULL) {
+ KDFerr(KDF_F_KDF_HKDF_DERIVE, KDF_R_MISSING_KEY);
return 0;
}
- switch (kctx->mode) {
- case EVP_PKEY_HKDEF_MODE_EXTRACT_AND_EXPAND:
- return HKDF(kctx->md, kctx->salt, kctx->salt_len, kctx->key,
- kctx->key_len, kctx->info, kctx->info_len, key,
- *keylen) != NULL;
+ switch (impl->mode) {
+ case EVP_KDF_HKDF_MODE_EXTRACT_AND_EXPAND:
+ return HKDF(impl->md, impl->salt, impl->salt_len, impl->key,
+ impl->key_len, impl->info, impl->info_len, key,
+ keylen);
- case EVP_PKEY_HKDEF_MODE_EXTRACT_ONLY:
- if (key == NULL) {
- *keylen = EVP_MD_size(kctx->md);
- return 1;
- }
- return HKDF_Extract(kctx->md, kctx->salt, kctx->salt_len, kctx->key,
- kctx->key_len, key, keylen) != NULL;
+ case EVP_KDF_HKDF_MODE_EXTRACT_ONLY:
+ return HKDF_Extract(impl->md, impl->salt, impl->salt_len, impl->key,
+ impl->key_len, key, keylen);
- case EVP_PKEY_HKDEF_MODE_EXPAND_ONLY:
- return HKDF_Expand(kctx->md, kctx->key, kctx->key_len, kctx->info,
- kctx->info_len, key, *keylen) != NULL;
+ case EVP_KDF_HKDF_MODE_EXPAND_ONLY:
+ return HKDF_Expand(impl->md, impl->key, impl->key_len, impl->info,
+ impl->info_len, key, keylen);
default:
return 0;
}
}
-const EVP_PKEY_METHOD hkdf_pkey_meth = {
- EVP_PKEY_HKDF,
- 0,
- pkey_hkdf_init,
- 0,
- pkey_hkdf_cleanup,
-
- 0, 0,
- 0, 0,
-
- 0,
- 0,
-
- 0,
- 0,
-
- 0, 0,
-
- 0, 0, 0, 0,
-
- 0, 0,
-
- 0, 0,
-
- pkey_hkdf_derive_init,
- pkey_hkdf_derive,
- pkey_hkdf_ctrl,
- pkey_hkdf_ctrl_str
+const EVP_KDF_METHOD hkdf_kdf_meth = {
+ EVP_KDF_HKDF,
+ kdf_hkdf_new,
+ kdf_hkdf_free,
+ kdf_hkdf_reset,
+ kdf_hkdf_ctrl,
+ kdf_hkdf_ctrl_str,
+ kdf_hkdf_size,
+ kdf_hkdf_derive
};
-static unsigned char *HKDF(const EVP_MD *evp_md,
- const unsigned char *salt, size_t salt_len,
- const unsigned char *key, size_t key_len,
- const unsigned char *info, size_t info_len,
- unsigned char *okm, size_t okm_len)
+static int HKDF(const EVP_MD *evp_md,
+ const unsigned char *salt, size_t salt_len,
+ const unsigned char *key, size_t key_len,
+ const unsigned char *info, size_t info_len,
+ unsigned char *okm, size_t okm_len)
{
unsigned char prk[EVP_MAX_MD_SIZE];
- unsigned char *ret;
- size_t prk_len;
+ int ret;
+ size_t prk_len = EVP_MD_size(evp_md);
- if (!HKDF_Extract(evp_md, salt, salt_len, key, key_len, prk, &prk_len))
- return NULL;
+ if (!HKDF_Extract(evp_md, salt, salt_len, key, key_len, prk, prk_len))
+ return 0;
ret = HKDF_Expand(evp_md, prk, prk_len, info, info_len, okm, okm_len);
OPENSSL_cleanse(prk, sizeof(prk));
@@ -273,43 +252,38 @@ static unsigned char *HKDF(const EVP_MD *evp_md,
return ret;
}
-static unsigned char *HKDF_Extract(const EVP_MD *evp_md,
- const unsigned char *salt, size_t salt_len,
- const unsigned char *key, size_t key_len,
- unsigned char *prk, size_t *prk_len)
+static int HKDF_Extract(const EVP_MD *evp_md,
+ const unsigned char *salt, size_t salt_len,
+ const unsigned char *key, size_t key_len,
+ unsigned char *prk, size_t prk_len)
{
- unsigned int tmp_len;
-
- if (!HMAC(evp_md, salt, salt_len, key, key_len, prk, &tmp_len))
- return NULL;
-
- *prk_len = tmp_len;
- return prk;
+ if (prk_len != (size_t)EVP_MD_size(evp_md)) {
+ KDFerr(KDF_F_HKDF_EXTRACT, KDF_R_WRONG_OUTPUT_BUFFER_SIZE);
+ return 0;
+ }
+ return HMAC(evp_md, salt, salt_len, key, key_len, prk, NULL) != NULL;
}
-static unsigned char *HKDF_Expand(const EVP_MD *evp_md,
- const unsigned char *prk, size_t prk_len,
- const unsigned char *info, size_t info_len,
- unsigned char *okm, size_t okm_len)
+static int HKDF_Expand(const EVP_MD *evp_md,
+ const unsigned char *prk, size_t prk_len,
+ const unsigned char *info, size_t info_len,
+ unsigned char *okm, size_t okm_len)
{
HMAC_CTX *hmac;
- unsigned char *ret = NULL;
-
+ int ret = 0;
unsigned int i;
-
unsigned char prev[EVP_MAX_MD_SIZE];
-
size_t done_len = 0, dig_len = EVP_MD_size(evp_md);
-
size_t n = okm_len / dig_len;
+
if (okm_len % dig_len)
n++;
if (n > 255 || okm == NULL)
- return NULL;
+ return 0;
if ((hmac = HMAC_CTX_new()) == NULL)
- return NULL;
+ return 0;
if (!HMAC_Init_ex(hmac, prk, prk_len, evp_md, NULL))
goto err;
@@ -343,7 +317,7 @@ static unsigned char *HKDF_Expand(const EVP_MD *evp_md,
done_len += copy_len;
}
- ret = okm;
+ ret = 1;
err:
OPENSSL_cleanse(prev, sizeof(prev));
diff --git a/crypto/kdf/kdf_err.c b/crypto/kdf/kdf_err.c
index 92e6a0c754..b62c25ff55 100644
--- a/crypto/kdf/kdf_err.c
+++ b/crypto/kdf/kdf_err.c
@@ -1,6 +1,6 @@
/*
* Generated by util/mkerr.pl DO NOT EDIT
- * Copyright 1995-2018 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 1995-2019 The OpenSSL Project Authors. All Rights Reserved.
*
* Licensed under the Apache License 2.0 (the "License"). You may not use
* this file except in compliance with the License. You can obtain a copy
@@ -14,6 +14,29 @@
#ifndef OPENSSL_NO_ERR
static const ERR_STRING_DATA KDF_str_functs[] = {
+ {ERR_PACK(ERR_LIB_KDF, KDF_F_HKDF_EXTRACT, 0), "HKDF_Extract"},
+ {ERR_PACK(ERR_LIB_KDF, KDF_F_KDF_HKDF_DERIVE, 0), "kdf_hkdf_derive"},
+ {ERR_PACK(ERR_LIB_KDF, KDF_F_KDF_HKDF_NEW, 0), "kdf_hkdf_new"},
+ {ERR_PACK(ERR_LIB_KDF, KDF_F_KDF_HKDF_SIZE, 0), "kdf_hkdf_size"},
+ {ERR_PACK(ERR_LIB_KDF, KDF_F_KDF_MD2CTRL, 0), "kdf_md2ctrl"},
+ {ERR_PACK(ERR_LIB_KDF, KDF_F_KDF_PBKDF2_CTRL_STR, 0),
+ "kdf_pbkdf2_ctrl_str"},
+ {ERR_PACK(ERR_LIB_KDF, KDF_F_KDF_PBKDF2_DERIVE, 0), "kdf_pbkdf2_derive"},
+ {ERR_PACK(ERR_LIB_KDF, KDF_F_KDF_PBKDF2_NEW, 0), "kdf_pbkdf2_new"},
+ {ERR_PACK(ERR_LIB_KDF, KDF_F_KDF_SCRYPT_CTRL_STR, 0),
+ "kdf_scrypt_ctrl_str"},
+ {ERR_PACK(ERR_LIB_KDF, KDF_F_KDF_SCRYPT_CTRL_UINT32, 0),
+ "kdf_scrypt_ctrl_uint32"},
+ {ERR_PACK(ERR_LIB_KDF, KDF_F_KDF_SCRYPT_CTRL_UINT64, 0),
+ "kdf_scrypt_ctrl_uint64"},
+ {ERR_PACK(ERR_LIB_KDF, KDF_F_KDF_SCRYPT_DERIVE, 0), "kdf_scrypt_derive"},
+ {ERR_PACK(ERR_LIB_KDF, KDF_F_KDF_SCRYPT_NEW, 0), "kdf_scrypt_new"},
+ {ERR_PACK(ERR_LIB_KDF, KDF_F_KDF_TLS1_PRF_CTRL_STR, 0),
+ "kdf_tls1_prf_ctrl_str"},
+ {ERR_PACK(ERR_LIB_KDF, KDF_F_KDF_TLS1_PRF_DERIVE, 0),
+ "kdf_tls1_prf_derive"},
+ {ERR_PACK(ERR_LIB_KDF, KDF_F_KDF_TLS1_PRF_NEW, 0), "kdf_tls1_prf_new"},
+ {ERR_PACK(ERR_LIB_KDF, KDF_F_PBKDF2_SET_MEMBUF, 0), "pbkdf2_set_membuf"},
{ERR_PACK(ERR_LIB_KDF, KDF_F_PKEY_HKDF_CTRL_STR, 0), "pkey_hkdf_ctrl_str"},
{ERR_PACK(ERR_LIB_KDF, KDF_F_PKEY_HKDF_DERIVE, 0), "pkey_hkdf_derive"},
{ERR_PACK(ERR_LIB_KDF, KDF_F_PKEY_HKDF_INIT, 0), "pkey_hkdf_init"},
@@ -30,6 +53,7 @@ static const ERR_STRING_DATA KDF_str_functs[] = {
{ERR_PACK(ERR_LIB_KDF, KDF_F_PKEY_TLS1_PRF_DERIVE, 0),
"pkey_tls1_prf_derive"},
{ERR_PACK(ERR_LIB_KDF, KDF_F_PKEY_TLS1_PRF_INIT, 0), "pkey_tls1_prf_init"},
+ {ERR_PACK(ERR_LIB_KDF, KDF_F_SCRYPT_SET_MEMBUF, 0), "scrypt_set_membuf"},
{ERR_PACK(ERR_LIB_KDF, KDF_F_TLS1_PRF_ALG, 0), "tls1_prf_alg"},
{0, NULL}
};
@@ -50,6 +74,8 @@ static const ERR_STRING_DATA KDF_str_reasons[] = {
"unknown parameter type"},
{ERR_PACK(ERR_LIB_KDF, 0, KDF_R_VALUE_ERROR), "value error"},
{ERR_PACK(ERR_LIB_KDF, 0, KDF_R_VALUE_MISSING), "value missing"},
+ {ERR_PACK(ERR_LIB_KDF, 0, KDF_R_WRONG_OUTPUT_BUFFER_SIZE),
+ "wrong output buffer size"},
{0, NULL}
};
diff --git a/crypto/kdf/kdf_local.h b/crypto/kdf/kdf_local.h
new file mode 100644
index 0000000000..4956dad920
--- /dev/null
+++ b/crypto/kdf/kdf_local.h
@@ -0,0 +1,22 @@
+/*
+ * Copyright 2018 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ *
+ * Licensed under the Apache License 2.0 (the "License"). You may not use
+ * this file except in compliance with the License. You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+int call_ctrl(int (*ctrl)(EVP_KDF_IMPL *impl, int cmd, va_list args),
+ EVP_KDF_IMPL *impl, int cmd, ...);
+int kdf_str2ctrl(EVP_KDF_IMPL *impl,
+ int (*ctrl)(EVP_KDF_IMPL *impl, int cmd, va_list args),
+ int cmd, const char *str);
+int kdf_hex2ctrl(EVP_KDF_IMPL *impl,
+ int (*ctrl)(EVP_KDF_IMPL *impl, int cmd, va_list args),
+ int cmd, const char *hex);
+int kdf_md2ctrl(EVP_KDF_IMPL *impl,
+ int (*ctrl)(EVP_KDF_IMPL *impl, int cmd, va_list args),
+ int cmd, const char *md_name);
+
diff --git a/crypto/kdf/kdf_util.c b/crypto/kdf/kdf_util.c
new file mode 100644
index 0000000000..8eb6d26b34
--- /dev/null
+++ b/crypto/kdf/kdf_util.c
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2018 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ *
+ * Licensed under the Apache License 2.0 (the "License"). You may not use
+ * this file except in compliance with the License. You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#include <string.h>
+#include <stdarg.h>
+#include <openssl/kdf.h>
+#include <openssl/evp.h>
+#include "internal/cryptlib.h"
+#include "internal/evp_int.h"
+#include "internal/numbers.h"
+#include "kdf_local.h"
+
+int call_ctrl(int (*ctrl)(EVP_KDF_IMPL *impl, int cmd, va_list args),
+ EVP_KDF_IMPL *impl, int cmd, ...)
+{
+ int ret;
+ va_list args;
+
+ va_start(args, cmd);
+ ret = ctrl(impl, cmd, args);
+ va_end(args);
+
+ return ret;
+}
+
+/* Utility functions to send a string or hex string to a ctrl */
+
+int kdf_str2ctrl(EVP_KDF_IMPL *impl,
+ int (*ctrl)(EVP_KDF_IMPL *impl, int cmd, va_list args),
+ int cmd, const char *str)
+{
+ return call_ctrl(ctrl, impl, cmd, (const unsigned char *)str, strlen(str));
+}
+
+int kdf_hex2ctrl(EVP_KDF_IMPL *impl,
+ int (*ctrl)(EVP_KDF_IMPL *impl, int cmd, va_list args),
+ int cmd, const char *hex)
+{
+ unsigned char *bin;
+ long binlen;
+ int ret = -1;
+
+ bin = OPENSSL_hexstr2buf(hex, &binlen);
+ if (bin == NULL)
+ return 0;
+
+ if (binlen <= INT_MAX)
+ ret = call_ctrl(ctrl, impl, cmd, bin, (size_t)binlen);
+ OPENSSL_free(bin);
+ return ret;
+}
+
+/* Pass a message digest to a ctrl */
+int kdf_md2ctrl(EVP_KDF_IMPL *impl,
+ int (*ctrl)(EVP_KDF_IMPL *impl, int cmd, va_list args),
+ int cmd, const char *md_name)
+{
+ const EVP_MD *md;
+
+ if (md_name == NULL || (md = EVP_get_digestbyname(md_name)) == NULL) {
+ KDFerr(KDF_F_KDF_MD2CTRL, KDF_R_INVALID_DIGEST);
+ return 0;
+ }
+ return call_ctrl(ctrl, impl, cmd, md);
+}
+
diff --git a/crypto/kdf/pbkdf2.c b/crypto/kdf/pbkdf2.c
new file mode 100644
index 0000000000..bf1ac6d78d
--- /dev/null
+++ b/crypto/kdf/pbkdf2.c
@@ -0,0 +1,264 @@
+/*
+ * Copyright 2018 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the Apache License 2.0 (the "License"). You may not use
+ * this file except in compliance with the License. You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <openssl/hmac.h>
+#include <openssl/evp.h>
+#include <openssl/kdf.h>
+#include "internal/cryptlib.h"
+#include "internal/evp_int.h"
+#include "kdf_local.h"
+
+static void kdf_pbkdf2_reset(EVP_KDF_IMPL *impl);
+static void kdf_pbkdf2_init(EVP_KDF_IMPL *impl);
+static int pkcs5_pbkdf2_alg(const char *pass, size_t passlen,
+ const unsigned char *salt, int saltlen, int iter,
+ const EVP_MD *digest, unsigned char *key,
+ size_t keylen);
+
+struct evp_kdf_impl_st {
+ unsigned char *pass;
+ size_t pass_len;
+ unsigned char *salt;
+ size_t salt_len;
+ int iter;
+ const EVP_MD *md;
+};
+
+static EVP_KDF_IMPL *kdf_pbkdf2_new(void)
+{
+ EVP_KDF_IMPL *impl;
+
+ impl = OPENSSL_zalloc(sizeof(*impl));
+ if (impl == NULL) {
+ KDFerr(KDF_F_KDF_PBKDF2_NEW, ERR_R_MALLOC_FAILURE);
+ return NULL;
+ }
+ kdf_pbkdf2_init(impl);
+ return impl;
+}
+
+static void kdf_pbkdf2_free(EVP_KDF_IMPL *impl)
+{
+ kdf_pbkdf2_reset(impl);
+ OPENSSL_free(impl);
+}
+
+static void kdf_pbkdf2_reset(EVP_KDF_IMPL *impl)
+{
+ OPENSSL_free(impl->salt);
+ OPENSSL_clear_free(impl->pass, impl->pass_len);
+ memset(impl, 0, sizeof(*impl));
+ kdf_pbkdf2_init(impl);
+}
+
+static void kdf_pbkdf2_init(EVP_KDF_IMPL *impl)
+{
+ impl->iter = PKCS5_DEFAULT_ITER;
+ impl->md = EVP_sha1();
+}
+
+static int pbkdf2_set_membuf(unsigned char **buffer, size_t *buflen,
+ const unsigned char *new_buffer,
+ size_t new_buflen)
+{
+ if (new_buffer == NULL)
+ return 1;
+
+ OPENSSL_clear_free(*buffer, *buflen);
+
+ if (new_buflen > 0) {
+ *buffer = OPENSSL_memdup(new_buffer, new_buflen);
+ } else {
+ *buffer = OPENSSL_malloc(1);
+ }
+ if (*buffer == NULL) {
+ KDFerr(KDF_F_PBKDF2_SET_MEMBUF, ERR_R_MALLOC_FAILURE);
+ return 0;
+ }
+
+ *buflen = new_buflen;
+ return 1;
+}
+
+static int kdf_pbkdf2_ctrl(EVP_KDF_IMPL *impl, int cmd, va_list args)
+{
+ int iter;
+ const unsigned char *p;
+ size_t len;
+ const EVP_MD *md;
+
+ switch (cmd) {
+ case EVP_KDF_CTRL_SET_PASS:
+ p = va_arg(args, const unsigned char *);
+ len = va_arg(args, size_t);
+ return pbkdf2_set_membuf(&impl->pass, &impl->pass_len, p, len);
+
+ case EVP_KDF_CTRL_SET_SALT:
+ p = va_arg(args, const unsigned char *);
+ len = va_arg(args, size_t);
+ return pbkdf2_set_membuf(&impl->salt, &impl->salt_len, p, len);
+
+ case EVP_KDF_CTRL_SET_ITER:
+ iter = va_arg(args, int);
+ if (iter < 1)
+ return 0;
+
+ impl->iter = iter;
+ return 1;
+
+ case EVP_KDF_CTRL_SET_MD:
+ md = va_arg(args, const EVP_MD *);
+ if (md == NULL)
+ return 0;
+
+ impl->md = md;
+ return 1;
+
+ default:
+ return -2;
+ }
+}
+
+static int kdf_pbkdf2_ctrl_str(EVP_KDF_IMPL *impl, const char *type,
+ const char *value)
+{
+ if (value == NULL) {
+ KDFerr(KDF_F_KDF_PBKDF2_CTRL_STR, KDF_R_VALUE_MISSING);
+ return 0;
+ }
+
+ if (strcmp(type, "pass") == 0)
+ return kdf_str2ctrl(impl, kdf_pbkdf2_ctrl, EVP_KDF_CTRL_SET_PASS,
+ value);
+
+ if (strcmp(type, "hexpass") == 0)
+ return kdf_hex2ctrl(impl, kdf_pbkdf2_ctrl, EVP_KDF_CTRL_SET_PASS,
+ value);
+
+ if (strcmp(type, "salt") == 0)
+ return kdf_str2ctrl(impl, kdf_pbkdf2_ctrl, EVP_KDF_CTRL_SET_SALT,
+ value);
+
+ if (strcmp(type, "hexsalt") == 0)
+ return kdf_hex2ctrl(impl, kdf_pbkdf2_ctrl, EVP_KDF_CTRL_SET_SALT,
+ value);
+
+ if (strcmp(type, "iter") == 0)
+ return call_ctrl(kdf_pbkdf2_ctrl, impl, EVP_KDF_CTRL_SET_ITER,
+ atoi(value));
+
+ if (strcmp(type, "digest") == 0)
+ return kdf_md2ctrl(impl, kdf_pbkdf2_ctrl, EVP_KDF_CTRL_SET_MD, value);
+
+ return -2;
+}
+
+static int kdf_pbkdf2_derive(EVP_KDF_IMPL *impl, unsigned char *key,
+ size_t keylen)
+{
+ if (impl->pass == NULL) {
+ KDFerr(KDF_F_KDF_PBKDF2_DERIVE, KDF_R_MISSING_PASS);
+ return 0;
+ }
+
+ if (impl->salt == NULL) {
+ KDFerr(KDF_F_KDF_PBKDF2_DERIVE, KDF_R_MISSING_SALT);
+ return 0;
+ }
+
+ return pkcs5_pbkdf2_alg((char *)impl->pass, impl->pass_len,
+ impl->salt, impl->salt_len, impl->iter,
+ impl->md, key, keylen);
+}
+
+const EVP_KDF_METHOD pbkdf2_kdf_meth = {
+ EVP_KDF_PBKDF2,
+ kdf_pbkdf2_new,
+ kdf_pbkdf2_free,
+ kdf_pbkdf2_reset,
+ kdf_pbkdf2_ctrl,
+ kdf_pbkdf2_ctrl_str,
+ NULL,
+ kdf_pbkdf2_derive
+};
+
+/*
+ * This is an implementation of PKCS#5 v2.0 password based encryption key
+ * derivation function PBKDF2. SHA1 version verified against test vectors
+ * posted by Peter Gutmann to the PKCS-TNG mailing list.
+ */
+
+static int pkcs5_pbkdf2_alg(const char *pass, size_t passlen,
+ const unsigned char *salt, int saltlen, int iter,
+ const EVP_MD *digest, unsigned char *key,
+ size_t keylen)
+{
+ int ret = 0;
+ unsigned char digtmp[EVP_MAX_MD_SIZE], *p, itmp[4];
+ int cplen, j, k, tkeylen, mdlen;
+ unsigned long i = 1;
+ HMAC_CTX *hctx_tpl = NULL, *hctx = NULL;
+
+ mdlen = EVP_MD_size(digest);
+ if (mdlen < 0)
+ return 0;
+
+ hctx_tpl = HMAC_CTX_new();
+ if (hctx_tpl == NULL)
+ return 0;
+ p = key;
+ tkeylen = keylen;
+ if (!HMAC_Init_ex(hctx_tpl, pass, passlen, digest, NULL))
+ goto err;
+ hctx = HMAC_CTX_new();
+ if (hctx == NULL)
+ goto err;
+ while (tkeylen) {
+ if (tkeylen > mdlen)
+ cplen = mdlen;
+ else
+ cplen = tkeylen;
+ /*
+ * We are unlikely to ever use more than 256 blocks (5120 bits!) but
+ * just in case...
+ */
+ itmp[0] = (unsigned char)((i >> 24) & 0xff);
+ itmp[1] = (unsigned char)((i >> 16) & 0xff);
+ itmp[2] = (unsigned char)((i >> 8) & 0xff);
+ itmp[3] = (unsigned char)(i & 0xff);
+ if (!HMAC_CTX_copy(hctx, hctx_tpl))
+ goto err;
+ if (!HMAC_Update(hctx, salt, saltlen)
+ || !HMAC_Update(hctx, itmp, 4)
+ || !HMAC_Final(hctx, digtmp, NULL))
+ goto err;
+ memcpy(p, digtmp, cplen);
+ for (j = 1; j < iter; j++) {
+ if (!HMAC_CTX_copy(hctx, hctx_tpl))
+ goto err;
+ if (!HMAC_Update(hctx, digtmp, mdlen)
+ || !HMAC_Final(hctx, digtmp, NULL))
+ goto err;
+ for (k = 0; k < cplen; k++)
+ p[k] ^= digtmp[k];
+ }
+ tkeylen -= cplen;
+ i++;
+ p += cplen;
+ }
+ ret = 1;
+
+err:
+ HMAC_CTX_free(hctx);
+ HMAC_CTX_free(hctx_tpl);
+ return ret;
+}
diff --git a/crypto/kdf/scrypt.c b/crypto/kdf/scrypt.c
index 6b35b77fd9..ee77f1ef7c 100644
--- a/crypto/kdf/scrypt.c
+++ b/crypto/kdf/scrypt.c
@@ -8,25 +8,34 @@
*/
#include <stdlib.h>
+#include <stdarg.h>
#include <string.h>
-#include <openssl/hmac.h>
-#include <openssl/kdf.h>
#include <openssl/evp.h>
-#include "internal/cryptlib.h"
+#include <openssl/kdf.h>
+#include <openssl/err.h>
#include "internal/evp_int.h"
+#include "internal/numbers.h"
+#include "kdf_local.h"
#ifndef OPENSSL_NO_SCRYPT
+static void kdf_scrypt_reset(EVP_KDF_IMPL *impl);
+static void kdf_scrypt_init(EVP_KDF_IMPL *impl);
static int atou64(const char *nptr, uint64_t *result);
+static int scrypt_alg(const char *pass, size_t passlen,
+ const unsigned char *salt, size_t saltlen,
+ uint64_t N, uint64_t r, uint64_t p, uint64_t maxmem,
+ unsigned char *key, size_t keylen);
-typedef struct {
+struct evp_kdf_impl_st {
unsigned char *pass;
size_t pass_len;
unsigned char *salt;
size_t salt_len;
- uint64_t N, r, p;
+ uint64_t N;
+ uint32_t r, p;
uint64_t maxmem_bytes;
-} SCRYPT_PKEY_CTX;
+};
/* Custom uint64_t parser since we do not have strtoull */
static int atou64(const char *nptr, uint64_t *result)
@@ -53,51 +62,53 @@ static int atou64(const char *nptr, uint64_t *result)