argon2.c 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156
  1. /*
  2. * Copyright 2023 The OpenSSL Project Authors. All Rights Reserved.
  3. *
  4. * Licensed under the Apache License 2.0 (the "License"). You may not use
  5. * this file except in compliance with the License. You can obtain a copy
  6. * in the file LICENSE in the source distribution or at
  7. * https://www.openssl.org/source/license.html
  8. */
  9. #include <stdio.h>
  10. #include <openssl/core_names.h>
  11. #include <openssl/crypto.h>
  12. #include <openssl/kdf.h>
  13. #include <openssl/params.h>
  14. #include <openssl/thread.h>
  15. /*
  16. * Example showing how to use Argon2 KDF.
  17. * See man EVP_KDF-ARGON2 for more information.
  18. *
  19. * test vector from
  20. * https://datatracker.ietf.org/doc/html/rfc9106
  21. */
  22. /*
  23. * Hard coding a password into an application is very bad.
  24. * It is done here solely for educational purposes.
  25. */
  26. static unsigned char password[] = {
  27. 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
  28. 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
  29. 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
  30. 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01
  31. };
  32. /*
  33. * The salt is better not being hard coded too. Each password should have a
  34. * different salt if possible. The salt is not considered secret information
  35. * and is safe to store with an encrypted password.
  36. */
  37. static unsigned char salt[] = {
  38. 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
  39. 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02
  40. };
  41. /*
  42. * Optional secret for KDF
  43. */
  44. static unsigned char secret[] = {
  45. 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03
  46. };
  47. /*
  48. * Optional additional data
  49. */
  50. static unsigned char ad[] = {
  51. 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
  52. 0x04, 0x04, 0x04, 0x04
  53. };
  54. /*
  55. * Argon2 cost parameters
  56. */
  57. static uint32_t memory_cost = 32;
  58. static uint32_t iteration_cost = 3;
  59. static uint32_t parallel_cost = 4;
  60. static const unsigned char expected_output[] = {
  61. 0x0d, 0x64, 0x0d, 0xf5, 0x8d, 0x78, 0x76, 0x6c,
  62. 0x08, 0xc0, 0x37, 0xa3, 0x4a, 0x8b, 0x53, 0xc9,
  63. 0xd0, 0x1e, 0xf0, 0x45, 0x2d, 0x75, 0xb6, 0x5e,
  64. 0xb5, 0x25, 0x20, 0xe9, 0x6b, 0x01, 0xe6, 0x59
  65. };
  66. int main(int argc, char **argv)
  67. {
  68. int rv = EXIT_FAILURE;
  69. EVP_KDF *kdf = NULL;
  70. EVP_KDF_CTX *kctx = NULL;
  71. unsigned char out[32];
  72. OSSL_PARAM params[9], *p = params;
  73. OSSL_LIB_CTX *library_context = NULL;
  74. unsigned int threads;
  75. library_context = OSSL_LIB_CTX_new();
  76. if (library_context == NULL) {
  77. fprintf(stderr, "OSSL_LIB_CTX_new() returned NULL\n");
  78. goto end;
  79. }
  80. /* Fetch the key derivation function implementation */
  81. kdf = EVP_KDF_fetch(library_context, "argon2id", NULL);
  82. if (kdf == NULL) {
  83. fprintf(stderr, "EVP_KDF_fetch() returned NULL\n");
  84. goto end;
  85. }
  86. /* Create a context for the key derivation operation */
  87. kctx = EVP_KDF_CTX_new(kdf);
  88. if (kctx == NULL) {
  89. fprintf(stderr, "EVP_KDF_CTX_new() returned NULL\n");
  90. goto end;
  91. }
  92. /*
  93. * Thread support can be turned off; use serialization if we cannot
  94. * set requested number of threads.
  95. */
  96. threads = parallel_cost;
  97. if (OSSL_set_max_threads(library_context, parallel_cost) != 1) {
  98. uint64_t max_threads = OSSL_get_max_threads(library_context);
  99. if (max_threads == 0)
  100. threads = 1;
  101. else if (max_threads < parallel_cost)
  102. threads = max_threads;
  103. }
  104. /* Set password */
  105. *p++ = OSSL_PARAM_construct_octet_string(OSSL_KDF_PARAM_PASSWORD, password, sizeof(password));
  106. /* Set salt */
  107. *p++ = OSSL_PARAM_construct_octet_string(OSSL_KDF_PARAM_SALT, salt, sizeof(salt));
  108. /* Set optional additional data */
  109. *p++ = OSSL_PARAM_construct_octet_string(OSSL_KDF_PARAM_ARGON2_AD, ad, sizeof(ad));
  110. /* Set optional secret */
  111. *p++ = OSSL_PARAM_construct_octet_string(OSSL_KDF_PARAM_SECRET, secret, sizeof(secret));
  112. /* Set iteration count */
  113. *p++ = OSSL_PARAM_construct_uint32(OSSL_KDF_PARAM_ITER, &iteration_cost);
  114. /* Set threads performing derivation (can be decreased) */
  115. *p++ = OSSL_PARAM_construct_uint(OSSL_KDF_PARAM_THREADS, &threads);
  116. /* Set parallel cost */
  117. *p++ = OSSL_PARAM_construct_uint32(OSSL_KDF_PARAM_ARGON2_LANES, &parallel_cost);
  118. /* Set memory requirement */
  119. *p++ = OSSL_PARAM_construct_uint32(OSSL_KDF_PARAM_ARGON2_MEMCOST, &memory_cost);
  120. *p = OSSL_PARAM_construct_end();
  121. /* Derive the key */
  122. if (EVP_KDF_derive(kctx, out, sizeof(out), params) != 1) {
  123. fprintf(stderr, "EVP_KDF_derive() failed\n");
  124. goto end;
  125. }
  126. if (CRYPTO_memcmp(expected_output, out, sizeof(expected_output)) != 0) {
  127. fprintf(stderr, "Generated key does not match expected value\n");
  128. goto end;
  129. }
  130. printf("Success\n");
  131. rv = EXIT_SUCCESS;
  132. end:
  133. EVP_KDF_CTX_free(kctx);
  134. EVP_KDF_free(kdf);
  135. OSSL_LIB_CTX_free(library_context);
  136. return rv;
  137. }