diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/lib/block/blowfish/blowfish.cpp | 59 | ||||
-rw-r--r-- | src/lib/block/blowfish/blowfish.h | 16 | ||||
-rw-r--r-- | src/lib/block/blowfish/info.txt | 2 | ||||
-rw-r--r-- | src/lib/passhash/bcrypt/bcrypt.cpp | 18 | ||||
-rw-r--r-- | src/tests/data/salted_blowfish.vec | 46 | ||||
-rw-r--r-- | src/tests/test_blowfish.cpp | 46 |
6 files changed, 151 insertions, 36 deletions
diff --git a/src/lib/block/blowfish/blowfish.cpp b/src/lib/block/blowfish/blowfish.cpp index 0bdc0ed92..9e906c80f 100644 --- a/src/lib/block/blowfish/blowfish.cpp +++ b/src/lib/block/blowfish/blowfish.cpp @@ -1,6 +1,6 @@ /* * Blowfish -* (C) 1999-2011 Jack Lloyd +* (C) 1999-2011,2018 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ @@ -319,39 +319,36 @@ void Blowfish::key_schedule(const uint8_t key[], size_t length) m_S.resize(1024); copy_mem(m_S.data(), S_INIT, 1024); - const uint8_t null_salt[16] = { 0 }; - - key_expansion(key, length, null_salt); + key_expansion(key, length, nullptr, 0); } void Blowfish::key_expansion(const uint8_t key[], size_t length, - const uint8_t salt[16]) + const uint8_t salt[], + size_t salt_length) { + BOTAN_ASSERT_NOMSG(salt_length % 4 == 0); + for(size_t i = 0, j = 0; i != 18; ++i, j += 4) m_P[i] ^= make_uint32(key[(j ) % length], key[(j+1) % length], key[(j+2) % length], key[(j+3) % length]); + const size_t P_salt_offset = (salt_length > 0) ? 18 % (salt_length / 4) : 0; + uint32_t L = 0, R = 0; - generate_sbox(m_P, L, R, salt, 0); - generate_sbox(m_S, L, R, salt, 2); + generate_sbox(m_P, L, R, salt, salt_length, 0); + generate_sbox(m_S, L, R, salt, salt_length, P_salt_offset); } /* * Modified key schedule used for bcrypt password hashing */ -void Blowfish::eks_key_schedule(const uint8_t key[], size_t length, - const uint8_t salt[16], size_t workfactor) +void Blowfish::salted_set_key(const uint8_t key[], size_t length, + const uint8_t salt[], size_t salt_length, + size_t workfactor) { - - /* - * On a 4 GHz Skylake, workfactor == 18 takes about 15 seconds to - * hash a password. This seems like a reasonable upper bound for the - * time being. - * Bcrypt allows up to work factor 31 (2^31 iterations) - */ - BOTAN_ARG_CHECK(workfactor >= 4 && workfactor <= 18, - "Invalid bcrypt work factor"); + BOTAN_ARG_CHECK(salt_length > 0 && salt_length % 4 == 0, + "Invalid salt length for Blowfish salted key schedule"); if(length > 72) { @@ -364,15 +361,17 @@ void Blowfish::eks_key_schedule(const uint8_t key[], size_t length, m_S.resize(1024); copy_mem(m_S.data(), S_INIT, 1024); - key_expansion(key, length, salt); - - const uint8_t null_salt[16] = { 0 }; - const size_t rounds = static_cast<size_t>(1) << workfactor; + key_expansion(key, length, salt, salt_length); - for(size_t r = 0; r != rounds; ++r) + if(workfactor > 0) { - key_expansion(key, length, null_salt); - key_expansion(salt, 16, null_salt); + const size_t rounds = static_cast<size_t>(1) << workfactor; + + for(size_t r = 0; r != rounds; ++r) + { + key_expansion(key, length, nullptr, 0); + key_expansion(salt, salt_length, nullptr, 0); + } } } @@ -381,13 +380,17 @@ void Blowfish::eks_key_schedule(const uint8_t key[], size_t length, */ void Blowfish::generate_sbox(secure_vector<uint32_t>& box, uint32_t& L, uint32_t& R, - const uint8_t salt[16], + const uint8_t salt[], + size_t salt_length, size_t salt_off) const { for(size_t i = 0; i != box.size(); i += 2) { - L ^= load_be<uint32_t>(salt, (i + salt_off) % 4); - R ^= load_be<uint32_t>(salt, (i + salt_off + 1) % 4); + if(salt_length > 0) + { + L ^= load_be<uint32_t>(salt, (i + salt_off) % (salt_length / 4)); + R ^= load_be<uint32_t>(salt, (i + salt_off + 1) % (salt_length / 4)); + } for(size_t r = 0; r != 16; r += 2) { diff --git a/src/lib/block/blowfish/blowfish.h b/src/lib/block/blowfish/blowfish.h index fa84e2a3d..d5c318752 100644 --- a/src/lib/block/blowfish/blowfish.h +++ b/src/lib/block/blowfish/blowfish.h @@ -24,8 +24,16 @@ class BOTAN_PUBLIC_API(2,0) Blowfish final : public Block_Cipher_Fixed_Params<8, /** * Modified EKSBlowfish key schedule, used for bcrypt password hashing */ + void salted_set_key(const uint8_t key[], size_t key_length, + const uint8_t salt[], size_t salt_length, + size_t workfactor); + + BOTAN_DEPRECATED("Use Blowfish::salted_set_key taking salt length") void eks_key_schedule(const uint8_t key[], size_t key_length, - const uint8_t salt[16], size_t workfactor); + const uint8_t salt[16], size_t workfactor) + { + salted_set_key(key, key_length, salt, 16, workfactor); + } void clear() override; std::string name() const override { return "Blowfish"; } @@ -35,11 +43,13 @@ class BOTAN_PUBLIC_API(2,0) Blowfish final : public Block_Cipher_Fixed_Params<8, void key_expansion(const uint8_t key[], size_t key_length, - const uint8_t salt[16]); + const uint8_t salt[], + size_t salt_length); void generate_sbox(secure_vector<uint32_t>& box, uint32_t& L, uint32_t& R, - const uint8_t salt[16], + const uint8_t salt[], + size_t salt_length, size_t salt_off) const; secure_vector<uint32_t> m_S, m_P; diff --git a/src/lib/block/blowfish/info.txt b/src/lib/block/blowfish/info.txt index e028a5559..cc72634df 100644 --- a/src/lib/block/blowfish/info.txt +++ b/src/lib/block/blowfish/info.txt @@ -1,3 +1,3 @@ <defines> -BLOWFISH -> 20131128 +BLOWFISH -> 20180718 </defines> diff --git a/src/lib/passhash/bcrypt/bcrypt.cpp b/src/lib/passhash/bcrypt/bcrypt.cpp index 5688df0e6..29bcc9d1b 100644 --- a/src/lib/passhash/bcrypt/bcrypt.cpp +++ b/src/lib/passhash/bcrypt/bcrypt.cpp @@ -92,6 +92,15 @@ std::string make_bcrypt(const std::string& pass, uint16_t work_factor, char version) { + /* + * On a 4 GHz Skylake, workfactor == 18 takes about 15 seconds to + * hash a password. This seems like a reasonable upper bound for the + * time being. + * Bcrypt allows up to work factor 31 (2^31 iterations) + */ + BOTAN_ARG_CHECK(work_factor >= 4 && work_factor <= 18, + "Invalid bcrypt work factor"); + static const uint8_t BCRYPT_MAGIC[8*3] = { 0x4F, 0x72, 0x70, 0x68, 0x65, 0x61, 0x6E, 0x42, 0x65, 0x68, 0x6F, 0x6C, 0x64, 0x65, 0x72, 0x53, @@ -101,10 +110,11 @@ std::string make_bcrypt(const std::string& pass, Blowfish blowfish; // Include the trailing NULL byte, so we need c_str() not data() - blowfish.eks_key_schedule(cast_char_ptr_to_uint8(pass.c_str()), - pass.length() + 1, - salt.data(), - work_factor); + blowfish.salted_set_key(cast_char_ptr_to_uint8(pass.c_str()), + pass.length() + 1, + salt.data(), + salt.size(), + work_factor); std::vector<uint8_t> ctext(BCRYPT_MAGIC, BCRYPT_MAGIC + 8*3); diff --git a/src/tests/data/salted_blowfish.vec b/src/tests/data/salted_blowfish.vec new file mode 100644 index 000000000..a69c39fe8 --- /dev/null +++ b/src/tests/data/salted_blowfish.vec @@ -0,0 +1,46 @@ + +# From tests in Golang x/crypto + +Key = 000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F +Salt = 20202020 +Out = d1e193f070a6db12 + +Key = 000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F +Salt = 20212021 +Out = fc5ebadecbf859ad + +Key = 000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F +Salt = 20212223 +Out = 2ccb7beeac7b7ff8 + +Key = 000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F +Salt = 2021222324252627 +Out = 67a1a9750e5bc6b4 + +Key = 000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F +Salt = 20212223242526272021222324252627 +Out = 67a1a9750e5bc6b4 + +Key = 000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F +Salt = 202122232425262728292A2B +Out = 4bfe43fdbf360447 + +Key = 000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F +Salt = 202122232425262728292A2B2C2D2E2F +Out = d9f0fddac023b793 + +Key = 000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F +Salt = 202122232425262728292A2B2C2D2E2F30313233 +Out = ff98dd0445b46d1f + +Key = 000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F +Salt = 202122232425262728292A2B2C2D2E2F3031323334353637 +Out = 6a0aee7c10d919fe + +Key = 000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F +Salt = 202122232425262728292A2B2C2D2E2F303132333435363738393A3B +Out = 978199a4de9e9fb6 + +Key = 000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F +Salt = 202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F +Out = C560AD4805E16248 diff --git a/src/tests/test_blowfish.cpp b/src/tests/test_blowfish.cpp new file mode 100644 index 000000000..58b28001e --- /dev/null +++ b/src/tests/test_blowfish.cpp @@ -0,0 +1,46 @@ +/* +* (C) 2018 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include "tests.h" + +#if defined(BOTAN_HAS_BLOWFISH) + +#include <botan/blowfish.h> + +namespace Botan_Tests { + +class Blowfish_Salted_Tests final : public Text_Based_Test + { + public: + Blowfish_Salted_Tests() : Text_Based_Test("salted_blowfish.vec", "Key,Salt,Out") {} + + Test::Result run_one_test(const std::string&, const VarMap& vars) override + { + Test::Result result("Blowfish salted key schedule"); + + const std::vector<uint8_t> key = vars.get_req_bin("Key"); + const std::vector<uint8_t> salt = vars.get_req_bin("Salt"); + const std::vector<uint8_t> expected = vars.get_req_bin("Out"); + + Botan::Blowfish blowfish; + + blowfish.salted_set_key(key.data(), key.size(), + salt.data(), salt.size(), 0); + + std::vector<uint8_t> block(8); + blowfish.encrypt(block); + + result.test_eq("Expected output", block, expected); + + return result; + } + }; + +BOTAN_REGISTER_TEST("blowfish_salted", Blowfish_Salted_Tests); + +} + +#endif |