diff options
author | lloyd <[email protected]> | 2011-03-08 22:18:37 +0000 |
---|---|---|
committer | lloyd <[email protected]> | 2011-03-08 22:18:37 +0000 |
commit | e8ae96510f3d87e3b142df81b51c3b15e30e77f9 (patch) | |
tree | 4f61ddba33a8e06b85ba2edc1b74d1a02e7c4739 /src | |
parent | 5f4aafe005d1031b955718fbb94d6beec3e6ea48 (diff) | |
parent | 41da07c02a36add833965be5ddc60ef1cf089beb (diff) |
propagate from branch 'net.randombit.botan' (head dd068808e5bf87c982765a8bcc314996053a5bdd)
to branch 'net.randombit.botan.c++0x' (head 34696d52a8148d64f7021b3e193fc56f051b9dd2)
Diffstat (limited to 'src')
26 files changed, 508 insertions, 56 deletions
diff --git a/src/block/aes/aes.cpp b/src/block/aes/aes.cpp index 7f32d243c..9fb12cd11 100644 --- a/src/block/aes/aes.cpp +++ b/src/block/aes/aes.cpp @@ -457,7 +457,7 @@ void aes_encrypt_n(const byte in[], byte out[], rotate_right(TE[get_byte(2, T1)], 16) ^ rotate_right(TE[get_byte(3, T2)], 24) ^ EK[7]; - for(u32bit r = 2*4; r < EK.size(); r += 2*4) + for(size_t r = 2*4; r < EK.size(); r += 2*4) { T0 = TE0[get_byte(0, B0)] ^ TE1[get_byte(1, B1)] ^ TE2[get_byte(2, B2)] ^ TE3[get_byte(3, B3)] ^ EK[r]; @@ -560,7 +560,7 @@ void aes_decrypt_n(const byte in[], byte out[], size_t blocks, rotate_right(TD[get_byte(2, T1)], 16) ^ rotate_right(TD[get_byte(3, T0)], 24) ^ DK[7]; - for(u32bit r = 2*4; r < DK.size(); r += 2*4) + for(size_t r = 2*4; r < DK.size(); r += 2*4) { T0 = TD0[get_byte(0, B0)] ^ TD1[get_byte(1, B3)] ^ TD2[get_byte(2, B2)] ^ TD3[get_byte(3, B1)] ^ DK[r]; diff --git a/src/block/blowfish/blowfish.cpp b/src/block/blowfish/blowfish.cpp index ea227e93e..b6319eec0 100644 --- a/src/block/blowfish/blowfish.cpp +++ b/src/block/blowfish/blowfish.cpp @@ -1,6 +1,6 @@ /* * Blowfish -* (C) 1999-2009 Jack Lloyd +* (C) 1999-2011 Jack Lloyd * * Distributed under the terms of the Botan license */ @@ -87,20 +87,66 @@ void Blowfish::key_schedule(const byte key[], size_t length) { clear(); + 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); - generate_sbox(S, L, R); + 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) + { + if(length == 0 || length >= 56) + throw Invalid_Key_Length("EKSBlowfish", length); + + 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 too large"); + + clear(); + + const byte null_salt[16] = { 0 }; + + key_expansion(key, length, salt); + + 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(MemoryRegion<u32bit>& box, - u32bit& L, u32bit& R) const + u32bit& L, u32bit& R, + const byte salt[16], + size_t salt_off) const { const u32bit* S1 = &S[0]; const u32bit* S2 = &S[256]; @@ -109,6 +155,9 @@ void Blowfish::generate_sbox(MemoryRegion<u32bit>& box, 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]; diff --git a/src/block/blowfish/blowfish.h b/src/block/blowfish/blowfish.h index b89ffcaaa..13706d21e 100644 --- a/src/block/blowfish/blowfish.h +++ b/src/block/blowfish/blowfish.h @@ -1,6 +1,6 @@ /* * Blowfish -* (C) 1999-2009 Jack Lloyd +* (C) 1999-2011 Jack Lloyd * * Distributed under the terms of the Botan license */ @@ -21,15 +21,28 @@ class BOTAN_DLL Blowfish : public Block_Cipher_Fixed_Params<8, 1, 56> void encrypt_n(const byte in[], byte out[], size_t blocks) const; void decrypt_n(const byte in[], byte out[], size_t blocks) const; + /** + * Modified EKSBlowfish key schedule, used for bcrypt password hashing + */ + void eks_key_schedule(const byte key[], size_t key_length, + const byte salt[16], size_t workfactor); + void clear(); std::string name() const { return "Blowfish"; } BlockCipher* clone() const { return new Blowfish; } Blowfish() : S(1024), P(18) {} private: - void key_schedule(const byte[], size_t); + void key_schedule(const byte key[], size_t length); + + void key_expansion(const byte key[], + size_t key_length, + const byte salt[16]); + void generate_sbox(MemoryRegion<u32bit>& box, - u32bit& L, u32bit& R) const; + u32bit& L, u32bit& R, + const byte salt[16], + size_t salt_off) const; static const u32bit P_INIT[18]; static const u32bit S_INIT[1024]; diff --git a/src/block/mars/mars.cpp b/src/block/mars/mars.cpp index 5ee5b0f19..171ce2945 100644 --- a/src/block/mars/mars.cpp +++ b/src/block/mars/mars.cpp @@ -110,7 +110,7 @@ const u32bit SBOX[512] = { inline void encrypt_round(u32bit& A, u32bit& B, u32bit& C, u32bit& D, u32bit EK1, u32bit EK2) { - u32bit X = A + EK1; + const u32bit X = A + EK1; A = rotate_left(A, 13); u32bit Y = A * EK2; u32bit Z = SBOX[X % 512]; @@ -132,7 +132,7 @@ inline void decrypt_round(u32bit& A, u32bit& B, u32bit& C, u32bit& D, { u32bit Y = A * EK1; A = rotate_right(A, 13); - u32bit X = A + EK2; + const u32bit X = A + EK2; u32bit Z = SBOX[X % 512]; Y = rotate_left(Y, 5); @@ -204,7 +204,7 @@ u32bit gen_mask(u32bit input) for(u32bit j = 2; j != 31; ++j) { - u32bit region = (input >> (j-1)) & 0x07; + const u32bit region = (input >> (j-1)) & 0x07; if(region == 0x00 || region == 0x07) { @@ -213,7 +213,7 @@ u32bit gen_mask(u32bit input) for(u32bit k = low; k != high; ++k) { - u32bit value = (input >> k) & 0x3FF; + const u32bit value = (input >> k) & 0x3FF; if(value == 0 || value == 0x3FF) { @@ -377,7 +377,7 @@ void MARS::key_schedule(const byte key[], size_t length) for(size_t i = 5; i != 37; i += 2) { - u32bit key3 = EK[i] & 3; + const u32bit key3 = EK[i] & 3; EK[i] |= 3; EK[i] ^= rotate_left(SBOX[265 + key3], EK[i-1] % 32) & gen_mask(EK[i]); } diff --git a/src/build-data/cc/sunstudio.txt b/src/build-data/cc/sunstudio.txt index 91a6ace65..d0b25d144 100644 --- a/src/build-data/cc/sunstudio.txt +++ b/src/build-data/cc/sunstudio.txt @@ -45,7 +45,9 @@ sparc64 -> "-xchip=SUBMODEL" sparc64- </mach_opt> <mach_abi_linking> -# On Linux, may need -library=stlport4 +# Needed on some Linux distros +#linux -> "-library=stlport4" + sparc64 -> "-xarch=v9" amd64 -> "-m64" </mach_abi_linking> diff --git a/src/cert/certstore/info.txt b/src/cert/certstore/info.txt index ee730490f..a5de1baff 100644 --- a/src/cert/certstore/info.txt +++ b/src/cert/certstore/info.txt @@ -1,5 +1,6 @@ define CERTIFICATE_STORE <requires> -asn1 +x509cert +x509crl </requires> diff --git a/src/cert/x509cert/info.txt b/src/cert/x509cert/info.txt index 3be50f077..5e3715e7a 100644 --- a/src/cert/x509cert/info.txt +++ b/src/cert/x509cert/info.txt @@ -2,4 +2,5 @@ define X509_CERTIFICATES <requires> certstore +datastor </requires> diff --git a/src/cert/x509cert/x509cert.cpp b/src/cert/x509cert/x509cert.cpp index a431cb66d..40b61b47d 100644 --- a/src/cert/x509cert/x509cert.cpp +++ b/src/cert/x509cert/x509cert.cpp @@ -325,8 +325,8 @@ std::string X509_Certificate::to_string() const continue; out << "Subject " << dn_fields[i] << ":"; - for(size_t i = 0; i != vals.size(); ++i) - out << " " << vals[i]; + for(size_t j = 0; j != vals.size(); ++j) + out << " " << vals[j]; out << "\n"; } @@ -338,8 +338,8 @@ std::string X509_Certificate::to_string() const continue; out << "Issuer " << dn_fields[i] << ":"; - for(size_t i = 0; i != vals.size(); ++i) - out << " " << vals[i]; + for(size_t j = 0; j != vals.size(); ++j) + out << " " << vals[j]; out << "\n"; } @@ -374,16 +374,16 @@ std::string X509_Certificate::to_string() const if(policies.size()) { out << "Policies: " << "\n"; - for(u32bit j = 0; j != policies.size(); j++) - out << " " << policies[j] << "\n"; + for(size_t i = 0; i != policies.size(); i++) + out << " " << policies[i] << "\n"; } std::vector<std::string> ex_constraints = this->ex_constraints(); if(ex_constraints.size()) { out << "Extended Constraints:\n"; - for(u32bit j = 0; j != ex_constraints.size(); j++) - out << " " << ex_constraints[j] << "\n"; + for(size_t i = 0; i != ex_constraints.size(); i++) + out << " " << ex_constraints[i] << "\n"; } out << "Signature algorithm: " << diff --git a/src/codec/pem/info.txt b/src/codec/pem/info.txt index 88f36594c..6f9635d10 100644 --- a/src/codec/pem/info.txt +++ b/src/codec/pem/info.txt @@ -2,5 +2,5 @@ define PEM_CODEC <requires> base64 -filters +codec_filt </requires> diff --git a/src/constructs/aont/package.cpp b/src/constructs/aont/package.cpp index 4d92a789c..4d46f6b61 100644 --- a/src/constructs/aont/package.cpp +++ b/src/constructs/aont/package.cpp @@ -46,13 +46,13 @@ void aont_package(RandomNumberGenerator& rng, clear_mem(final_block, BLOCK_SIZE); // XOR the hash blocks into the final block - for(u32bit i = 0; i != blocks; ++i) + for(size_t i = 0; i != blocks; ++i) { const size_t left = std::min<size_t>(BLOCK_SIZE, input_len - BLOCK_SIZE * i); zeroise(buf); - copy_mem(&buf[0], output + BLOCK_SIZE * i, left); + copy_mem(&buf[0], output + (BLOCK_SIZE * i), left); for(size_t j = 0; j != sizeof(i); ++j) buf[BLOCK_SIZE - 1 - j] ^= get_byte(sizeof(i)-1-j, i); @@ -94,13 +94,13 @@ void aont_unpackage(BlockCipher* cipher, const size_t blocks = ((input_len - 1) / BLOCK_SIZE); // XOR the blocks into the package key bits - for(u32bit i = 0; i != blocks; ++i) + for(size_t i = 0; i != blocks; ++i) { const size_t left = std::min<size_t>(BLOCK_SIZE, input_len - BLOCK_SIZE * (i+1)); zeroise(buf); - copy_mem(&buf[0], input + BLOCK_SIZE * i, left); + copy_mem(&buf[0], input + (BLOCK_SIZE * i), left); for(size_t j = 0; j != sizeof(i); ++j) buf[BLOCK_SIZE - 1 - j] ^= get_byte(sizeof(i)-1-j, i); diff --git a/src/constructs/rfc3394/info.txt b/src/constructs/rfc3394/info.txt new file mode 100644 index 000000000..496f3e138 --- /dev/null +++ b/src/constructs/rfc3394/info.txt @@ -0,0 +1 @@ +define RFC3394_KEYWRAP diff --git a/src/constructs/rfc3394/rfc3394.cpp b/src/constructs/rfc3394/rfc3394.cpp new file mode 100644 index 000000000..b000873fd --- /dev/null +++ b/src/constructs/rfc3394/rfc3394.cpp @@ -0,0 +1,122 @@ +/* +* AES Key Wrap (RFC 3394) +* (C) 2011 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include <botan/rfc3394.h> +#include <botan/algo_factory.h> +#include <botan/block_cipher.h> +#include <botan/loadstor.h> +#include <botan/exceptn.h> +#include <botan/internal/xor_buf.h> +#include <memory> + +namespace Botan { + +namespace { + +BlockCipher* make_aes(size_t keylength, + Algorithm_Factory& af) + { + if(keylength == 16) + return af.make_block_cipher("AES-128"); + else if(keylength == 24) + return af.make_block_cipher("AES-192"); + else if(keylength == 32) + return af.make_block_cipher("AES-256"); + else + throw std::invalid_argument("Bad KEK length for NIST keywrap"); + } + +} + +SecureVector<byte> rfc3394_keywrap(const MemoryRegion<byte>& key, + const SymmetricKey& kek, + Algorithm_Factory& af) + { + if(key.size() % 8 != 0) + throw std::invalid_argument("Bad input key size for NIST key wrap"); + + std::auto_ptr<BlockCipher> aes(make_aes(kek.length(), af)); + aes->set_key(kek); + + const size_t n = key.size() / 8; + + SecureVector<byte> R((n + 1) * 8); + SecureVector<byte> A(16); + + for(size_t i = 0; i != 8; ++i) + A[i] = 0xA6; + + copy_mem(&R[8], key.begin(), key.size()); + + for(size_t j = 0; j <= 5; ++j) + { + for(size_t i = 1; i <= n; ++i) + { + const u32bit t = (n * j) + i; + + copy_mem(&A[8], &R[8*i], 8); + + aes->encrypt(&A[0]); + copy_mem(&R[8*i], &A[8], 8); + + byte t_buf[4] = { 0 }; + store_be(t, t_buf); + xor_buf(&A[4], &t_buf[0], 4); + } + } + + copy_mem(&R[0], &A[0], 8); + + return R; + } + +SecureVector<byte> rfc3394_keyunwrap(const MemoryRegion<byte>& key, + const SymmetricKey& kek, + Algorithm_Factory& af) + { + if(key.size() < 16 || key.size() % 8 != 0) + throw std::invalid_argument("Bad input key size for NIST key unwrap"); + + std::auto_ptr<BlockCipher> aes(make_aes(kek.length(), af)); + aes->set_key(kek); + + const size_t n = (key.size() - 8) / 8; + + SecureVector<byte> R(n * 8); + SecureVector<byte> A(16); + + for(size_t i = 0; i != 8; ++i) + A[i] = key[i]; + + copy_mem(&R[0], key.begin() + 8, key.size() - 8); + + for(size_t j = 0; j <= 5; ++j) + { + for(size_t i = n; i != 0; --i) + { + const u32bit t = (5 - j) * n + i; + + byte t_buf[4] = { 0 }; + store_be(t, t_buf); + + xor_buf(&A[4], &t_buf[0], 4); + + copy_mem(&A[8], &R[8*(i-1)], 8); + + aes->decrypt(&A[0]); + + copy_mem(&R[8*(i-1)], &A[8], 8); + } + } + + if(load_be<u64bit>(&A[0], 0) != 0xA6A6A6A6A6A6A6A6) + throw Integrity_Failure("NIST key unwrap failed"); + + return R; + } + +} diff --git a/src/constructs/rfc3394/rfc3394.h b/src/constructs/rfc3394/rfc3394.h new file mode 100644 index 000000000..645586ee2 --- /dev/null +++ b/src/constructs/rfc3394/rfc3394.h @@ -0,0 +1,45 @@ +/* +* AES Key Wrap (RFC 3394) +* (C) 2011 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_AES_KEY_WRAP_H__ +#define BOTAN_AES_KEY_WRAP_H__ + +#include <botan/symkey.h> + +namespace Botan { + +class Algorithm_Factory; + +/** +* Encrypt a key under a key encryption key using the algorithm +* described in RFC 3394 +* +* @param key the plaintext key to encrypt +* @param kek the key encryption key +* @param af an algorithm factory +* @return key encrypted under kek +*/ +SecureVector<byte> BOTAN_DLL rfc3394_keywrap(const MemoryRegion<byte>& key, + const SymmetricKey& kek, + Algorithm_Factory& af); + +/** +* Decrypt a key under a key encryption key using the algorithm +* described in RFC 3394 +* +* @param key the encrypted key to decrypt +* @param kek the key encryption key +* @param af an algorithm factory +* @return key decrypted under kek +*/ +SecureVector<byte> BOTAN_DLL rfc3394_keyunwrap(const MemoryRegion<byte>& key, + const SymmetricKey& kek, + Algorithm_Factory& af); + +} + +#endif diff --git a/src/entropy/hres_timer/hres_timer.cpp b/src/entropy/hres_timer/hres_timer.cpp index e9307743f..b0f99170a 100644 --- a/src/entropy/hres_timer/hres_timer.cpp +++ b/src/entropy/hres_timer/hres_timer.cpp @@ -45,7 +45,7 @@ void High_Resolution_Timestamp::poll(Entropy_Accumulator& accum) #elif defined(BOTAN_TARGET_ARCH_IS_ALPHA) asm volatile("rpcc %0" : "=r" (rtc)); -#elif defined(BOTAN_TARGET_ARCH_IS_SPARC64) +#elif defined(BOTAN_TARGET_ARCH_IS_SPARC64) && !defined(BOTAN_TARGET_OS_IS_OPENBSD) asm volatile("rd %%tick, %0" : "=r" (rtc)); #elif defined(BOTAN_TARGET_ARCH_IS_IA64) diff --git a/src/filters/bzip2/bzip2.cpp b/src/filters/bzip2/bzip2.cpp index b166017c3..a291c1173 100644 --- a/src/filters/bzip2/bzip2.cpp +++ b/src/filters/bzip2/bzip2.cpp @@ -168,10 +168,14 @@ void Bzip_Compression::flush() */ void Bzip_Compression::clear() { - if(!bz) return; - BZ2_bzCompressEnd(&(bz->stream)); - delete bz; - bz = 0; + zeroise(buffer); + + if(bz) + { + BZ2_bzCompressEnd(&(bz->stream)); + delete bz; + bz = 0; + } } /* @@ -278,10 +282,14 @@ void Bzip_Decompression::end_msg() */ void Bzip_Decompression::clear() { - if(!bz) return; - BZ2_bzDecompressEnd(&(bz->stream)); - delete bz; - bz = 0; + zeroise(buffer); + + if(bz) + { + BZ2_bzDecompressEnd(&(bz->stream)); + delete bz; + bz = 0; + } } } diff --git a/src/filters/out_buf.cpp b/src/filters/out_buf.cpp index 7fa13b8e3..7b79b4b70 100644 --- a/src/filters/out_buf.cpp +++ b/src/filters/out_buf.cpp @@ -1,6 +1,6 @@ /* * Pipe Output Buffer -* (C) 1999-2007 Jack Lloyd +* (C) 1999-2007,2011 Jack Lloyd * * Distributed under the terms of the Botan license */ @@ -65,16 +65,17 @@ void Output_Buffers::add(SecureQueue* queue) */ void Output_Buffers::retire() { - while(buffers.size()) - { - if(buffers[0] == 0 || buffers[0]->size() == 0) + for(size_t i = 0; i != buffers.size(); ++i) + if(buffers[i] && buffers[i]->size() == 0) { - delete buffers[0]; - buffers.pop_front(); - offset = offset + Pipe::message_id(1); + delete buffers[i]; + buffers[i] = 0; } - else - break; + + while(buffers.size() && !buffers[0]) + { + buffers.pop_front(); + offset = offset + Pipe::message_id(1); } } diff --git a/src/filters/zlib/zlib.cpp b/src/filters/zlib/zlib.cpp index 30dee0225..0f88b5558 100644 --- a/src/filters/zlib/zlib.cpp +++ b/src/filters/zlib/zlib.cpp @@ -138,9 +138,11 @@ void Zlib_Compression::end_msg() { zlib->stream.next_out = reinterpret_cast<Bytef*>(buffer.begin()); zlib->stream.avail_out = buffer.size(); + rc = deflate(&(zlib->stream), Z_FINISH); send(buffer.begin(), buffer.size() - zlib->stream.avail_out); } + clear(); } @@ -155,13 +157,13 @@ void Zlib_Compression::flush() while(true) { zlib->stream.avail_out = buffer.size(); - zlib->stream.next_out = reinterpret_cast<Bytef*>(buffer.begin()); - deflate(&(zlib->stream), Z_FULL_FLUSH); send(buffer.begin(), buffer.size() - zlib->stream.avail_out); - if(zlib->stream.avail_out == buffer.size()) break; + + if(zlib->stream.avail_out == buffer.size()) + break; } } @@ -170,14 +172,14 @@ void Zlib_Compression::flush() */ void Zlib_Compression::clear() { + zeroise(buffer); + if(zlib) { deflateEnd(&(zlib->stream)); delete zlib; zlib = 0; } - - buffer.clear(); } /* @@ -283,6 +285,8 @@ void Zlib_Decompression::end_msg() */ void Zlib_Decompression::clear() { + zeroise(buffer); + no_writes = true; if(zlib) @@ -291,8 +295,6 @@ void Zlib_Decompression::clear() delete zlib; zlib = 0; } - - buffer.clear(); } } diff --git a/src/libstate/info.txt b/src/libstate/info.txt index a017589fc..ef0c9a47e 100644 --- a/src/libstate/info.txt +++ b/src/libstate/info.txt @@ -24,6 +24,7 @@ scan_name.cpp </source> <requires> +aes algo_factory alloc bigint @@ -32,6 +33,8 @@ core_engine engine filters hash +hmac +hmac_rng kdf mac mode_pad @@ -39,6 +42,8 @@ pbkdf pk_pad pubkey rng +sha2_32 +sha2_64 stream system_alloc </requires> diff --git a/src/passhash/bcrypt/bcrypt.cpp b/src/passhash/bcrypt/bcrypt.cpp new file mode 100644 index 000000000..e533c6081 --- /dev/null +++ b/src/passhash/bcrypt/bcrypt.cpp @@ -0,0 +1,154 @@ +/* +* Bcrypt Password Hashing +* (C) 2010 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include <botan/bcrypt.h> +#include <botan/loadstor.h> +#include <botan/libstate.h> +#include <botan/blowfish.h> +#include <botan/base64.h> + +#include <botan/pipe.h> +#include <botan/b64_filt.h> +#include <iostream> +#include <stdio.h> + +namespace Botan { + +namespace { + +std::string bcrypt_base64_encode(const byte input[], size_t length) + { + // Bcrypt uses a non-standard base64 alphabet + const byte OPENBSD_BASE64_SUB[256] = { + 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x38, 0x80, 0x80, 0x80, 0x39, + 0x79, 0x7A, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x2E, 0x2F, 0x41, 0x42, 0x43, 0x44, 0x45, + 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51, + 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x59, 0x5A, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, + 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, + 0x76, 0x77, 0x78, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80 + }; + + std::string b64 = base64_encode(input, length); + + while(b64.size() && b64[b64.size()-1] == '=') + b64 = b64.substr(0, b64.size() - 1); + + for(size_t i = 0; i != b64.size(); ++i) + b64[i] = OPENBSD_BASE64_SUB[static_cast<byte>(b64[i])]; + + return b64; + } + +MemoryVector<byte> bcrypt_base64_decode(std::string input) + { + const byte OPENBSD_BASE64_SUB[256] = { + 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x41, 0x42, + 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x2B, 0x2F, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, + 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, + 0x56, 0x57, 0x58, 0x59, 0x5A, 0x61, 0x62, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, + 0x6E, 0x6F, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, + 0x7A, 0x30, 0x31, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80 + }; + + for(size_t i = 0; i != input.size(); ++i) + input[i] = OPENBSD_BASE64_SUB[static_cast<byte>(input[i])]; + + //return base64_decode(input); + Pipe pipe(new Base64_Decoder); + pipe.process_msg(input); + return pipe.read_all(); + } + +std::string make_bcrypt(const std::string& pass, + const MemoryRegion<byte>& salt, + u16bit work_factor) + { + const byte magic[24] = { + 0x4F, 0x72, 0x70, 0x68, 0x65, 0x61, 0x6E, 0x42, + 0x65, 0x68, 0x6F, 0x6C, 0x64, 0x65, 0x72, 0x53, + 0x63, 0x72, 0x79, 0x44, 0x6F, 0x75, 0x62, 0x74 + }; + + MemoryVector<byte> ctext(magic, 24); + + Blowfish blowfish; + + // Include the trailing NULL byte + blowfish.eks_key_schedule(reinterpret_cast<const byte*>(pass.c_str()), + pass.length() + 1, + salt, + work_factor); + + for(size_t i = 0; i != 64; ++i) + blowfish.encrypt_n(&ctext[0], &ctext[0], 3); + + std::string salt_b64 = bcrypt_base64_encode(&salt[0], salt.size()); + + return "$2a$" + to_string(work_factor, 2) + "$" + salt_b64.substr(0, 22) + + bcrypt_base64_encode(&ctext[0], ctext.size() - 1); + } + +} + +std::string generate_bcrypt(const std::string& pass, + RandomNumberGenerator& rng, + u16bit work_factor) + { + return make_bcrypt(pass, rng.random_vec(16), work_factor); + } + +bool check_bcrypt(const std::string& pass, const std::string& hash) + { + if(hash.size() != 60 || + hash[0] != '$' || hash[1] != '2' || hash[2] != 'a' || + hash[3] != '$' || hash[6] != '$') + { + return false; + } + + const u16bit workfactor = to_u32bit(hash.substr(4, 2)); + + MemoryVector<byte> salt = bcrypt_base64_decode(hash.substr(7, 22)); + + const std::string compare = make_bcrypt(pass, salt, workfactor); + + return (hash == compare); + } + +} diff --git a/src/passhash/bcrypt/bcrypt.h b/src/passhash/bcrypt/bcrypt.h new file mode 100644 index 000000000..8a6ab58ea --- /dev/null +++ b/src/passhash/bcrypt/bcrypt.h @@ -0,0 +1,37 @@ +/* +* Bcrypt Password Hashing +* (C) 2011 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_BCRYPT_H__ +#define BOTAN_BCRYPT_H__ + +#include <botan/rng.h> + +namespace Botan { + +/** +* Create a password hash using Bcrypt +* @param password the password +* @param rng a random number generator +* @param work_factor how much work to do to slow down guessing attacks +* +* @see http://www.usenix.org/events/usenix99/provos/provos_html/ +*/ +std::string BOTAN_DLL generate_bcrypt(const std::string& password, + RandomNumberGenerator& rng, + u16bit work_factor = 10); + +/** +* Check a previously created password hash +* @param password the password to check against +* @param hash the stored hash to check against +*/ +bool BOTAN_DLL check_bcrypt(const std::string& password, + const std::string& hash); + +} + +#endif diff --git a/src/passhash/bcrypt/info.txt b/src/passhash/bcrypt/info.txt new file mode 100644 index 000000000..91ab92e88 --- /dev/null +++ b/src/passhash/bcrypt/info.txt @@ -0,0 +1,9 @@ +define BCRYPT + +<requires> +libstate +blowfish +rng +base64 +</requires> + diff --git a/src/constructs/passhash/info.txt b/src/passhash/passhash9/info.txt index f96809f29..f96809f29 100644 --- a/src/constructs/passhash/info.txt +++ b/src/passhash/passhash9/info.txt diff --git a/src/constructs/passhash/passhash9.cpp b/src/passhash/passhash9/passhash9.cpp index 367583a0a..367583a0a 100644 --- a/src/constructs/passhash/passhash9.cpp +++ b/src/passhash/passhash9/passhash9.cpp diff --git a/src/constructs/passhash/passhash9.h b/src/passhash/passhash9/passhash9.h index 92cc391dc..92cc391dc 100644 --- a/src/constructs/passhash/passhash9.h +++ b/src/passhash/passhash9/passhash9.h diff --git a/src/ssl/info.txt b/src/ssl/info.txt index 8f1eda497..1f11772cd 100644 --- a/src/ssl/info.txt +++ b/src/ssl/info.txt @@ -46,6 +46,8 @@ asn1 des dh dsa +eme_pkcs +emsa3 filters hmac md5 diff --git a/src/stream/ctr/ctr.cpp b/src/stream/ctr/ctr.cpp index 0de0b7b84..d221dc441 100644 --- a/src/stream/ctr/ctr.cpp +++ b/src/stream/ctr/ctr.cpp @@ -97,7 +97,7 @@ void CTR_BE::set_iv(const byte iv[], size_t iv_len) &counter[(i-1)*BLOCK_SIZE], BLOCK_SIZE); - for(u32bit j = 0; j != BLOCK_SIZE; ++j) + for(size_t j = 0; j != BLOCK_SIZE; ++j) if(++counter[i*BLOCK_SIZE + (BLOCK_SIZE-1-j)]) break; } @@ -115,7 +115,7 @@ void CTR_BE::increment_counter() for(size_t i = 0; i != 256; ++i) { - for(u32bit j = 1; j != BLOCK_SIZE; ++j) + for(size_t j = 1; j != BLOCK_SIZE; ++j) if(++counter[i*BLOCK_SIZE + (BLOCK_SIZE-1-j)]) break; } |