Difference between revisions of "EVP Key Derivation"
m (Add KDF example; stop redirect to Key Agreement page.) |
|||
(7 intermediate revisions by 3 users not shown) | |||
Line 1: | Line 1: | ||
− | Key derivation is the process of deriving one or more secret keys from a secret value such as a password or a passphrase. Several key derivation algoirthms have been standardized, and they are usually referred to a Key Derivation Functions (KDFs). KDFs include PBKDF2 from RFC 2898, HKDF form RFC 5869 and Scrypt from RFC 7914. OpenSSL provides PBKDF2, Scrypt, HKDF, ANSI X9.42 | + | Key derivation is the process of deriving one or more secret keys from a secret value such as a password or a passphrase. Several key derivation algoirthms have been standardized, and they are usually referred to a Key Derivation Functions (KDFs). KDFs include PBKDF2 from RFC 2898, HKDF form RFC 5869 and Scrypt from RFC 7914. |
+ | |||
+ | OpenSSL 1.0.2 and above provides PBKDF2 by way of <tt>PKCS5_PBKDF2_HMAC</tt> and <tt>PKCS5_PBKDF2_HMAC_SHA1</tt>. | ||
+ | |||
+ | OpenSSL 1.1.0 and above additionally provides HKDF and TLS1 PRF KDF by way of <tt>EVP_PKEY_derive</tt> and Scrypt by way of <tt>EVP_PBE_scrypt</tt> | ||
+ | |||
+ | OpenSSL 1.1.1 and above additionally provides Scrypt by way of <tt>EVP_PKEY_derive</tt>. | ||
+ | |||
+ | OpenSSL 3.0 additionally provides Single Step KDF, SSH KDF, PBKDF2, Scrypt, HKDF, ANSI X9.42 KDF, ANSI X9.63 KDF and TLS1 PRF KDF by way of <tt>EVP_KDF</tt>. | ||
+ | |||
+ | From OpenSSL 3.0 the recommended way of performing key derivation is to use the EVP_KDF functions. If compatibility with OpenSSL 1.1.1 is required then a limited set of KDFs can be used via EVP_PKEY_derive. | ||
− | |||
== HKDF key derivation == | == HKDF key derivation == | ||
− | The following | + | The following example derives a key and initialization vector using HKDF from RFC 5869 and SHA-256. HKDF was designed by Krawczyk and Eronen, and it is state of the art in expand-then-extract key derivation algorithms. It is usually a good choice when you need a KDF. The program below was taken from the OpenSSL man pages. |
HKDF takes three parameter: | HKDF takes three parameter: | ||
− | <tt>secret</tt> - private information to use during derivation, like a password or passphrase. The parameter is set using <tt>EVP_KDF_CTRL_SET_KEY</tt>. | + | * <tt>secret</tt> - private information to use during derivation, like a password or passphrase. The parameter is set using <tt>EVP_KDF_CTRL_SET_KEY</tt>. |
− | <tt>salt</tt> - possibly public information to use during derivation. <tt>salt</tt> is optional. The parameter is set using <tt>EVP_KDF_CTRL_SET_SALT</tt>. | + | * <tt>salt</tt> - possibly public information to use during derivation. <tt>salt</tt> is optional. The parameter is set using <tt>EVP_KDF_CTRL_SET_SALT</tt>. |
− | <tt>info</tt> - additional, possibly public information to use during derivation. <tt>info</tt> is optional. The parameter is set using <tt>EVP_KDF_CTRL_ADD_HKDF_INFO</tt>. | + | * <tt>info</tt> - additional, possibly public information to use during derivation. <tt>info</tt> is optional. The parameter is set using <tt>EVP_KDF_CTRL_ADD_HKDF_INFO</tt>. |
<pre>#include <openssl/evp.h> | <pre>#include <openssl/evp.h> | ||
#include <openssl/kdf.h> | #include <openssl/kdf.h> | ||
+ | #include <openssl/params.h> | ||
#include <stdio.h> | #include <stdio.h> | ||
Line 23: | Line 33: | ||
int main(int argc, char* argv[]) | int main(int argc, char* argv[]) | ||
{ | { | ||
+ | EVP_KDF *kdf; | ||
EVP_KDF_CTX *kctx = NULL; | EVP_KDF_CTX *kctx = NULL; | ||
− | unsigned char | + | unsigned char derived[32]; |
− | + | OSSL_PARAM params[5], *p = params; | |
− | |||
− | if ( | + | /* Find and allocate a context for the HKDF algorithm */ |
− | error(" | + | if ((kdf = EVP_KDF_fetch(NULL, "hkdf", NULL)) == NULL) { |
+ | error("EVP_KDF_fetch"); | ||
} | } | ||
− | + | kctx = EVP_KDF_CTX_new(kdf); | |
− | error(" | + | EVP_KDF_free(kdf); /* The kctx keeps a reference so this is safe */ |
+ | if (kctx == NULL) { | ||
+ | error("EVP_KDF_CTX_new"); | ||
} | } | ||
− | + | ||
− | error(" | + | /* Build up the parameters for the derivation */ |
+ | *p++ = OSSL_PARAM_construct_utf8_string("digest", "sha256", (size_t)7); | ||
+ | *p++ = OSSL_PARAM_construct_octet_string("salt", "salt", (size_t)4); | ||
+ | *p++ = OSSL_PARAM_construct_octet_string("key", "secret", (size_t)6); | ||
+ | *p++ = OSSL_PARAM_construct_octet_string("info", "label", (size_t)5); | ||
+ | *p = OSSL_PARAM_construct_end(); | ||
+ | if (EVP_KDF_CTX_set_params(kctx, params) <= 0) { | ||
+ | error("EVP_KDF_CTX_set_params"); | ||
} | } | ||
− | + | ||
− | + | /* Do the derivation */ | |
− | + | if (EVP_KDF_derive(kctx, derived, sizeof(derived), NULL) <= 0) { | |
− | if (EVP_KDF_derive(kctx, | ||
error("EVP_KDF_derive"); | error("EVP_KDF_derive"); | ||
} | } | ||
− | + | ||
/* Use the 32 bytes as a Key and IV */ | /* Use the 32 bytes as a Key and IV */ | ||
− | const unsigned char *key = | + | const unsigned char *key = derived+0; |
− | const unsigned char *iv = | + | const unsigned char *iv = derived+16; |
− | + | ||
printf("Key: "); | printf("Key: "); | ||
for (size_t i=0; i<16; ++i) | for (size_t i=0; i<16; ++i) |
Latest revision as of 06:42, 14 June 2022
Key derivation is the process of deriving one or more secret keys from a secret value such as a password or a passphrase. Several key derivation algoirthms have been standardized, and they are usually referred to a Key Derivation Functions (KDFs). KDFs include PBKDF2 from RFC 2898, HKDF form RFC 5869 and Scrypt from RFC 7914.
OpenSSL 1.0.2 and above provides PBKDF2 by way of PKCS5_PBKDF2_HMAC and PKCS5_PBKDF2_HMAC_SHA1.
OpenSSL 1.1.0 and above additionally provides HKDF and TLS1 PRF KDF by way of EVP_PKEY_derive and Scrypt by way of EVP_PBE_scrypt
OpenSSL 1.1.1 and above additionally provides Scrypt by way of EVP_PKEY_derive.
OpenSSL 3.0 additionally provides Single Step KDF, SSH KDF, PBKDF2, Scrypt, HKDF, ANSI X9.42 KDF, ANSI X9.63 KDF and TLS1 PRF KDF by way of EVP_KDF.
From OpenSSL 3.0 the recommended way of performing key derivation is to use the EVP_KDF functions. If compatibility with OpenSSL 1.1.1 is required then a limited set of KDFs can be used via EVP_PKEY_derive.
HKDF key derivation[edit]
The following example derives a key and initialization vector using HKDF from RFC 5869 and SHA-256. HKDF was designed by Krawczyk and Eronen, and it is state of the art in expand-then-extract key derivation algorithms. It is usually a good choice when you need a KDF. The program below was taken from the OpenSSL man pages.
HKDF takes three parameter:
- secret - private information to use during derivation, like a password or passphrase. The parameter is set using EVP_KDF_CTRL_SET_KEY.
- salt - possibly public information to use during derivation. salt is optional. The parameter is set using EVP_KDF_CTRL_SET_SALT.
- info - additional, possibly public information to use during derivation. info is optional. The parameter is set using EVP_KDF_CTRL_ADD_HKDF_INFO.
#include <openssl/evp.h> #include <openssl/kdf.h> #include <openssl/params.h> #include <stdio.h> #include <stdlib.h> int main(int argc, char* argv[]) { EVP_KDF *kdf; EVP_KDF_CTX *kctx = NULL; unsigned char derived[32]; OSSL_PARAM params[5], *p = params; /* Find and allocate a context for the HKDF algorithm */ if ((kdf = EVP_KDF_fetch(NULL, "hkdf", NULL)) == NULL) { error("EVP_KDF_fetch"); } kctx = EVP_KDF_CTX_new(kdf); EVP_KDF_free(kdf); /* The kctx keeps a reference so this is safe */ if (kctx == NULL) { error("EVP_KDF_CTX_new"); } /* Build up the parameters for the derivation */ *p++ = OSSL_PARAM_construct_utf8_string("digest", "sha256", (size_t)7); *p++ = OSSL_PARAM_construct_octet_string("salt", "salt", (size_t)4); *p++ = OSSL_PARAM_construct_octet_string("key", "secret", (size_t)6); *p++ = OSSL_PARAM_construct_octet_string("info", "label", (size_t)5); *p = OSSL_PARAM_construct_end(); if (EVP_KDF_CTX_set_params(kctx, params) <= 0) { error("EVP_KDF_CTX_set_params"); } /* Do the derivation */ if (EVP_KDF_derive(kctx, derived, sizeof(derived), NULL) <= 0) { error("EVP_KDF_derive"); } /* Use the 32 bytes as a Key and IV */ const unsigned char *key = derived+0; const unsigned char *iv = derived+16; printf("Key: "); for (size_t i=0; i<16; ++i) printf("%02x ", key[i]); printf("\n"); printf("IV: "); for (size_t i=0; i<16; ++i) printf("%02x ", iv[i]); printf("\n"); EVP_KDF_CTX_free(kctx); return 0; }
You can compile the program using C99 with the following command.
openssl$ gcc -std=c99 test.c -o test.exe -l:libcrypto.a -pthread -ldl openssl$
Running the program results in the following output.
$ ./test.exe Key: 2a c4 36 9f 52 59 96 f8 de 13 73 1f 56 22 4f 34 IV: df 0e 4c 96 ca a9 3b fd ec cf 23 7b 50 39 c8 db