aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/lib/block/blowfish/blowfish.cpp59
-rw-r--r--src/lib/block/blowfish/blowfish.h16
-rw-r--r--src/lib/block/blowfish/info.txt2
-rw-r--r--src/lib/passhash/bcrypt/bcrypt.cpp18
-rw-r--r--src/tests/data/salted_blowfish.vec46
-rw-r--r--src/tests/test_blowfish.cpp46
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