openssl/openssl-1.1.1-krb5-kdf.patch

3031 lines
102 KiB
Diff
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

diff -up openssl-1.1.1d/crypto/err/openssl.txt.krb5-kdf openssl-1.1.1d/crypto/err/openssl.txt
--- openssl-1.1.1d/crypto/err/openssl.txt.krb5-kdf 2019-11-14 15:07:05.320094521 +0100
+++ openssl-1.1.1d/crypto/err/openssl.txt 2019-11-14 15:07:05.342094129 +0100
@@ -821,6 +821,11 @@ EVP_F_S390X_AES_GCM_CTRL:201:s390x_aes_g
EVP_F_SCRYPT_ALG:228:scrypt_alg
EVP_F_UPDATE:173:update
KDF_F_HKDF_EXTRACT:112:HKDF_Extract
+KDF_F_KBKDF_CTRL:134:kbkdf_ctrl
+KDF_F_KBKDF_CTRL_STR:135:kbkdf_ctrl_str
+KDF_F_KBKDF_DERIVE:136:kbkdf_derive
+KDF_F_KBKDF_NEW:137:kbkdf_new
+KDF_F_KDF_CIPHER2CTRL:138:kdf_cipher2ctrl
KDF_F_KDF_HKDF_DERIVE:113:kdf_hkdf_derive
KDF_F_KDF_HKDF_NEW:114:kdf_hkdf_new
KDF_F_KDF_HKDF_SIZE:115:kdf_hkdf_size
@@ -840,6 +845,8 @@ KDF_F_KDF_SSHKDF_NEW:133:kdf_sshkdf_new
KDF_F_KDF_TLS1_PRF_CTRL_STR:125:kdf_tls1_prf_ctrl_str
KDF_F_KDF_TLS1_PRF_DERIVE:126:kdf_tls1_prf_derive
KDF_F_KDF_TLS1_PRF_NEW:127:kdf_tls1_prf_new
+KDF_F_KRB5KDF:139:KRB5KDF
+KDF_F_KRB5KDF_DERIVE:140:krb5kdf_derive
KDF_F_PBKDF2_SET_MEMBUF:128:pbkdf2_set_membuf
KDF_F_PKEY_HKDF_CTRL_STR:103:pkey_hkdf_ctrl_str
KDF_F_PKEY_HKDF_DERIVE:102:pkey_hkdf_derive
@@ -853,6 +860,9 @@ KDF_F_PKEY_TLS1_PRF_CTRL_STR:100:pkey_tl
KDF_F_PKEY_TLS1_PRF_DERIVE:101:pkey_tls1_prf_derive
KDF_F_PKEY_TLS1_PRF_INIT:110:pkey_tls1_prf_init
KDF_F_SCRYPT_SET_MEMBUF:129:scrypt_set_membuf
+KDF_F_SSKDF_DERIVE:141:sskdf_derive
+KDF_F_SSKDF_NEW:142:sskdf_new
+KDF_F_SSKDF_SIZE:143:sskdf_size
KDF_F_TLS1_PRF_ALG:111:tls1_prf_alg
OBJ_F_OBJ_ADD_OBJECT:105:OBJ_add_object
OBJ_F_OBJ_ADD_SIGID:107:OBJ_add_sigid
@@ -2325,7 +2335,13 @@ EVP_R_UNSUPPORTED_SALT_TYPE:126:unsuppor
EVP_R_WRAP_MODE_NOT_ALLOWED:170:wrap mode not allowed
EVP_R_WRONG_FINAL_BLOCK_LENGTH:109:wrong final block length
EVP_R_XTS_DUPLICATED_KEYS:183:xts duplicated keys
+KDF_R_FAILED_TO_GENERATE_KEY:118:failed to generate key
+KDF_R_INVALID_CIPHER:116:invalid cipher
+KDF_R_INVALID_CONSTANT_LENGTH:119:invalid constant length
KDF_R_INVALID_DIGEST:100:invalid digest
+KDF_R_INVALID_SEED_LENGTH:117:invalid seed length
+KDF_R_MISSING_CIPHER:120:missing cipher
+KDF_R_MISSING_CONSTANT:121:missing constant
KDF_R_MISSING_ITERATION_COUNT:109:missing iteration count
KDF_R_MISSING_KEY:104:missing key
KDF_R_MISSING_MESSAGE_DIGEST:105:missing message digest
@@ -2340,6 +2356,7 @@ KDF_R_MISSING_XCGHASH:115:missing xcghas
KDF_R_UNKNOWN_PARAMETER_TYPE:103:unknown parameter type
KDF_R_VALUE_ERROR:108:value error
KDF_R_VALUE_MISSING:102:value missing
+KDF_R_WRONG_FINAL_BLOCK_LENGTH:120:wrong final block length
KDF_R_WRONG_OUTPUT_BUFFER_SIZE:112:wrong output buffer size
OBJ_R_OID_EXISTS:102:oid exists
OBJ_R_UNKNOWN_NID:101:unknown nid
diff -up openssl-1.1.1d/crypto/evp/kdf_lib.c.krb5-kdf openssl-1.1.1d/crypto/evp/kdf_lib.c
--- openssl-1.1.1d/crypto/evp/kdf_lib.c.krb5-kdf 2019-11-14 15:07:05.320094521 +0100
+++ openssl-1.1.1d/crypto/evp/kdf_lib.c 2019-11-14 15:07:05.342094129 +0100
@@ -31,6 +31,9 @@ static const EVP_KDF_METHOD *standard_me
&tls1_prf_kdf_meth,
&hkdf_kdf_meth,
&sshkdf_kdf_meth,
+ &kb_kdf_meth,
+ &krb5kdf_kdf_meth,
+ &ss_kdf_meth
};
DECLARE_OBJ_BSEARCH_CMP_FN(const EVP_KDF_METHOD *, const EVP_KDF_METHOD *,
diff -up openssl-1.1.1d/include/crypto/evp.h.krb5-kdf openssl-1.1.1d/include/crypto/evp.h
--- openssl-1.1.1d/include/crypto/evp.h.krb5-kdf 2019-11-14 15:07:05.320094521 +0100
+++ openssl-1.1.1d/include/crypto/evp.h 2019-11-14 15:07:05.342094129 +0100
@@ -130,6 +130,9 @@ extern const EVP_KDF_METHOD scrypt_kdf_m
extern const EVP_KDF_METHOD tls1_prf_kdf_meth;
extern const EVP_KDF_METHOD hkdf_kdf_meth;
extern const EVP_KDF_METHOD sshkdf_kdf_meth;
+extern const EVP_KDF_METHOD kb_kdf_meth;
+extern const EVP_KDF_METHOD krb5kdf_kdf_meth;
+extern const EVP_KDF_METHOD ss_kdf_meth;
struct evp_md_st {
int type;
diff -up openssl-1.1.1d/crypto/kdf/build.info.krb5-kdf openssl-1.1.1d/crypto/kdf/build.info
--- openssl-1.1.1d/crypto/kdf/build.info.krb5-kdf 2019-11-14 15:07:05.320094521 +0100
+++ openssl-1.1.1d/crypto/kdf/build.info 2019-11-14 15:07:05.342094129 +0100
@@ -1,3 +1,3 @@
LIBS=../../libcrypto
SOURCE[../../libcrypto]=\
- tls1_prf.c kdf_err.c kdf_util.c hkdf.c scrypt.c pbkdf2.c sshkdf.c
+ tls1_prf.c kdf_err.c kdf_util.c hkdf.c scrypt.c pbkdf2.c sshkdf.c kbkdf.c krb5kdf.c sskdf.c
diff -up openssl-1.1.1d/crypto/kdf/kbkdf.c.krb5-kdf openssl-1.1.1d/crypto/kdf/kbkdf.c
--- openssl-1.1.1d/crypto/kdf/kbkdf.c.krb5-kdf 2019-11-14 15:07:05.343094112 +0100
+++ openssl-1.1.1d/crypto/kdf/kbkdf.c 2019-11-18 17:21:58.326635901 +0100
@@ -0,0 +1,540 @@
+/*
+ * Copyright 2019 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 2019 Red Hat, Inc.
+ *
+ * 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
+ */
+
+/*
+ * This implements https://csrc.nist.gov/publications/detail/sp/800-108/final
+ * section 5.1 ("counter mode") and section 5.2 ("feedback mode") in both HMAC
+ * and CMAC. That document does not name the KDFs it defines; the name is
+ * derived from
+ * https://csrc.nist.gov/Projects/Cryptographic-Algorithm-Validation-Program/Key-Derivation
+ *
+ * Note that section 5.3 ("double-pipeline mode") is not implemented, though
+ * it would be possible to do so in the future.
+ *
+ * These versions all assume the counter is used. It would be relatively
+ * straightforward to expose a configuration handle should the need arise.
+ *
+ * Variable names attempt to match those of SP800-108.
+ */
+
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <openssl/evp.h>
+#include <openssl/hmac.h>
+#include <openssl/cmac.h>
+#include <openssl/kdf.h>
+
+#include "internal/numbers.h"
+#include "internal/cryptlib.h"
+#include "crypto/evp.h"
+#include "kdf_local.h"
+
+#include "e_os.h"
+
+#ifdef MIN
+# undef MIN
+#endif
+#define MIN(a, b) ((a) < (b)) ? (a) : (b)
+
+typedef struct {
+ int mac_type;
+ union {
+ HMAC_CTX *hmac;
+ CMAC_CTX *cmac;
+ } m;
+} MAC_CTX;
+
+/* Our context structure. */
+struct evp_kdf_impl_st {
+ int mode;
+
+ MAC_CTX *ctx_init;
+
+ const EVP_CIPHER *cipher;
+ const EVP_MD *md;
+
+ /* Names are lowercased versions of those found in SP800-108. */
+ unsigned char *ki;
+ size_t ki_len;
+ unsigned char *label;
+ size_t label_len;
+ unsigned char *context;
+ size_t context_len;
+ unsigned char *iv;
+ size_t iv_len;
+};
+
+static MAC_CTX *EVP_MAC_CTX_new(int mac_type)
+{
+ MAC_CTX *ctx;
+
+ ctx = OPENSSL_zalloc(sizeof(*ctx));
+ if (ctx == NULL)
+ return NULL;
+
+ ctx->mac_type = mac_type;
+ if (mac_type == EVP_KDF_KB_MAC_TYPE_HMAC) {
+ if ((ctx->m.hmac = HMAC_CTX_new()) == NULL)
+ goto err;
+ } else {
+ if ((ctx->m.cmac = CMAC_CTX_new()) == NULL)
+ goto err;
+ }
+ return ctx;
+
+err:
+ OPENSSL_free(ctx);
+ return NULL;
+}
+
+static void EVP_MAC_CTX_free(MAC_CTX *ctx)
+{
+ if (ctx == NULL)
+ return;
+
+ if (ctx->mac_type == EVP_KDF_KB_MAC_TYPE_HMAC)
+ HMAC_CTX_free(ctx->m.hmac);
+ else
+ CMAC_CTX_free(ctx->m.cmac);
+ OPENSSL_free(ctx);
+}
+
+static MAC_CTX *EVP_MAC_CTX_dup(MAC_CTX *sctx)
+{
+ MAC_CTX *ctx;
+
+ ctx = OPENSSL_zalloc(sizeof(*sctx));
+ if (ctx == NULL)
+ return NULL;
+
+ ctx->mac_type = sctx->mac_type;
+ if (sctx->mac_type == EVP_KDF_KB_MAC_TYPE_HMAC) {
+ if ((ctx->m.hmac = HMAC_CTX_new()) == NULL
+ || HMAC_CTX_copy(ctx->m.hmac, sctx->m.hmac) <= 0)
+ goto err;
+ } else {
+ if ((ctx->m.cmac = CMAC_CTX_new()) == NULL
+ || CMAC_CTX_copy(ctx->m.cmac, sctx->m.cmac) <= 0)
+ goto err;
+ }
+ return ctx;
+
+err:
+ EVP_MAC_CTX_free(ctx);
+ return NULL;
+}
+
+static size_t EVP_MAC_size(MAC_CTX *ctx)
+{
+ if (ctx->mac_type == EVP_KDF_KB_MAC_TYPE_HMAC) {
+ const EVP_MD *md;
+
+ if (ctx->m.hmac == NULL)
+ return 0;
+ if ((md = HMAC_CTX_get_md(ctx->m.hmac)) == NULL)
+ return 0;
+ return (size_t)EVP_MD_size(md);
+ } else {
+ const EVP_CIPHER_CTX *cctx;
+
+ if (ctx->m.cmac == NULL)
+ return 0;
+ if ((cctx = CMAC_CTX_get0_cipher_ctx(ctx->m.cmac)) == NULL)
+ return 0;
+ return EVP_CIPHER_CTX_block_size(cctx);
+ }
+}
+
+static int EVP_MAC_update(MAC_CTX *ctx, const unsigned char *data,
+ size_t datalen)
+{
+ if (ctx->mac_type == EVP_KDF_KB_MAC_TYPE_HMAC)
+ return HMAC_Update(ctx->m.hmac, data, datalen);
+ else
+ return CMAC_Update(ctx->m.cmac, data, datalen);
+}
+
+static int EVP_MAC_final(MAC_CTX *ctx, unsigned char *out,
+ size_t *outl, size_t outsize)
+{
+ if (outsize != EVP_MAC_size(ctx))
+ /* we do not cope with anything else */
+ return 0;
+
+ if (ctx->mac_type == EVP_KDF_KB_MAC_TYPE_HMAC) {
+ unsigned int intsize = (unsigned int)outsize;
+ int ret;
+
+ ret = HMAC_Final(ctx->m.hmac, out, &intsize);
+ if (outl != NULL)
+ *outl = intsize;
+ return ret;
+ } else {
+ size_t size = outsize;
+ int ret;
+
+ ret = CMAC_Final(ctx->m.cmac, out, &size);
+ if (outl != NULL)
+ *outl = size;
+ return ret;
+ }
+}
+
+static int evp_mac_init(MAC_CTX *ctx, const EVP_MD *md,
+ const EVP_CIPHER *cipher, unsigned char *key, size_t keylen)
+{
+ if (ctx->mac_type == EVP_KDF_KB_MAC_TYPE_HMAC) {
+ if (md == NULL)
+ return 0;
+ return HMAC_Init_ex(ctx->m.hmac, key, (int)keylen, md, NULL);
+ } else {
+ if (cipher == NULL)
+ return 0;
+ return CMAC_Init(ctx->m.cmac, key, keylen, cipher, NULL);
+ }
+}
+
+static void kbkdf_reset(EVP_KDF_IMPL *ctx);
+
+/* Not all platforms have htobe32(). */
+static uint32_t be32(uint32_t host)
+{
+ uint32_t big = 0;
+ const union {
+ long one;
+ char little;
+ } is_endian = { 1 };
+
+ if (!is_endian.little)
+ return host;
+
+ big |= (host & 0xff000000) >> 24;
+ big |= (host & 0x00ff0000) >> 8;
+ big |= (host & 0x0000ff00) << 8;
+ big |= (host & 0x000000ff) << 24;
+ return big;
+}
+
+static EVP_KDF_IMPL *kbkdf_new(void)
+{
+ EVP_KDF_IMPL *ctx;
+
+ ctx = OPENSSL_zalloc(sizeof(*ctx));
+ if (ctx == NULL) {
+ KDFerr(KDF_F_KBKDF_NEW, ERR_R_MALLOC_FAILURE);
+ return NULL;
+ }
+
+ return ctx;
+}
+
+static void kbkdf_free(EVP_KDF_IMPL *ctx)
+{
+ kbkdf_reset(ctx);
+ OPENSSL_free(ctx);
+}
+
+static void kbkdf_reset(EVP_KDF_IMPL *ctx)
+{
+ EVP_MAC_CTX_free(ctx->ctx_init);
+ OPENSSL_clear_free(ctx->context, ctx->context_len);
+ OPENSSL_clear_free(ctx->label, ctx->label_len);
+ OPENSSL_clear_free(ctx->ki, ctx->ki_len);
+ OPENSSL_clear_free(ctx->iv, ctx->iv_len);
+ memset(ctx, 0, sizeof(*ctx));
+}
+
+/* SP800-108 section 5.1 or section 5.2 depending on mode. */
+static int derive(MAC_CTX *ctx_init, int mode, unsigned char *iv,
+ size_t iv_len, unsigned char *label, size_t label_len,
+ unsigned char *context, size_t context_len,
+ unsigned char *k_i, size_t h, uint32_t l, unsigned char *ko,
+ size_t ko_len)
+{
+ int ret = 0;
+ MAC_CTX *ctx = NULL;
+ size_t written = 0, to_write, k_i_len = iv_len;
+ const unsigned char zero = 0;
+ uint32_t counter, i;
+
+ /* Setup K(0) for feedback mode. */
+ if (iv_len > 0)
+ memcpy(k_i, iv, iv_len);
+
+ for (counter = 1; written < ko_len; counter++) {
+ i = be32(counter);
+
+ ctx = EVP_MAC_CTX_dup(ctx_init);
+ if (ctx == NULL)
+ goto done;
+
+ /* Perform feedback, if appropriate. */
+ if (mode == EVP_KDF_KB_MODE_FEEDBACK && !EVP_MAC_update(ctx, k_i, k_i_len))
+ goto done;
+
+ if (!EVP_MAC_update(ctx, (unsigned char *)&i, 4)
+ || !EVP_MAC_update(ctx, label, label_len)
+ || !EVP_MAC_update(ctx, &zero, 1)
+ || !EVP_MAC_update(ctx, context, context_len)
+ || !EVP_MAC_update(ctx, (unsigned char *)&l, 4)
+ || !EVP_MAC_final(ctx, k_i, NULL, h))
+ goto done;
+
+ to_write = ko_len - written;
+ memcpy(ko + written, k_i, MIN(to_write, h));
+ written += h;
+
+ k_i_len = h;
+ EVP_MAC_CTX_free(ctx);
+ ctx = NULL;
+ }
+
+ ret = 1;
+done:
+ EVP_MAC_CTX_free(ctx);
+ return ret;
+}
+
+static int kbkdf_derive(EVP_KDF_IMPL *ctx, unsigned char *key, size_t keylen)
+{
+ int ret = 0;
+ unsigned char *k_i = NULL;
+ uint32_t l = be32(keylen * 8);
+ size_t h = 0;
+
+ /* label, context, and iv are permitted to be empty. Check everything
+ * else. */
+ if (ctx->ctx_init == NULL
+ || evp_mac_init(ctx->ctx_init, ctx->md, ctx->cipher, ctx->ki, ctx->ki_len) <= 0) {
+ if (ctx->ki_len == 0 || ctx->ki == NULL) {
+ KDFerr(KDF_F_KBKDF_DERIVE, KDF_R_MISSING_KEY);
+ return 0;
+ }
+ /* Could either be missing MAC or missing message digest or missing
+ * cipher - arbitrarily, I pick this one. */
+ KDFerr(KDF_F_KBKDF_DERIVE, KDF_R_MISSING_PARAMETER);
+ return 0;
+ }
+
+ h = EVP_MAC_size(ctx->ctx_init);
+ if (h == 0)
+ goto done;
+ if (ctx->iv_len != 0 && ctx->iv_len != h) {
+ KDFerr(KDF_F_KBKDF_DERIVE, KDF_R_INVALID_SEED_LENGTH);
+ goto done;
+ }
+
+ k_i = OPENSSL_zalloc(h);
+ if (k_i == NULL)
+ goto done;
+
+ ret = derive(ctx->ctx_init, ctx->mode, ctx->iv, ctx->iv_len, ctx->label,
+ ctx->label_len, ctx->context, ctx->context_len, k_i, h, l,
+ key, keylen);
+done:
+ if (ret != 1)
+ OPENSSL_cleanse(key, keylen);
+ OPENSSL_clear_free(k_i, h);
+ return ret;
+}
+
+static size_t kbkdf_size(EVP_KDF_IMPL *ctx)
+{
+ return UINT32_MAX/8;
+}
+
+static int kbkdf_parse_buffer_arg(unsigned char **dst, size_t *dst_len,
+ va_list args)
+{
+ const unsigned char *p;
+ size_t len;
+
+ p = va_arg(args, const unsigned char *);
+ len = va_arg(args, size_t);
+ OPENSSL_clear_free(*dst, *dst_len);
+ if (len == 0) {
+ *dst = NULL;
+ *dst_len = 0;
+ return 1;
+ }
+
+ *dst = OPENSSL_memdup(p, len);
+ if (*dst == NULL)
+ return 0;
+
+ *dst_len = len;
+ return 1;
+}
+
+static int kbkdf_ctrl(EVP_KDF_IMPL *ctx, int cmd, va_list args)
+{
+ int t;
+
+ switch (cmd) {
+ case EVP_KDF_CTRL_SET_MD:
+ ctx->md = va_arg(args, const EVP_MD *);
+ if (ctx->md == NULL)
+ return 0;
+
+ return 1;
+
+ case EVP_KDF_CTRL_SET_CIPHER:
+ ctx->cipher = va_arg(args, const EVP_CIPHER *);
+ if (ctx->cipher == NULL)
+ return 0;
+
+ return 1;
+
+ case EVP_KDF_CTRL_SET_KEY:
+ return kbkdf_parse_buffer_arg(&ctx->ki,
+ &ctx->ki_len, args);
+
+ case EVP_KDF_CTRL_SET_SALT:
+ return kbkdf_parse_buffer_arg(&ctx->label,
+ &ctx->label_len, args);
+
+ case EVP_KDF_CTRL_SET_KB_INFO:
+ return kbkdf_parse_buffer_arg(&ctx->context,
+ &ctx->context_len, args);
+
+ case EVP_KDF_CTRL_SET_KB_SEED:
+ return kbkdf_parse_buffer_arg(&ctx->iv,
+ &ctx->iv_len, args);
+
+ case EVP_KDF_CTRL_SET_KB_MODE:
+ t = va_arg(args, int);
+ if (t != EVP_KDF_KB_MODE_COUNTER && t != EVP_KDF_KB_MODE_FEEDBACK ) {
+ KDFerr(KDF_F_KBKDF_CTRL, KDF_R_VALUE_ERROR);
+ return 0;
+ }
+ ctx->mode = t;
+ return 1;
+
+ case EVP_KDF_CTRL_SET_KB_MAC_TYPE:
+ t = va_arg(args, int);
+ if (t != EVP_KDF_KB_MAC_TYPE_HMAC && t != EVP_KDF_KB_MAC_TYPE_CMAC ) {
+ KDFerr(KDF_F_KBKDF_CTRL, KDF_R_VALUE_ERROR);
+ return 0;
+ }
+
+ if (ctx->ctx_init != NULL) {
+ EVP_MAC_CTX_free(ctx->ctx_init);
+ }
+ ctx->ctx_init = EVP_MAC_CTX_new(t);
+ if (ctx->ctx_init == NULL) {
+ KDFerr(KDF_F_KBKDF_CTRL, ERR_R_MALLOC_FAILURE);
+ return 0;
+ }
+ return 1;
+
+ default:
+ return -2;
+
+ }
+}
+
+static int kbkdf_ctrl_str(EVP_KDF_IMPL *ctx, const char *type,
+ const char *value)
+{
+ if (value == NULL) {
+ KDFerr(KDF_F_KDF_SSHKDF_CTRL_STR, KDF_R_VALUE_MISSING);
+ return 0;
+ }
+
+ if (strcmp(type, "digest") == 0)
+ return kdf_md2ctrl(ctx, kbkdf_ctrl, EVP_KDF_CTRL_SET_MD, value);
+ /* alias, for historical reasons */
+ if (strcmp(type, "md") == 0)
+ return kdf_md2ctrl(ctx, kbkdf_ctrl, EVP_KDF_CTRL_SET_MD, value);
+
+ if (strcmp(type, "cipher") == 0)
+ return kdf_cipher2ctrl(ctx, kbkdf_ctrl, EVP_KDF_CTRL_SET_CIPHER, value);
+
+ if (strcmp(type, "key") == 0)
+ return kdf_str2ctrl(ctx, kbkdf_ctrl,
+ EVP_KDF_CTRL_SET_KEY, value);
+
+ if (strcmp(type, "hexkey") == 0)
+ return kdf_hex2ctrl(ctx, kbkdf_ctrl,
+ EVP_KDF_CTRL_SET_KEY, value);
+
+ if (strcmp(type, "salt") == 0)
+ return kdf_str2ctrl(ctx, kbkdf_ctrl,
+ EVP_KDF_CTRL_SET_SALT, value);
+
+ if (strcmp(type, "hexsalt") == 0)
+ return kdf_hex2ctrl(ctx, kbkdf_ctrl,
+ EVP_KDF_CTRL_SET_SALT, value);
+
+ if (strcmp(type, "info") == 0)
+ return kdf_str2ctrl(ctx, kbkdf_ctrl,
+ EVP_KDF_CTRL_SET_KB_INFO, value);
+
+ if (strcmp(type, "hexinfo") == 0)
+ return kdf_hex2ctrl(ctx, kbkdf_ctrl,
+ EVP_KDF_CTRL_SET_KB_INFO, value);
+
+ if (strcmp(type, "seed") == 0)
+ return kdf_str2ctrl(ctx, kbkdf_ctrl,
+ EVP_KDF_CTRL_SET_KB_SEED, value);
+
+ if (strcmp(type, "hexseed") == 0)
+ return kdf_hex2ctrl(ctx, kbkdf_ctrl,
+ EVP_KDF_CTRL_SET_KB_SEED, value);
+
+ if (strcmp(type, "mode") == 0) {
+ int mode;
+
+ if (strcasecmp(value, "counter") == 0) {
+ mode = EVP_KDF_KB_MODE_COUNTER;
+ } else if (strcasecmp(value, "feedback") == 0) {
+ mode = EVP_KDF_KB_MODE_FEEDBACK;
+ } else {
+ KDFerr(KDF_F_KBKDF_CTRL_STR, KDF_R_VALUE_ERROR);
+ return 0;
+ }
+
+ return call_ctrl(kbkdf_ctrl, ctx, EVP_KDF_CTRL_SET_KB_MODE,
+ mode);
+ }
+
+ if (strcmp(type, "mac_type") == 0) {
+ int mac_type;
+
+ if (strcasecmp(value, "hmac") == 0) {
+ mac_type = EVP_KDF_KB_MAC_TYPE_HMAC;
+ } else if (strcasecmp(value, "cmac") == 0) {
+ mac_type = EVP_KDF_KB_MAC_TYPE_CMAC;
+ } else {
+ KDFerr(KDF_F_KBKDF_CTRL_STR, KDF_R_VALUE_ERROR);
+ return 0;
+ }
+
+ return call_ctrl(kbkdf_ctrl, ctx, EVP_KDF_CTRL_SET_KB_MAC_TYPE,
+ mac_type);
+ }
+
+ KDFerr(KDF_F_KBKDF_CTRL_STR, KDF_R_UNKNOWN_PARAMETER_TYPE);
+ return -2;
+}
+
+const EVP_KDF_METHOD kb_kdf_meth = {
+ EVP_KDF_KB,
+ kbkdf_new,
+ kbkdf_free,
+ kbkdf_reset,
+ kbkdf_ctrl,
+ kbkdf_ctrl_str,
+ kbkdf_size,
+ kbkdf_derive,
+};
+
diff -up openssl-1.1.1d/crypto/kdf/kdf_err.c.krb5-kdf openssl-1.1.1d/crypto/kdf/kdf_err.c
--- openssl-1.1.1d/crypto/kdf/kdf_err.c.krb5-kdf 2019-11-14 15:07:05.320094521 +0100
+++ openssl-1.1.1d/crypto/kdf/kdf_err.c 2019-11-14 15:07:05.343094112 +0100
@@ -15,6 +15,11 @@
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_KBKDF_CTRL, 0), "kbkdf_ctrl"},
+ {ERR_PACK(ERR_LIB_KDF, KDF_F_KBKDF_CTRL_STR, 0), "kbkdf_ctrl_str"},
+ {ERR_PACK(ERR_LIB_KDF, KDF_F_KBKDF_DERIVE, 0), "kbkdf_derive"},
+ {ERR_PACK(ERR_LIB_KDF, KDF_F_KBKDF_NEW, 0), "kbkdf_new"},
+ {ERR_PACK(ERR_LIB_KDF, KDF_F_KDF_CIPHER2CTRL, 0), "kdf_cipher2ctrl"},
{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"},
@@ -41,6 +46,8 @@ static const ERR_STRING_DATA KDF_str_fun
{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_KRB5KDF, 0), "KRB5KDF"},
+ {ERR_PACK(ERR_LIB_KDF, KDF_F_KRB5KDF_DERIVE, 0), "krb5kdf_derive"},
{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"},
@@ -59,12 +66,22 @@ static const ERR_STRING_DATA KDF_str_fun
"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_SSKDF_DERIVE, 0), "sskdf_derive"},
+ {ERR_PACK(ERR_LIB_KDF, KDF_F_SSKDF_NEW, 0), "sskdf_new"},
+ {ERR_PACK(ERR_LIB_KDF, KDF_F_SSKDF_SIZE, 0), "sskdf_size"},
{ERR_PACK(ERR_LIB_KDF, KDF_F_TLS1_PRF_ALG, 0), "tls1_prf_alg"},
{0, NULL}
};
static const ERR_STRING_DATA KDF_str_reasons[] = {
+ {ERR_PACK(ERR_LIB_KDF, 0, KDF_R_FAILED_TO_GENERATE_KEY),
+ "failed to generate key"},
+ {ERR_PACK(ERR_LIB_KDF, 0, KDF_R_INVALID_CIPHER), "invalid cipher"},
+ {ERR_PACK(ERR_LIB_KDF, 0, KDF_R_INVALID_CONSTANT_LENGTH), "invalid constant length"},
{ERR_PACK(ERR_LIB_KDF, 0, KDF_R_INVALID_DIGEST), "invalid digest"},
+ {ERR_PACK(ERR_LIB_KDF, 0, KDF_R_INVALID_SEED_LENGTH), "invalid seed length"},
+ {ERR_PACK(ERR_LIB_KDF, 0, KDF_R_MISSING_CIPHER), "missing cipher"},
+ {ERR_PACK(ERR_LIB_KDF, 0, KDF_R_MISSING_CONSTANT), "missing constant"},
{ERR_PACK(ERR_LIB_KDF, 0, KDF_R_MISSING_ITERATION_COUNT),
"missing iteration count"},
{ERR_PACK(ERR_LIB_KDF, 0, KDF_R_MISSING_KEY), "missing key"},
@@ -82,6 +99,8 @@ static const ERR_STRING_DATA KDF_str_rea
"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_FINAL_BLOCK_LENGTH),
+ "wrong final block length"},
{ERR_PACK(ERR_LIB_KDF, 0, KDF_R_WRONG_OUTPUT_BUFFER_SIZE),
"wrong output buffer size"},
{0, NULL}
diff -up openssl-1.1.1d/crypto/kdf/kdf_local.h.krb5-kdf openssl-1.1.1d/crypto/kdf/kdf_local.h
--- openssl-1.1.1d/crypto/kdf/kdf_local.h.krb5-kdf 2019-11-14 15:07:05.313094646 +0100
+++ openssl-1.1.1d/crypto/kdf/kdf_local.h 2019-11-14 15:07:05.344094093 +0100
@@ -19,4 +19,6 @@ int kdf_hex2ctrl(EVP_KDF_IMPL *impl,
int kdf_md2ctrl(EVP_KDF_IMPL *impl,
int (*ctrl)(EVP_KDF_IMPL *impl, int cmd, va_list args),
int cmd, const char *md_name);
-
+int kdf_cipher2ctrl(EVP_KDF_IMPL *impl,
+ int (*ctrl)(EVP_KDF_IMPL *impl, int cmd, va_list args),
+ int cmd, const char *cipher_name);
diff -up openssl-1.1.1d/crypto/kdf/kdf_util.c.krb5-kdf openssl-1.1.1d/crypto/kdf/kdf_util.c
--- openssl-1.1.1d/crypto/kdf/kdf_util.c.krb5-kdf 2019-11-14 15:07:05.313094646 +0100
+++ openssl-1.1.1d/crypto/kdf/kdf_util.c 2019-11-14 15:07:05.344094093 +0100
@@ -71,3 +71,16 @@ int kdf_md2ctrl(EVP_KDF_IMPL *impl,
return call_ctrl(ctrl, impl, cmd, md);
}
+/* Pass a cipher to a ctrl */
+int kdf_cipher2ctrl(EVP_KDF_IMPL *impl,
+ int (*ctrl)(EVP_KDF_IMPL *impl, int cmd, va_list args),
+ int cmd, const char *cipher_name)
+{
+ const EVP_CIPHER *cipher;
+
+ if (cipher_name == NULL || (cipher = EVP_get_cipherbyname(cipher_name)) == NULL) {
+ KDFerr(KDF_F_KDF_CIPHER2CTRL, KDF_R_INVALID_CIPHER);
+ return 0;
+ }
+ return call_ctrl(ctrl, impl, cmd, cipher);
+}
diff -up openssl-1.1.1d/crypto/kdf/krb5kdf.c.krb5-kdf openssl-1.1.1d/crypto/kdf/krb5kdf.c
--- openssl-1.1.1d/crypto/kdf/krb5kdf.c.krb5-kdf 2019-11-14 15:07:05.344094093 +0100
+++ openssl-1.1.1d/crypto/kdf/krb5kdf.c 2019-11-18 17:18:13.056604404 +0100
@@ -0,0 +1,423 @@
+/*
+ * Copyright 2018-2019 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the OpenSSL license (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/des.h>
+#include <openssl/evp.h>
+#include <openssl/kdf.h>
+
+#include "internal/cryptlib.h"
+#include "crypto/evp.h"
+#include "kdf_local.h"
+
+/* KRB5 KDF defined in RFC 3961, Section 5.1 */
+
+static int KRB5KDF(const EVP_CIPHER *cipher,
+ const unsigned char *key, size_t key_len,
+ const unsigned char *constant, size_t constant_len,
+ unsigned char *okey, size_t okey_len);
+
+struct evp_kdf_impl_st {
+ const EVP_CIPHER *cipher;
+ unsigned char *key;
+ size_t key_len;
+ unsigned char *constant;
+ size_t constant_len;
+};
+
+static void krb5kdf_reset(EVP_KDF_IMPL *ctx);
+
+static EVP_KDF_IMPL *krb5kdf_new(void)
+{
+ EVP_KDF_IMPL *ctx;
+
+ if ((ctx = OPENSSL_zalloc(sizeof(*ctx))) == NULL)
+ KDFerr(KDF_F_KBKDF_NEW, ERR_R_MALLOC_FAILURE);
+ return ctx;
+}
+
+static void krb5kdf_free(EVP_KDF_IMPL *ctx)
+{
+ krb5kdf_reset(ctx);
+ OPENSSL_free(ctx);
+}
+
+static void krb5kdf_reset(EVP_KDF_IMPL *ctx)
+{
+ OPENSSL_clear_free(ctx->key, ctx->key_len);
+ OPENSSL_clear_free(ctx->constant, ctx->constant_len);
+ memset(ctx, 0, sizeof(*ctx));
+}
+
+static int krb5kdf_derive(EVP_KDF_IMPL *ctx, unsigned char *key,
+ size_t keylen)
+{
+ if (ctx->cipher == NULL) {
+ KDFerr(KDF_F_KRB5KDF_DERIVE, KDF_R_MISSING_CIPHER);
+ return 0;
+ }
+ if (ctx->key == NULL) {
+ KDFerr(KDF_F_KRB5KDF_DERIVE, KDF_R_MISSING_KEY);
+ return 0;
+ }
+ if (ctx->constant == NULL) {
+ KDFerr(KDF_F_KRB5KDF_DERIVE, KDF_R_MISSING_CONSTANT);
+ return 0;
+ }
+ return KRB5KDF(ctx->cipher, ctx->key, ctx->key_len,
+ ctx->constant, ctx->constant_len,
+ key, keylen);
+}
+
+static size_t krb5kdf_size(EVP_KDF_IMPL *ctx)
+{
+ if (ctx->cipher != NULL)
+ return EVP_CIPHER_key_length(ctx->cipher);
+ else
+ return EVP_MAX_KEY_LENGTH;
+}
+
+
+static int krb5kdf_parse_buffer_arg(unsigned char **dst, size_t *dst_len,
+ va_list args)
+{
+ const unsigned char *p;
+ size_t len;
+
+ p = va_arg(args, const unsigned char *);
+ len = va_arg(args, size_t);
+ OPENSSL_clear_free(*dst, *dst_len);
+ if (len == 0) {
+ *dst = NULL;
+ *dst_len = 0;
+ return 1;
+ }
+
+ *dst = OPENSSL_memdup(p, len);
+ if (*dst == NULL)
+ return 0;
+
+ *dst_len = len;
+ return 1;
+}
+
+static int krb5kdf_ctrl(EVP_KDF_IMPL *ctx, int cmd, va_list args)
+{
+ switch (cmd) {
+ case EVP_KDF_CTRL_SET_CIPHER:
+ ctx->cipher = va_arg(args, const EVP_CIPHER *);
+ if (ctx->cipher == NULL)
+ return 0;
+
+ return 1;
+
+ case EVP_KDF_CTRL_SET_KEY:
+ return krb5kdf_parse_buffer_arg(&ctx->key,
+ &ctx->key_len, args);
+
+ case EVP_KDF_CTRL_SET_KRB5KDF_CONSTANT:
+ return krb5kdf_parse_buffer_arg(&ctx->constant,
+ &ctx->constant_len, args);
+ default:
+ return -2;
+
+ }
+}
+
+static int krb5kdf_ctrl_str(EVP_KDF_IMPL *ctx, const char *type,
+ const char *value)
+{
+ if (value == NULL) {
+ KDFerr(KDF_F_KDF_SSHKDF_CTRL_STR, KDF_R_VALUE_MISSING);
+ return 0;
+ }
+
+ if (strcmp(type, "cipher") == 0)
+ return kdf_cipher2ctrl(ctx, krb5kdf_ctrl, EVP_KDF_CTRL_SET_CIPHER, value);
+
+ if (strcmp(type, "key") == 0)
+ return kdf_str2ctrl(ctx, krb5kdf_ctrl,
+ EVP_KDF_CTRL_SET_KEY, value);
+
+ if (strcmp(type, "hexkey") == 0)
+ return kdf_hex2ctrl(ctx, krb5kdf_ctrl,
+ EVP_KDF_CTRL_SET_KEY, value);
+
+ if (strcmp(type, "constant") == 0)
+ return kdf_str2ctrl(ctx, krb5kdf_ctrl,
+ EVP_KDF_CTRL_SET_KRB5KDF_CONSTANT, value);
+
+ if (strcmp(type, "hexconstant") == 0)
+ return kdf_hex2ctrl(ctx, krb5kdf_ctrl,
+ EVP_KDF_CTRL_SET_KRB5KDF_CONSTANT, value);
+
+ KDFerr(KDF_F_KBKDF_CTRL_STR, KDF_R_UNKNOWN_PARAMETER_TYPE);
+ return -2;
+}
+
+
+#ifndef OPENSSL_NO_DES
+/*
+ * DES3 is a special case, it requires a random-to-key function and its
+ * input truncated to 21 bytes of the 24 produced by the cipher.
+ * See RFC3961 6.3.1
+ */
+static int fixup_des3_key(unsigned char *key)
+{
+ unsigned char *cblock;
+ int i, j;
+
+ for (i = 2; i >= 0; i--) {
+ cblock = &key[i * 8];
+ memmove(cblock, &key[i * 7], 7);
+ cblock[7] = 0;
+ for (j = 0; j < 7; j++)
+ cblock[7] |= (cblock[j] & 1) << (j + 1);
+ DES_set_odd_parity((DES_cblock *)cblock);
+ }
+
+ /* fail if keys are such that triple des degrades to single des */
+ if (CRYPTO_memcmp(&key[0], &key[8], 8) == 0 ||
+ CRYPTO_memcmp(&key[8], &key[16], 8) == 0) {
+ return 0;
+ }
+
+ return 1;
+}
+#endif
+
+/*
+ * N-fold(K) where blocksize is N, and constant_len is K
+ * Note: Here |= denotes concatenation
+ *
+ * L = lcm(N,K)
+ * R = L/K
+ *
+ * for r: 1 -> R
+ * s |= constant rot 13*(r-1))
+ *
+ * block = 0
+ * for k: 1 -> K
+ * block += s[N(k-1)..(N-1)k] (one's complement addition)
+ *
+ * Optimizing for space we compute:
+ * for each l in L-1 -> 0:
+ * s[l] = (constant rot 13*(l/K))[l%k]
+ * block[l % N] += s[l] (with carry)
+ * finally add carry if any
+ */
+static void n_fold(unsigned char *block, unsigned int blocksize,
+ const unsigned char *constant, size_t constant_len)
+{
+ unsigned int tmp, gcd, remainder, lcm, carry;
+ int b, l;
+
+ if (constant_len == blocksize) {
+ memcpy(block, constant, constant_len);
+ return;
+ }
+
+ /* Least Common Multiple of lengths: LCM(a,b)*/
+ gcd = blocksize;
+ remainder = constant_len;
+ /* Calculate Great Common Divisor first GCD(a,b) */
+ while (remainder != 0) {
+ tmp = gcd % remainder;
+ gcd = remainder;
+ remainder = tmp;
+ }
+ /* resulting a is the GCD, LCM(a,b) = |a*b|/GCD(a,b) */
+ lcm = blocksize * constant_len / gcd;
+
+ /* now spread out the bits */
+ memset(block, 0, blocksize);
+
+ /* last to first to be able to bring carry forward */
+ carry = 0;
+ for (l = lcm - 1; l >= 0; l--) {
+ unsigned int rotbits, rshift, rbyte;
+
+ /* destination byte in block is l % N */
+ b = l % blocksize;
+ /* Our virtual s buffer is R = L/K long (K = constant_len) */
+ /* So we rotate backwards from R-1 to 0 (none) rotations */
+ rotbits = 13 * (l / constant_len);
+ /* find the byte on s where rotbits falls onto */
+ rbyte = l - (rotbits / 8);
+ /* calculate how much shift on that byte */
+ rshift = rotbits & 0x07;
+ /* rbyte % constant_len gives us the unrotated byte in the
+ * constant buffer, get also the previous byte then
+ * appropriately shift them to get the rotated byte we need */
+ tmp = (constant[(rbyte-1) % constant_len] << (8 - rshift)
+ | constant[rbyte % constant_len] >> rshift)
+ & 0xff;
+ /* add with carry to any value placed by previous passes */
+ tmp += carry + block[b];
+ block[b] = tmp & 0xff;
+ /* save any carry that may be left */
+ carry = tmp >> 8;
+ }
+
+ /* if any carry is left at the end, add it through the number */
+ for (b = blocksize - 1; b >= 0 && carry != 0; b--) {
+ carry += block[b];
+ block[b] = carry & 0xff;
+ carry >>= 8;
+ }
+}
+
+static int cipher_init(EVP_CIPHER_CTX *ctx,
+ const EVP_CIPHER *cipher,
+ const unsigned char *key, size_t key_len)
+{
+ int klen, ret;
+
+ ret = EVP_EncryptInit_ex(ctx, cipher, NULL, key, NULL);
+ if (!ret)
+ goto out;
+ /* set the key len for the odd variable key len cipher */
+ klen = EVP_CIPHER_CTX_key_length(ctx);
+ if (key_len != (size_t)klen) {
+ ret = EVP_CIPHER_CTX_set_key_length(ctx, key_len);
+ if (!ret)
+ goto out;
+ }
+ /* we never want padding, either the length requested is a multiple of
+ * the cipher block size or we are passed a cipher that can cope with
+ * partial blocks via techniques like cipher text stealing */
+ ret = EVP_CIPHER_CTX_set_padding(ctx, 0);
+ if (!ret)
+ goto out;
+
+out:
+ return ret;
+}
+
+static int KRB5KDF(const EVP_CIPHER *cipher,
+ const unsigned char *key, size_t key_len,
+ const unsigned char *constant, size_t constant_len,
+ unsigned char *okey, size_t okey_len)
+{
+ EVP_CIPHER_CTX *ctx = NULL;
+ unsigned char block[EVP_MAX_BLOCK_LENGTH * 2];
+ unsigned char *plainblock, *cipherblock;
+ size_t blocksize;
+ size_t cipherlen;
+ size_t osize;
+ int des3_no_fixup = 0;
+ int ret;
+
+ if (key_len != okey_len) {
+ /* special case for 3des, where the caller may be requesting
+ * the random raw key, instead of the fixed up key */
+ if (EVP_CIPHER_nid(cipher) == NID_des_ede3_cbc &&
+ key_len == 24 && okey_len == 21) {
+ des3_no_fixup = 1;
+ } else {
+ KDFerr(KDF_F_KRB5KDF, KDF_R_WRONG_OUTPUT_BUFFER_SIZE);
+ return 0;
+ }
+ }
+
+ ctx = EVP_CIPHER_CTX_new();
+ if (ctx == NULL)
+ return 0;
+
+ ret = cipher_init(ctx, cipher, key, key_len);
+ if (!ret)
+ goto out;
+
+ /* Initialize input block */
+ blocksize = EVP_CIPHER_CTX_block_size(ctx);
+
+ if (constant_len == 0 || constant_len > blocksize) {
+ KDFerr(KDF_F_KRB5KDF, KDF_R_INVALID_CONSTANT_LENGTH);
+ ret = 0;
+ goto out;
+ }
+
+ n_fold(block, blocksize, constant, constant_len);
+ plainblock = block;
+ cipherblock = block + EVP_MAX_BLOCK_LENGTH;
+
+ for (osize = 0; osize < okey_len; osize += cipherlen) {
+ int olen;
+
+ ret = EVP_EncryptUpdate(ctx, cipherblock, &olen,
+ plainblock, blocksize);
+ if (!ret)
+ goto out;
+ cipherlen = olen;
+ ret = EVP_EncryptFinal_ex(ctx, cipherblock, &olen);
+ if (!ret)
+ goto out;
+ if (olen != 0) {
+ KDFerr(KDF_F_KRB5KDF, KDF_R_WRONG_FINAL_BLOCK_LENGTH);
+ ret = 0;
+ goto out;
+ }
+
+ /* write cipherblock out */
+ if (cipherlen > okey_len - osize)
+ cipherlen = okey_len - osize;
+ memcpy(okey + osize, cipherblock, cipherlen);
+
+ if (okey_len > osize + cipherlen) {
+ /* we need to reinitialize cipher context per spec */
+ ret = EVP_CIPHER_CTX_reset(ctx);
+ if (!ret)
+ goto out;
+ ret = cipher_init(ctx, cipher, key, key_len);
+ if (!ret)
+ goto out;
+
+ /* also swap block offsets so last ciphertext becomes new
+ * plaintext */
+ plainblock = cipherblock;
+ if (cipherblock == block) {
+ cipherblock += EVP_MAX_BLOCK_LENGTH;
+ } else {
+ cipherblock = block;
+ }
+ }
+ }
+
+#ifndef OPENSSL_NO_DES
+ if (EVP_CIPHER_nid(cipher) == NID_des_ede3_cbc && !des3_no_fixup) {
+ ret = fixup_des3_key(okey);
+ if (!ret) {
+ KDFerr(KDF_F_KRB5KDF, KDF_R_FAILED_TO_GENERATE_KEY);
+ goto out;
+ }
+ }
+#endif
+
+ ret = 1;
+
+out:
+ EVP_CIPHER_CTX_free(ctx);
+ OPENSSL_cleanse(block, EVP_MAX_BLOCK_LENGTH * 2);
+ return ret;
+}
+
+const EVP_KDF_METHOD krb5kdf_kdf_meth = {
+ EVP_KDF_KRB5KDF,
+ krb5kdf_new,
+ krb5kdf_free,
+ krb5kdf_reset,
+ krb5kdf_ctrl,
+ krb5kdf_ctrl_str,
+ krb5kdf_size,
+ krb5kdf_derive,
+};
+
diff -up openssl-1.1.1d/crypto/kdf/sshkdf.c.krb5-kdf openssl-1.1.1d/crypto/kdf/sshkdf.c
--- openssl-1.1.1d/crypto/kdf/sshkdf.c.krb5-kdf 2019-11-14 15:07:05.327094396 +0100
+++ openssl-1.1.1d/crypto/kdf/sshkdf.c 2019-11-18 17:18:25.343388314 +0100
@@ -12,6 +12,7 @@
#include <string.h>
#include <openssl/evp.h>
#include <openssl/kdf.h>
+#include "internal/numbers.h"
#include "internal/cryptlib.h"
#include "crypto/evp.h"
#include "kdf_local.h"
@@ -68,6 +69,12 @@ static int kdf_sshkdf_parse_buffer_arg(u
p = va_arg(args, const unsigned char *);
len = va_arg(args, size_t);
OPENSSL_clear_free(*dst, *dst_len);
+ if (len == 0) {
+ *dst = NULL;
+ *dst_len = 0;
+ return 1;
+ }
+
*dst = OPENSSL_memdup(p, len);
if (*dst == NULL)
return 0;
diff -up openssl-1.1.1d/crypto/kdf/sskdf.c.krb5-kdf openssl-1.1.1d/crypto/kdf/sskdf.c
--- openssl-1.1.1d/crypto/kdf/sskdf.c.krb5-kdf 2019-11-14 15:07:05.344094093 +0100
+++ openssl-1.1.1d/crypto/kdf/sskdf.c 2019-11-18 17:21:40.349952802 +0100
@@ -0,0 +1,255 @@
+/*
+ * Copyright 2019 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright (c) 2019, 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
+ */
+
+/*
+ * Refer to https://csrc.nist.gov/publications/detail/sp/800-56c/rev-1/final
+ * Section 4.1.
+ *
+ * The Single Step KDF algorithm is given by:
+ *
+ * Result(0) = empty bit string (i.e., the null string).
+ * For i = 1 to reps, do the following:
+ * Increment counter by 1.
+ * Result(i) = Result(i 1) || H(counter || Z || FixedInfo).
+ * DKM = LeftmostBits(Result(reps), L))
+ *
+ * NOTES:
+ * Z is a shared secret required to produce the derived key material.
+ * counter is a 4 byte buffer.
+ * FixedInfo is a bit string containing context specific data.
+ * DKM is the output derived key material.
+ * L is the required size of the DKM.
+ * reps = [L / H_outputBits]
+ * H(x) is the auxiliary function that can be either a hash, HMAC or KMAC.
+ * This backported version supports only a hash.
+ * H_outputBits is the length of the output of the auxiliary function H(x).
+ *
+ * Currently there is not a comprehensive list of test vectors for this
+ * algorithm, especially for H(x) = HMAC and H(x) = KMAC.
+ * Test vectors for H(x) = Hash are indirectly used by CAVS KAS tests.
+ */
+#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 "crypto/evp.h"
+#include "kdf_local.h"
+
+struct evp_kdf_impl_st {
+ const EVP_MD *md; /* H(x) = hash */
+ unsigned char *secret;
+ size_t secret_len;
+ unsigned char *info;
+ size_t info_len;
+};
+
+#define SSKDF_MAX_INLEN (1<<30)
+
+/*
+ * 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)
+ */
+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 char *derived_key, size_t derived_key_len)
+{
+ int ret = 0, hlen;
+ size_t counter, out_len, len = derived_key_len;
+ unsigned char c[4];
+ unsigned char mac[EVP_MAX_MD_SIZE];
+ unsigned char *out = derived_key;
+ EVP_MD_CTX *ctx = NULL, *ctx_init = NULL;
+
+ if (z_len > SSKDF_MAX_INLEN || info_len > SSKDF_MAX_INLEN
+ || derived_key_len > SSKDF_MAX_INLEN
+ || derived_key_len == 0)
+ return 0;
+
+ hlen = EVP_MD_size(kdf_md);
+ if (hlen <= 0)
+ return 0;
+ out_len = (size_t)hlen;
+
+ ctx = EVP_MD_CTX_create();
+ ctx_init = EVP_MD_CTX_create();
+ if (ctx == NULL || ctx_init == NULL)
+ goto end;
+
+ if (!EVP_DigestInit(ctx_init, kdf_md))
+ goto end;
+
+ for (counter = 1;; counter++) {
+ c[0] = (unsigned char)((counter >> 24) & 0xff);
+ c[1] = (unsigned char)((counter >> 16) & 0xff);
+ c[2] = (unsigned char)((counter >> 8) & 0xff);
+ c[3] = (unsigned char)(counter & 0xff);
+
+ if (!(EVP_MD_CTX_copy_ex(ctx, ctx_init)
+ && EVP_DigestUpdate(ctx, c, sizeof(c))
+ && EVP_DigestUpdate(ctx, z, z_len)
+ && EVP_DigestUpdate(ctx, info, info_len)))
+ goto end;
+ if (len >= out_len) {
+ if (!EVP_DigestFinal_ex(ctx, out, NULL))
+ goto end;
+ out += out_len;
+ len -= out_len;
+ if (len == 0)
+ break;
+ } else {
+ if (!EVP_DigestFinal_ex(ctx, mac, NULL))
+ goto end;
+ memcpy(out, mac, len);
+ break;
+ }
+ }
+ ret = 1;
+end:
+ EVP_MD_CTX_destroy(ctx);
+ EVP_MD_CTX_destroy(ctx_init);
+ OPENSSL_cleanse(mac, sizeof(mac));
+ return ret;
+}
+
+static EVP_KDF_IMPL *sskdf_new(void)
+{
+ EVP_KDF_IMPL *impl;
+
+ if ((impl = OPENSSL_zalloc(sizeof(*impl))) == NULL)
+ KDFerr(KDF_F_SSKDF_NEW, ERR_R_MALLOC_FAILURE);
+ return impl;
+}
+
+static void sskdf_reset(EVP_KDF_IMPL *impl)
+{
+ OPENSSL_clear_free(impl->secret, impl->secret_len);
+ OPENSSL_clear_free(impl->info, impl->info_len);
+ memset(impl, 0, sizeof(*impl));
+}
+
+static void sskdf_free(EVP_KDF_IMPL *impl)
+{
+ sskdf_reset(impl);
+ OPENSSL_free(impl);
+}
+
+static int sskdf_set_buffer(va_list args, unsigned char **out, size_t *out_len)
+{
+ const unsigned char *p;
+ size_t len;
+
+ p = va_arg(args, const unsigned char *);
+ len = va_arg(args, size_t);
+ OPENSSL_clear_free(*out, *out_len);
+ if (len == 0) {
+ *out = NULL;
+ *out_len = 0;
+ return 1;
+ }
+
+ *out = OPENSSL_memdup(p, len);
+ if (*out == NULL)
+ return 0;
+
+ *out_len = len;
+ return 1;
+}
+
+static int sskdf_ctrl(EVP_KDF_IMPL *impl, int cmd, va_list args)
+{
+ const EVP_MD *md;
+
+ switch (cmd) {
+ case EVP_KDF_CTRL_SET_KEY:
+ return sskdf_set_buffer(args, &impl->secret, &impl->secret_len);
+
+ case EVP_KDF_CTRL_SET_SSKDF_INFO:
+ return sskdf_set_buffer(args, &impl->info, &impl->info_len);
+
+ 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 sskdf_ctrl_str(EVP_KDF_IMPL *impl, const char *type,
+ const char *value)
+{
+ if (strcmp(type, "secret") == 0 || strcmp(type, "key") == 0)
+ return kdf_str2ctrl(impl, sskdf_ctrl, EVP_KDF_CTRL_SET_KEY,
+ value);
+
+ if (strcmp(type, "hexsecret") == 0 || strcmp(type, "hexkey") == 0)
+ return kdf_hex2ctrl(impl, sskdf_ctrl, EVP_KDF_CTRL_SET_KEY,
+ value);
+
+ if (strcmp(type, "info") == 0)
+ return kdf_str2ctrl(impl, sskdf_ctrl, EVP_KDF_CTRL_SET_SSKDF_INFO,
+ value);
+
+ if (strcmp(type, "hexinfo") == 0)
+ return kdf_hex2ctrl(impl, sskdf_ctrl, EVP_KDF_CTRL_SET_SSKDF_INFO,
+ value);
+
+ if (strcmp(type, "digest") == 0)
+ return kdf_md2ctrl(impl, sskdf_ctrl, EVP_KDF_CTRL_SET_MD, value);
+
+ return -2;
+}
+
+static size_t sskdf_size(EVP_KDF_IMPL *impl)
+{
+ int len;
+
+ if (impl->md == NULL) {
+ KDFerr(KDF_F_SSKDF_SIZE, KDF_R_MISSING_MESSAGE_DIGEST);
+ return 0;
+ }
+ len = EVP_MD_size(impl->md);
+ return (len <= 0) ? 0 : (size_t)len;
+}
+
+static int sskdf_derive(EVP_KDF_IMPL *impl, unsigned char *key, size_t keylen)
+{
+ if (impl->secret == NULL) {
+ KDFerr(KDF_F_SSKDF_DERIVE, KDF_R_MISSING_SECRET);
+ return 0;
+ }
+
+ /* H(x) = hash */
+ if (impl->md == NULL) {
+ KDFerr(KDF_F_SSKDF_DERIVE, KDF_R_MISSING_MESSAGE_DIGEST);
+ return 0;
+ }
+ return SSKDF_hash_kdm(impl->md, impl->secret, impl->secret_len,
+ impl->info, impl->info_len, key, keylen);
+}
+
+const EVP_KDF_METHOD ss_kdf_meth = {
+ EVP_KDF_SS,
+ sskdf_new,
+ sskdf_free,
+ sskdf_reset,
+ sskdf_ctrl,
+ sskdf_ctrl_str,
+ sskdf_size,
+ sskdf_derive
+};
diff -up openssl-1.1.1d/crypto/objects/obj_dat.h.krb5-kdf openssl-1.1.1d/crypto/objects/obj_dat.h
--- openssl-1.1.1d/crypto/objects/obj_dat.h.krb5-kdf 2019-11-14 15:07:05.322094485 +0100
+++ openssl-1.1.1d/crypto/objects/obj_dat.h 2019-11-14 15:07:05.345094076 +0100
@@ -1078,7 +1078,7 @@ static const unsigned char so[7762] = {
0x2A,0x86,0x48,0x86,0xF7,0x0D,0x02,0x0D, /* [ 7753] OBJ_hmacWithSHA512_256 */
};
-#define NUM_NID 1196
+#define NUM_NID 1199
static const ASN1_OBJECT nid_objs[NUM_NID] = {
{"UNDEF", "undefined", NID_undef},
{"rsadsi", "RSA Data Security, Inc.", NID_rsadsi, 6, &so[0]},
@@ -2276,9 +2276,12 @@ static const ASN1_OBJECT nid_objs[NUM_NI
{"hmacWithSHA512-224", "hmacWithSHA512-224", NID_hmacWithSHA512_224, 8, &so[7745]},
{"hmacWithSHA512-256", "hmacWithSHA512-256", NID_hmacWithSHA512_256, 8, &so[7753]},
{"SSHKDF", "sshkdf", NID_sshkdf},
+ {"KBKDF", "kbkdf", NID_kbkdf},
+ {"KRB5KDF", "krb5kdf", NID_krb5kdf},
+ {"SSKDF", "sskdf", NID_sskdf},
};
-#define NUM_SN 1187
+#define NUM_SN 1190
static const unsigned int sn_objs[NUM_SN] = {
364, /* "AD_DVCS" */
419, /* "AES-128-CBC" */
@@ -2442,7 +2445,9 @@ static const unsigned int sn_objs[NUM_SN
183, /* "ISO-US" */
645, /* "ITU-T" */
646, /* "JOINT-ISO-ITU-T" */
+ 1196, /* "KBKDF" */
773, /* "KISA" */
+ 1197, /* "KRB5KDF" */
1063, /* "KxANY" */
1039, /* "KxDHE" */
1041, /* "KxDHE-PSK" */
@@ -2557,6 +2562,7 @@ static const unsigned int sn_objs[NUM_SN
100, /* "SN" */
1006, /* "SNILS" */
1195, /* "SSHKDF" */
+ 1198, /* "SSKDF" */
16, /* "ST" */
143, /* "SXNetID" */
1062, /* "SipHash" */
@@ -3469,7 +3475,7 @@ static const unsigned int sn_objs[NUM_SN
1093, /* "x509ExtAdmission" */
};
-#define NUM_LN 1187
+#define NUM_LN 1190
static const unsigned int ln_objs[NUM_LN] = {
363, /* "AD Time Stamping" */
405, /* "ANSI X9.62" */
@@ -4262,8 +4268,10 @@ static const unsigned int ln_objs[NUM_LN
957, /* "jurisdictionCountryName" */
955, /* "jurisdictionLocalityName" */
956, /* "jurisdictionStateOrProvinceName" */
+ 1196, /* "kbkdf" */
150, /* "keyBag" */
773, /* "kisa" */
+ 1197, /* "krb5kdf" */
1063, /* "kx-any" */
1039, /* "kx-dhe" */
1041, /* "kx-dhe-psk" */
@@ -4612,6 +4620,7 @@ static const unsigned int ln_objs[NUM_LN
1133, /* "sm4-ecb" */
1135, /* "sm4-ofb" */
1195, /* "sshkdf" */
+ 1198, /* "sskdf" */
16, /* "stateOrProvinceName" */
660, /* "streetAddress" */
498, /* "subtreeMaximumQuality" */
diff -up openssl-1.1.1d/crypto/objects/objects.txt.krb5-kdf openssl-1.1.1d/crypto/objects/objects.txt
--- openssl-1.1.1d/crypto/objects/objects.txt.krb5-kdf 2019-11-14 15:07:05.322094485 +0100
+++ openssl-1.1.1d/crypto/objects/objects.txt 2019-11-14 15:07:05.345094076 +0100
@@ -1603,6 +1603,15 @@ secg-scheme 14 3 : dhSinglePass-cofactor
# NID for SSHKDF
: SSHKDF : sshkdf
+# NID for KBKDF
+ : KBKDF : kbkdf
+
+# NID for KRB5KDF
+ : KRB5KDF : krb5kdf
+
+# NID for SSKDF
+ : SSKDF : sskdf
+
# RFC 4556
1 3 6 1 5 2 3 : id-pkinit
id-pkinit 4 : pkInitClientAuth : PKINIT Client Auth
diff -up openssl-1.1.1d/crypto/objects/obj_mac.num.krb5-kdf openssl-1.1.1d/crypto/objects/obj_mac.num
--- openssl-1.1.1d/crypto/objects/obj_mac.num.krb5-kdf 2019-11-14 15:07:05.322094485 +0100
+++ openssl-1.1.1d/crypto/objects/obj_mac.num 2019-11-14 15:07:05.346094058 +0100
@@ -1193,3 +1193,6 @@ magma_mac 1192
hmacWithSHA512_224 1193
hmacWithSHA512_256 1194
sshkdf 1195
+kbkdf 1196
+krb5kdf 1197
+sskdf 1198
diff -up openssl-1.1.1d/doc/man3/EVP_KDF_CTX.pod.krb5-kdf openssl-1.1.1d/doc/man3/EVP_KDF_CTX.pod
--- openssl-1.1.1d/doc/man3/EVP_KDF_CTX.pod.krb5-kdf 2019-11-14 15:07:05.314094628 +0100
+++ openssl-1.1.1d/doc/man3/EVP_KDF_CTX.pod 2019-11-14 15:07:05.346094058 +0100
@@ -140,7 +140,14 @@ The value string is expected to be a dec
This control expects one argument: C<EVP_MD *md>
For MAC implementations that use a message digest as an underlying computation
-algorithm, this control set what the digest algorithm should be.
+algorithm, this control sets what the digest algorithm should be.
+
+=item B<EVP_KDF_CTRL_SET_CIPHER>
+
+This control expects one argument: C<EVP_CIPHER *cipher>
+
+For MAC implementations that use a cipher as an underlying computation
+algorithm, this control sets what the cipher algorithm should be.
EVP_KDF_ctrl_str() type string: "md"
diff -up openssl-1.1.1d/doc/man7/EVP_KDF_KB.pod.krb5-kdf openssl-1.1.1d/doc/man7/EVP_KDF_KB.pod
--- openssl-1.1.1d/doc/man7/EVP_KDF_KB.pod.krb5-kdf 2019-11-14 15:07:05.346094058 +0100
+++ openssl-1.1.1d/doc/man7/EVP_KDF_KB.pod 2019-11-14 15:07:05.346094058 +0100
@@ -0,0 +1,173 @@
+=pod
+
+=head1 NAME
+
+EVP_KDF_KB - The Key-Based EVP_KDF implementation
+
+=head1 DESCRIPTION
+
+The EVP_KDF_KB algorithm implements the Key-Based key derivation function
+(KBKDF). KBKDF derives a key from repeated application of a keyed MAC to an
+input secret (and other optional values).
+
+=head2 Numeric identity
+
+B<EVP_KDF_KB> is the numeric identity for this implementation; it can be used with the
+EVP_KDF_CTX_new_id() function.
+
+=head2 Supported controls
+
+The supported controls are:
+
+=over 4
+
+=item B<EVP_KDF_CTRL_SET_KB_MODE>
+
+This control expects one argument: C<int mode>
+
+Sets the mode for the KBKDF operation. There are two supported modes:
+
+=over 4
+
+=item B<EVP_KDF_KB_MODE_COUNTER>
+
+The counter mode of KBKDF should be used. This is the default.
+
+=item B<EVP_KDF_KB_MODE_FEEDBACK>
+
+The feedback mode of KBKDF should be used.
+
+=back
+
+=item B<EVP_KDF_CTRL_SET_KB_MAC_TYPE>
+
+This control expects one argument: C<int mac_type>
+
+Sets the mac type for the KBKDF operation. There are two supported mac types:
+
+=over 4
+
+=item B<EVP_KDF_KB_MAC_TYPE_HMAC>
+
+The HMAC with the digest set by B<EVP_KDF_CTRL_SET_MD> should be used as the mac.
+
+=item B<EVP_KDF_KB_MAC_TYPE_CMAC>
+
+The CMAC with the cipher set by B<EVP_KDF_CTRL_SET_CIPHER> should be used as the mac.
+
+=back
+
+=item B<EVP_KDF_CTRL_SET_MD>
+
+=item B<EVP_KDF_CTRL_SET_CIPHER>
+
+=item B<EVP_KDF_CTRL_SET_KEY>
+
+=item B<EVP_KDF_CTRL_SET_SALT>
+
+These controls work as described in L<EVP_KDF_CTX(3)/CONTROLS>.
+
+=item B<EVP_KDF_CTRL_SET_KB_INFO>
+
+This control expects two arguments: C<unsigned char *info>, C<size_t infolen>
+
+=item B<EVP_KDF_CTRL_SET_KB_SEED>
+
+This control expects two arguments: C<unsigned char *seed>, C<size_t seedlen>
+
+It is used only in the feedback mode and the length must be the same
+as the block length of the cipher in CMAC or the size of the digest in HMAC.
+
+=back
+
+The controls B<EVP_KDF_CTRL_SET_KEY>, B<EVP_KDF_CTRL_SET_SALT>,
+B<EVP_KDF_CTRL_SET_KB_INFO>, and B<EVP_KDF_CTRL_SET_KB_SEED>
+correspond to KI, Label, Context, and IV (respectively) in SP800-108.
+As in that document, salt, info, and seed are optional and may be
+omitted.
+
+Depending on whether mac is CMAC or HMAC, either digest or cipher is
+required (respectively) and the other is unused.
+
+=head1 NOTES
+
+A context for KBKDF can be obtained by calling:
+
+ EVP_KDF_CTX *kctx = EVP_KDF_CTX_new_id(EVP_KDF_KB);
+
+The output length of an KBKDF is specified via the C<keylen>
+parameter to the L<EVP_KDF_derive(3)> function.
+
+Note that currently OpenSSL only implements counter and feedback modes. Other
+variants may be supported in the future.
+
+=head1 EXAMPLES
+
+This example derives 10 bytes using COUNTER-HMAC-SHA256, with KI "secret",
+Label "label", and Context "context".
+
+ EVP_KDF_CTX *kctx;
+ unsigned char out[10];
+
+ kctx = EVP_KDF_CTX_new_id(EVP_KDF_KB);
+
+ EVP_KDF_ctrl(kctx, EVP_KDF_CTRL_SET_MD, EVP_sha256());
+ EVP_KDF_ctrl(kctx, EVP_KDF_CTRL_SET_KB_MAC_TYPE, EVP_KDF_KB_MAC_TYPE_HMAC);
+ EVP_KDF_ctrl(kctx, EVP_KDF_CTRL_SET_KEY, "secret", strlen("secret"));
+ EVP_KDF_ctrl(kctx, EVP_KDF_CTRL_SET_SALT, "label", strlen("label"));
+ EVP_KDF_ctrl(kctx, EVP_KDF_CTRL_SET_KB_INFO, "context", strlen("context"));
+ if (EVP_KDF_derive(kctx, out, sizeof(out)) <= 0)
+ error("EVP_KDF_derive");
+
+ EVP_KDF_CTX_free(kctx);
+
+This example derives 10 bytes using FEEDBACK-CMAC-AES256, with KI "secret",
+Label "label", Context "context", and IV "sixteen bytes iv".
+
+ EVP_KDF_CTX *kctx;
+ unsigned char out[10];
+ unsigned char *iv = "sixteen bytes iv";
+
+ kctx = EVP_KDF_CTX_new_id(EVP_KDF_KB);
+
+ EVP_KDF_ctrl(kctx, EVP_KDF_CTRL_SET_CIPHER, EVP_aes_256_cbc());
+ EVP_KDF_ctrl(kctx, EVP_KDF_CTRL_SET_KB_MAC_TYPE, EVP_KDF_KB_MAC_TYPE_CMAC);
+ EVP_KDF_ctrl(kctx, EVP_KDF_CTRL_SET_KB_MODE, EVP_KDF_KB_MODE_FEEDBACK);
+ EVP_KDF_ctrl(kctx, EVP_KDF_CTRL_SET_KEY, "secret", strlen("secret"));
+ EVP_KDF_ctrl(kctx, EVP_KDF_CTRL_SET_SALT, "label", strlen("label"));
+ EVP_KDF_ctrl(kctx, EVP_KDF_CTRL_SET_KB_INFO, "context", strlen("context"));
+ EVP_KDF_ctrl(kctx, EVP_KDF_CTRL_SET_KB_SEED, iv, strlen(iv));
+ if (EVP_KDF_derive(kctx, out, sizeof(out)) <= 0)
+ error("EVP_KDF_derive");
+
+ EVP_KDF_CTX_free(kctx);
+
+=head1 CONFORMING TO
+
+NIST SP800-108, IETF RFC 6803, IETF RFC 8009.
+
+=head1 SEE ALSO
+
+L<EVP_KDF_CTX(3)>,
+L<EVP_KDF_CTX_new_id(3)>,
+L<EVP_KDF_CTX_free(3)>,
+L<EVP_KDF_ctrl(3)>,
+L<EVP_KDF_size(3)>,
+L<EVP_KDF_derive(3)>,
+L<EVP_KDF_CTX(3)/CONTROLS>
+
+=head1 HISTORY
+
+This functionality was added to OpenSSL 3.0.
+
+=head1 COPYRIGHT
+
+Copyright 2019 The OpenSSL Project Authors. All Rights Reserved.
+Copyright 2019 Red Hat, Inc.
+
+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
+L<https://www.openssl.org/source/license.html>.
+
+=cut
diff -up openssl-1.1.1d/doc/man7/EVP_KDF_KRB5KDF.pod.krb5-kdf openssl-1.1.1d/doc/man7/EVP_KDF_KRB5KDF.pod
--- openssl-1.1.1d/doc/man7/EVP_KDF_KRB5KDF.pod.krb5-kdf 2019-11-14 15:07:05.346094058 +0100
+++ openssl-1.1.1d/doc/man7/EVP_KDF_KRB5KDF.pod 2019-11-14 15:07:05.346094058 +0100
@@ -0,0 +1,107 @@
+=pod
+
+=head1 NAME
+
+EVP_KDF_KRB5KDF - The RFC3961 Krb5 KDF EVP_KDF implementation
+
+=head1 DESCRIPTION
+
+Support for computing the B<KRB5KDF> KDF through the B<EVP_KDF> API.
+
+The B<EVP_KDF_KRB5KDF> algorithm implements the key derivation function defined
+in RFC 3961, section 5.1 and is used by Krb5 to derive session keys.
+Three inputs are required to perform key derivation: a cipher, (for example
+AES-128-CBC), the initial key, and a constant.
+
+=head2 Numeric identity
+
+B<EVP_KDF_KRB5KDF> is the numeric identity for this implementation; it can be used with the
+EVP_KDF_CTX_new_id() function.
+
+=head2 Supported controls
+
+The supported controls are:
+
+=over 4
+
+=item B<EVP_KDF_CTRL_SET_CIPHER>
+
+=item B<EVP_KDF_CTRL_SET_KEY>
+
+These controls work as described in L<EVP_KDF_CTX(3)/CONTROLS>.
+
+=item B<EVP_KDF_CTRL_SET_KRB5KDF_CONSTANT>
+
+This control expects two arguments: C<unsigned char *constant>, C<size_t constantlen>
+
+This control sets the I<constant> value for the KDF.
+If a value is already set, the contents are replaced.
+
+=back
+
+
+=head1 NOTES
+
+A context for KRB5KDF can be obtained by calling:
+
+ EVP_KDF_CTX *kctx = EVP_KDF_CTX_new_id(EVP_KDF_KRB5KDF);
+
+The output length of the KRB5KDF derivation is specified via the I<keylen>
+parameter to the L<EVP_KDF_derive(3)> function, and MUST match the key
+length for the chosen cipher or an error is returned. Moreover the
+I<constant>'s length must not exceed the block size of the cipher.
+Since the KRB5KDF output length depends on the chosen cipher, calling
+L<EVP_KDF_size()> to obtain the requisite length returns the correct length
+only after the cipher is set. Prior to that B<EVP_MAX_KEY_LENGTH> is returned.
+The caller must allocate a buffer of the correct length for the chosen
+cipher, and pass that buffer to the L<EVP_KDF_derive(3)> function along
+with that length.
+
+=head1 EXAMPLES
+
+This example derives a key using the AES-128-CBC cipher:
+
+ EVP_KDF_CTX *kctx;
+ unsigned char key[16] = "01234...";
+ unsigned char constant[] = "I'm a constant";
+ unsigned char out[16];
+ size_t outlen = sizeof(out);
+
+ kctx = EVP_KDF_CTX_new_id(EVP_KDF_KRB5KDF);
+
+ EVP_KDF_ctrl(kctx, EVP_KDF_CTRL_SET_CIPHER, EVP_aes_128_cbc());
+ EVP_KDF_ctrl(kctx, EVP_KDF_CTRL_SET_KEY, key, (size_t)16);
+ EVP_KDF_ctrl(kctx, EVP_KDF_CTRL_SET_KRB5KDF_CONSTANT, constant, strlen(constant));
+ if (EVP_KDF_derive(kctx, out, outlen) <= 0)
+ /* Error */
+ EVP_KDF_CTX_free(kctx);
+
+=head1 CONFORMING TO
+
+RFC 3961
+
+=head1 SEE ALSO
+
+L<EVP_KDF_CTX(3)>,
+L<EVP_KDF_CTX_new_id(3)>,
+L<EVP_KDF_CTX_free(3)>,
+L<EVP_KDF_ctrl(3)>,
+L<EVP_KDF_size(3)>,
+L<EVP_KDF_derive(3)>,
+L<EVP_KDF_CTX(3)/CONTROLS>
+
+=head1 HISTORY
+
+This functionality was added to OpenSSL 3.0.
+
+=head1 COPYRIGHT
+
+Copyright 2016-2019 The OpenSSL Project Authors. All Rights Reserved.
+
+Licensed under the OpenSSL license (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
+L<https://www.openssl.org/source/license.html>.
+
+=cut
+
diff -up openssl-1.1.1d/doc/man7/EVP_KDF_SS.pod.krb5-kdf openssl-1.1.1d/doc/man7/EVP_KDF_SS.pod
--- openssl-1.1.1d/doc/man7/EVP_KDF_SS.pod.krb5-kdf 2019-11-14 15:07:05.346094058 +0100
+++ openssl-1.1.1d/doc/man7/EVP_KDF_SS.pod 2019-11-14 15:07:05.346094058 +0100
@@ -0,0 +1,146 @@
+=pod
+
+=head1 NAME
+
+EVP_KDF_SS - The Single Step / One Step EVP_KDF implementation
+
+=head1 DESCRIPTION
+
+The EVP_KDF_SS algorithm implements the Single Step key derivation function (SSKDF).
+SSKDF derives a key using input such as a shared secret key (that was generated
+during the execution of a key establishment scheme) and fixedinfo.
+SSKDF is also informally referred to as 'Concat KDF'.
+
+=head2 Auxilary function
+
+The implementation uses a selectable auxiliary function H, which can be in the
+backported version only a:
+
+=over 4
+
+=item B<H(x) = hash(x, digest=md)>
+
+=back
+
+=head2 Numeric identity
+
+B<EVP_KDF_SS> is the numeric identity for this implementation; it
+can be used with the EVP_KDF_CTX_new_id() function.
+
+=head2 Supported controls
+
+The supported controls are:
+
+=over 4
+
+=item B<EVP_KDF_CTRL_SET_MD>
+
+This control works as described in L<EVP_KDF_CTX(3)/CONTROLS>.
+
+=item B<EVP_KDF_CTRL_SET_KEY>
+
+This control expects two arguments: C<unsigned char *secret>, C<size_t secretlen>
+
+The shared secret used for key derivation. This control sets the secret.
+
+EVP_KDF_ctrl_str() takes two type strings for this control:
+
+=over 4
+
+=item "secret"
+
+The value string is used as is.
+
+=item "hexsecret"
+
+The value string is expected to be a hexadecimal number, which will be
+decoded before being passed on as the control value.
+
+=back
+
+=item B<EVP_KDF_CTRL_SET_SSKDF_INFO>
+
+This control expects two arguments: C<unsigned char *info>, C<size_t infolen>
+
+An optional value for fixedinfo, also known as otherinfo. This control sets the fixedinfo.
+
+EVP_KDF_ctrl_str() takes two type strings for this control:
+
+=over 4
+
+=item "info"
+
+The value string is used as is.
+
+=item "hexinfo"
+
+The value string is expected to be a hexadecimal number, which will be
+decoded before being passed on as the control value.
+
+=back
+
+=back
+
+=head1 NOTES
+
+A context for SSKDF can be obtained by calling:
+
+EVP_KDF_CTX *kctx = EVP_KDF_CTX_new_id(EVP_KDF_SS);
+
+The output length of an SSKDF is specified via the C<keylen>
+parameter to the L<EVP_KDF_derive(3)> function.
+
+=head1 EXAMPLE
+
+This example derives 10 bytes using H(x) = SHA-256, with the secret key "secret"
+and fixedinfo value "label":
+
+ EVP_KDF_CTX *kctx;
+ unsigned char out[10];
+
+ kctx = EVP_KDF_CTX_new_id(EVP_KDF_SS);
+
+ if (EVP_KDF_ctrl(kctx, EVP_KDF_CTRL_SET_MD, EVP_sha256()) <= 0) {
+ error("EVP_KDF_CTRL_SET_MD");
+ }
+ if (EVP_KDF_ctrl(kctx, EVP_KDF_CTRL_SET_KEY, "secret", (size_t)6) <= 0) {
+ error("EVP_KDF_CTRL_SET_KEY");
+ }
+ if (EVP_KDF_ctrl(kctx, EVP_KDF_CTRL_SET_SSKDF_INFO, "label", (size_t)5) <= 0) {
+ error("EVP_KDF_CTRL_SET_SSKDF_INFO");
+ }
+ if (EVP_KDF_derive(kctx, out, sizeof(out)) <= 0) {
+ error("EVP_KDF_derive");
+ }
+
+ EVP_KDF_CTX_free(kctx);
+
+=head1 CONFORMING TO
+
+NIST SP800-56Cr1.
+
+=head1 SEE ALSO
+
+L<EVP_KDF_CTX>,
+L<EVP_KDF_CTX_new_id(3)>,
+L<EVP_KDF_CTX_free(3)>,
+L<EVP_KDF_ctrl(3)>,
+L<EVP_KDF_size(3)>,
+L<EVP_KDF_derive(3)>,
+L<EVP_KDF_CTX(3)/CONTROLS>
+
+=head1 HISTORY
+
+This functionality was added to OpenSSL 3.0.0.
+
+=head1 COPYRIGHT
+
+Copyright 2019 The OpenSSL Project Authors. All Rights Reserved. Copyright
+(c) 2019, 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
+L<https://www.openssl.org/source/license.html>.
+
+=cut
diff -up openssl-1.1.1d/include/openssl/kdferr.h.krb5-kdf openssl-1.1.1d/include/openssl/kdferr.h
--- openssl-1.1.1d/include/openssl/kdferr.h.krb5-kdf 2019-11-14 15:07:05.323094468 +0100
+++ openssl-1.1.1d/include/openssl/kdferr.h 2019-11-14 15:07:05.347094040 +0100
@@ -24,6 +24,11 @@ int ERR_load_KDF_strings(void);
* KDF function codes.
*/
# define KDF_F_HKDF_EXTRACT 112
+# define KDF_F_KBKDF_CTRL 134
+# define KDF_F_KBKDF_CTRL_STR 135
+# define KDF_F_KBKDF_DERIVE 136
+# define KDF_F_KBKDF_NEW 137
+# define KDF_F_KDF_CIPHER2CTRL 138
# define KDF_F_KDF_HKDF_DERIVE 113
# define KDF_F_KDF_HKDF_NEW 114
# define KDF_F_KDF_HKDF_SIZE 115
@@ -43,6 +48,8 @@ int ERR_load_KDF_strings(void);
# define KDF_F_KDF_TLS1_PRF_CTRL_STR 125
# define KDF_F_KDF_TLS1_PRF_DERIVE 126
# define KDF_F_KDF_TLS1_PRF_NEW 127
+# define KDF_F_KRB5KDF 139
+# define KDF_F_KRB5KDF_DERIVE 140
# define KDF_F_PBKDF2_SET_MEMBUF 128
# define KDF_F_PKEY_HKDF_CTRL_STR 103
# define KDF_F_PKEY_HKDF_DERIVE 102
@@ -56,12 +63,21 @@ int ERR_load_KDF_strings(void);
# define KDF_F_PKEY_TLS1_PRF_DERIVE 101
# define KDF_F_PKEY_TLS1_PRF_INIT 110
# define KDF_F_SCRYPT_SET_MEMBUF 129
+# define KDF_F_SSKDF_DERIVE 141
+# define KDF_F_SSKDF_NEW 142
+# define KDF_F_SSKDF_SIZE 143
# define KDF_F_TLS1_PRF_ALG 111
/*
* KDF reason codes.
*/
+# define KDF_R_FAILED_TO_GENERATE_KEY 118
+# define KDF_R_INVALID_CIPHER 116
+# define KDF_R_INVALID_CONSTANT_LENGTH 119
# define KDF_R_INVALID_DIGEST 100
+# define KDF_R_INVALID_SEED_LENGTH 117
+# define KDF_R_MISSING_CIPHER 120
+# define KDF_R_MISSING_CONSTANT 121
# define KDF_R_MISSING_ITERATION_COUNT 109
# define KDF_R_MISSING_KEY 104
# define KDF_R_MISSING_MESSAGE_DIGEST 105
@@ -76,6 +92,7 @@ int ERR_load_KDF_strings(void);
# define KDF_R_UNKNOWN_PARAMETER_TYPE 103
# define KDF_R_VALUE_ERROR 108
# define KDF_R_VALUE_MISSING 102
+# define KDF_R_WRONG_FINAL_BLOCK_LENGTH 122
# define KDF_R_WRONG_OUTPUT_BUFFER_SIZE 112
#endif
diff -up openssl-1.1.1d/include/openssl/kdf.h.krb5-kdf openssl-1.1.1d/include/openssl/kdf.h
--- openssl-1.1.1d/include/openssl/kdf.h.krb5-kdf 2019-11-14 15:07:05.323094468 +0100
+++ openssl-1.1.1d/include/openssl/kdf.h 2019-11-14 15:07:05.347094040 +0100
@@ -21,6 +21,9 @@ extern "C" {
# define EVP_KDF_TLS1_PRF NID_tls1_prf
# define EVP_KDF_HKDF NID_hkdf
# define EVP_KDF_SSHKDF NID_sshkdf
+# define EVP_KDF_KB NID_kbkdf
+# define EVP_KDF_KRB5KDF NID_krb5kdf
+# define EVP_KDF_SS NID_sskdf
EVP_KDF_CTX *EVP_KDF_CTX_new_id(int id);
void EVP_KDF_CTX_free(EVP_KDF_CTX *ctx);
@@ -51,6 +54,13 @@ int EVP_KDF_derive(EVP_KDF_CTX *ctx, uns
# define EVP_KDF_CTRL_SET_SSHKDF_XCGHASH 0x10 /* unsigned char *, size_t */
# define EVP_KDF_CTRL_SET_SSHKDF_SESSION_ID 0x11 /* unsigned char *, size_t */
# define EVP_KDF_CTRL_SET_SSHKDF_TYPE 0x12 /* int */
+# define EVP_KDF_CTRL_SET_KB_MODE 0x13 /* int */
+# define EVP_KDF_CTRL_SET_KB_MAC_TYPE 0x14 /* int */
+# define EVP_KDF_CTRL_SET_CIPHER 0x15 /* EVP_CIPHER * */
+# define EVP_KDF_CTRL_SET_KB_INFO 0x16 /* unsigned char *, size_t */
+# define EVP_KDF_CTRL_SET_KB_SEED 0x17 /* unsigned char *, size_t */
+# define EVP_KDF_CTRL_SET_KRB5KDF_CONSTANT 0x18 /* unsigned char *, size_t */
+# define EVP_KDF_CTRL_SET_SSKDF_INFO 0x19 /* unsigned char *, size_t */
# define EVP_KDF_HKDF_MODE_EXTRACT_AND_EXPAND 0
# define EVP_KDF_HKDF_MODE_EXTRACT_ONLY 1
@@ -63,6 +73,12 @@ int EVP_KDF_derive(EVP_KDF_CTX *ctx, uns
#define EVP_KDF_SSHKDF_TYPE_INTEGRITY_KEY_CLI_TO_SRV 69
#define EVP_KDF_SSHKDF_TYPE_INTEGRITY_KEY_SRV_TO_CLI 70
+#define EVP_KDF_KB_MODE_COUNTER 0
+#define EVP_KDF_KB_MODE_FEEDBACK 1
+
+#define EVP_KDF_KB_MAC_TYPE_HMAC 0
+#define EVP_KDF_KB_MAC_TYPE_CMAC 1
+
/**** The legacy PKEY-based KDF API follows. ****/
# define EVP_PKEY_CTRL_TLS_MD (EVP_PKEY_ALG_CTRL)
diff -up openssl-1.1.1d/include/openssl/obj_mac.h.krb5-kdf openssl-1.1.1d/include/openssl/obj_mac.h
--- openssl-1.1.1d/include/openssl/obj_mac.h.krb5-kdf 2019-11-14 15:07:05.323094468 +0100
+++ openssl-1.1.1d/include/openssl/obj_mac.h 2019-11-14 15:07:05.347094040 +0100
@@ -4974,6 +4974,18 @@
#define LN_sshkdf "sshkdf"
#define NID_sshkdf 1203
+#define SN_kbkdf "KBKDF"
+#define LN_kbkdf "kbkdf"
+#define NID_kbkdf 1204
+
+#define SN_krb5kdf "KRB5KDF"
+#define LN_krb5kdf "krb5kdf"
+#define NID_krb5kdf 1205
+
+#define SN_sskdf "SSKDF"
+#define LN_sskdf "sskdf"
+#define NID_sskdf 1206
+
#define SN_id_pkinit "id-pkinit"
#define NID_id_pkinit 1031
#define OBJ_id_pkinit 1L,3L,6L,1L,5L,2L,3L
diff -up openssl-1.1.1d/test/evp_kdf_test.c.krb5-kdf openssl-1.1.1d/test/evp_kdf_test.c
--- openssl-1.1.1d/test/evp_kdf_test.c.krb5-kdf 2019-11-14 15:07:05.315094610 +0100
+++ openssl-1.1.1d/test/evp_kdf_test.c 2019-11-14 15:07:05.348094022 +0100
@@ -225,13 +225,358 @@ err:
}
#endif
+/*
+ * KBKDF test vectors from RFC 6803 (Camellia Encryption for Kerberos 5)
+ * section 10.
+ */
+static int test_kdf_kbkdf_6803_128(void)
+{
+ int ret = 0, i;
+ EVP_KDF_CTX *kctx;
+ static unsigned char input_key[] = {
+ 0x57, 0xD0, 0x29, 0x72, 0x98, 0xFF, 0xD9, 0xD3,
+ 0x5D, 0xE5, 0xA4, 0x7F, 0xB4, 0xBD, 0xE2, 0x4B,
+ };
+ static unsigned char constants[][5] = {
+ { 0x00, 0x00, 0x00, 0x02, 0x99 },
+ { 0x00, 0x00, 0x00, 0x02, 0xaa },
+ { 0x00, 0x00, 0x00, 0x02, 0x55 },
+ };
+ static unsigned char outputs[][16] = {
+ {0xD1, 0x55, 0x77, 0x5A, 0x20, 0x9D, 0x05, 0xF0,
+ 0x2B, 0x38, 0xD4, 0x2A, 0x38, 0x9E, 0x5A, 0x56},
+ {0x64, 0xDF, 0x83, 0xF8, 0x5A, 0x53, 0x2F, 0x17,
+ 0x57, 0x7D, 0x8C, 0x37, 0x03, 0x57, 0x96, 0xAB},
+ {0x3E, 0x4F, 0xBD, 0xF3, 0x0F, 0xB8, 0x25, 0x9C,
+ 0x42, 0x5C, 0xB6, 0xC9, 0x6F, 0x1F, 0x46, 0x35}
+ };
+ static unsigned char iv[16] = { 0 };
+ unsigned char result[16] = { 0 };
+
+ for (i = 0; i < 3; i++) {
+ ret = 0;
+ if ((kctx = EVP_KDF_CTX_new_id(EVP_KDF_KB)) == NULL) {
+ TEST_error("EVP_KDF_KB");
+ goto err;
+ }
+ if (EVP_KDF_ctrl(kctx, EVP_KDF_CTRL_SET_KB_MAC_TYPE, EVP_KDF_KB_MAC_TYPE_CMAC) <= 0) {
+ TEST_error("EVP_KDF_CTRL_SET_KB_MAC_TYPE");
+ goto err;
+ }
+ if (EVP_KDF_ctrl(kctx, EVP_KDF_CTRL_SET_KB_MODE, EVP_KDF_KB_MODE_FEEDBACK) <= 0) {
+ TEST_error("EVP_KDF_CTRL_SET_KB_MODE");
+ goto err;
+ }
+ if (EVP_KDF_ctrl(kctx, EVP_KDF_CTRL_SET_CIPHER, EVP_camellia_128_cbc()) <= 0) {
+ TEST_error("EVP_KDF_CTRL_SET_CIPHER");
+ goto err;
+ }
+ if (EVP_KDF_ctrl(kctx, EVP_KDF_CTRL_SET_KEY, input_key, sizeof(input_key)) <= 0) {
+ TEST_error("EVP_KDF_CTRL_SET_KEY");
+ goto err;
+ }
+ if (EVP_KDF_ctrl(kctx, EVP_KDF_CTRL_SET_SALT, constants[i], sizeof(constants[i])) <= 0) {
+ TEST_error("EVP_KDF_CTRL_SET_SALT");
+ goto err;
+ }
+ if (EVP_KDF_ctrl(kctx, EVP_KDF_CTRL_SET_KB_SEED, iv, sizeof(iv)) <= 0) {
+ TEST_error("EVP_KDF_CTRL_SET_KB_SEED");
+ goto err;
+ }
+ ret = TEST_int_gt(EVP_KDF_derive(kctx, result, sizeof(result)), 0)
+ && TEST_mem_eq(result, sizeof(result), outputs[i],
+ sizeof(outputs[i]));
+err:
+ EVP_KDF_CTX_free(kctx);
+ if (ret != 1)
+ return ret;
+ }
+ return ret;
+}
+
+static int test_kdf_kbkdf_6803_256(void)
+{
+ int ret = 0, i;
+ EVP_KDF_CTX *kctx;
+ static unsigned char input_key[] = {
+ 0xB9, 0xD6, 0x82, 0x8B, 0x20, 0x56, 0xB7, 0xBE,
+ 0x65, 0x6D, 0x88, 0xA1, 0x23, 0xB1, 0xFA, 0xC6,
+ 0x82, 0x14, 0xAC, 0x2B, 0x72, 0x7E, 0xCF, 0x5F,
+ 0x69, 0xAF, 0xE0, 0xC4, 0xDF, 0x2A, 0x6D, 0x2C,
+ };
+ static unsigned char constants[][5] = {
+ { 0x00, 0x00, 0x00, 0x02, 0x99 },
+ { 0x00, 0x00, 0x00, 0x02, 0xaa },
+ { 0x00, 0x00, 0x00, 0x02, 0x55 },
+ };
+ static unsigned char outputs[][32] = {
+ {0xE4, 0x67, 0xF9, 0xA9, 0x55, 0x2B, 0xC7, 0xD3,
+ 0x15, 0x5A, 0x62, 0x20, 0xAF, 0x9C, 0x19, 0x22,
+ 0x0E, 0xEE, 0xD4, 0xFF, 0x78, 0xB0, 0xD1, 0xE6,
+ 0xA1, 0x54, 0x49, 0x91, 0x46, 0x1A, 0x9E, 0x50,
+ },
+ {0x41, 0x2A, 0xEF, 0xC3, 0x62, 0xA7, 0x28, 0x5F,
+ 0xC3, 0x96, 0x6C, 0x6A, 0x51, 0x81, 0xE7, 0x60,
+ 0x5A, 0xE6, 0x75, 0x23, 0x5B, 0x6D, 0x54, 0x9F,
+ 0xBF, 0xC9, 0xAB, 0x66, 0x30, 0xA4, 0xC6, 0x04,
+ },
+ {0xFA, 0x62, 0x4F, 0xA0, 0xE5, 0x23, 0x99, 0x3F,
+ 0xA3, 0x88, 0xAE, 0xFD, 0xC6, 0x7E, 0x67, 0xEB,
+ 0xCD, 0x8C, 0x08, 0xE8, 0xA0, 0x24, 0x6B, 0x1D,
+ 0x73, 0xB0, 0xD1, 0xDD, 0x9F, 0xC5, 0x82, 0xB0,
+ },
+ };
+ static unsigned char iv[16] = { 0 };
+ unsigned char result[32] = { 0 };
+
+ for (i = 0; i < 3; i++) {
+ ret = 0;
+ if ((kctx = EVP_KDF_CTX_new_id(EVP_KDF_KB)) == NULL) {
+ TEST_error("EVP_KDF_KB");
+ goto err;
+ }
+ if (EVP_KDF_ctrl(kctx, EVP_KDF_CTRL_SET_KB_MAC_TYPE, EVP_KDF_KB_MAC_TYPE_CMAC) <= 0) {
+ TEST_error("EVP_KDF_CTRL_SET_KB_MAC_TYPE");
+ goto err;
+ }
+ if (EVP_KDF_ctrl(kctx, EVP_KDF_CTRL_SET_KB_MODE, EVP_KDF_KB_MODE_FEEDBACK) <= 0) {
+ TEST_error("EVP_KDF_CTRL_SET_KB_MODE");
+ goto err;
+ }
+ if (EVP_KDF_ctrl(kctx, EVP_KDF_CTRL_SET_CIPHER, EVP_camellia_256_cbc()) <= 0) {
+ TEST_error("EVP_KDF_CTRL_SET_CIPHER");
+ goto err;
+ }
+ if (EVP_KDF_ctrl(kctx, EVP_KDF_CTRL_SET_KEY, input_key, sizeof(input_key)) <= 0) {
+ TEST_error("EVP_KDF_CTRL_SET_KEY");
+ goto err;
+ }
+ if (EVP_KDF_ctrl(kctx, EVP_KDF_CTRL_SET_SALT, constants[i], sizeof(constants[i])) <= 0) {
+ TEST_error("EVP_KDF_CTRL_SET_SALT");
+ goto err;
+ }
+ if (EVP_KDF_ctrl(kctx, EVP_KDF_CTRL_SET_KB_SEED, iv, sizeof(iv)) <= 0) {
+ TEST_error("EVP_KDF_CTRL_SET_KB_SEED");
+ goto err;
+ }
+ ret = TEST_int_gt(EVP_KDF_derive(kctx, result, sizeof(result)), 0)
+ && TEST_mem_eq(result, sizeof(result), outputs[i],
+ sizeof(outputs[i]));
+err:
+ EVP_KDF_CTX_free(kctx);
+ if (ret != 1)
+ return ret;
+ }
+ return ret;
+}
+
+/* Two test vectors from RFC 8009 (AES Encryption with HMAC-SHA2 for Kerberos
+ * 5) appendix A. */
+static int test_kdf_kbkdf_8009_prf1(void)
+{
+ int ret = 0;
+ EVP_KDF_CTX *kctx;
+ char *label = "prf", *prf_input = "test";
+ static unsigned char input_key[] = {
+ 0x37, 0x05, 0xD9, 0x60, 0x80, 0xC1, 0x77, 0x28,
+ 0xA0, 0xE8, 0x00, 0xEA, 0xB6, 0xE0, 0xD2, 0x3C,
+ };
+ static unsigned char output[] = {
+ 0x9D, 0x18, 0x86, 0x16, 0xF6, 0x38, 0x52, 0xFE,
+ 0x86, 0x91, 0x5B, 0xB8, 0x40, 0xB4, 0xA8, 0x86,
+ 0xFF, 0x3E, 0x6B, 0xB0, 0xF8, 0x19, 0xB4, 0x9B,
+ 0x89, 0x33, 0x93, 0xD3, 0x93, 0x85, 0x42, 0x95,
+ };
+ unsigned char result[sizeof(output)] = { 0 };
+
+ if ((kctx = EVP_KDF_CTX_new_id(EVP_KDF_KB)) == NULL) {
+ TEST_error("EVP_KDF_KB");
+ goto err;
+ }
+ if (EVP_KDF_ctrl(kctx, EVP_KDF_CTRL_SET_KB_MAC_TYPE, EVP_KDF_KB_MAC_TYPE_HMAC) <= 0) {
+ TEST_error("EVP_KDF_CTRL_SET_KB_MAC_TYPE");
+ goto err;
+ }
+ if (EVP_KDF_ctrl(kctx, EVP_KDF_CTRL_SET_MD, EVP_sha256()) <= 0) {
+ TEST_error("EVP_KDF_CTRL_SET_MD");
+ goto err;
+ }
+ if (EVP_KDF_ctrl(kctx, EVP_KDF_CTRL_SET_KEY, input_key, sizeof(input_key)) <= 0) {
+ TEST_error("EVP_KDF_CTRL_SET_KEY");
+ goto err;
+ }
+ if (EVP_KDF_ctrl(kctx, EVP_KDF_CTRL_SET_SALT, label, strlen(label)) <= 0) {
+ TEST_error("EVP_KDF_CTRL_SET_SALT");
+ goto err;
+ }
+ if (EVP_KDF_ctrl(kctx, EVP_KDF_CTRL_SET_KB_INFO, prf_input, strlen(prf_input)) <= 0) {
+ TEST_error("EVP_KDF_CTRL_SET_KB_INFO");
+ goto err;
+ }
+ ret = TEST_int_gt(EVP_KDF_derive(kctx, result, sizeof(result)), 0)
+ && TEST_mem_eq(result, sizeof(result), output,
+ sizeof(output));
+err:
+ EVP_KDF_CTX_free(kctx);
+ return ret;
+}
+
+static int test_kdf_kbkdf_8009_prf2(void)
+{
+ int ret = 0;
+ EVP_KDF_CTX *kctx;
+ char *label = "prf", *prf_input = "test";
+ static unsigned char input_key[] = {
+ 0x6D, 0x40, 0x4D, 0x37, 0xFA, 0xF7, 0x9F, 0x9D,
+ 0xF0, 0xD3, 0x35, 0x68, 0xD3, 0x20, 0x66, 0x98,
+ 0x00, 0xEB, 0x48, 0x36, 0x47, 0x2E, 0xA8, 0xA0,
+ 0x26, 0xD1, 0x6B, 0x71, 0x82, 0x46, 0x0C, 0x52,
+ };
+ static unsigned char output[] = {
+ 0x98, 0x01, 0xF6, 0x9A, 0x36, 0x8C, 0x2B, 0xF6,
+ 0x75, 0xE5, 0x95, 0x21, 0xE1, 0x77, 0xD9, 0xA0,
+ 0x7F, 0x67, 0xEF, 0xE1, 0xCF, 0xDE, 0x8D, 0x3C,
+ 0x8D, 0x6F, 0x6A, 0x02, 0x56, 0xE3, 0xB1, 0x7D,
+ 0xB3, 0xC1, 0xB6, 0x2A, 0xD1, 0xB8, 0x55, 0x33,
+ 0x60, 0xD1, 0x73, 0x67, 0xEB, 0x15, 0x14, 0xD2,
+ };
+ unsigned char result[sizeof(output)] = { 0 };
+
+ if ((kctx = EVP_KDF_CTX_new_id(EVP_KDF_KB)) == NULL) {
+ TEST_error("EVP_KDF_KB");
+ goto err;
+ }
+ if (EVP_KDF_ctrl(kctx, EVP_KDF_CTRL_SET_KB_MAC_TYPE, EVP_KDF_KB_MAC_TYPE_HMAC) <= 0) {
+ TEST_error("EVP_KDF_CTRL_SET_KB_MAC_TYPE");
+ goto err;
+ }
+ if (EVP_KDF_ctrl(kctx, EVP_KDF_CTRL_SET_MD, EVP_sha384()) <= 0) {
+ TEST_error("EVP_KDF_CTRL_SET_MD");
+ goto err;
+ }
+ if (EVP_KDF_ctrl(kctx, EVP_KDF_CTRL_SET_KEY, input_key, sizeof(input_key)) <= 0) {
+ TEST_error("EVP_KDF_CTRL_SET_KEY");
+ goto err;
+ }
+ if (EVP_KDF_ctrl(kctx, EVP_KDF_CTRL_SET_SALT, label, strlen(label)) <= 0) {
+ TEST_error("EVP_KDF_CTRL_SET_SALT");
+ goto err;
+ }
+ if (EVP_KDF_ctrl(kctx, EVP_KDF_CTRL_SET_KB_INFO, prf_input, strlen(prf_input)) <= 0) {
+ TEST_error("EVP_KDF_CTRL_SET_KB_INFO");
+ goto err;
+ }
+ ret = TEST_int_gt(EVP_KDF_derive(kctx, result, sizeof(result)), 0)
+ && TEST_mem_eq(result, sizeof(result), output,
+ sizeof(output));
+err:
+ EVP_KDF_CTX_free(kctx);
+ return ret;
+}
+
+static int test_kdf_krb5kdf(void)
+{
+ int ret = 0;
+ EVP_KDF_CTX *kctx;
+ unsigned char out[16];
+ static unsigned char key[] = {
+ 0x42, 0x26, 0x3C, 0x6E, 0x89, 0xF4, 0xFC, 0x28,
+ 0xB8, 0xDF, 0x68, 0xEE, 0x09, 0x79, 0x9F, 0x15
+ };
+ static unsigned char constant[] = {
+ 0x00, 0x00, 0x00, 0x02, 0x99
+ };
+ static const unsigned char expected[sizeof(out)] = {
+ 0x34, 0x28, 0x0A, 0x38, 0x2B, 0xC9, 0x27, 0x69,
+ 0xB2, 0xDA, 0x2F, 0x9E, 0xF0, 0x66, 0x85, 0x4B
+ };
+
+ if ((kctx = EVP_KDF_CTX_new_id(EVP_KDF_KRB5KDF)) == NULL) {
+ TEST_error("EVP_KDF_KRB5KDF");
+ goto err;
+ }
+ if (EVP_KDF_ctrl(kctx, EVP_KDF_CTRL_SET_CIPHER, EVP_aes_128_cbc()) <= 0) {
+ TEST_error("EVP_KDF_CTRL_SET_CIPHER");
+ goto err;
+ }
+ if (EVP_KDF_ctrl(kctx, EVP_KDF_CTRL_SET_KEY, key, sizeof(key)) <= 0) {
+ TEST_error("EVP_KDF_CTRL_SET_KEY");
+ goto err;
+ }
+ if (EVP_KDF_ctrl(kctx, EVP_KDF_CTRL_SET_KRB5KDF_CONSTANT, constant, sizeof(constant)) <= 0) {
+ TEST_error("EVP_KDF_CTRL_SET_KRB5KDF_CONSTANT");
+ goto err;
+ }
+
+ ret =
+ TEST_int_gt(EVP_KDF_derive(kctx, out, sizeof(out)), 0)
+ && TEST_mem_eq(out, sizeof(out), expected, sizeof(expected));
+
+err:
+ EVP_KDF_CTX_free(kctx);
+ return ret;
+}
+
+static int test_kdf_ss_hash(void)
+{
+ EVP_KDF_CTX *kctx;
+ const unsigned char z[] = {
+ 0x6d,0xbd,0xc2,0x3f,0x04,0x54,0x88,0xe4,0x06,0x27,0x57,0xb0,0x6b,0x9e,
+ 0xba,0xe1,0x83,0xfc,0x5a,0x59,0x46,0xd8,0x0d,0xb9,0x3f,0xec,0x6f,0x62,
+ 0xec,0x07,0xe3,0x72,0x7f,0x01,0x26,0xae,0xd1,0x2c,0xe4,0xb2,0x62,0xf4,
+ 0x7d,0x48,0xd5,0x42,0x87,0xf8,0x1d,0x47,0x4c,0x7c,0x3b,0x18,0x50,0xe9
+ };
+ const unsigned char other[] = {
+ 0xa1,0xb2,0xc3,0xd4,0xe5,0x43,0x41,0x56,0x53,0x69,0x64,0x3c,0x83,0x2e,
+ 0x98,0x49,0xdc,0xdb,0xa7,0x1e,0x9a,0x31,0x39,0xe6,0x06,0xe0,0x95,0xde,
+ 0x3c,0x26,0x4a,0x66,0xe9,0x8a,0x16,0x58,0x54,0xcd,0x07,0x98,0x9b,0x1e,
+ 0xe0,0xec,0x3f,0x8d,0xbe
+ };
+ const unsigned char expected[] = {
+ 0xa4,0x62,0xde,0x16,0xa8,0x9d,0xe8,0x46,0x6e,0xf5,0x46,0x0b,0x47,0xb8
+ };
+ unsigned char out[14];
+
+ kctx = EVP_KDF_CTX_new_id(EVP_KDF_SS);
+
+ if (EVP_KDF_ctrl(kctx, EVP_KDF_CTRL_SET_MD, EVP_sha224()) <= 0) {
+ TEST_error("EVP_KDF_CTRL_SET_MD");
+ return 0;
+ }
+ if (EVP_KDF_ctrl(kctx, EVP_KDF_CTRL_SET_KEY, z, sizeof(z)) <= 0) {
+ TEST_error("EVP_KDF_CTRL_SET_KEY");
+ return 0;
+ }
+ if (EVP_KDF_ctrl(kctx, EVP_KDF_CTRL_SET_SSKDF_INFO, other,
+ sizeof(other)) <= 0) {
+ TEST_error("EVP_KDF_CTRL_SET_SSKDF_INFO");
+ return 0;
+ }
+ if (EVP_KDF_derive(kctx, out, sizeof(out)) <= 0) {
+ TEST_error("EVP_KDF_derive");
+ return 0;
+ }
+
+ if (!TEST_mem_eq(out, sizeof(out), expected, sizeof(expected)))
+ return 0;
+
+ EVP_KDF_CTX_free(kctx);
+ return 1;
+}
+
int setup_tests(void)
{
+ ADD_TEST(test_kdf_kbkdf_6803_128);
+ ADD_TEST(test_kdf_kbkdf_6803_256);
+ ADD_TEST(test_kdf_kbkdf_8009_prf1);
+ ADD_TEST(test_kdf_kbkdf_8009_prf2);
ADD_TEST(test_kdf_tls1_prf);
ADD_TEST(test_kdf_hkdf);
ADD_TEST(test_kdf_pbkdf2);
#ifndef OPENSSL_NO_SCRYPT
ADD_TEST(test_kdf_scrypt);
#endif
+ ADD_TEST(test_kdf_krb5kdf);
+ ADD_TEST(test_kdf_ss_hash);
return 1;
}
diff -up openssl-1.1.1d/test/recipes/30-test_evp_data/evpkdf.txt.krb5-kdf openssl-1.1.1d/test/recipes/30-test_evp_data/evpkdf.txt
--- openssl-1.1.1d/test/recipes/30-test_evp_data/evpkdf.txt.krb5-kdf 2019-11-14 15:07:05.327094396 +0100
+++ openssl-1.1.1d/test/recipes/30-test_evp_data/evpkdf.txt 2019-11-14 15:07:05.349094005 +0100
@@ -5286,3 +5286,559 @@ Ctrl.hexsession_id = hexsession_id:a4ebd
Ctrl.type = type:A
Output = FF
Result = KDF_MISMATCH
+
+Title = KRB5KDF tests (from RFC 3961 test vectors and krb5 sources)
+
+#RFC3961
+KDF = KRB5KDF
+Ctrl.cipher = cipher:DES-EDE3-CBC
+Ctrl.hexkey = hexkey:dce06b1f64c857a11c3db57c51899b2cc1791008ce973b92
+Ctrl.hexconstant = hexconstant:0000000155
+Output = 925179d04591a79b5d3192c4a7e9c289b049c71f6ee604cd
+
+KDF = KRB5KDF
+Ctrl.cipher = cipher:DES-EDE3-CBC
+Ctrl.hexkey = hexkey:5e13d31c70ef765746578531cb51c15bf11ca82c97cee9f2
+Ctrl.hexconstant = hexconstant:00000001aa
+Output = 9e58e5a146d9942a101c469845d67a20e3c4259ed913f207
+
+KDF = KRB5KDF
+Ctrl.cipher = cipher:DES-EDE3-CBC
+Ctrl.hexkey = hexkey:98e6fd8a04a4b6859b75a176540b9752bad3ecd610a252bc
+Ctrl.hexconstant = hexconstant:0000000155
+Output = 13fef80d763e94ec6d13fd2ca1d085070249dad39808eabf
+
+KDF = KRB5KDF
+Ctrl.cipher = cipher:DES-EDE3-CBC
+Ctrl.hexkey = hexkey:622aec25a2fe2cad7094680b7c64940280084c1a7cec92b5
+Ctrl.hexconstant = hexconstant:00000001aa
+Output = f8dfbf04b097e6d9dc0702686bcb3489d91fd9a4516b703e
+
+KDF = KRB5KDF
+Ctrl.cipher = cipher:DES-EDE3-CBC
+Ctrl.hexkey = hexkey:d3f8298ccb166438dcb9b93ee5a7629286a491f838f802fb
+Ctrl.hexconstant = hexconstant:6b65726265726f73
+Output = 2370da575d2a3da864cebfdc5204d56df779a7df43d9da43
+
+KDF = KRB5KDF
+Ctrl.cipher = cipher:DES-EDE3-CBC
+Ctrl.hexkey = hexkey:c1081649ada74362e6a1459d01dfd30d67c2234c940704da
+Ctrl.hexconstant = hexconstant:0000000155
+Output = 348057ec98fdc48016161c2a4c7a943e92ae492c989175f7
+
+KDF = KRB5KDF
+Ctrl.cipher = cipher:DES-EDE3-CBC
+Ctrl.hexkey = hexkey:5d154af238f46713155719d55e2f1f790dd661f279a7917c
+Ctrl.hexconstant = hexconstant:00000001aa
+Output = a8808ac267dada3dcbe9a7c84626fbc761c294b01315e5c1
+
+KDF = KRB5KDF
+Ctrl.cipher = cipher:DES-EDE3-CBC
+Ctrl.hexkey = hexkey:798562e049852f57dc8c343ba17f2ca1d97394efc8adc443
+Ctrl.hexconstant = hexconstant:0000000155
+Output = c813f88a3be3b334f75425ce9175fbe3c8493b89c8703b49
+
+KDF = KRB5KDF
+Ctrl.cipher = cipher:DES-EDE3-CBC
+Ctrl.hexkey = hexkey:26dce334b545292f2feab9a8701a89a4b99eb9942cecd016
+Ctrl.hexconstant = hexconstant:00000001aa
+Output = f48ffd6e83f83e7354e694fd252cf83bfe58f7d5ba37ec5d
+
+#Krb5 sources
+KDF = KRB5KDF
+Ctrl.cipher = cipher:DES-EDE3-CBC
+Ctrl.hexkey = hexkey:850BB51358548CD05E86768C313E3BFEF7511937DCF72C3E
+Ctrl.hexconstant = hexconstant:0000000299
+Output = F78C496D16E6C2DAE0E0B6C24057A84C0426AEEF26FD6DCE
+
+KDF = KRB5KDF
+Ctrl.cipher = cipher:DES-EDE3-CBC
+Ctrl.hexkey = hexkey:850BB51358548CD05E86768C313E3BFEF7511937DCF72C3E
+Ctrl.hexconstant = hexconstant:00000002AA
+Output = 5B5723D0B634CB684C3EBA5264E9A70D52E683231AD3C4CE
+
+KDF = KRB5KDF
+Ctrl.cipher = cipher:DES-EDE3-CBC
+Ctrl.hexkey = hexkey:850BB51358548CD05E86768C313E3BFEF7511937DCF72C3E
+Ctrl.hexconstant = hexconstant:0000000255
+Output = A77C94980E9B7345A81525C423A737CE67F4CD91B6B3DA45
+
+KDF = KRB5KDF
+Ctrl.cipher = cipher:AES-128-CBC
+Ctrl.hexkey = hexkey:42263C6E89F4FC28B8DF68EE09799F15
+Ctrl.hexconstant = hexconstant:0000000299
+Output = 34280A382BC92769B2DA2F9EF066854B
+
+KDF = KRB5KDF
+Ctrl.cipher = cipher:AES-128-CBC
+Ctrl.hexkey = hexkey:42263C6E89F4FC28B8DF68EE09799F15
+Ctrl.hexconstant = hexconstant:00000002AA
+Output = 5B14FC4E250E14DDF9DCCF1AF6674F53
+
+KDF = KRB5KDF
+Ctrl.cipher = cipher:AES-128-CBC
+Ctrl.hexkey = hexkey:42263C6E89F4FC28B8DF68EE09799F15
+Ctrl.hexconstant = hexconstant:0000000255
+Output = 4ED31063621684F09AE8D89991AF3E8F
+
+KDF = KRB5KDF
+Ctrl.cipher = cipher:AES-256-CBC
+Ctrl.hexkey = hexkey:FE697B52BC0D3CE14432BA036A92E65BBB52280990A2FA27883998D72AF30161
+Ctrl.hexconstant = hexconstant:0000000299
+Output = BFAB388BDCB238E9F9C98D6A878304F04D30C82556375AC507A7A852790F4674
+
+KDF = KRB5KDF
+Ctrl.cipher = cipher:AES-256-CBC
+Ctrl.hexkey = hexkey:FE697B52BC0D3CE14432BA036A92E65BBB52280990A2FA27883998D72AF30161
+Ctrl.hexconstant = hexconstant:00000002AA
+Output = C7CFD9CD75FE793A586A542D87E0D1396F1134A104BB1A9190B8C90ADA3DDF37
+
+KDF = KRB5KDF
+Ctrl.cipher = cipher:AES-256-CBC
+Ctrl.hexkey = hexkey:FE697B52BC0D3CE14432BA036A92E65BBB52280990A2FA27883998D72AF30161
+Ctrl.hexconstant = hexconstant:0000000255
+Output = 97151B4C76945063E2EB0529DC067D97D7BBA90776D8126D91F34F3101AEA8BA
+
+#Same as the first but with no "fixup"
+KDF = KRB5KDF
+Ctrl.cipher = cipher:DES-EDE3-CBC
+Ctrl.hexkey = hexkey:dce06b1f64c857a11c3db57c51899b2cc1791008ce973b92
+Ctrl.hexconstant = hexconstant:0000000155
+Output = 935079d14490a75c3093c4a6e8c3b049c71e6ee705
+
+#There are currently no official test vectors for Single Step KDF
+#https://github.com/patrickfav/singlestep-kdf/wiki/NIST-SP-800-56C-Rev1:-Non-Official-Test-Vectors
+Title = Single Step KDF tests
+
+KDF = SSKDF
+Ctrl.digest = digest:SHA1
+Ctrl.hexsecret = hexsecret:d09a6b1a472f930db4f5e6b967900744
+Ctrl.hexinfo = hexinfo:b117255ab5f1b6b96fc434b0
+Output = b5a3c52e97ae6e8c5069954354eab3c7
+
+KDF = SSKDF
+Ctrl.digest = digest:SHA1
+Ctrl.hexsecret = hexsecret:343666c0dd34b756e70f759f14c304f5
+Ctrl.hexinfo = hexinfo:722b28448d7eab85491bce09
+Output = 1003b650ddd3f0891a15166db5ec881d
+
+KDF = SSKDF
+Ctrl.digest = digest:SHA1
+Ctrl.hexsecret = hexsecret:b84acf03ab08652dd7f82fa956933261
+Ctrl.hexinfo = hexinfo:3d8773ec068c86053a918565
+Output = 1635dcd1ce698f736831b4badb68ab2b
+
+KDF = SSKDF
+Ctrl.digest = digest:SHA1
+Ctrl.hexsecret = hexsecret:8cc24ca3f1d1a8b34783780b79890430
+Ctrl.hexinfo = hexinfo:f08d4f2d9a8e6d7105c0bc16
+Output = b8e716fb84a420aed4812cd76d9700ee
+
+KDF = SSKDF
+Ctrl.digest = digest:SHA1
+Ctrl.hexsecret = hexsecret:b616905a6f7562cd2689142ce21e42a3
+Ctrl.hexinfo = hexinfo:ead310159a909da87e7b4b40
+Output = 1b9201358c50fe5d5d42907c4a9fce78
+
+KDF = SSKDF
+Ctrl.digest = digest:SHA1
+Ctrl.hexsecret = hexsecret:3f57fd3fd56199b3eb33890f7ee28180
+Ctrl.hexinfo = hexinfo:7a5056ba4fdb034c7cb6c4fe
+Output = e51ebd30a8c4b8449b0fb29d9adc11af
+
+KDF = SSKDF
+Ctrl.digest = digest:SHA1
+Ctrl.hexsecret = hexsecret:fb9fb108d104e9f662d6593fc84cde69
+Ctrl.hexinfo = hexinfo:5faf29211c1bdbf1b2696a7c
+Output = 7a3a7e670656e48c390cdd7c51e167e0
+
+KDF = SSKDF
+Ctrl.digest = digest:SHA1
+Ctrl.hexsecret = hexsecret:237a39981794f4516dccffc3dda28396
+Ctrl.hexinfo = hexinfo:62ed9528d104c241e0f66275
+Output = 0c26fc9e90e1c5c5f943428301682045
+
+KDF = SSKDF
+Ctrl.digest = digest:SHA1
+Ctrl.hexsecret = hexsecret:b9b6c45f7279218fa09894e06366a3a1
+Ctrl.hexinfo = hexinfo:0f384339670aaed4b89ecb7e
+Output = ee5fad414e32fad5d52a2bf61a7f6c72
+
+KDF = SSKDF
+Ctrl.digest = digest:SHA1
+Ctrl.hexsecret = hexsecret:08b7140e2cd0a4abd79171e4d5a71cad
+Ctrl.hexinfo = hexinfo:099211f0d8a2e02dbb5958c0
+Output = 6162f5142e057efafd2c4f2bad5985a1
+
+KDF = SSKDF
+Ctrl.digest = digest:SHA1
+Ctrl.hexsecret = hexsecret:ebe28edbae5a410b87a479243db3f690
+Ctrl.hexinfo = hexinfo:e60dd8b28228ce5b9be74d3b
+Output = b4a2
+
+KDF = SSKDF
+Ctrl.digest = digest:SHA1
+Ctrl.hexsecret = hexsecret:ebe28edbae5a410b87a479243db3f690
+Ctrl.hexinfo = hexinfo:e60dd8b28228ce5b9be74d3b
+Output = b4a23963
+
+KDF = SSKDF
+Ctrl.digest = digest:SHA1
+Ctrl.hexsecret = hexsecret:ebe28edbae5a410b87a479243db3f690
+Ctrl.hexinfo = hexinfo:e60dd8b28228ce5b9be74d3b
+Output = b4a23963e07f
+
+KDF = SSKDF
+Ctrl.digest = digest:SHA1
+Ctrl.hexsecret = hexsecret:ebe28edbae5a410b87a479243db3f690
+Ctrl.hexinfo = hexinfo:e60dd8b28228ce5b9be74d3b
+Output = b4a23963e07f4853
+
+KDF = SSKDF
+Ctrl.digest = digest:SHA1
+Ctrl.hexsecret = hexsecret:ebe28edbae5a410b87a479243db3f690
+Ctrl.hexinfo = hexinfo:e60dd8b28228ce5b9be74d3b
+Output = b4a23963e07f485382cb
+
+KDF = SSKDF
+Ctrl.digest = digest:SHA1
+Ctrl.hexsecret = hexsecret:ebe28edbae5a410b87a479243db3f690
+Ctrl.hexinfo = hexinfo:e60dd8b28228ce5b9be74d3b
+Output = b4a23963e07f485382cb358a
+
+KDF = SSKDF
+Ctrl.digest = digest:SHA1
+Ctrl.hexsecret = hexsecret:ebe28edbae5a410b87a479243db3f690
+Ctrl.hexinfo = hexinfo:e60dd8b28228ce5b9be74d3b
+Output = b4a23963e07f485382cb358a493d
+
+KDF = SSKDF
+Ctrl.digest = digest:SHA1
+Ctrl.hexsecret = hexsecret:ebe28edbae5a410b87a479243db3f690
+Ctrl.hexinfo = hexinfo:e60dd8b28228ce5b9be74d3b
+Output = b4a23963e07f485382cb358a493daec1
+
+KDF = SSKDF
+Ctrl.digest = digest:SHA1
+Ctrl.hexsecret = hexsecret:ebe28edbae5a410b87a479243db3f690
+Ctrl.hexinfo = hexinfo:e60dd8b28228ce5b9be74d3b
+Output = b4a23963e07f485382cb358a493daec1759a
+
+KDF = SSKDF
+Ctrl.digest = digest:SHA1
+Ctrl.hexsecret = hexsecret:ebe28edbae5a410b87a479243db3f690
+Ctrl.hexinfo = hexinfo:e60dd8b28228ce5b9be74d3b
+Output = b4a23963e07f485382cb358a493daec1759ac704
+
+KDF = SSKDF
+Ctrl.digest = digest:SHA1
+Ctrl.hexsecret = hexsecret:ebe28edbae5a410b87a479243db3f690
+Ctrl.hexinfo = hexinfo:e60dd8b28228ce5b9be74d3b
+Output = b4a23963e07f485382cb358a493daec1759ac7043dbe
+
+KDF = SSKDF
+Ctrl.digest = digest:SHA1
+Ctrl.hexsecret = hexsecret:ebe28edbae5a410b87a479243db3f690
+Ctrl.hexinfo = hexinfo:e60dd8b28228ce5b9be74d3b
+Output = b4a23963e07f485382cb358a493daec1759ac7043dbeac37
+
+KDF = SSKDF
+Ctrl.digest = digest:SHA1
+Ctrl.hexsecret = hexsecret:ebe28edbae5a410b87a479243db3f690
+Ctrl.hexinfo = hexinfo:e60dd8b28228ce5b9be74d3b
+Output = b4a23963e07f485382cb358a493daec1759ac7043dbeac37152c
+
+KDF = SSKDF
+Ctrl.digest = digest:SHA1
+Ctrl.hexsecret = hexsecret:ebe28edbae5a410b87a479243db3f690
+Ctrl.hexinfo = hexinfo:e60dd8b28228ce5b9be74d3b
+Output = b4a23963e07f485382cb358a493daec1759ac7043dbeac37152c6ddf
+
+KDF = SSKDF
+Ctrl.digest = digest:SHA1
+Ctrl.hexsecret = hexsecret:ebe28edbae5a410b87a479243db3f690
+Ctrl.hexinfo = hexinfo:e60dd8b28228ce5b9be74d3b
+Output = b4a23963e07f485382cb358a493daec1759ac7043dbeac37152c6ddf1050
+
+KDF = SSKDF
+Ctrl.digest = digest:SHA1
+Ctrl.hexsecret = hexsecret:ebe28edbae5a410b87a479243db3f690
+Ctrl.hexinfo = hexinfo:e60dd8b28228ce5b9be74d3b
+Output = b4a23963e07f485382cb358a493daec1759ac7043dbeac37152c6ddf105031f0
+
+KDF = SSKDF
+Ctrl.digest = digest:SHA1
+Ctrl.hexsecret = hexsecret:ebe28edbae5a410b87a479243db3f690
+Ctrl.hexinfo = hexinfo:e60dd8b28228ce5b9be74d3b
+Output = b4a23963e07f485382cb358a493daec1759ac7043dbeac37152c6ddf105031f0f239
+
+KDF = SSKDF
+Ctrl.digest = digest:SHA1
+Ctrl.hexsecret = hexsecret:ebe28edbae5a410b87a479243db3f690
+Ctrl.hexinfo = hexinfo:e60dd8b28228ce5b9be74d3b
+Output = b4a23963e07f485382cb358a493daec1759ac7043dbeac37152c6ddf105031f0f239f270
+
+KDF = SSKDF
+Ctrl.digest = digest:SHA1
+Ctrl.hexsecret = hexsecret:ebe28edbae5a410b87a479243db3f690
+Ctrl.hexinfo = hexinfo:e60dd8b28228ce5b9be74d3b
+Output = b4a23963e07f485382cb358a493daec1759ac7043dbeac37152c6ddf105031f0f239f270b7f3
+
+KDF = SSKDF
+Ctrl.digest = digest:SHA1
+Ctrl.hexsecret = hexsecret:ebe28edbae5a410b87a479243db3f690
+Ctrl.hexinfo = hexinfo:e60dd8b28228ce5b9be74d3b
+Output = b4a23963e07f485382cb358a493daec1759ac7043dbeac37152c6ddf105031f0f239f270b7f30616
+
+KDF = SSKDF
+Ctrl.digest = digest:SHA1
+Ctrl.hexsecret = hexsecret:ebe28edbae5a410b87a479243db3f690
+Ctrl.hexinfo = hexinfo:e60dd8b28228ce5b9be74d3b
+Output = b4a23963e07f485382cb358a493daec1759ac7043dbeac37152c6ddf105031f0f239f270b7f30616166f
+
+KDF = SSKDF
+Ctrl.digest = digest:SHA1
+Ctrl.hexsecret = hexsecret:ebe28edbae5a410b87a479243db3f690
+Ctrl.hexinfo = hexinfo:e60dd8b28228ce5b9be74d3b
+Output = b4a23963e07f485382cb358a493daec1759ac7043dbeac37152c6ddf105031f0f239f270b7f30616166f10e5
+
+KDF = SSKDF
+Ctrl.digest = digest:SHA1
+Ctrl.hexsecret = hexsecret:ebe28edbae5a410b87a479243db3f690
+Ctrl.hexinfo = hexinfo:e60dd8b28228ce5b9be74d3b
+Output = b4a23963e07f485382cb358a493daec1759ac7043dbeac37152c6ddf105031f0f239f270b7f30616166f10e5d2b4
+
+KDF = SSKDF
+Ctrl.digest = digest:SHA1
+Ctrl.hexsecret = hexsecret:ebe28edbae5a410b87a479243db3f690
+Ctrl.hexinfo = hexinfo:e60dd8b28228ce5b9be74d3b
+Output = b4a23963e07f485382cb358a493daec1759ac7043dbeac37152c6ddf105031f0f239f270b7f30616166f10e5d2b4cb11
+
+KDF = SSKDF
+Ctrl.digest = digest:SHA1
+Ctrl.hexsecret = hexsecret:ebe28edbae5a410b87a479243db3f690
+Ctrl.hexinfo = hexinfo:e60dd8b28228ce5b9be74d3b
+Output = b4a23963e07f485382cb358a493daec1759ac7043dbeac37152c6ddf105031f0f239f270b7f30616166f10e5d2b4cb11ba8b
+
+KDF = SSKDF
+Ctrl.digest = digest:SHA1
+Ctrl.hexsecret = hexsecret:ebe28edbae5a410b87a479243db3f690
+Ctrl.hexinfo = hexinfo:e60dd8b28228ce5b9be74d3b
+Output = b4a23963e07f485382cb358a493daec1759ac7043dbeac37152c6ddf105031f0f239f270b7f30616166f10e5d2b4cb11ba8bf4ba
+
+KDF = SSKDF
+Ctrl.digest = digest:SHA1
+Ctrl.hexsecret = hexsecret:ebe28edbae5a410b87a479243db3f690
+Ctrl.hexinfo = hexinfo:e60dd8b28228ce5b9be74d3b
+Output = b4a23963e07f485382cb358a493daec1759ac7043dbeac37152c6ddf105031f0f239f270b7f30616166f10e5d2b4cb11ba8bf4ba3f22
+
+KDF = SSKDF
+Ctrl.digest = digest:SHA1
+Ctrl.hexsecret = hexsecret:ebe28edbae5a410b87a479243db3f690
+Ctrl.hexinfo = hexinfo:e60dd8b28228ce5b9be74d3b
+Output = b4a23963e07f485382cb358a493daec1759ac7043dbeac37152c6ddf105031f0f239f270b7f30616166f10e5d2b4cb11ba8bf4ba3f227688
+
+KDF = SSKDF
+Ctrl.digest = digest:SHA1
+Ctrl.hexsecret = hexsecret:ebe28edbae5a410b87a479243db3f690
+Ctrl.hexinfo = hexinfo:e60dd8b28228ce5b9be74d3b
+Output = b4a23963e07f485382cb358a493daec1759ac7043dbeac37152c6ddf105031f0f239f270b7f30616166f10e5d2b4cb11ba8bf4ba3f2276885abf
+
+KDF = SSKDF
+Ctrl.digest = digest:SHA1
+Ctrl.hexsecret = hexsecret:ebe28edbae5a410b87a479243db3f690
+Ctrl.hexinfo = hexinfo:e60dd8b28228ce5b9be74d3b
+Output = b4a23963e07f485382cb358a493daec1759ac7043dbeac37152c6ddf105031f0f239f270b7f30616166f10e5d2b4cb11ba8bf4ba3f2276885abfbc3e
+
+KDF = SSKDF
+Ctrl.digest = digest:SHA1
+Ctrl.hexsecret = hexsecret:ebe28edbae5a410b87a479243db3f690
+Ctrl.hexinfo = hexinfo:e60dd8b28228ce5b9be74d3b
+Output = b4a23963e07f485382cb358a493daec1759ac7043dbeac37152c6ddf105031f0f239f270b7f30616166f10e5d2b4cb11ba8bf4ba3f2276885abfbc3e811a
+
+KDF = SSKDF
+Ctrl.digest = digest:SHA1
+Ctrl.hexsecret = hexsecret:ebe28edbae5a410b87a479243db3f690
+Ctrl.hexinfo = hexinfo:e60dd8b28228ce5b9be74d3b
+Output = b4a23963e07f485382cb358a493daec1759ac7043dbeac37152c6ddf105031f0f239f270b7f30616166f10e5d2b4cb11ba8bf4ba3f2276885abfbc3e811a568d
+
+KDF = SSKDF
+Ctrl.digest = digest:SHA1
+Ctrl.hexsecret = hexsecret:ebe28edbae5a410b87a479243db3f690
+Ctrl.hexinfo = hexinfo:e60dd8b28228ce5b9be74d3b
+Output = b4a23963e07f485382cb358a493daec1759ac7043dbeac37152c6ddf105031f0f239f270b7f30616166f10e5d2b4cb11ba8bf4ba3f2276885abfbc3e811a568d480d
+
+KDF = SSKDF
+Ctrl.digest = digest:SHA1
+Ctrl.hexsecret = hexsecret:ebe28edbae5a410b87a479243db3f690
+Ctrl.hexinfo = hexinfo:e60dd8b28228ce5b9be74d3b
+Output = b4a23963e07f485382cb358a493daec1759ac7043dbeac37152c6ddf105031f0f239f270b7f30616166f10e5d2b4cb11ba8bf4ba3f2276885abfbc3e811a568d480d9192
+
+KDF = SSKDF
+Ctrl.digest = digest:SHA1
+Ctrl.hexsecret = hexsecret:d7e6
+Ctrl.hexinfo = hexinfo:0bbe1fa8722023d7c3da4fff
+Output = 31e798e9931b612a3ad1b9b1008faa8c
+
+KDF = SSKDF
+Ctrl.digest = digest:SHA1
+Ctrl.hexsecret = hexsecret:4646779d
+Ctrl.hexinfo = hexinfo:0bbe1fa8722023d7c3da4fff
+Output = 139f68bcca879b490e268e569087d04d
+
+KDF = SSKDF
+Ctrl.digest = digest:SHA1
+Ctrl.hexsecret = hexsecret:d9811c81d4c6
+Ctrl.hexinfo = hexinfo:0bbe1fa8722023d7c3da4fff
+Output = 914dc4f09cb633a76e6c389e04c64485
+
+KDF = SSKDF
+Ctrl.digest = digest:SHA1
+Ctrl.hexsecret = hexsecret:8838f9d99ec46f09
+Ctrl.hexinfo = hexinfo:0bbe1fa8722023d7c3da4fff
+Output = 4f07dfb6f7a5bf348689e08b2e29c948
+
+KDF = SSKDF
+Ctrl.digest = digest:SHA1
+Ctrl.hexsecret = hexsecret:3e0939b33f34e779f30e
+Ctrl.hexinfo = hexinfo:0bbe1fa8722023d7c3da4fff
+Output = b42c7a98c23be19d1187ff960e87557f
+
+KDF = SSKDF
+Ctrl.digest = digest:SHA1
+Ctrl.hexsecret = hexsecret:f36230cacca4d245d303058c
+Ctrl.hexinfo = hexinfo:0bbe1fa8722023d7c3da4fff
+Output = 50f2068d8010d355d56c5e34aaffbc67
+
+KDF = SSKDF
+Ctrl.digest = digest:SHA1
+Ctrl.hexsecret = hexsecret:7005d32c3d4284c73c3aefc70438
+Ctrl.hexinfo = hexinfo:0bbe1fa8722023d7c3da4fff
+Output = 66fd712ccf5462bbd41e89041ea7ea26
+
+KDF = SSKDF
+Ctrl.digest = digest:SHA1
+Ctrl.hexsecret = hexsecret:c01c83150b7734f8dbd6efd6f54d7365
+Ctrl.hexinfo = hexinfo:0bbe1fa8722023d7c3da4fff
+Output = 5c5edb0ceda9cd0c7f1f3d9e239c67d5
+
+KDF = SSKDF
+Ctrl.digest = digest:SHA1
+Ctrl.hexsecret = hexsecret:da69f1dbbebc837480af692e7e9ee6b9
+Ctrl.hexinfo = hexinfo:9949
+Output = 33c83f54ed00fb1bccd2113e88550941
+
+KDF = SSKDF
+Ctrl.digest = digest:SHA1
+Ctrl.hexsecret = hexsecret:da69f1dbbebc837480af692e7e9ee6b9
+Ctrl.hexinfo = hexinfo:17144da6
+Output = a999c28961424cab35ec06015e8c376a
+
+KDF = SSKDF
+Ctrl.digest = digest:SHA1
+Ctrl.hexsecret = hexsecret:da69f1dbbebc837480af692e7e9ee6b9
+Ctrl.hexinfo = hexinfo:dffdee1062eb
+Output = 4101ad50e626ed6f957bff926dfbb7db
+
+KDF = SSKDF
+Ctrl.digest = digest:SHA1
+Ctrl.hexsecret = hexsecret:da69f1dbbebc837480af692e7e9ee6b9
+Ctrl.hexinfo = hexinfo:9f365043e23b4648
+Output = 4d3e4b971b88771f229df9f564984832
+
+KDF = SSKDF
+Ctrl.digest = digest:SHA1
+Ctrl.hexsecret = hexsecret:da69f1dbbebc837480af692e7e9ee6b9
+Ctrl.hexinfo = hexinfo:a885a0c4567ddc4f96da
+Output = bebbc30f5a83df5e9c9b57db33c0c879
+
+KDF = SSKDF
+Ctrl.digest = digest:SHA1
+Ctrl.hexsecret = hexsecret:da69f1dbbebc837480af692e7e9ee6b9
+Ctrl.hexinfo = hexinfo:c9d86183295bfe4c3d85f0fd
+Output = 87c947e45407db63eb94cbaa02d14e94
+
+KDF = SSKDF
+Ctrl.digest = digest:SHA1
+Ctrl.hexsecret = hexsecret:da69f1dbbebc837480af692e7e9ee6b9
+Ctrl.hexinfo = hexinfo:825fadce46964236a486732c5dad
+Output = 192370a85ff78e3c0245129d9b398558
+
+KDF = SSKDF
+Ctrl.digest = digest:SHA1
+Ctrl.hexsecret = hexsecret:da69f1dbbebc837480af692e7e9ee6b9
+Ctrl.hexinfo = hexinfo:5c0b5eb3ac9f342347d73d7a521723aa
+Output = c7b7634fd809383e87c4b1b3e728be56
+
+KDF = SSKDF
+Ctrl.digest = digest:SHA1
+Ctrl.hexsecret = hexsecret:8d7a4e7d5cf34b3f74873b862aeb33b7
+Output = 6a5594f402f74f69
+
+KDF = SSKDF
+Ctrl.digest = digest:SHA1
+Ctrl.hexsecret = hexsecret:9b208e7ee1e641fac1dff48fc1beb2d2
+Output = 556ed67e24ac0c7c46cc432da8bdb23c
+
+KDF = SSKDF
+Ctrl.digest = digest:SHA1
+Ctrl.hexsecret = hexsecret:4d2572539fed433211da28c8a0eebac3
+Output = 5a4054c59c5b92814025578f43c1b79fe84968fc284e240b
+
+KDF = SSKDF
+Ctrl.digest = digest:SHA1
+Ctrl.hexsecret = hexsecret:4e1e70c9886819a31bc29a537911add9
+Output = ddbfc440449aab4131c6d8aec08ce1496f2702241d0e27cc155c5c7c3cda75b5
+
+KDF = SSKDF
+Ctrl.digest = digest:SHA1
+Ctrl.hexsecret = hexsecret:68f144c952528e540c686dc353b766f2
+Output = 59ed66bb6f54a9688a0b891d0b2ea6743621d9e1b5cc098cf3a55e6f864f9af8a95e4d945d2f987f
+
+KDF = SSKDF
+Ctrl.digest = digest:SHA1
+Ctrl.hexsecret = hexsecret:b66c9d507c9f837fbe60b6675fdbf38b
+Output = c282787ddf421a72fc88811be81b08d0d6ab66c92d1011974aa58335a6bbbd62e9e982bfae5929865ea1d517247089d2
+
+KDF = SSKDF
+Ctrl.digest = digest:SHA1
+Ctrl.hexsecret = hexsecret:34e730b49e46c7ed2fb25975a4cccd2d
+Output = 39e76e6571cb00740260b9070accbdcc4a492c295cbef33d9e37dac21e5e9d07e0f12dc7063d2172641475d4e08b8e3712fb26a10c8376b8
+
+KDF = SSKDF
+Ctrl.digest = digest:SHA1
+Ctrl.hexsecret = hexsecret:e340d87e2d7adbc1b95ec2dbdc3b82be
+Output = a660c0037a53f76f1e7667043f5869348ad07ac0e272e615ce31f16d4ab90d4b35fe5c370c0010ce79aff45682c6fb8b97f9a05b7d40b5af3c62999a10df9c6d
+
+KDF = SSKDF
+Ctrl.digest = digest:SHA256
+Ctrl.hexsecret = hexsecret:afc4e154498d4770aa8365f6903dc83b
+Ctrl.hexinfo = hexinfo:662af20379b29d5ef813e655
+Output = f0b80d6ae4c1e19e2105a37024e35dc6
+
+
+KDF = SSKDF
+Ctrl.digest = digest:SHA512
+Ctrl.hexsecret = hexsecret:108cf63318555c787fa578731dd4f037
+Ctrl.hexinfo = hexinfo:53191b1dd3f94d83084d61d6
+Output = 0ad475c1826da3007637970c8b92b993
+
+Title = SSKDF Test vectors from RFC 8636 Section 8 (With precoumputed ASN.1 info)
+
+KDF = SSKDF
+Ctrl.digest = digest:SHA1
+Ctrl.hexsecret = hexsecret:00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+Ctrl.hexinfo = hexinfo:307e300a06082b06010502030601a01f041d301ba0071b0553552e5345a110300ea003020101a10730051b036c6861a12904273025a0071b0553552e5345a11a3018a003020101a111300f1b066b72627467741b0553552e5345a22404223020a003020112a10c040aaaaaaaaaaaaaaaaaaaaaa20b0409bbbbbbbbbbbbbbbbbb
+Output = e6ab38c9413e035bb079201ed0b6b73d8d49a814a737c04ee6649614206f73ad
+
+KDF = SSKDF
+Ctrl.digest = digest:SHA256
+Ctrl.hexsecret = hexsecret:00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+Ctrl.hexinfo = hexinfo:307e300a06082b06010502030602a01f041d301ba0071b0553552e5345a110300ea003020101a10730051b036c6861a12904273025a0071b0553552e5345a11a3018a003020101a111300f1b066b72627467741b0553552e5345a22404223020a003020112a10c040aaaaaaaaaaaaaaaaaaaaaa20b0409bbbbbbbbbbbbbbbbbb
+Output = 77ef4e48c420ae3fec75109d7981697eed5d295c90c62564f7bfd101fa9bc1d5
+
+KDF = SSKDF
+Ctrl.digest = digest:SHA512
+Ctrl.hexsecret = hexsecret:00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+Ctrl.hexinfo = hexinfo:307e300a06082b06010502030603a01f041d301ba0071b0553552e5345a110300ea003020101a10730051b036c6861a12904273025a0071b0553552e5345a11a3018a003020101a111300f1b066b72627467741b0553552e5345a22404223020a003020110a10c040aaaaaaaaaaaaaaaaaaaaaa20b0409bbbbbbbbbbbbbbbbbb
+Output = d3c78b78d75313e9a926f75dfb012363fa17fa01db