1 1.1 christos /* 2 1.1 christos * Copyright 2021-2023 The OpenSSL Project Authors. All Rights Reserved. 3 1.1 christos * 4 1.1 christos * Licensed under the Apache License 2.0 (the "License"). You may not use 5 1.1 christos * this file except in compliance with the License. You can obtain a copy 6 1.1 christos * in the file LICENSE in the source distribution or at 7 1.1 christos * https://www.openssl.org/source/license.html 8 1.1 christos */ 9 1.1 christos 10 1.1 christos #include <stdio.h> 11 1.1 christos #include <openssl/core_names.h> 12 1.1 christos #include <openssl/crypto.h> 13 1.1 christos #include <openssl/kdf.h> 14 1.1 christos #include <openssl/obj_mac.h> 15 1.1 christos #include <openssl/params.h> 16 1.1 christos 17 1.1 christos /* 18 1.1 christos * test vector from 19 1.1 christos * https://datatracker.ietf.org/doc/html/rfc7914 20 1.1 christos */ 21 1.1 christos 22 1.1 christos /* 23 1.1 christos * Hard coding a password into an application is very bad. 24 1.1 christos * It is done here solely for educational purposes. 25 1.1 christos */ 26 1.1 christos static unsigned char password[] = { 27 1.1 christos 'P', 'a', 's', 's', 'w', 'o', 'r', 'd' 28 1.1 christos }; 29 1.1 christos 30 1.1 christos /* 31 1.1 christos * The salt is better not being hard coded too. Each password should have a 32 1.1 christos * different salt if possible. The salt is not considered secret information 33 1.1 christos * and is safe to store with an encrypted password. 34 1.1 christos */ 35 1.1 christos static unsigned char pbkdf2_salt[] = { 36 1.1 christos 'N', 'a', 'C', 'l' 37 1.1 christos }; 38 1.1 christos 39 1.1 christos /* 40 1.1 christos * The iteration parameter can be variable or hard coded. The disadvantage with 41 1.1 christos * hard coding them is that they cannot easily be adjusted for future 42 1.1 christos * technological improvements appear. 43 1.1 christos */ 44 1.1 christos static unsigned int pbkdf2_iterations = 80000; 45 1.1 christos 46 1.1 christos static const unsigned char expected_output[] = { 47 1.1 christos 48 1.1 christos 0x4d, 0xdc, 0xd8, 0xf6, 0x0b, 0x98, 0xbe, 0x21, 49 1.1 christos 0x83, 0x0c, 0xee, 0x5e, 0xf2, 0x27, 0x01, 0xf9, 50 1.1 christos 0x64, 0x1a, 0x44, 0x18, 0xd0, 0x4c, 0x04, 0x14, 51 1.1 christos 0xae, 0xff, 0x08, 0x87, 0x6b, 0x34, 0xab, 0x56, 52 1.1 christos 0xa1, 0xd4, 0x25, 0xa1, 0x22, 0x58, 0x33, 0x54, 53 1.1 christos 0x9a, 0xdb, 0x84, 0x1b, 0x51, 0xc9, 0xb3, 0x17, 54 1.1 christos 0x6a, 0x27, 0x2b, 0xde, 0xbb, 0xa1, 0xd0, 0x78, 55 1.1 christos 0x47, 0x8f, 0x62, 0xb3, 0x97, 0xf3, 0x3c, 0x8d 56 1.1 christos }; 57 1.1 christos 58 1.1 christos int main(int argc, char **argv) 59 1.1 christos { 60 1.1 christos int ret = EXIT_FAILURE; 61 1.1 christos EVP_KDF *kdf = NULL; 62 1.1 christos EVP_KDF_CTX *kctx = NULL; 63 1.1 christos unsigned char out[64]; 64 1.1 christos OSSL_PARAM params[5], *p = params; 65 1.1 christos OSSL_LIB_CTX *library_context = NULL; 66 1.1 christos 67 1.1 christos library_context = OSSL_LIB_CTX_new(); 68 1.1 christos if (library_context == NULL) { 69 1.1 christos fprintf(stderr, "OSSL_LIB_CTX_new() returned NULL\n"); 70 1.1 christos goto end; 71 1.1 christos } 72 1.1 christos 73 1.1 christos /* Fetch the key derivation function implementation */ 74 1.1 christos kdf = EVP_KDF_fetch(library_context, "PBKDF2", NULL); 75 1.1 christos if (kdf == NULL) { 76 1.1 christos fprintf(stderr, "EVP_KDF_fetch() returned NULL\n"); 77 1.1 christos goto end; 78 1.1 christos } 79 1.1 christos 80 1.1 christos /* Create a context for the key derivation operation */ 81 1.1 christos kctx = EVP_KDF_CTX_new(kdf); 82 1.1 christos if (kctx == NULL) { 83 1.1 christos fprintf(stderr, "EVP_KDF_CTX_new() returned NULL\n"); 84 1.1 christos goto end; 85 1.1 christos } 86 1.1 christos 87 1.1 christos /* Set password */ 88 1.1 christos *p++ = OSSL_PARAM_construct_octet_string(OSSL_KDF_PARAM_PASSWORD, password, 89 1.1.1.2 christos sizeof(password)); 90 1.1 christos /* Set salt */ 91 1.1 christos *p++ = OSSL_PARAM_construct_octet_string(OSSL_KDF_PARAM_SALT, pbkdf2_salt, 92 1.1.1.2 christos sizeof(pbkdf2_salt)); 93 1.1 christos /* Set iteration count (default 2048) */ 94 1.1 christos *p++ = OSSL_PARAM_construct_uint(OSSL_KDF_PARAM_ITER, &pbkdf2_iterations); 95 1.1 christos /* Set the underlying hash function used to derive the key */ 96 1.1 christos *p++ = OSSL_PARAM_construct_utf8_string(OSSL_KDF_PARAM_DIGEST, 97 1.1.1.2 christos "SHA256", 0); 98 1.1 christos *p = OSSL_PARAM_construct_end(); 99 1.1 christos 100 1.1 christos /* Derive the key */ 101 1.1 christos if (EVP_KDF_derive(kctx, out, sizeof(out), params) != 1) { 102 1.1 christos fprintf(stderr, "EVP_KDF_derive() failed\n"); 103 1.1 christos goto end; 104 1.1 christos } 105 1.1 christos 106 1.1 christos if (CRYPTO_memcmp(expected_output, out, sizeof(expected_output)) != 0) { 107 1.1 christos fprintf(stderr, "Generated key does not match expected value\n"); 108 1.1 christos goto end; 109 1.1 christos } 110 1.1 christos 111 1.1 christos printf("Success\n"); 112 1.1 christos 113 1.1 christos ret = EXIT_SUCCESS; 114 1.1 christos end: 115 1.1 christos EVP_KDF_CTX_free(kctx); 116 1.1 christos EVP_KDF_free(kdf); 117 1.1 christos OSSL_LIB_CTX_free(library_context); 118 1.1 christos return ret; 119 1.1 christos } 120