diff options
-rw-r--r-- | src/lib/base/buf_comp.h | 19 | ||||
-rw-r--r-- | src/lib/pbkdf/argon2/argon2.cpp | 411 | ||||
-rw-r--r-- | src/lib/pbkdf/argon2/argon2.h | 36 | ||||
-rw-r--r-- | src/lib/pbkdf/argon2/info.txt | 8 | ||||
-rw-r--r-- | src/tests/data/argon2.vec | 359 | ||||
-rw-r--r-- | src/tests/test_pbkdf.cpp | 54 |
6 files changed, 882 insertions, 5 deletions
diff --git a/src/lib/base/buf_comp.h b/src/lib/base/buf_comp.h index a6cc84ba3..e1971c458 100644 --- a/src/lib/base/buf_comp.h +++ b/src/lib/base/buf_comp.h @@ -57,11 +57,20 @@ class BOTAN_PUBLIC_API(2,0) Buffered_Computation */ template<typename T> void update_be(const T in) { - for(size_t i = 0; i != sizeof(T); ++i) - { - uint8_t b = get_byte(i, in); - add_data(&b, 1); - } + uint8_t inb[sizeof(T)]; + store_be(in, inb); + add_data(inb, sizeof(inb)); + } + + /** + * Add an integer in little-endian order + * @param in the value + */ + template<typename T> void update_le(const T in) + { + uint8_t inb[sizeof(T)]; + store_le(in, inb); + add_data(inb, sizeof(inb)); } /** diff --git a/src/lib/pbkdf/argon2/argon2.cpp b/src/lib/pbkdf/argon2/argon2.cpp new file mode 100644 index 000000000..e446e1513 --- /dev/null +++ b/src/lib/pbkdf/argon2/argon2.cpp @@ -0,0 +1,411 @@ +/** +* (C) 2018,2019 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/argon2.h> +#include <botan/hash.h> +#include <botan/mem_ops.h> +#include <botan/rotate.h> +#include <botan/exceptn.h> + +namespace Botan { + +namespace { + +static const size_t SYNC_POINTS = 4; + +secure_vector<uint8_t> argon2_H0(HashFunction& blake2b, + size_t output_len, + const char* password, size_t password_len, + const uint8_t salt[], size_t salt_len, + const uint8_t key[], size_t key_len, + const uint8_t ad[], size_t ad_len, + size_t y, size_t p, size_t M, size_t t) + { + const uint8_t v = 19; // Argon2 version code + + blake2b.update_le<uint32_t>(p); + blake2b.update_le<uint32_t>(output_len); + blake2b.update_le<uint32_t>(M); + blake2b.update_le<uint32_t>(t); + blake2b.update_le<uint32_t>(v); + blake2b.update_le<uint32_t>(y); + + blake2b.update_le<uint32_t>(password_len); + blake2b.update(cast_char_ptr_to_uint8(password), password_len); + + blake2b.update_le<uint32_t>(salt_len); + blake2b.update(salt, salt_len); + + blake2b.update_le<uint32_t>(key_len); + blake2b.update(key, key_len); + + blake2b.update_le<uint32_t>(ad_len); + blake2b.update(ad, ad_len); + + return blake2b.final(); + } + +void Htick(uint8_t output[], + size_t output_len, + HashFunction& blake2b, + const secure_vector<uint8_t>& H0, + size_t p0, size_t p1) + { + BOTAN_ASSERT_NOMSG(output_len % 64 == 0); + + secure_vector<uint8_t> B(blake2b.output_length()); + + blake2b.update_le<uint32_t>(output_len); + blake2b.update(H0); + blake2b.update_le<uint32_t>(p0); + blake2b.update_le<uint32_t>(p1); + + blake2b.final(&B[0]); + + while(output_len > 64) + { + copy_mem(output, &B[0], 32); + output_len -= 32; + output += 32; + + blake2b.update(B); + blake2b.final(&B[0]); + } + + if(output_len > 0) + copy_mem(output, &B[0], output_len); + } + +void extract_key(uint8_t output[], size_t output_len, + const secure_vector<uint64_t>& B, + size_t memory, size_t threads) + { + const size_t lanes = memory / threads; + + secure_vector<uint64_t> sum(128); + + for(size_t lane = 0; lane != threads; ++lane) + { + size_t start = 128*(lane * lanes + lanes - 1); + size_t end = 128*(lane * lanes + lanes); + + for(size_t j = start; j != end; ++j) + { + sum[j % 128] ^= B[j]; + } + } + + secure_vector<uint8_t> sum8(1024); + copy_out_le(sum8.data(), 1024, sum.data()); + + if(output_len <= 64) + { + std::unique_ptr<HashFunction> blake2b = HashFunction::create_or_throw("BLAKE2b(" + std::to_string(output_len*8) + ")"); + + blake2b->update_le(static_cast<uint32_t>(output_len)); + blake2b->update(sum8.data(), sum8.size()); + + blake2b->final(output); + } + else + { + throw Not_Implemented("todo"); + } + } + +void init_blocks(secure_vector<uint64_t>& B, + HashFunction& blake2b, + const secure_vector<uint8_t>& H0, + size_t memory, + size_t threads) + { + BOTAN_ASSERT_NOMSG(B.size() >= threads*256); + + secure_vector<uint8_t> H(1024); + + for(size_t i = 0; i != threads; ++i) + { + const size_t B_off = i * (memory / threads); + + BOTAN_ASSERT_NOMSG(B.size() >= 128*(B_off+2)); + + Htick(&H[0], H.size(), blake2b, H0, 0, i); + + for(size_t j = 0; j != 128; ++j) + { + B[128*B_off+j] = load_le<uint64_t>(H.data(), j); + } + + Htick(&H[0], H.size(), blake2b, H0, 1, i); + + for(size_t j = 0; j != 128; ++j) + { + B[128*(B_off+1)+j] = load_le<uint64_t>(H.data(), j); + } + } + } + +inline void blamka_G(uint64_t& A, uint64_t& B, uint64_t& C, uint64_t& D) + { + A += B + 2*(A & 0xFFFFFFFF)*(B & 0xFFFFFFFF); + D = rotr<32>(A ^ D); + + C += D + 2*(C & 0xFFFFFFFF) * (D & 0xFFFFFFFF); + B = rotr<24>(B ^ C); + + A += B + 2*(A & 0xFFFFFFFF) * (B & 0xFFFFFFFF); + D = rotr<16>(A ^ D); + + C += D + 2*(C & 0xFFFFFFFF) * (D & 0xFFFFFFFF); + B = rotr<63>(B ^ C); + } + +inline void blamka(uint64_t& V0, uint64_t& V1, uint64_t& V2, uint64_t& V3, + uint64_t& V4, uint64_t& V5, uint64_t& V6, uint64_t& V7, + uint64_t& V8, uint64_t& V9, uint64_t& VA, uint64_t& VB, + uint64_t& VC, uint64_t& VD, uint64_t& VE, uint64_t& VF) + { + blamka_G(V0, V4, V8, VC); + blamka_G(V1, V5, V9, VD); + blamka_G(V2, V6, VA, VE); + blamka_G(V3, V7, VB, VF); + + blamka_G(V0, V5, VA, VF); + blamka_G(V1, V6, VB, VC); + blamka_G(V2, V7, V8, VD); + blamka_G(V3, V4, V9, VE); + } + +void process_block_xor(secure_vector<uint64_t>& B, + size_t offset, + size_t prev, + size_t new_offset) + { + secure_vector<uint64_t> T(128); + + for(size_t i = 0; i != 128; ++i) + T[i] = B[128*prev+i] ^ B[128*new_offset+i]; + + for(size_t i = 0; i != 128; i += 16) + { + blamka(T[i+ 0], T[i+ 1], T[i+ 2], T[i+ 3], + T[i+ 4], T[i+ 5], T[i+ 6], T[i+ 7], + T[i+ 8], T[i+ 9], T[i+10], T[i+11], + T[i+12], T[i+13], T[i+14], T[i+15]); + } + + for(size_t i = 0; i != 128 / 8; i += 2) + { + blamka(T[ i], T[ i+1], T[ 16+i], T[ 16+i+1], + T[ 32+i], T[ 32+i+1], T[ 48+i], T[ 48+i+1], + T[ 64+i], T[ 64+i+1], T[ 80+i], T[ 80+i+1], + T[ 96+i], T[ 96+i+1], T[112+i], T[112+i+1]); + } + + for(size_t i = 0; i != 128; ++i) + B[128*offset + i] ^= T[i] ^ B[128*prev+i] ^ B[128*new_offset+i]; + } + +void gen_2i_addresses(secure_vector<uint64_t>& B, + size_t n, size_t lane, size_t slice, size_t memory, + size_t time, size_t mode, size_t cnt) + { + BOTAN_ASSERT_NOMSG(B.size() == 128); + + clear_mem(B.data(), B.size()); + B[0] = n; + B[1] = lane; + B[2] = slice; + B[3] = memory; + B[4] = time; + B[5] = mode; + B[6] = cnt; + + for(size_t r = 0; r != 2; ++r) + { + secure_vector<uint64_t> T = B; + + for(size_t i = 0; i != 128; i += 16) + { + blamka(T[i+ 0], T[i+ 1], T[i+ 2], T[i+ 3], + T[i+ 4], T[i+ 5], T[i+ 6], T[i+ 7], + T[i+ 8], T[i+ 9], T[i+10], T[i+11], + T[i+12], T[i+13], T[i+14], T[i+15]); + } + for(size_t i = 0; i != 128 / 8; i += 2) + { + blamka(T[ i], T[ i+1], T[ 16+i], T[ 16+i+1], + T[ 32+i], T[ 32+i+1], T[ 48+i], T[ 48+i+1], + T[ 64+i], T[ 64+i+1], T[ 80+i], T[ 80+i+1], + T[ 96+i], T[ 96+i+1], T[112+i], T[112+i+1]); + } + + for(size_t i = 0; i != 128; ++i) + B[i] ^= T[i]; + } + } + +uint32_t index_alpha(uint64_t random, + size_t lanes, + size_t segments, + size_t threads, + size_t n, + size_t slice, + size_t lane, + size_t index) + { + size_t ref_lane = static_cast<uint32_t>(random >> 32) % threads; + + if(n == 0 && slice == 0) + ref_lane = lane; + + size_t m = 3*segments; + size_t s = ((slice+1) % 4)*segments; + + if(lane == ref_lane) + m += index; + + if(n == 0) { + m = slice*segments; + s = 0; + if(slice == 0 || lane == ref_lane) + m += index; + } + + if(index == 0 || lane == ref_lane) + m -= 1; + + uint64_t p = static_cast<uint32_t>(random); + p = (p * p) >> 32; + p = (p * m) >> 32; + + return ref_lane*lanes + (s + m - (p+1)) % lanes; + } + +void process_block_argon2d(secure_vector<uint64_t>& B, + size_t n, size_t slice, size_t lane, + size_t lanes, size_t segments, size_t threads) + { + size_t index = 0; + if(n == 0 && slice == 0) + index = 2; + + while(index < segments) + { + const size_t offset = lane*lanes + slice*segments + index; + + size_t prev = offset - 1; + if(index == 0 && slice == 0) + prev += lanes; + + const uint64_t random = B.at(128*prev); + const size_t new_offset = index_alpha(random, lanes, segments, threads, n, slice, lane, index); + + process_block_xor(B, offset, prev, new_offset); + + index += 1; + } + } + +void process_block_argon2i(secure_vector<uint64_t>& B, + size_t n, size_t slice, size_t lane, + size_t lanes, size_t segments, size_t threads, uint8_t mode, + size_t memory, size_t time) + { + size_t index = 0; + if(n == 0 && slice == 0) + index = 2; + + secure_vector<uint64_t> addresses(128); + size_t address_counter = 1; + + gen_2i_addresses(addresses, n, lane, slice, memory, time, mode, address_counter); + + while(index < segments) + { + const size_t offset = lane*lanes + slice*segments + index; + + size_t prev = offset - 1; + if(index == 0 && slice == 0) + prev += lanes; + + if(index > 0 && index % 128 == 0) + { + address_counter += 1; + gen_2i_addresses(addresses, n, lane, slice, memory, time, mode, address_counter); + } + + const uint64_t random = addresses[index % 128]; + const size_t new_offset = index_alpha(random, lanes, segments, threads, n, slice, lane, index); + + process_block_xor(B, offset, prev, new_offset); + + index += 1; + } + } + +void process_blocks(secure_vector<uint64_t>& B, + size_t t, + size_t memory, + size_t threads, + size_t mode) + { + const size_t lanes = memory / threads; + const size_t segments = lanes / SYNC_POINTS; + + for(size_t n = 0; n != t; ++n) + { + for(size_t slice = 0; slice != SYNC_POINTS; ++slice) + { + // TODO can run this in Thread_Pool + for(size_t lane = 0; lane != threads; ++lane) + { + if(mode == 1 || (mode == 2 && n == 0 && slice < SYNC_POINTS/2)) + process_block_argon2i(B, n, slice, lane, lanes, segments, threads, mode, memory, t); + else + process_block_argon2d(B, n, slice, lane, lanes, segments, threads); + } + } + } + + } + +} + +void argon2(uint8_t output[], size_t output_len, + const char* password, size_t password_len, + const uint8_t salt[], size_t salt_len, + const uint8_t key[], size_t key_len, + const uint8_t ad[], size_t ad_len, + size_t mode, size_t threads, size_t M, size_t t) + { + BOTAN_ARG_CHECK(mode == 0 || mode == 1 || mode == 2, "Unknown Argon2 mode parameter"); + BOTAN_ARG_CHECK(output_len >= 4, "Invalid Argon2 output length"); + BOTAN_ARG_CHECK(threads >= 1 && threads <= 128, "Invalid Argon2 threads parameter"); + BOTAN_ARG_CHECK(M >= 8*threads && M <= 8192*1024, "Invalid Argon2 M parameter"); + BOTAN_ARG_CHECK(t >= 1, "Invalid Argon2 t parameter"); + + std::unique_ptr<HashFunction> blake2 = HashFunction::create_or_throw("BLAKE2b"); + + const auto H0 = argon2_H0(*blake2, output_len, + password, password_len, + salt, salt_len, + key, key_len, + ad, ad_len, + mode, threads, M, t); + + const size_t memory = (M / (SYNC_POINTS*threads)) * (SYNC_POINTS*threads); + + secure_vector<uint64_t> B(memory * 1024/8); + + init_blocks(B, *blake2, H0, memory, threads); + process_blocks(B, t, memory, threads, mode); + + clear_mem(output, output_len); + extract_key(output, output_len, B, memory, threads); + } + +} diff --git a/src/lib/pbkdf/argon2/argon2.h b/src/lib/pbkdf/argon2/argon2.h new file mode 100644 index 000000000..27a6a3220 --- /dev/null +++ b/src/lib/pbkdf/argon2/argon2.h @@ -0,0 +1,36 @@ +/** +* (C) 2018 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_ARGON2_H_ +#define BOTAN_ARGON2_H_ + +#include <botan/types.h> + +namespace Botan { + +/** +* Argon2 key derivation function +* +* @param output the output will be placed here +* @param output_len length of output +* @param password the user password +* @param salt the salt +* @param salt_len length of salt +* @param y the Argon2 variant (0 = Argon2d, 1 = Argon2i, 2 = Argon2id) +* @param p the parallelization parameter +* @param M the amount of memory to use in Kb +* @param t the number of iterations to use +*/ +void BOTAN_PUBLIC_API(2,11) argon2(uint8_t output[], size_t output_len, + const char* password, size_t password_len, + const uint8_t salt[], size_t salt_len, + const uint8_t key[], size_t key_len, + const uint8_t ad[], size_t ad_len, + size_t y, size_t p, size_t M, size_t t); + +} + +#endif diff --git a/src/lib/pbkdf/argon2/info.txt b/src/lib/pbkdf/argon2/info.txt new file mode 100644 index 000000000..0c7adfeea --- /dev/null +++ b/src/lib/pbkdf/argon2/info.txt @@ -0,0 +1,8 @@ +<defines> +ARGON2 -> 20190527 +</defines> + +<requires> +blake2 +</requires> + diff --git a/src/tests/data/argon2.vec b/src/tests/data/argon2.vec new file mode 100644 index 000000000..b81d14c0e --- /dev/null +++ b/src/tests/data/argon2.vec @@ -0,0 +1,359 @@ + +# First three are the official test vectors + +[Argon2d] + +M = 32 +T = 3 +P = 4 +Passphrase = 0101010101010101010101010101010101010101010101010101010101010101 +Salt = 02020202020202020202020202020202 +AD = 040404040404040404040404 +Secret = 0303030303030303 +Output = 512b391b6f1162975371d30919734294f868e3be3984f3c1a13a4db9fabe4acb + +[Argon2i] +M = 32 +T = 3 +P = 4 +Passphrase = 0101010101010101010101010101010101010101010101010101010101010101 +Salt = 02020202020202020202020202020202 +Secret = 0303030303030303 +AD = 040404040404040404040404 +Output = c814d9d1dc7f37aa13f0d77f2494bda1c8de6b016dd388d29952a4c4672b6ce8 + +[Argon2id] + +M = 32 +T = 3 +P = 4 +Passphrase = 0101010101010101010101010101010101010101010101010101010101010101 +Salt = 02020202020202020202020202020202 +AD = 040404040404040404040404 +Secret = 0303030303030303 +Output = 0d640df58d78766c08c037a34a8b53c9d01ef0452d75b65eb52520e96b01e659 + + +# Remainder generated by Golang x/crypto + +[Argon2d] + +M = 64 +T = 3 +P = 4 +Passphrase = 0101010101010101010101010101010101010101010101010101010101010101 +Salt = 02020202020202020202020202020202 +AD = 040404040404040404040404 +Secret = 0303030303030303 +Output = ab75c7556cd63bbaa818e02dbdfe8c69e80375d64b31d6a7b2bf41da7f7c9951 + +M = 128 +T = 3 +P = 4 +Passphrase = 0101010101010101010101010101010101010101010101010101010101010101 +Salt = 02020202020202020202020202020202 +AD = 040404040404040404040404 +Secret = 0303030303030303 +Output = 5fc18a6a56b67cadf60287babc490ca0e866f0880a2b51e56a0ab0a640179d13 + +M = 128 +T = 10 +P = 16 +Passphrase = 0101010101010101010101010101010101010101010101010101010101010101 +Salt = 02020202020202020202020202020202 +AD = 040404040404040404040404 +Secret = 0303030303030303 +Output = ff62eb9ab9e3f258def9fc50ce2e79ef15affb0f3a4d68768592c4934dc8e942b1b36c404e62d0878d5886bfbed5ef3f9de33559ebcdc4dedc80af5d7c5337cd + +M = 256 +T = 3 +P = 4 +Passphrase = 0101010101010101010101010101010101010101010101010101010101010101 +Salt = 02020202020202020202020202020202 +AD = 040404040404040404040404 +Secret = 0303030303030303 +Output = e0626056972c990e1de37b1da8542ee5dafa2538c304576bb22f403ea815507c + +M = 256 +T = 10 +P = 16 +Passphrase = 0101010101010101010101010101010101010101010101010101010101010101 +Salt = 02020202020202020202020202020202 +AD = 040404040404040404040404 +Secret = 0303030303030303 +Output = d30dab40b07d39f728b2acb2e8c30a4c94606d1acee7834c48d89d8425daa2ec270e76159f0364e6cf139c55e91d57581b128de54ffd2dfaeb881cdad6da8546 + +M = 256 +T = 16 +P = 32 +Passphrase = 0101010101010101010101010101010101010101010101010101010101010101 +Salt = 02020202020202020202020202020202 +AD = 040404040404040404040404 +Secret = 0303030303030303 +Output = 30a011a4b36ab8cf855998346b3c73bc15cc79b39a736959aac9f0fc798b62647985b517214ea28b8f841633012f9057241d2f9ea38e2d15c7d8397910fe896e + +M = 512 +T = 3 +P = 4 +Passphrase = 0101010101010101010101010101010101010101010101010101010101010101 +Salt = 02020202020202020202020202020202 +AD = 040404040404040404040404 +Secret = 0303030303030303 +Output = 61176735ba6480f0640edb93536f182a1966bf4d2174ce549a755c8947be774b + +M = 512 +T = 10 +P = 16 +Passphrase = 0101010101010101010101010101010101010101010101010101010101010101 +Salt = 02020202020202020202020202020202 +AD = 040404040404040404040404 +Secret = 0303030303030303 +Output = 50ac3a40ebb256aacac62c477c9748d931b37de951f3f1a39810b51b6381f7a2799bd169729bb7de2cdbb7315482ec3a6a13817d2b42543b5f8445963d330651 + +M = 512 +T = 16 +P = 32 +Passphrase = 0101010101010101010101010101010101010101010101010101010101010101 +Salt = 02020202020202020202020202020202 +AD = 040404040404040404040404 +Secret = 0303030303030303 +Output = 31103f14f51f0b2f474706086daec764a75384296ca80cac52147839fa02d9edc23cbdb1b478d9912c11c58fe07ec7597e5ea8a5f173b9ef5700d77a779da9e9 + +M = 1024 +T = 32 +P = 16 +Passphrase = 0101010101010101010101010101010101010101010101010101010101010101 +Salt = 02020202020202020202020202020202 +AD = 040404040404040404040404 +Secret = 0303030303030303 +Output = 24fdf8ec8416e8fa5a235747530984098a9c925298eb32924a7c3a2b8bddd520fc96e22501d45bd74ed9b4384fcdc5b62d034052cff68558b8c85dac23fee8cb + +M = 1024 +T = 32 +P = 64 +Passphrase = 0101010101010101010101010101010101010101010101010101010101010101 +Salt = 02020202020202020202020202020202 +AD = 040404040404040404040404 +Secret = 0303030303030303 +Output = 9344d8ec27e27ca85b233fd1b7d0ff25a28856266ffce47d35a85352cb7c1cae052ba852da31508e312802586cfd795c9efc6e280c2bf7065884f30a14736779 + +[Argon2i] + +M = 64 +T = 3 +P = 4 +Passphrase = 0101010101010101010101010101010101010101010101010101010101010101 +Salt = 02020202020202020202020202020202 +AD = 040404040404040404040404 +Secret = 0303030303030303 +Output = 0f639e5eb9ae1d4d582ccb6033b95551f916a2bdf48ae23d2b8ba4414eb6a182 + +M = 128 +T = 3 +P = 4 +Passphrase = 0101010101010101010101010101010101010101010101010101010101010101 +Salt = 02020202020202020202020202020202 +AD = 040404040404040404040404 +Secret = 0303030303030303 +Output = 88031ec2094b24a9c4399e7f3fdaa5701dc3bae89917c6ba582e924a547a623d + +M = 128 +T = 10 +P = 16 +Passphrase = 0101010101010101010101010101010101010101010101010101010101010101 +Salt = 02020202020202020202020202020202 +AD = 040404040404040404040404 +Secret = 0303030303030303 +Output = 74d7ce52764e26f3288e3904d0a38a5e91d15ee9227853b19406c383f6495d813e1eec283eb6bde34657b70b821bde646f4d89012b55be281cd5e68812fb4d73 + +M = 256 +T = 3 +P = 4 +Passphrase = 0101010101010101010101010101010101010101010101010101010101010101 +Salt = 02020202020202020202020202020202 +AD = 040404040404040404040404 +Secret = 0303030303030303 +Output = bba02f115715a78c61a11aa3457169f781c86566d01841872dad7a2eeefce06a + +M = 256 +T = 10 +P = 16 +Passphrase = 0101010101010101010101010101010101010101010101010101010101010101 +Salt = 02020202020202020202020202020202 +AD = 040404040404040404040404 +Secret = 0303030303030303 +Output = b61c0c8f5fabb9fcf186e0786c8df566ea2ea715a096d7d02ff30417569076f1a98af9ea0e511775a09c866ae8692ba56986a4b1580c5455531f0ed8924498fa + +M = 256 +T = 16 +P = 32 +Passphrase = 0101010101010101010101010101010101010101010101010101010101010101 +Salt = 02020202020202020202020202020202 +AD = 040404040404040404040404 +Secret = 0303030303030303 +Output = ab86056dfbe69955d2c0985d388a4a45424c33c4ce8d15d30035da14d117640229e136974d07ac980a3d41ebbf566f61f8e1b42575eeb16d4757fdf358b30daa + +M = 512 +T = 3 +P = 4 +Passphrase = 0101010101010101010101010101010101010101010101010101010101010101 +Salt = 02020202020202020202020202020202 +AD = 040404040404040404040404 +Secret = 0303030303030303 +Output = c999a66d8811e28ba8b48334021845290c7e8cd4f010035bf212f24bacb49a96 + +M = 512 +T = 10 +P = 16 +Passphrase = 0101010101010101010101010101010101010101010101010101010101010101 +Salt = 02020202020202020202020202020202 +AD = 040404040404040404040404 +Secret = 0303030303030303 +Output = f38964a89962f22ccbbbde4452298f4d33e12361c4ace50b4aacdac88f5f13b18935dc9a29424f283808904e77e3f6690fe5f83834cc7205a7e03791389b7b77 + +M = 512 +T = 16 +P = 32 +Passphrase = 0101010101010101010101010101010101010101010101010101010101010101 +Salt = 02020202020202020202020202020202 +AD = 040404040404040404040404 +Secret = 0303030303030303 +Output = 431e57fbf29ff740d24f1922acc89f5cc28984f0b7d4ef3fb9a4eee5bc50fdcdafbc386dd9232447093fe6afe5d3a0f0c3732d363fb66f1c0dc696af70180546 + +M = 1024 +T = 32 +P = 16 +Passphrase = 0101010101010101010101010101010101010101010101010101010101010101 +Salt = 02020202020202020202020202020202 +AD = 040404040404040404040404 +Secret = 0303030303030303 +Output = 66be17b18ad5626e2a872672379da0072178fb8844414cb340333a21d6670c9c1c7440b1a7dd3e6f7a110f79d86f568952733bbdc48f00355a843d55f0c0d129 + +M = 1024 +T = 32 +P = 64 +Passphrase = 0101010101010101010101010101010101010101010101010101010101010101 +Salt = 02020202020202020202020202020202 +AD = 040404040404040404040404 +Secret = 0303030303030303 +Output = 06835f6c5acd842f29dc5dc9a92b163082ebde4784b55684dcc9ece1537be68057dbc686a2fdf525e51b3af60b25ea4065e93b99640f0728362c8f0a7d5e6f1e + +M = 4096 +T = 32 +P = 64 +Passphrase = 0101010101010101010101010101010101010101010101010101010101010101 +Salt = 02020202020202020202020202020202 +AD = 040404040404040404040404 +Secret = 0303030303030303 +Output = 2a5f4b6db72e56a65e3ae159d1761dce1f5e139d19655bd981c97977b6b5ee713944279681e4b9c73402a2c4e2aceee5d67fe84a3868b7fcf2ce4c817005d1ed + +[Argon2id] + +M = 64 +T = 3 +P = 4 +Passphrase = 0101010101010101010101010101010101010101010101010101010101010101 +Salt = 02020202020202020202020202020202 +AD = 040404040404040404040404 +Secret = 0303030303030303 +Output = 4275ee5ad887fe3270e82f01e97db8af3cf63fc7f2102bfea84b305f416a4544 + +M = 128 +T = 3 +P = 4 +Passphrase = 0101010101010101010101010101010101010101010101010101010101010101 +Salt = 02020202020202020202020202020202 +AD = 040404040404040404040404 +Secret = 0303030303030303 +Output = 8ec72f253bd35d55c3e49c587c77665c9c7fcff26cb3cabe179039b7c4281a48 + +M = 128 +T = 10 +P = 16 +Passphrase = 0101010101010101010101010101010101010101010101010101010101010101 +Salt = 02020202020202020202020202020202 +AD = 040404040404040404040404 +Secret = 0303030303030303 +Output = 5b52005e900e0435ecdf7167e51ff629eb6ee6f475904878592180af8653bdd6ac6a891a6b386feea7db9c1addafce08a72e30822227307d4dfe4d171c1dd53a + +M = 256 +T = 3 +P = 4 +Passphrase = 0101010101010101010101010101010101010101010101010101010101010101 +Salt = 02020202020202020202020202020202 +AD = 040404040404040404040404 +Secret = 0303030303030303 +Output = 42dd95b7d33d4162b307eb5520b90c2b718726cb40076092f92a450b1498fde0 + +M = 256 +T = 10 +P = 16 +Passphrase = 0101010101010101010101010101010101010101010101010101010101010101 +Salt = 02020202020202020202020202020202 +AD = 040404040404040404040404 +Secret = 0303030303030303 +Output = f73b80dd42a7669e98aa98c58007b022055a0c0024d6b9064119b9d3ecba2476e4dcf4e444ba59762960a16660fff039ea80448a1f1e9b35814a05e311f52426 + +M = 256 +T = 16 +P = 32 +Passphrase = 0101010101010101010101010101010101010101010101010101010101010101 +Salt = 02020202020202020202020202020202 +AD = 040404040404040404040404 +Secret = 0303030303030303 +Output = 4e984d66d607d29a027b9a5a5844b3156c691772132bbba877ca317445f242d50a438a79a5efa8c2d54049d54aaf91e47576c7f331dd4d34bc710259d49b7b06 + +M = 512 +T = 3 +P = 4 +Passphrase = 0101010101010101010101010101010101010101010101010101010101010101 +Salt = 02020202020202020202020202020202 +AD = 040404040404040404040404 +Secret = 0303030303030303 +Output = 7c0d17d7212b31faf30b60db73e7c561be0b477d34fa1d58fb6896c5a0b8e697 + +M = 512 +T = 10 +P = 16 +Passphrase = 0101010101010101010101010101010101010101010101010101010101010101 +Salt = 02020202020202020202020202020202 +AD = 040404040404040404040404 +Secret = 0303030303030303 +Output = 768bef077ad20536af34bd81ff054eb81f100d3e718768cc87f21948645594b9b452932f3ec9bd4ccf55786898942d3acc0ddd8efbeca7cc7d7ebab3df6c1758 + +M = 512 +T = 16 +P = 32 +Passphrase = 0101010101010101010101010101010101010101010101010101010101010101 +Salt = 02020202020202020202020202020202 +AD = 040404040404040404040404 +Secret = 0303030303030303 +Output = a4f25b3979795e79979fde49be72cb59a4a50567a306d0a380f33103ee6ebc9fcb7a4bd9decc5ef84def1e3c24a60e43988e874c2689b1303c68701c58f099d6 + +M = 1024 +T = 32 +P = 16 +Passphrase = 0101010101010101010101010101010101010101010101010101010101010101 +Salt = 02020202020202020202020202020202 +AD = 040404040404040404040404 +Secret = 0303030303030303 +Output = ab56ff1ec4b64f32083b6edad23cd880c2ade2f8474882f55ca034ab850adcdb55f565c05062f5e13ae3ac6829678518cba652b539d503902d36922773f55bdf + +M = 1024 +T = 32 +P = 64 +Passphrase = 0101010101010101010101010101010101010101010101010101010101010101 +Salt = 02020202020202020202020202020202 +AD = 040404040404040404040404 +Secret = 0303030303030303 +Output = a1187c4a4406093d68c6844731b9d9315ea9d03ff8031564dbe7f437a35debe327ea852d5a5b66a564838a5d2b5c48cc7b4ecde663f6713f4cb4e967295eafbf + +M = 4096 +T = 32 +P = 64 +Passphrase = 0101010101010101010101010101010101010101010101010101010101010101 +Salt = 02020202020202020202020202020202 +AD = 040404040404040404040404 +Secret = 0303030303030303 +Output = f76f7ac4e23bae5c3d1797f5d8a7b40222f770f0b6d339d8b5d4c168a2dfb512838b2bd5f110397e1c15267f782f0067d8ef567a7556470cd13af4dedf1d585d + diff --git a/src/tests/test_pbkdf.cpp b/src/tests/test_pbkdf.cpp index 34ed64c3f..9ddb1e171 100644 --- a/src/tests/test_pbkdf.cpp +++ b/src/tests/test_pbkdf.cpp @@ -20,6 +20,10 @@ #include <botan/scrypt.h> #endif +#if defined(BOTAN_HAS_ARGON2) + #include <botan/argon2.h> +#endif + namespace Botan_Tests { namespace { @@ -192,6 +196,56 @@ BOTAN_REGISTER_TEST("scrypt", Scrypt_KAT_Tests); #endif +#if defined(BOTAN_HAS_ARGON2) + +class Argon2_KAT_Tests final : public Text_Based_Test + { + public: + Argon2_KAT_Tests() : Text_Based_Test("argon2.vec", "Passphrase,Salt,P,M,T,Output", "Secret,AD") {} + + Test::Result run_one_test(const std::string& mode, const VarMap& vars) override + { + const size_t P = vars.get_req_sz("P"); + const size_t M = vars.get_req_sz("M"); + const size_t T = vars.get_req_sz("T"); + const std::vector<uint8_t> key = vars.get_opt_bin("Secret"); + const std::vector<uint8_t> ad = vars.get_opt_bin("AD"); + const std::vector<uint8_t> salt = vars.get_req_bin("Salt"); + const std::vector<uint8_t> passphrase = vars.get_req_bin("Passphrase"); + const std::vector<uint8_t> expected = vars.get_req_bin("Output"); + + uint8_t family; + if(mode == "Argon2d") + family = 0; + else if(mode == "Argon2i") + family = 1; + else if(mode == "Argon2id") + family = 2; + else + throw Test_Error("Unknown Argon2 mode"); + + Test::Result result(mode); + + std::vector<uint8_t> output(expected.size()); + Botan::argon2(output.data(), output.size(), + reinterpret_cast<const char*>(passphrase.data()), + passphrase.size(), + salt.data(), salt.size(), + key.data(), key.size(), + ad.data(), ad.size(), + family, P, M, T); + + result.test_eq("derived key", output, expected); + + return result; + } + + }; + +BOTAN_REGISTER_TEST("argon2", Argon2_KAT_Tests); + +#endif + #if defined(BOTAN_HAS_PGP_S2K) class PGP_S2K_Iter_Test final : public Test |