Difference between revisions of "EVP Key Derivation"

From OpenSSLWiki
Jump to navigationJump to search
(moved EVP Key Derivation to EVP Key Agreement: OpenSSL uses the "derive" function to perform key agreement. However more generally this process is referred to as key agreement - derivation can mean other things. All a bit confusing. Changing n)
 
(Updated version information for KDFs)
(6 intermediate revisions by one other user not shown)
Line 1: Line 1:
#REDIRECT [[EVP Key Agreement]]
+
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 ==
 +
 
 +
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:
 +
 
 +
* <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>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>
 +
#include <openssl/kdf.h>
 +
 
 +
#include <stdio.h>
 +
#include <stdlib.h>
 +
 
 +
int main(int argc, char* argv[])
 +
{
 +
    EVP_KDF_CTX *kctx = NULL;
 +
    unsigned char derived[32];
 +
 
 +
    if ((kctx = EVP_KDF_CTX_new_id(EVP_KDF_HKDF)) == NULL) {
 +
        error("EVP_KDF_CTX_new_id");
 +
    }
 +
    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_SALT, "salt", (size_t)4) <= 0) {
 +
        error("EVP_KDF_CTRL_SET_SALT");
 +
    }
 +
    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_ADD_HKDF_INFO, "label", (size_t)5) <= 0) {
 +
        error("EVP_KDF_CTRL_ADD_HKDF_INFO");
 +
    }
 +
    if (EVP_KDF_derive(kctx, derived, sizeof(derived)) <= 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;
 +
}</pre>
 +
 
 +
You can compile the program using C99 with the following command.
 +
 
 +
<pre>openssl$ gcc -std=c99 test.c -o test.exe -l:libcrypto.a -pthread -ldl
 +
openssl$</pre>
 +
 
 +
Running the program results in the following output.
 +
 
 +
<pre>$ ./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</pre>

Revision as of 08:31, 24 July 2019

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

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 <stdio.h>
#include <stdlib.h>

int main(int argc, char* argv[])
{
    EVP_KDF_CTX *kctx = NULL;
    unsigned char derived[32];

    if ((kctx = EVP_KDF_CTX_new_id(EVP_KDF_HKDF)) == NULL) {
        error("EVP_KDF_CTX_new_id");
    }
    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_SALT, "salt", (size_t)4) <= 0) {
        error("EVP_KDF_CTRL_SET_SALT");
    }
    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_ADD_HKDF_INFO, "label", (size_t)5) <= 0) {
        error("EVP_KDF_CTRL_ADD_HKDF_INFO");
    }
    if (EVP_KDF_derive(kctx, derived, sizeof(derived)) <= 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