diff options
author | lloyd <[email protected]> | 2014-01-10 03:41:59 +0000 |
---|---|---|
committer | lloyd <[email protected]> | 2014-01-10 03:41:59 +0000 |
commit | 6894dca64c04936d07048c0e8cbf7e25858548c3 (patch) | |
tree | 5d572bfde9fe667dab14e3f04b5285a85d8acd95 /src/lib/block/blowfish/blowfish.cpp | |
parent | 9efa3be92442afb3d0b69890a36c7f122df18eda (diff) |
Move lib into src
Diffstat (limited to 'src/lib/block/blowfish/blowfish.cpp')
-rw-r--r-- | src/lib/block/blowfish/blowfish.cpp | 195 |
1 files changed, 195 insertions, 0 deletions
diff --git a/src/lib/block/blowfish/blowfish.cpp b/src/lib/block/blowfish/blowfish.cpp new file mode 100644 index 000000000..e93359141 --- /dev/null +++ b/src/lib/block/blowfish/blowfish.cpp @@ -0,0 +1,195 @@ +/* +* Blowfish +* (C) 1999-2011 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include <botan/blowfish.h> +#include <botan/loadstor.h> + +namespace Botan { + +/* +* Blowfish Encryption +*/ +void Blowfish::encrypt_n(const byte in[], byte out[], size_t blocks) const + { + const u32bit* S1 = &S[0]; + const u32bit* S2 = &S[256]; + const u32bit* S3 = &S[512]; + const u32bit* S4 = &S[768]; + + for(size_t i = 0; i != blocks; ++i) + { + u32bit L = load_be<u32bit>(in, 0); + u32bit R = load_be<u32bit>(in, 1); + + for(size_t j = 0; j != 16; j += 2) + { + L ^= P[j]; + R ^= ((S1[get_byte(0, L)] + S2[get_byte(1, L)]) ^ + S3[get_byte(2, L)]) + S4[get_byte(3, L)]; + + R ^= P[j+1]; + L ^= ((S1[get_byte(0, R)] + S2[get_byte(1, R)]) ^ + S3[get_byte(2, R)]) + S4[get_byte(3, R)]; + } + + L ^= P[16]; R ^= P[17]; + + store_be(out, R, L); + + in += BLOCK_SIZE; + out += BLOCK_SIZE; + } + } + +/* +* Blowfish Decryption +*/ +void Blowfish::decrypt_n(const byte in[], byte out[], size_t blocks) const + { + const u32bit* S1 = &S[0]; + const u32bit* S2 = &S[256]; + const u32bit* S3 = &S[512]; + const u32bit* S4 = &S[768]; + + for(size_t i = 0; i != blocks; ++i) + { + u32bit L = load_be<u32bit>(in, 0); + u32bit R = load_be<u32bit>(in, 1); + + for(size_t j = 17; j != 1; j -= 2) + { + L ^= P[j]; + R ^= ((S1[get_byte(0, L)] + S2[get_byte(1, L)]) ^ + S3[get_byte(2, L)]) + S4[get_byte(3, L)]; + + R ^= P[j-1]; + L ^= ((S1[get_byte(0, R)] + S2[get_byte(1, R)]) ^ + S3[get_byte(2, R)]) + S4[get_byte(3, R)]; + } + + L ^= P[1]; R ^= P[0]; + + store_be(out, R, L); + + in += BLOCK_SIZE; + out += BLOCK_SIZE; + } + } + +/* +* Blowfish Key Schedule +*/ +void Blowfish::key_schedule(const byte key[], size_t length) + { + P.resize(18); + std::copy(P_INIT, P_INIT + 18, P.begin()); + + S.resize(1024); + std::copy(S_INIT, S_INIT + 1024, S.begin()); + + const byte null_salt[16] = { 0 }; + + key_expansion(key, length, null_salt); + } + +void Blowfish::key_expansion(const byte key[], + size_t length, + const byte salt[16]) + { + for(size_t i = 0, j = 0; i != 18; ++i, j += 4) + P[i] ^= make_u32bit(key[(j ) % length], key[(j+1) % length], + key[(j+2) % length], key[(j+3) % length]); + + u32bit L = 0, R = 0; + generate_sbox(P, L, R, salt, 0); + generate_sbox(S, L, R, salt, 2); + } + +/* +* Modified key schedule used for bcrypt password hashing +*/ +void Blowfish::eks_key_schedule(const byte key[], size_t length, + const byte salt[16], size_t workfactor) + { + // Truncate longer passwords to the 56 byte limit Blowfish enforces + length = std::min<size_t>(length, 55); + + if(workfactor == 0) + throw std::invalid_argument("Bcrypt work factor must be at least 1"); + + /* + * On a 2.8 GHz Core-i7, workfactor == 18 takes about 25 seconds to + * hash a password. This seems like a reasonable upper bound for the + * time being. + */ + if(workfactor > 18) + throw std::invalid_argument("Requested Bcrypt work factor " + + std::to_string(workfactor) + " too large"); + + P.resize(18); + std::copy(P_INIT, P_INIT + 18, P.begin()); + + S.resize(1024); + std::copy(S_INIT, S_INIT + 1024, S.begin()); + + key_expansion(key, length, salt); + + const byte null_salt[16] = { 0 }; + const size_t rounds = 1 << workfactor; + + for(size_t r = 0; r != rounds; ++r) + { + key_expansion(key, length, null_salt); + key_expansion(salt, 16, null_salt); + } + } + +/* +* Generate one of the Sboxes +*/ +void Blowfish::generate_sbox(secure_vector<u32bit>& box, + u32bit& L, u32bit& R, + const byte salt[16], + size_t salt_off) const + { + const u32bit* S1 = &S[0]; + const u32bit* S2 = &S[256]; + const u32bit* S3 = &S[512]; + const u32bit* S4 = &S[768]; + + for(size_t i = 0; i != box.size(); i += 2) + { + L ^= load_be<u32bit>(salt, (i + salt_off) % 4); + R ^= load_be<u32bit>(salt, (i + salt_off + 1) % 4); + + for(size_t j = 0; j != 16; j += 2) + { + L ^= P[j]; + R ^= ((S1[get_byte(0, L)] + S2[get_byte(1, L)]) ^ + S3[get_byte(2, L)]) + S4[get_byte(3, L)]; + + R ^= P[j+1]; + L ^= ((S1[get_byte(0, R)] + S2[get_byte(1, R)]) ^ + S3[get_byte(2, R)]) + S4[get_byte(3, R)]; + } + + u32bit T = R; R = L ^ P[16]; L = T ^ P[17]; + box[i] = L; + box[i+1] = R; + } + } + +/* +* Clear memory of sensitive data +*/ +void Blowfish::clear() + { + zap(P); + zap(S); + } + +} |