diff options
Diffstat (limited to 'src')
70 files changed, 1335 insertions, 265 deletions
diff --git a/src/algo_factory/algo_factory.cpp b/src/algo_factory/algo_factory.cpp index 38c6387e5..ad8b1215f 100644 --- a/src/algo_factory/algo_factory.cpp +++ b/src/algo_factory/algo_factory.cpp @@ -70,8 +70,7 @@ const T* factory_prototype(const std::string& algo_spec, { if(provider == "" || engines[i]->provider_name() == provider) { - T* impl = engine_get_algo<T>(engines[i], scan_name, af); - if(impl) + if(T* impl = engine_get_algo<T>(engines[i], scan_name, af)) cache->add(impl, algo_spec, engines[i]->provider_name()); } } diff --git a/src/asn1/ber_dec.cpp b/src/asn1/ber_dec.cpp index b34bf8ca2..66a27dd4e 100644 --- a/src/asn1/ber_dec.cpp +++ b/src/asn1/ber_dec.cpp @@ -7,7 +7,7 @@ #include <botan/ber_dec.h> #include <botan/bigint.h> -#include <botan/loadstor.h> +#include <botan/get_byte.h> namespace Botan { diff --git a/src/asn1/der_enc.cpp b/src/asn1/der_enc.cpp index 3c318c291..e410292bb 100644 --- a/src/asn1/der_enc.cpp +++ b/src/asn1/der_enc.cpp @@ -8,9 +8,9 @@ #include <botan/der_enc.h> #include <botan/asn1_int.h> #include <botan/bigint.h> -#include <botan/loadstor.h> -#include <botan/internal/bit_ops.h> +#include <botan/get_byte.h> #include <botan/parsing.h> +#include <botan/internal/bit_ops.h> #include <algorithm> namespace Botan { diff --git a/src/block/idea_sse2/idea_sse2.cpp b/src/block/idea_sse2/idea_sse2.cpp index c00d13ee9..0fe35112d 100644 --- a/src/block/idea_sse2/idea_sse2.cpp +++ b/src/block/idea_sse2/idea_sse2.cpp @@ -6,7 +6,6 @@ */ #include <botan/idea_sse2.h> -#include <botan/loadstor.h> #include <emmintrin.h> namespace Botan { diff --git a/src/block/noekeon/noekeon.h b/src/block/noekeon/noekeon.h index 4532c1be2..22ef65342 100644 --- a/src/block/noekeon/noekeon.h +++ b/src/block/noekeon/noekeon.h @@ -26,7 +26,7 @@ class BOTAN_DLL Noekeon : public BlockCipher BlockCipher* clone() const { return new Noekeon; } Noekeon() : BlockCipher(16, 16) {} - private: + protected: void key_schedule(const byte[], u32bit); static const byte RC[17]; diff --git a/src/block/noekeon_simd/info.txt b/src/block/noekeon_simd/info.txt new file mode 100644 index 000000000..b73954cff --- /dev/null +++ b/src/block/noekeon_simd/info.txt @@ -0,0 +1,7 @@ +define NOEKEON_SIMD + +<requires> +noekeon +simd_32 +simd_engine +</requires> diff --git a/src/block/noekeon_simd/noekeon_simd.cpp b/src/block/noekeon_simd/noekeon_simd.cpp new file mode 100644 index 000000000..f44104901 --- /dev/null +++ b/src/block/noekeon_simd/noekeon_simd.cpp @@ -0,0 +1,161 @@ +/* +* Noekeon in SIMD +* (C) 2010 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include <botan/noekeon_simd.h> +#include <botan/internal/simd_32.h> + +namespace Botan { + +/* +* Noekeon's Theta Operation +*/ +#define NOK_SIMD_THETA(A0, A1, A2, A3, K0, K1, K2, K3) \ + do { \ + SIMD_32 T = A0 ^ A2; \ + T ^= rotate_left(T, 8) ^ rotate_right(T, 8); \ + A1 ^= T; \ + A3 ^= T; \ + \ + A0 ^= K0; \ + A1 ^= K1; \ + A2 ^= K2; \ + A3 ^= K3; \ + \ + T = A1 ^ A3; \ + T ^= rotate_left(T, 8) ^ rotate_right(T, 8); \ + A0 ^= T; \ + A2 ^= T; \ + } while(0) + +/* +* Noekeon's Gamma S-Box Layer +*/ +#define NOK_SIMD_GAMMA(A0, A1, A2, A3) \ + do \ + { \ + A1 ^= A3.andc(~A2); \ + A0 ^= A2 & A1; \ + \ + SIMD_32 T = A3; \ + A3 = A0; \ + A0 = T; \ + \ + A2 ^= A0 ^ A1 ^ A3; \ + \ + A1 ^= A3.andc(~A2); \ + A0 ^= A2 & A1; \ + } while(0) + +/* +* Noekeon Encryption +*/ +void Noekeon_SIMD::encrypt_n(const byte in[], byte out[], u32bit blocks) const + { + SIMD_32 K0 = SIMD_32(EK[0]); + SIMD_32 K1 = SIMD_32(EK[1]); + SIMD_32 K2 = SIMD_32(EK[2]); + SIMD_32 K3 = SIMD_32(EK[3]); + + while(blocks >= 4) + { + SIMD_32 A0 = SIMD_32::load_be(in ); + SIMD_32 A1 = SIMD_32::load_be(in + 16); + SIMD_32 A2 = SIMD_32::load_be(in + 32); + SIMD_32 A3 = SIMD_32::load_be(in + 48); + + SIMD_32::transpose(A0, A1, A2, A3); + + for(u32bit i = 0; i != 16; ++i) + { + A0 ^= SIMD_32(RC[i]); + + NOK_SIMD_THETA(A0, A1, A2, A3, K0, K1, K2, K3); + + A1.rotate_left(1); + A2.rotate_left(5); + A3.rotate_left(2); + + NOK_SIMD_GAMMA(A0, A1, A2, A3); + + A1.rotate_right(1); + A2.rotate_right(5); + A3.rotate_right(2); + } + + A0 ^= SIMD_32(RC[16]); + NOK_SIMD_THETA(A0, A1, A2, A3, K0, K1, K2, K3); + + SIMD_32::transpose(A0, A1, A2, A3); + + A0.store_be(out); + A1.store_be(out + 16); + A2.store_be(out + 32); + A3.store_be(out + 48); + + in += 64; + out += 64; + blocks -= 4; + } + + Noekeon::encrypt_n(in, out, blocks); + } + +/* +* Noekeon Encryption +*/ +void Noekeon_SIMD::decrypt_n(const byte in[], byte out[], u32bit blocks) const + { + SIMD_32 K0 = SIMD_32(DK[0]); + SIMD_32 K1 = SIMD_32(DK[1]); + SIMD_32 K2 = SIMD_32(DK[2]); + SIMD_32 K3 = SIMD_32(DK[3]); + + while(blocks >= 4) + { + SIMD_32 A0 = SIMD_32::load_be(in ); + SIMD_32 A1 = SIMD_32::load_be(in + 16); + SIMD_32 A2 = SIMD_32::load_be(in + 32); + SIMD_32 A3 = SIMD_32::load_be(in + 48); + + SIMD_32::transpose(A0, A1, A2, A3); + + for(u32bit i = 0; i != 16; ++i) + { + NOK_SIMD_THETA(A0, A1, A2, A3, K0, K1, K2, K3); + + A0 ^= SIMD_32(RC[16-i]); + + A1.rotate_left(1); + A2.rotate_left(5); + A3.rotate_left(2); + + NOK_SIMD_GAMMA(A0, A1, A2, A3); + + A1.rotate_right(1); + A2.rotate_right(5); + A3.rotate_right(2); + } + + NOK_SIMD_THETA(A0, A1, A2, A3, K0, K1, K2, K3); + A0 ^= SIMD_32(RC[0]); + + SIMD_32::transpose(A0, A1, A2, A3); + + A0.store_be(out); + A1.store_be(out + 16); + A2.store_be(out + 32); + A3.store_be(out + 48); + + in += 64; + out += 64; + blocks -= 4; + } + + Noekeon::decrypt_n(in, out, blocks); + } + +} diff --git a/src/block/noekeon_simd/noekeon_simd.h b/src/block/noekeon_simd/noekeon_simd.h new file mode 100644 index 000000000..466c4b741 --- /dev/null +++ b/src/block/noekeon_simd/noekeon_simd.h @@ -0,0 +1,29 @@ +/* +* Noekeon in SIMD +* (C) 2010 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_NOEKEON_SIMD_H__ +#define BOTAN_NOEKEON_SIMD_H__ + +#include <botan/noekeon.h> + +namespace Botan { + +/* +* Noekeon +*/ +class BOTAN_DLL Noekeon_SIMD : public Noekeon + { + public: + void encrypt_n(const byte in[], byte out[], u32bit blocks) const; + void decrypt_n(const byte in[], byte out[], u32bit blocks) const; + + BlockCipher* clone() const { return new Noekeon_SIMD; } + }; + +} + +#endif diff --git a/src/build-data/makefile/nmake.in b/src/build-data/makefile/nmake.in index 79b80745c..2d89850fd 100644 --- a/src/build-data/makefile/nmake.in +++ b/src/build-data/makefile/nmake.in @@ -17,7 +17,7 @@ DESTDIR = %{prefix} LIBDIR = $(DESTDIR)\%{libdir} HEADERDIR = $(DESTDIR)\%{includedir}\botan -DOCDIR = $(DESTDIR)\%{docdir}\Botan-$(VERSION) +DOCDIR = $(DESTDIR)\%{docdir}\botan-$(VERSION) ### Aliases for Common Programs AR = %{ar_command} diff --git a/src/build-data/makefile/unix.in b/src/build-data/makefile/unix.in index a39a10907..c525aa6bf 100644 --- a/src/build-data/makefile/unix.in +++ b/src/build-data/makefile/unix.in @@ -16,7 +16,7 @@ DESTDIR = %{prefix} BINDIR = $(DESTDIR)/bin LIBDIR = $(DESTDIR)/%{libdir} HEADERDIR = $(DESTDIR)/%{includedir}/botan -DOCDIR = $(DESTDIR)/%{docdir}/Botan-$(VERSION) +DOCDIR = $(DESTDIR)/%{docdir}/botan-$(VERSION) PKGCONF_DIR = $(LIBDIR)/pkgconfig CONFIG_SCRIPT = %{botan_config} diff --git a/src/build-data/makefile/unix_shr.in b/src/build-data/makefile/unix_shr.in index db445163e..aaedeeaf8 100644 --- a/src/build-data/makefile/unix_shr.in +++ b/src/build-data/makefile/unix_shr.in @@ -19,7 +19,7 @@ DESTDIR = %{prefix} BINDIR = $(DESTDIR)/bin LIBDIR = $(DESTDIR)/%{libdir} HEADERDIR = $(DESTDIR)/%{includedir}/botan -DOCDIR = $(DESTDIR)/%{docdir}/Botan-$(VERSION) +DOCDIR = $(DESTDIR)/%{docdir}/botan-$(VERSION) PKGCONF_DIR = $(LIBDIR)/pkgconfig CONFIG_SCRIPT = %{botan_config} diff --git a/src/cert/cvc/cvc_self.cpp b/src/cert/cvc/cvc_self.cpp index 98e74a6b0..06b7eb1ab 100644 --- a/src/cert/cvc/cvc_self.cpp +++ b/src/cert/cvc/cvc_self.cpp @@ -80,7 +80,7 @@ EAC1_1_CVC create_self_signed_cert(Private_Key const& key, ASN1_Chr chr(opt.car.value()); AlgorithmIdentifier sig_algo; - std::string padding_and_hash(eac_cvc_emsa + "(" + opt.hash_alg + ")"); + std::string padding_and_hash("EMSA1_BSI(" + opt.hash_alg + ")"); sig_algo.oid = OIDS::lookup(priv_key->algo_name() + "/" + padding_and_hash); sig_algo = AlgorithmIdentifier(sig_algo.oid, AlgorithmIdentifier::USE_NULL_PARAM); @@ -109,7 +109,7 @@ EAC1_1_Req create_cvc_req(Private_Key const& key, throw Invalid_Argument("CVC_EAC::create_self_signed_cert(): unsupported key type"); } AlgorithmIdentifier sig_algo; - std::string padding_and_hash(eac_cvc_emsa + "(" + hash_alg + ")"); + std::string padding_and_hash("EMSA1_BSI(" + hash_alg + ")"); sig_algo.oid = OIDS::lookup(priv_key->algo_name() + "/" + padding_and_hash); sig_algo = AlgorithmIdentifier(sig_algo.oid, AlgorithmIdentifier::USE_NULL_PARAM); diff --git a/src/cert/cvc/eac_obj.h b/src/cert/cvc/eac_obj.h index d357adb7d..646bbeee6 100644 --- a/src/cert/cvc/eac_obj.h +++ b/src/cert/cvc/eac_obj.h @@ -23,8 +23,6 @@ namespace Botan { -const std::string eac_cvc_emsa("EMSA1_BSI"); - /* * TR03110 v1.1 EAC CV Certificate */ diff --git a/src/checksum/crc24/crc24.cpp b/src/checksum/crc24/crc24.cpp index e50b4d33e..5441020f5 100644 --- a/src/checksum/crc24/crc24.cpp +++ b/src/checksum/crc24/crc24.cpp @@ -6,7 +6,7 @@ */ #include <botan/crc24.h> -#include <botan/loadstor.h> +#include <botan/get_byte.h> namespace Botan { diff --git a/src/constructs/aont/package.cpp b/src/constructs/aont/package.cpp index 8d2d7257d..5d1e674ca 100644 --- a/src/constructs/aont/package.cpp +++ b/src/constructs/aont/package.cpp @@ -9,7 +9,7 @@ #include <botan/package.h> #include <botan/filters.h> #include <botan/ctr.h> -#include <botan/loadstor.h> +#include <botan/get_byte.h> #include <botan/internal/xor_buf.h> namespace Botan { diff --git a/src/constructs/cryptobox/cryptobox.cpp b/src/constructs/cryptobox/cryptobox.cpp index 20435fa59..371b52e66 100644 --- a/src/constructs/cryptobox/cryptobox.cpp +++ b/src/constructs/cryptobox/cryptobox.cpp @@ -13,7 +13,7 @@ #include <botan/hmac.h> #include <botan/pbkdf2.h> #include <botan/pem.h> -#include <botan/loadstor.h> +#include <botan/get_byte.h> #include <botan/mem_ops.h> namespace Botan { @@ -48,10 +48,10 @@ std::string encrypt(const byte input[], u32bit input_len, rng.randomize(pbkdf_salt.begin(), pbkdf_salt.size()); PKCS5_PBKDF2 pbkdf(new HMAC(new SHA_512)); - pbkdf.change_salt(pbkdf_salt.begin(), pbkdf_salt.size()); - pbkdf.set_iterations(PBKDF_ITERATIONS); - OctetString mk = pbkdf.derive_key(PBKDF_OUTPUT_LEN, passphrase); + OctetString mk = pbkdf.derive_key(PBKDF_OUTPUT_LEN, passphrase, + &pbkdf_salt[0], pbkdf_salt.size(), + PBKDF_ITERATIONS); SymmetricKey cipher_key(mk.begin(), CIPHER_KEY_LEN); SymmetricKey mac_key(mk.begin() + CIPHER_KEY_LEN, MAC_KEY_LEN); @@ -109,10 +109,10 @@ std::string decrypt(const byte input[], u32bit input_len, SecureVector<byte> pbkdf_salt(ciphertext + VERSION_CODE_LEN, PBKDF_SALT_LEN); PKCS5_PBKDF2 pbkdf(new HMAC(new SHA_512)); - pbkdf.change_salt(pbkdf_salt.begin(), pbkdf_salt.size()); - pbkdf.set_iterations(PBKDF_ITERATIONS); - OctetString mk = pbkdf.derive_key(PBKDF_OUTPUT_LEN, passphrase); + OctetString mk = pbkdf.derive_key(PBKDF_OUTPUT_LEN, passphrase, + &pbkdf_salt[0], pbkdf_salt.size(), + PBKDF_ITERATIONS); SymmetricKey cipher_key(mk.begin(), CIPHER_KEY_LEN); SymmetricKey mac_key(mk.begin() + CIPHER_KEY_LEN, MAC_KEY_LEN); diff --git a/src/constructs/fpe/fpe.cpp b/src/constructs/fpe/fpe.cpp index 86e56625d..a0b3274b5 100644 --- a/src/constructs/fpe/fpe.cpp +++ b/src/constructs/fpe/fpe.cpp @@ -12,7 +12,7 @@ #include <botan/numthry.h> #include <botan/hmac.h> #include <botan/sha2_32.h> -#include <botan/loadstor.h> +#include <botan/get_byte.h> #include <stdexcept> namespace Botan { diff --git a/src/constructs/passhash/info.txt b/src/constructs/passhash/info.txt new file mode 100644 index 000000000..f96809f29 --- /dev/null +++ b/src/constructs/passhash/info.txt @@ -0,0 +1,9 @@ +define PASSHASH9 + +<requires> +libstate +pbkdf2 +rng +base64 +</requires> + diff --git a/src/constructs/passhash/passhash9.cpp b/src/constructs/passhash/passhash9.cpp new file mode 100644 index 000000000..9e5ff3257 --- /dev/null +++ b/src/constructs/passhash/passhash9.cpp @@ -0,0 +1,127 @@ +/* +* Passhash9 Password Hashing +* (C) 2010 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include <botan/passhash9.h> +#include <botan/loadstor.h> +#include <botan/libstate.h> +#include <botan/pbkdf2.h> +#include <botan/base64.h> +#include <botan/pipe.h> + +namespace Botan { + +namespace { + +const std::string MAGIC_PREFIX = "$9$"; + +const u32bit WORKFACTOR_BYTES = 2; +const u32bit ALGID_BYTES = 1; +const u32bit SALT_BYTES = 12; // 96 bits of salt +const u32bit PBKDF_OUTPUT_LEN = 24; // 192 bits output + +const u32bit WORK_FACTOR_SCALE = 10000; + +MessageAuthenticationCode* get_pbkdf_prf(byte alg_id) + { + Algorithm_Factory& af = global_state().algorithm_factory(); + + if(alg_id == 0) + return af.make_mac("HMAC(SHA-1)"); + + return 0; + } + +std::pair<byte, MessageAuthenticationCode*> choose_pbkdf_prf() + { + byte alg_id = 0; + return std::make_pair(alg_id, get_pbkdf_prf(alg_id)); + } + +} + +std::string generate_passhash9(const std::string& pass, + RandomNumberGenerator& rng, + u16bit work_factor) + { + std::pair<byte, MessageAuthenticationCode*> prf = choose_pbkdf_prf(); + byte alg_id = prf.first; + + PKCS5_PBKDF2 kdf(prf.second); // takes ownership of pointer + + SecureVector<byte> salt(SALT_BYTES); + rng.randomize(&salt[0], salt.size()); + + u32bit kdf_iterations = WORK_FACTOR_SCALE * work_factor; + + SecureVector<byte> pbkdf2_output = + kdf.derive_key(PBKDF_OUTPUT_LEN, pass, + &salt[0], salt.size(), + kdf_iterations).bits_of(); + + Pipe pipe(new Base64_Encoder); + pipe.start_msg(); + pipe.write(alg_id); + pipe.write(get_byte(0, work_factor)); + pipe.write(get_byte(1, work_factor)); + pipe.write(salt); + pipe.write(pbkdf2_output); + pipe.end_msg(); + + return MAGIC_PREFIX + pipe.read_all_as_string(); + } + +bool check_passhash9(const std::string& pass, const std::string& hash) + { + const u32bit BINARY_LENGTH = + (ALGID_BYTES + WORKFACTOR_BYTES + PBKDF_OUTPUT_LEN + SALT_BYTES); + + const u32bit BASE64_LENGTH = + MAGIC_PREFIX.size() + (BINARY_LENGTH * 8) / 6; + + if(hash.size() != BASE64_LENGTH) + return false; + + for(size_t i = 0; i != MAGIC_PREFIX.size(); ++i) + if(hash[i] != MAGIC_PREFIX[i]) + return false; + + Pipe pipe(new Base64_Decoder); + pipe.start_msg(); + pipe.write(hash.c_str() + MAGIC_PREFIX.size()); + pipe.end_msg(); + + SecureVector<byte> bin = pipe.read_all(); + + if(bin.size() != BINARY_LENGTH) + return false; + + byte alg_id = bin[0]; + + u32bit kdf_iterations = + WORK_FACTOR_SCALE * load_be<u16bit>(bin + ALGID_BYTES, 0); + + if(kdf_iterations == 0) + return false; + + MessageAuthenticationCode* pbkdf_prf = get_pbkdf_prf(alg_id); + + if(pbkdf_prf == 0) + return false; // unknown algorithm, reject + + PKCS5_PBKDF2 kdf(pbkdf_prf); // takes ownership of pointer + + SecureVector<byte> cmp = kdf.derive_key( + PBKDF_OUTPUT_LEN, pass, + &bin[ALGID_BYTES + WORKFACTOR_BYTES], SALT_BYTES, + kdf_iterations).bits_of(); + + return same_mem(cmp.begin(), + bin.begin() + ALGID_BYTES + WORKFACTOR_BYTES + SALT_BYTES, + PBKDF_OUTPUT_LEN); + } + +} diff --git a/src/constructs/passhash/passhash9.h b/src/constructs/passhash/passhash9.h new file mode 100644 index 000000000..6020dce42 --- /dev/null +++ b/src/constructs/passhash/passhash9.h @@ -0,0 +1,35 @@ +/* +* Passhash9 Password Hashing +* (C) 2010 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_PASSHASH9_H__ +#define BOTAN_PASSHASH9_H__ + +#include <botan/rng.h> + +namespace Botan { + +/** +* Create a password hash using PBKDF2 +* @param password the password +* @param rng a random number generator +* @Param work_factor how much work to do to slow down guessing attacks +*/ +std::string BOTAN_DLL generate_passhash9(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_passhash9(const std::string& password, + const std::string& hash); + +} + +#endif diff --git a/src/engine/gnump/gmp_mem.cpp b/src/engine/gnump/gmp_mem.cpp index 59e0cc4c5..f3650e716 100644 --- a/src/engine/gnump/gmp_mem.cpp +++ b/src/engine/gnump/gmp_mem.cpp @@ -1,6 +1,6 @@ /* * GNU MP Memory Handlers -* (C) 1999-2007 Jack Lloyd +* (C) 1999-2010 Jack Lloyd * * Distributed under the terms of the Botan license */ @@ -17,6 +17,7 @@ namespace { * Allocator used by GNU MP */ Allocator* gmp_alloc = 0; +u32bit gmp_alloc_refcnt = 0; /* * Allocation Function for GNU MP @@ -48,23 +49,28 @@ void gmp_free(void* ptr, size_t n) } /* -* Set the GNU MP memory functions +* GMP_Engine Constructor */ -void GMP_Engine::set_memory_hooks() +GMP_Engine::GMP_Engine() { if(gmp_alloc == 0) { gmp_alloc = Allocator::get(true); mp_set_memory_functions(gmp_malloc, gmp_realloc, gmp_free); } + + ++gmp_alloc_refcnt; } -/* -* GMP_Engine Constructor -*/ -GMP_Engine::GMP_Engine() +GMP_Engine::~GMP_Engine() { - set_memory_hooks(); + --gmp_alloc_refcnt; + + if(gmp_alloc_refcnt == 0) + { + mp_set_memory_functions(NULL, NULL, NULL); + gmp_alloc = 0; + } } } diff --git a/src/engine/gnump/gnump_engine.h b/src/engine/gnump/gnump_engine.h index ec4a7e721..d0b070441 100644 --- a/src/engine/gnump/gnump_engine.h +++ b/src/engine/gnump/gnump_engine.h @@ -18,6 +18,9 @@ namespace Botan { class GMP_Engine : public Engine { public: + GMP_Engine(); + ~GMP_Engine(); + std::string provider_name() const { return "gmp"; } #if defined(BOTAN_HAS_IF_PUBLIC_KEY_FAMILY) @@ -46,10 +49,6 @@ class GMP_Engine : public Engine Modular_Exponentiator* mod_exp(const BigInt&, Power_Mod::Usage_Hints) const; - - GMP_Engine(); - private: - static void set_memory_hooks(); }; } diff --git a/src/engine/simd_engine/simd_engine.cpp b/src/engine/simd_engine/simd_engine.cpp index b8ebd6a80..e889ca161 100644 --- a/src/engine/simd_engine/simd_engine.cpp +++ b/src/engine/simd_engine/simd_engine.cpp @@ -13,6 +13,10 @@ #include <botan/serp_simd.h> #endif +#if defined(BOTAN_HAS_NOEKEON_SIMD) + #include <botan/noekeon_simd.h> +#endif + #if defined(BOTAN_HAS_XTEA_SIMD) #include <botan/xtea_simd.h> #endif @@ -36,6 +40,11 @@ SIMD_Engine::find_block_cipher(const SCAN_Name& request, return new IDEA_SSE2; #endif +#if defined(BOTAN_HAS_NOEKEON_SIMD) + if(request.algo_name() == "Noekeon" && SIMD_32::enabled()) + return new Noekeon_SIMD; +#endif + #if defined(BOTAN_HAS_SERPENT_SIMD) if(request.algo_name() == "Serpent" && SIMD_32::enabled()) return new Serpent_SIMD; diff --git a/src/filters/buf_filt.cpp b/src/filters/buf_filt.cpp index 97dd1b890..9b4f4af88 100644 --- a/src/filters/buf_filt.cpp +++ b/src/filters/buf_filt.cpp @@ -12,14 +12,6 @@ namespace Botan { -namespace { - -const size_t BUFFER_MULTIPLE = 2; - -//static_assert(BUFFER_MULTIPLE >= 2, "BUFFER_MULTIPLE must be >= 2"); - -} - /* * Buffered_Filter Constructor */ @@ -32,7 +24,7 @@ Buffered_Filter::Buffered_Filter(u32bit b, u32bit f) : if(final_minimum > main_block_mod) throw std::invalid_argument("final_minimum > main_block_mod"); - buffer.resize(BUFFER_MULTIPLE * main_block_mod); + buffer.resize(2 * main_block_mod); buffer_pos = 0; } @@ -54,23 +46,22 @@ void Buffered_Filter::write(const byte input[], u32bit input_size) input += to_copy; input_size -= to_copy; - if(input_size >= final_minimum) - { - u32bit to_proc_blocks = buffer_pos / main_block_mod; - u32bit to_proc_bytes = to_proc_blocks * main_block_mod; + u32bit total_to_consume = + round_down(std::min(buffer_pos, + buffer_pos + input_size - final_minimum), + main_block_mod); - buffered_block(&buffer[0], to_proc_bytes); + buffered_block(&buffer[0], total_to_consume); - buffer_pos -= to_proc_bytes; + buffer_pos -= total_to_consume; - copy_mem(&buffer[0], &buffer[to_proc_bytes], buffer_pos); - } + copy_mem(&buffer[0], &buffer[total_to_consume], buffer_pos); } if(input_size >= final_minimum) { - u32bit full_blocks = (input_size - final_minimum) / buffer.size(); - u32bit to_copy = full_blocks * buffer.size(); + u32bit full_blocks = (input_size - final_minimum) / main_block_mod; + u32bit to_copy = full_blocks * main_block_mod; if(to_copy) { diff --git a/src/filters/modes/cbc/cbc.h b/src/filters/modes/cbc/cbc.h index b303a841f..6d9092041 100644 --- a/src/filters/modes/cbc/cbc.h +++ b/src/filters/modes/cbc/cbc.h @@ -39,7 +39,7 @@ class BOTAN_DLL CBC_Encryption : public Keyed_Filter, const SymmetricKey& key, const InitializationVector& iv); - ~CBC_Encryption() { delete padder; } + ~CBC_Encryption() { delete cipher; delete padder; } private: void buffered_block(const byte input[], u32bit input_length); void buffered_final(const byte input[], u32bit input_length); @@ -76,7 +76,7 @@ class BOTAN_DLL CBC_Decryption : public Keyed_Filter, const SymmetricKey& key, const InitializationVector& iv); - ~CBC_Decryption() { delete padder; } + ~CBC_Decryption() { delete cipher; delete padder; } private: void buffered_block(const byte input[], u32bit input_length); void buffered_final(const byte input[], u32bit input_length); diff --git a/src/filters/modes/cfb/cfb.h b/src/filters/modes/cfb/cfb.h index 917125e46..249ae21db 100644 --- a/src/filters/modes/cfb/cfb.h +++ b/src/filters/modes/cfb/cfb.h @@ -34,6 +34,8 @@ class BOTAN_DLL CFB_Encryption : public Keyed_Filter const SymmetricKey& key, const InitializationVector& iv, u32bit feedback = 0); + + ~CFB_Encryption() { delete cipher; } private: void write(const byte[], u32bit); @@ -63,6 +65,8 @@ class BOTAN_DLL CFB_Decryption : public Keyed_Filter const SymmetricKey& key, const InitializationVector& iv, u32bit feedback = 0); + + ~CFB_Decryption() { delete cipher; } private: void write(const byte[], u32bit); diff --git a/src/filters/modes/cts/cts.h b/src/filters/modes/cts/cts.h index 4a7513fa0..c15fa9510 100644 --- a/src/filters/modes/cts/cts.h +++ b/src/filters/modes/cts/cts.h @@ -33,6 +33,8 @@ class BOTAN_DLL CTS_Encryption : public Keyed_Filter CTS_Encryption(BlockCipher* cipher, const SymmetricKey& key, const InitializationVector& iv); + + ~CTS_Encryption() { delete cipher; } private: void write(const byte[], u32bit); void end_msg(); @@ -63,6 +65,8 @@ class BOTAN_DLL CTS_Decryption : public Keyed_Filter CTS_Decryption(BlockCipher* cipher, const SymmetricKey& key, const InitializationVector& iv); + + ~CTS_Decryption() { delete cipher; } private: void write(const byte[], u32bit); void end_msg(); diff --git a/src/filters/modes/xts/xts.cpp b/src/filters/modes/xts/xts.cpp index cfea0b34b..aeef4e88d 100644 --- a/src/filters/modes/xts/xts.cpp +++ b/src/filters/modes/xts/xts.cpp @@ -176,6 +176,15 @@ void XTS_Encryption::buffered_final(const byte input[], u32bit length) } else { // steal ciphertext + + u32bit leftover_blocks = + ((length / cipher->BLOCK_SIZE) - 1) * cipher->BLOCK_SIZE; + + buffered_block(input, leftover_blocks); + + input += leftover_blocks; + length -= leftover_blocks; + SecureVector<byte> temp(input, length); xor_buf(temp, tweak, cipher->BLOCK_SIZE); @@ -201,9 +210,13 @@ void XTS_Encryption::buffered_final(const byte input[], u32bit length) * XTS_Decryption constructor */ XTS_Decryption::XTS_Decryption(BlockCipher* ciph) : - Buffered_Filter(BOTAN_PARALLEL_BLOCKS_XTS * ciph->BLOCK_SIZE, 1) + Buffered_Filter(BOTAN_PARALLEL_BLOCKS_XTS * ciph->BLOCK_SIZE, + ciph->BLOCK_SIZE + 1), + cipher(ciph) { - cipher = ciph; + if(cipher->BLOCK_SIZE != 8 && cipher->BLOCK_SIZE != 16) + throw std::invalid_argument("Bad cipher for XTS: " + cipher->name()); + cipher2 = ciph->clone(); tweak.resize(BOTAN_PARALLEL_BLOCKS_XTS * cipher->BLOCK_SIZE); } @@ -214,9 +227,13 @@ XTS_Decryption::XTS_Decryption(BlockCipher* ciph) : XTS_Decryption::XTS_Decryption(BlockCipher* ciph, const SymmetricKey& key, const InitializationVector& iv) : - Buffered_Filter(BOTAN_PARALLEL_BLOCKS_XTS * ciph->BLOCK_SIZE, 1) + Buffered_Filter(BOTAN_PARALLEL_BLOCKS_XTS * ciph->BLOCK_SIZE, + ciph->BLOCK_SIZE + 1), + cipher(ciph) { - cipher = ciph; + if(cipher->BLOCK_SIZE != 8 && cipher->BLOCK_SIZE != 16) + throw std::invalid_argument("Bad cipher for XTS: " + cipher->name()); + cipher2 = ciph->clone(); tweak.resize(BOTAN_PARALLEL_BLOCKS_XTS * cipher->BLOCK_SIZE); @@ -320,18 +337,26 @@ void XTS_Decryption::buffered_block(const byte input[], u32bit input_length) } } -void XTS_Decryption::buffered_final(const byte input[], u32bit input_length) +void XTS_Decryption::buffered_final(const byte input[], u32bit length) { - if(input_length <= cipher->BLOCK_SIZE) + if(length <= cipher->BLOCK_SIZE) throw Decoding_Error("XTS_Decryption: insufficient data to decrypt"); - if(input_length % cipher->BLOCK_SIZE == 0) + if(length % cipher->BLOCK_SIZE == 0) { - buffered_block(input, input_length); + buffered_block(input, length); } else { - SecureVector<byte> temp(input, input_length); + u32bit leftover_blocks = + ((length / cipher->BLOCK_SIZE) - 1) * cipher->BLOCK_SIZE; + + buffered_block(input, leftover_blocks); + + input += leftover_blocks; + length -= leftover_blocks; + + SecureVector<byte> temp(input, length); SecureVector<byte> tweak_copy(&tweak[0], cipher->BLOCK_SIZE); poly_double(tweak_copy, cipher->BLOCK_SIZE); @@ -340,14 +365,14 @@ void XTS_Decryption::buffered_final(const byte input[], u32bit input_length) cipher->decrypt(temp); xor_buf(temp, tweak_copy, cipher->BLOCK_SIZE); - for(u32bit i = 0; i != input_length - cipher->BLOCK_SIZE; ++i) + for(u32bit i = 0; i != length - cipher->BLOCK_SIZE; ++i) std::swap(temp[i], temp[i + cipher->BLOCK_SIZE]); xor_buf(temp, tweak, cipher->BLOCK_SIZE); cipher->decrypt(temp); xor_buf(temp, tweak, cipher->BLOCK_SIZE); - send(temp, input_length); + send(temp, length); } buffer_reset(); diff --git a/src/filters/modes/xts/xts.h b/src/filters/modes/xts/xts.h index 724085d9d..a01b1da1d 100644 --- a/src/filters/modes/xts/xts.h +++ b/src/filters/modes/xts/xts.h @@ -68,6 +68,8 @@ class BOTAN_DLL XTS_Decryption : public Keyed_Filter, XTS_Decryption(BlockCipher* ciph, const SymmetricKey& key, const InitializationVector& iv); + + ~XTS_Decryption() { delete cipher; delete cipher2; } private: void write(const byte[], u32bit); void end_msg(); diff --git a/src/hash/md4/md4.h b/src/hash/md4/md4.h index 0b76a70e4..0bff5a4ce 100644 --- a/src/hash/md4/md4.h +++ b/src/hash/md4/md4.h @@ -27,7 +27,7 @@ class BOTAN_DLL MD4 : public MDx_HashFunction void hash_old(const byte[]); void copy_out(byte[]); - SecureBuffer<u32bit, 48> M; + SecureBuffer<u32bit, 16> M; SecureBuffer<u32bit, 4> digest; }; diff --git a/src/hash/md4_ia32/md4_ia32.cpp b/src/hash/md4_ia32/md4_ia32.cpp index 12fe71da4..8a60d8f0e 100644 --- a/src/hash/md4_ia32/md4_ia32.cpp +++ b/src/hash/md4_ia32/md4_ia32.cpp @@ -6,7 +6,6 @@ */ #include <botan/md4_ia32.h> -#include <botan/loadstor.h> namespace Botan { diff --git a/src/hash/md5_ia32/md5_ia32.cpp b/src/hash/md5_ia32/md5_ia32.cpp index 443569b3b..affd0b8f7 100644 --- a/src/hash/md5_ia32/md5_ia32.cpp +++ b/src/hash/md5_ia32/md5_ia32.cpp @@ -6,7 +6,6 @@ */ #include <botan/md5_ia32.h> -#include <botan/loadstor.h> namespace Botan { diff --git a/src/hash/sha1/sha160.cpp b/src/hash/sha1/sha160.cpp index ff44593f6..1ad08d483 100644 --- a/src/hash/sha1/sha160.cpp +++ b/src/hash/sha1/sha160.cpp @@ -134,8 +134,8 @@ void SHA_160::compress_n(const byte input[], u32bit blocks) */ void SHA_160::copy_out(byte output[]) { - for(u32bit j = 0; j != OUTPUT_LENGTH; j += 4) - store_be(digest[j/4], output + j); + for(u32bit i = 0; i != OUTPUT_LENGTH; i += 4) + store_be(digest[i/4], output + i); } /* diff --git a/src/hash/sha1_ia32/sha1_ia32.cpp b/src/hash/sha1_ia32/sha1_ia32.cpp index 0fa0b6bf2..6eecdab56 100644 --- a/src/hash/sha1_ia32/sha1_ia32.cpp +++ b/src/hash/sha1_ia32/sha1_ia32.cpp @@ -6,7 +6,6 @@ */ #include <botan/sha1_ia32.h> -#include <botan/loadstor.h> namespace Botan { diff --git a/src/kdf/kdf2/kdf2.cpp b/src/kdf/kdf2/kdf2.cpp index 167f64436..7cc1d7416 100644 --- a/src/kdf/kdf2/kdf2.cpp +++ b/src/kdf/kdf2/kdf2.cpp @@ -6,7 +6,7 @@ */ #include <botan/kdf2.h> -#include <botan/loadstor.h> +#include <botan/get_byte.h> namespace Botan { diff --git a/src/kdf/mgf1/mgf1.cpp b/src/kdf/mgf1/mgf1.cpp index a8c7e5fa3..340e87a7c 100644 --- a/src/kdf/mgf1/mgf1.cpp +++ b/src/kdf/mgf1/mgf1.cpp @@ -6,7 +6,7 @@ */ #include <botan/mgf1.h> -#include <botan/loadstor.h> +#include <botan/get_byte.h> #include <botan/exceptn.h> #include <botan/internal/xor_buf.h> #include <algorithm> diff --git a/src/libstate/policy.cpp b/src/libstate/policy.cpp index 4f5884630..c11fc28ce 100644 --- a/src/libstate/policy.cpp +++ b/src/libstate/policy.cpp @@ -48,6 +48,7 @@ void set_default_oids(Library_State& config) add_oid(config, "2.16.840.1.101.3.4.1.22", "AES-192/CBC"); add_oid(config, "2.16.840.1.101.3.4.1.42", "AES-256/CBC"); add_oid(config, "1.2.410.200004.1.4", "SEED/CBC"); // RFC 4010 + add_oid(config, "1.3.6.1.4.1.25258.3.1", "Serpent/CBC"); /* Hash Functions */ add_oid(config, "1.2.840.113549.2.5", "MD5"); diff --git a/src/libstate/scan_name.cpp b/src/libstate/scan_name.cpp index 861934200..eccb15565 100644 --- a/src/libstate/scan_name.cpp +++ b/src/libstate/scan_name.cpp @@ -63,7 +63,7 @@ deref_aliases(const std::pair<u32bit, std::string>& in) } -SCAN_Name::SCAN_Name(const std::string& algo_spec) +SCAN_Name::SCAN_Name(std::string algo_spec) { orig_algo_spec = algo_spec; @@ -73,6 +73,8 @@ SCAN_Name::SCAN_Name(const std::string& algo_spec) std::string decoding_error = "Bad SCAN name '" + algo_spec + "': "; + algo_spec = global_state().deref_alias(algo_spec); + for(u32bit i = 0; i != algo_spec.size(); ++i) { char c = algo_spec[i]; diff --git a/src/libstate/scan_name.h b/src/libstate/scan_name.h index 7992d7498..4350dca86 100644 --- a/src/libstate/scan_name.h +++ b/src/libstate/scan_name.h @@ -23,9 +23,9 @@ class BOTAN_DLL SCAN_Name { public: /** - @param algo_spec A SCAN name + @param algo_spec A SCAN-format name */ - SCAN_Name(const std::string& algo_spec); + SCAN_Name(std::string algo_spec); /** @return the original input string diff --git a/src/math/bigint/bigint.cpp b/src/math/bigint/bigint.cpp index 70bb11a83..09ac2a75d 100644 --- a/src/math/bigint/bigint.cpp +++ b/src/math/bigint/bigint.cpp @@ -7,7 +7,7 @@ #include <botan/bigint.h> #include <botan/internal/mp_core.h> -#include <botan/loadstor.h> +#include <botan/get_byte.h> #include <botan/parsing.h> #include <botan/internal/rounding.h> diff --git a/src/pbe/pbes1/pbes1.cpp b/src/pbe/pbes1/pbes1.cpp index 1d851d1a5..36cfaa6b4 100644 --- a/src/pbe/pbes1/pbes1.cpp +++ b/src/pbe/pbes1/pbes1.cpp @@ -80,9 +80,9 @@ void PBE_PKCS5v15::set_key(const std::string& passphrase) { PKCS5_PBKDF1 pbkdf(hash_function->clone()); - pbkdf.set_iterations(iterations); - pbkdf.change_salt(salt, salt.size()); - SymmetricKey key_and_iv = pbkdf.derive_key(16, passphrase); + SymmetricKey key_and_iv = pbkdf.derive_key(16, passphrase, + &salt[0], salt.size(), + iterations); key.set(key_and_iv.begin(), 8); iv.set(key_and_iv.begin() + 8, 8); diff --git a/src/pbe/pbes2/pbes2.cpp b/src/pbe/pbes2/pbes2.cpp index bd24c449b..63772263f 100644 --- a/src/pbe/pbes2/pbes2.cpp +++ b/src/pbe/pbes2/pbes2.cpp @@ -87,9 +87,9 @@ void PBE_PKCS5v20::set_key(const std::string& passphrase) { PKCS5_PBKDF2 pbkdf(new HMAC(hash_function->clone())); - pbkdf.set_iterations(iterations); - pbkdf.change_salt(salt, salt.size()); - key = pbkdf.derive_key(key_length, passphrase).bits_of(); + key = pbkdf.derive_key(key_length, passphrase, + &salt[0], salt.size(), + iterations).bits_of(); } /** diff --git a/src/rng/hmac_rng/hmac_rng.cpp b/src/rng/hmac_rng/hmac_rng.cpp index 995ec9259..84a7b1c13 100644 --- a/src/rng/hmac_rng/hmac_rng.cpp +++ b/src/rng/hmac_rng/hmac_rng.cpp @@ -6,7 +6,7 @@ */ #include <botan/hmac_rng.h> -#include <botan/loadstor.h> +#include <botan/get_byte.h> #include <botan/internal/xor_buf.h> #include <botan/internal/stl_util.h> #include <algorithm> diff --git a/src/rng/randpool/randpool.cpp b/src/rng/randpool/randpool.cpp index f6479b2dd..9a4d77e55 100644 --- a/src/rng/randpool/randpool.cpp +++ b/src/rng/randpool/randpool.cpp @@ -6,7 +6,7 @@ */ #include <botan/randpool.h> -#include <botan/loadstor.h> +#include <botan/get_byte.h> #include <botan/internal/xor_buf.h> #include <botan/internal/stl_util.h> #include <algorithm> diff --git a/src/s2k/info.txt b/src/s2k/info.txt index 1d5226524..861b6f760 100644 --- a/src/s2k/info.txt +++ b/src/s2k/info.txt @@ -1,4 +1,3 @@ <requires> -rng sym_algo </requires> diff --git a/src/s2k/pbkdf1/pbkdf1.cpp b/src/s2k/pbkdf1/pbkdf1.cpp index fcc5b9a97..a8270e26f 100644 --- a/src/s2k/pbkdf1/pbkdf1.cpp +++ b/src/s2k/pbkdf1/pbkdf1.cpp @@ -6,16 +6,17 @@ */ #include <botan/pbkdf1.h> +#include <botan/exceptn.h> namespace Botan { /* * Return a PKCS#5 PBKDF1 derived key */ -OctetString PKCS5_PBKDF1::derive(u32bit key_len, - const std::string& passphrase, - const byte salt[], u32bit salt_size, - u32bit iterations) const +OctetString PKCS5_PBKDF1::derive_key(u32bit key_len, + const std::string& passphrase, + const byte salt[], u32bit salt_size, + u32bit iterations) const { if(iterations == 0) throw Invalid_Argument("PKCS5_PBKDF1: Invalid iteration count"); diff --git a/src/s2k/pbkdf1/pbkdf1.h b/src/s2k/pbkdf1/pbkdf1.h index 4e5cafdb0..053a2dbe1 100644 --- a/src/s2k/pbkdf1/pbkdf1.h +++ b/src/s2k/pbkdf1/pbkdf1.h @@ -22,6 +22,11 @@ class BOTAN_DLL PKCS5_PBKDF1 : public S2K std::string name() const; S2K* clone() const; + OctetString derive_key(u32bit output_len, + const std::string& passphrase, + const byte salt[], u32bit salt_len, + u32bit iterations) const; + /** * Create a PKCS #5 instance using the specified hash function. * @param hash a pointer to a hash function object to use @@ -33,9 +38,6 @@ class BOTAN_DLL PKCS5_PBKDF1 : public S2K ~PKCS5_PBKDF1() { delete hash; } private: - OctetString derive(u32bit, const std::string&, - const byte[], u32bit, u32bit) const; - HashFunction* hash; }; diff --git a/src/s2k/pbkdf2/pbkdf2.cpp b/src/s2k/pbkdf2/pbkdf2.cpp index 6f790c06b..f1fc6e29f 100644 --- a/src/s2k/pbkdf2/pbkdf2.cpp +++ b/src/s2k/pbkdf2/pbkdf2.cpp @@ -6,7 +6,7 @@ */ #include <botan/pbkdf2.h> -#include <botan/loadstor.h> +#include <botan/get_byte.h> #include <botan/internal/xor_buf.h> namespace Botan { @@ -14,10 +14,10 @@ namespace Botan { /* * Return a PKCS#5 PBKDF2 derived key */ -OctetString PKCS5_PBKDF2::derive(u32bit key_len, - const std::string& passphrase, - const byte salt[], u32bit salt_size, - u32bit iterations) const +OctetString PKCS5_PBKDF2::derive_key(u32bit key_len, + const std::string& passphrase, + const byte salt[], u32bit salt_size, + u32bit iterations) const { if(iterations == 0) throw Invalid_Argument("PKCS#5 PBKDF2: Invalid iteration count"); diff --git a/src/s2k/pbkdf2/pbkdf2.h b/src/s2k/pbkdf2/pbkdf2.h index 7510338bb..b6d231916 100644 --- a/src/s2k/pbkdf2/pbkdf2.h +++ b/src/s2k/pbkdf2/pbkdf2.h @@ -22,6 +22,11 @@ class BOTAN_DLL PKCS5_PBKDF2 : public S2K std::string name() const; S2K* clone() const; + OctetString derive_key(u32bit output_len, + const std::string& passphrase, + const byte salt[], u32bit salt_len, + u32bit iterations) const; + /** * Create a PKCS #5 instance using the specified message auth code * @param mac the MAC to use @@ -29,9 +34,6 @@ class BOTAN_DLL PKCS5_PBKDF2 : public S2K PKCS5_PBKDF2(MessageAuthenticationCode* mac); ~PKCS5_PBKDF2(); private: - OctetString derive(u32bit, const std::string&, - const byte[], u32bit, u32bit) const; - MessageAuthenticationCode* mac; }; diff --git a/src/s2k/pgps2k/pgp_s2k.cpp b/src/s2k/pgps2k/pgp_s2k.cpp index 86394d84d..49ff6892c 100644 --- a/src/s2k/pgps2k/pgp_s2k.cpp +++ b/src/s2k/pgps2k/pgp_s2k.cpp @@ -14,9 +14,10 @@ namespace Botan { /* * Derive a key using the OpenPGP S2K algorithm */ -OctetString OpenPGP_S2K::derive(u32bit key_len, const std::string& passphrase, - const byte salt_buf[], u32bit salt_size, - u32bit iterations) const +OctetString OpenPGP_S2K::derive_key(u32bit key_len, + const std::string& passphrase, + const byte salt_buf[], u32bit salt_size, + u32bit iterations) const { SecureVector<byte> key(key_len), hash_buf; diff --git a/src/s2k/pgps2k/pgp_s2k.h b/src/s2k/pgps2k/pgp_s2k.h index 00e95f7fa..7f25623f3 100644 --- a/src/s2k/pgps2k/pgp_s2k.h +++ b/src/s2k/pgps2k/pgp_s2k.h @@ -22,12 +22,14 @@ class BOTAN_DLL OpenPGP_S2K : public S2K std::string name() const; S2K* clone() const; + OctetString derive_key(u32bit output_len, + const std::string& passphrase, + const byte salt[], u32bit salt_len, + u32bit iterations) const; + OpenPGP_S2K(HashFunction* hash_in) : hash(hash_in) {} ~OpenPGP_S2K() { delete hash; } private: - OctetString derive(u32bit, const std::string&, - const byte[], u32bit, u32bit) const; - HashFunction* hash; }; diff --git a/src/s2k/s2k.cpp b/src/s2k/s2k.cpp deleted file mode 100644 index 42064529d..000000000 --- a/src/s2k/s2k.cpp +++ /dev/null @@ -1,55 +0,0 @@ -/* -* S2K -* (C) 1999-2007 Jack Lloyd -* -* Distributed under the terms of the Botan license -*/ - -#include <botan/s2k.h> - -namespace Botan { - -/* -* Derive a key from a passphrase -*/ -OctetString S2K::derive_key(u32bit key_len, - const std::string& passphrase) const - { - return derive(key_len, passphrase, salt, salt.size(), iterations()); - } - -/* -* Set the number of iterations -*/ -void S2K::set_iterations(u32bit i) - { - iter = i; - } - -/* -* Change the salt -*/ -void S2K::change_salt(const byte new_salt[], u32bit length) - { - salt.set(new_salt, length); - } - -/* -* Change the salt -*/ -void S2K::change_salt(const MemoryRegion<byte>& new_salt) - { - change_salt(new_salt.begin(), new_salt.size()); - } - -/* -* Create a new random salt -*/ -void S2K::new_random_salt(RandomNumberGenerator& rng, - u32bit length) - { - salt.resize(length); - rng.randomize(salt, length); - } - -} diff --git a/src/s2k/s2k.h b/src/s2k/s2k.h index 7af92519b..9ab71344e 100644 --- a/src/s2k/s2k.h +++ b/src/s2k/s2k.h @@ -9,7 +9,6 @@ #define BOTAN_S2K_H__ #include <botan/symkey.h> -#include <botan/rng.h> namespace Botan { @@ -39,62 +38,22 @@ class BOTAN_DLL S2K /** * Derive a key from a passphrase with this S2K object. It will use * the salt value and number of iterations configured in this object. - * @param key_len the desired length of the key to produce + * @param output_len the desired length of the key to produce * @param passphrase the password to derive the key from + * @param salt the randomly chosen salt + * @param salt_len length of salt in bytes + * @param iterations the number of iterations to use (use 10K or more) */ - OctetString derive_key(u32bit key_len, - const std::string& passphrase) const; + virtual OctetString derive_key(u32bit output_len, + const std::string& passphrase, + const byte salt[], u32bit salt_len, + u32bit iterations) const = 0; - /** - * Set the number of iterations for the one-way function during - * key generation. - * @param n the desired number of iterations - */ - void set_iterations(u32bit n); - - /** - * Set a new salt value. - * @param new_salt a byte array defining the new salt value - * @param len the length of the above byte array - */ - void change_salt(const byte new_salt[], u32bit len); - - /** - * Set a new salt value. - * @param new_salt the new salt value - */ - void change_salt(const MemoryRegion<byte>& new_salt); - - /** - * Create a new random salt value using the rng - * @param rng the random number generator to use - * @param len the desired length of the new salt value - */ - void new_random_salt(RandomNumberGenerator& rng, u32bit len); - - /** - * Get the number of iterations for the key derivation currently - * configured in this S2K object. - * @return the current number of iterations - */ - u32bit iterations() const { return iter; } - - /** - * Get the currently configured salt value of this S2K object. - * @return the current salt value - */ - SecureVector<byte> current_salt() const { return salt; } - - S2K() { iter = 0; } + S2K() {} virtual ~S2K() {} private: S2K(const S2K&) {} S2K& operator=(const S2K&) { return (*this); } - - virtual OctetString derive(u32bit, const std::string&, - const byte[], u32bit, u32bit) const = 0; - SecureVector<byte> salt; - u32bit iter; }; } diff --git a/src/utils/cpuid.cpp b/src/utils/cpuid.cpp index 924d29b1b..8d801b75f 100644 --- a/src/utils/cpuid.cpp +++ b/src/utils/cpuid.cpp @@ -7,7 +7,7 @@ #include <botan/cpuid.h> #include <botan/types.h> -#include <botan/loadstor.h> +#include <botan/get_byte.h> #include <botan/mem_ops.h> #if defined(BOTAN_TARGET_OS_IS_DARWIN) diff --git a/src/utils/debug.cpp b/src/utils/debug.cpp deleted file mode 100644 index 894418650..000000000 --- a/src/utils/debug.cpp +++ /dev/null @@ -1,33 +0,0 @@ -/** -* Internal-use debugging functions for Botan -* (C) 2009 Jack Lloyd -* -* Distributed under the terms of the Botan license -*/ - -#include <botan/internal/debug.h> -#include <cstdio> - -namespace Botan { - -namespace Debug { - -void print_vec(const std::string& name, - const byte array[], - size_t array_len) - { - std::printf("%s = ", name.c_str()); - for(size_t i = 0; i != array_len; ++i) - std::printf("%02X", array[i]); - std::printf("\n"); - } - -void print_vec(const std::string& name, - const MemoryRegion<byte>& vec) - { - print_vec(name, &vec[0], vec.size()); - } - -} - -} diff --git a/src/utils/debug.h b/src/utils/debug.h index ee93d5ea0..c7f19c1b1 100644 --- a/src/utils/debug.h +++ b/src/utils/debug.h @@ -9,18 +9,29 @@ #define BOTAN_DEBUG_H__ #include <botan/secmem.h> +#include <iostream> namespace Botan { namespace Debug { +template<typename T> void print_vec(const std::string& name, - const byte array[], - size_t array_len); + const T array[], size_t array_len) + { + std::cout << name << " = "; -void print_vec(const std::string& name, - const MemoryRegion<byte>& vec); + for(size_t i = 0; i != array_len; ++i) + std::cout << std::hex << array[i]; + std::cout << std::endl; + } +template<typename T> +void print_vec(const std::string& name, + const MemoryRegion<T>& vec) + { + print_vec(name, &vec[0], vec.size()); + } } diff --git a/src/utils/get_byte.h b/src/utils/get_byte.h new file mode 100644 index 000000000..fce87af83 --- /dev/null +++ b/src/utils/get_byte.h @@ -0,0 +1,27 @@ +/* +* Read out bytes +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_GET_BYTE_H__ +#define BOTAN_GET_BYTE_H__ + +#include <botan/types.h> + +namespace Botan { + +/* +* Byte Extraction Function +*/ +template<typename T> inline byte get_byte(u32bit byte_num, T input) + { + return static_cast<byte>( + input >> ((sizeof(T)-1-(byte_num&(sizeof(T)-1))) << 3) + ); + } + +} + +#endif diff --git a/src/utils/info.txt b/src/utils/info.txt index 9d8f7976e..2fb3e79a5 100644 --- a/src/utils/info.txt +++ b/src/utils/info.txt @@ -5,7 +5,6 @@ load_on always <source> charset.cpp cpuid.cpp -debug.cpp mlock.cpp parsing.cpp time.cpp @@ -36,6 +35,7 @@ time.h types.h ui.h version.h +get_byte.h </header:public> <libs> diff --git a/src/utils/loadstor.h b/src/utils/loadstor.h index bd2acc87d..ffd27540d 100644 --- a/src/utils/loadstor.h +++ b/src/utils/loadstor.h @@ -11,6 +11,7 @@ #include <botan/types.h> #include <botan/bswap.h> +#include <botan/get_byte.h> #include <cstring> #if BOTAN_TARGET_UNALIGNED_MEMORY_ACCESS_OK @@ -38,16 +39,6 @@ namespace Botan { /* -* Byte Extraction Function -*/ -template<typename T> inline byte get_byte(u32bit byte_num, T input) - { - return static_cast<byte>( - input >> ((sizeof(T)-1-(byte_num&(sizeof(T)-1))) << 3) - ); - } - -/* * Byte to Word Conversions */ inline u16bit make_u16bit(byte i0, byte i1) diff --git a/src/utils/parsing.cpp b/src/utils/parsing.cpp index 4b99ac1ec..e8259ac52 100644 --- a/src/utils/parsing.cpp +++ b/src/utils/parsing.cpp @@ -8,7 +8,7 @@ #include <botan/parsing.h> #include <botan/exceptn.h> #include <botan/charset.h> -#include <botan/loadstor.h> +#include <botan/get_byte.h> namespace Botan { diff --git a/src/utils/simd_32/simd_32.h b/src/utils/simd_32/simd_32.h index 38ea078d0..4bd983f5e 100644 --- a/src/utils/simd_32/simd_32.h +++ b/src/utils/simd_32/simd_32.h @@ -27,4 +27,20 @@ #endif +namespace Botan { + +inline SIMD_32 rotate_left(SIMD_32 x, u32bit rot) + { + x.rotate_left(rot); + return x; + } + +inline SIMD_32 rotate_right(SIMD_32 x, u32bit rot) + { + x.rotate_right(rot); + return x; + } + +} + #endif diff --git a/src/utils/simd_32/simd_altivec.h b/src/utils/simd_32/simd_altivec.h index 9cc5c1068..859a48a5f 100644 --- a/src/utils/simd_32/simd_altivec.h +++ b/src/utils/simd_32/simd_altivec.h @@ -145,6 +145,11 @@ class SIMD_Altivec reg = vec_or(reg, other.reg); } + SIMD_Altivec operator&(const SIMD_Altivec& other) + { + return vec_and(reg, other.reg); + } + void operator&=(const SIMD_Altivec& other) { reg = vec_and(reg, other.reg); diff --git a/src/utils/simd_32/simd_scalar.h b/src/utils/simd_32/simd_scalar.h index 148b76c35..5cf1a11c3 100644 --- a/src/utils/simd_32/simd_scalar.h +++ b/src/utils/simd_32/simd_scalar.h @@ -142,6 +142,14 @@ class SIMD_Scalar R3 |= other.R3; } + SIMD_Scalar operator&(const SIMD_Scalar& other) + { + return SIMD_Scalar(R0 & other.R0, + R1 & other.R1, + R2 & other.R2, + R3 & other.R3); + } + void operator&=(const SIMD_Scalar& other) { R0 &= other.R0; diff --git a/src/utils/simd_32/simd_sse.h b/src/utils/simd_32/simd_sse.h index 31bbce2c7..0189c2e4d 100644 --- a/src/utils/simd_32/simd_sse.h +++ b/src/utils/simd_32/simd_sse.h @@ -101,6 +101,11 @@ class SIMD_SSE2 reg = _mm_or_si128(reg, other.reg); } + SIMD_SSE2 operator&(const SIMD_SSE2& other) + { + return _mm_and_si128(reg, other.reg); + } + void operator&=(const SIMD_SSE2& other) { reg = _mm_and_si128(reg, other.reg); diff --git a/src/wrap/sqlite/codec.cpp b/src/wrap/sqlite/codec.cpp new file mode 100644 index 000000000..5dfcea82e --- /dev/null +++ b/src/wrap/sqlite/codec.cpp @@ -0,0 +1,123 @@ +/* + * Codec class for SQLite3 encryption codec. + * (C) 2010 Olivier de Gaalon + * + * Distributed under the terms of the Botan license + */ + +#include "codec.h" +#include <botan/init.h> + +Codec::Codec(void *db) +{ + InitializeCodec(db); +} + +Codec::Codec(const Codec& other, void *db) +{ + //Only used to copy main db key for an attached db + InitializeCodec(db); + m_hasReadKey = other.m_hasReadKey; + m_hasWriteKey = other.m_hasWriteKey; + m_readKey = other.m_readKey; + m_ivReadKey = other.m_ivReadKey; + m_writeKey = other.m_writeKey; + m_ivWriteKey = other.m_ivWriteKey; +} + +void +Codec::InitializeCodec(void *db) +{ + bool botanInitialized = false; + Library_State* state = swap_global_state(0); + if(state) + { + botanInitialized = true; + swap_global_state(state); // should return NULL FIXME: what if not? + } + + if (!botanInitialized) + LibraryInitializer::initialize(); + + m_hasReadKey = false; + m_hasWriteKey = false; + m_db = db; + + m_encipherFilter = get_cipher(BLOCK_CIPHER_STR, ENCRYPTION); + m_decipherFilter = get_cipher(BLOCK_CIPHER_STR, DECRYPTION); + m_cmac = new MAC_Filter(MAC_STR); + m_encipherPipe.append(m_encipherFilter); + m_decipherPipe.append(m_decipherFilter); + m_macPipe.append(m_cmac); +} + +void +Codec::GenerateWriteKey(const char* userPassword, int passwordLength) +{ + S2K* s2k = get_s2k(S2K_STR); + s2k->set_iterations(S2K_ITERATIONS); + s2k->change_salt((const byte*)SALT_STR.c_str(), SALT_SIZE); + + SymmetricKey masterKey = + s2k->derive_key(KEY_SIZE + IV_DERIVATION_KEY_SIZE, std::string(userPassword, passwordLength)); + + m_writeKey = SymmetricKey(masterKey.bits_of(), KEY_SIZE); + m_ivWriteKey = SymmetricKey(masterKey.bits_of() + KEY_SIZE, IV_DERIVATION_KEY_SIZE); + + m_hasWriteKey = true; +} + +void +Codec::DropWriteKey() +{ + m_hasWriteKey = false; +} + +void +Codec::SetReadIsWrite() +{ + m_readKey = m_writeKey; + m_ivReadKey = m_ivWriteKey; + m_hasReadKey = m_hasWriteKey; +} + +void +Codec::SetWriteIsRead() +{ + m_writeKey = m_readKey; + m_ivWriteKey = m_ivReadKey; + m_hasWriteKey = m_hasReadKey; +} + +unsigned char * +Codec::Encrypt(int page, unsigned char* data, bool useWriteKey) +{ + memcpy(m_page, data, m_pageSize); + + m_encipherFilter->set_key(useWriteKey ? m_writeKey : m_readKey); + m_encipherFilter->set_iv(GetIVForPage(page, useWriteKey)); + m_encipherPipe.process_msg(m_page, m_pageSize); + m_encipherPipe.read(m_page, m_encipherPipe.remaining(Pipe::LAST_MESSAGE), Pipe::LAST_MESSAGE); + + return m_page; //return location of newly ciphered data +} + +void +Codec::Decrypt(int page, unsigned char* data) +{ + m_decipherFilter->set_key(m_readKey); + m_decipherFilter->set_iv(GetIVForPage(page, false)); + m_decipherPipe.process_msg(data, m_pageSize); + m_decipherPipe.read(data, m_decipherPipe.remaining(Pipe::LAST_MESSAGE), Pipe::LAST_MESSAGE); +} + +InitializationVector +Codec::GetIVForPage(u32bit page, bool useWriteKey) +{ + static unsigned char* intiv[4]; + store_le(page, (byte*)intiv); + m_cmac->set_key(useWriteKey ? m_ivWriteKey : m_ivReadKey); + m_macPipe.process_msg((byte*)intiv, 4); + return m_macPipe.read_all(Pipe::LAST_MESSAGE); +} + diff --git a/src/wrap/sqlite/codec.h b/src/wrap/sqlite/codec.h new file mode 100644 index 000000000..8b753be62 --- /dev/null +++ b/src/wrap/sqlite/codec.h @@ -0,0 +1,127 @@ +/* + * Codec class for SQLite3 encryption codec. + * (C) 2010 Olivier de Gaalon + * + * Distributed under the terms of the Botan license + */ + +#ifndef _CODEC_H_ +#define _CODEC_H_ + +#include <string> +#include <botan/botan.h> +#include <botan/loadstor.h> + +#ifdef __cplusplus +extern "C" { +#endif + +#if defined(__BORLANDC__) +#define __STDC__ 1 +#endif + +#include "./sqliteInt.h" + +#if defined(__BORLANDC__) +#undef __STDC__ +#endif + +/* ATTENTION: Macro similar to that in pager.c + * Needed because pager is forward declared when needed most + * TODO: Check in case of new version of SQLite + * ... but it's VERY unlikely to change (it'd break all past DBs) + */ +#include "./os.h" +#define CODEC_PAGER_MJ_PGNO(x) ((PENDING_BYTE/(x))+1) + +#ifdef __cplusplus +} /* End of the 'extern "C"' block */ +#endif + +using namespace std; +using namespace Botan; + +/*These constants can be used to tweak the codec behavior as follows + *Note that once you've encrypted a database with these settings, + *recompiling with any different settings will give you a library that + *cannot read that database, even given the same passphrase.*/ + +//BLOCK_CIPHER_STR: Cipher and mode used for encrypting the database +//make sure to add "/NoPadding" for modes that use padding schemes +const string BLOCK_CIPHER_STR = "Twofish/XTS"; + +//S2K_STR: Key derivation function used to derive both the encryption +//and IV derivation keys from the given database passphrase +const string S2K_STR = "PBKDF2(SHA-160)"; + +//SALT_STR: Hard coded salt used to derive the key from the passphrase. +const string SALT_STR = "&g#nB'9]"; + +//MAC_STR: CMAC used to derive the IV that is used for db page +//encryption +const string MAC_STR = "CMAC(Twofish)"; + +//S2K_ITERATIONS: Number of hash iterations used in the key derivation +//process. +const int S2K_ITERATIONS = 10000; + +//SALT_SIZE: Size of the salt in bytes (as given in SALT_STR) +const int SALT_SIZE = 64/8; //64 bit, 8 byte salt + +//KEY_SIZE: Size of the encryption key. Note that XTS splits the key +//between two ciphers, so if you're using XTS, double the intended key +//size. (ie, "AES-128/XTS" should have a 256 bit KEY_SIZE) +const int KEY_SIZE = 512/8; //512 bit, 64 byte key. (256 bit XTS key) + +//IV_DERIVATION_KEY_SIZE: Size of the key used with the CMAC (MAC_STR) +//above. +const int IV_DERIVATION_KEY_SIZE = 256/8; //256 bit, 32 byte key + +class Codec +{ +public: + Codec(void *db); + Codec(const Codec& other, void *db); + + void GenerateWriteKey(const char* userPassword, int passwordLength); + void DropWriteKey(); + void SetWriteIsRead(); + void SetReadIsWrite(); + + unsigned char* Encrypt(int page, unsigned char* data, bool useWriteKey); + void Decrypt(int page, unsigned char* data); + + void SetPageSize(int pageSize) { m_pageSize = pageSize; } + + bool HasReadKey() { return m_hasReadKey; } + bool HasWriteKey() { return m_hasWriteKey; } + void* GetDB() { return m_db; } + +private: + bool m_hasReadKey; + bool m_hasWriteKey; + + SymmetricKey + m_readKey, + m_writeKey, + m_ivReadKey, + m_ivWriteKey; + + Pipe + m_encipherPipe, + m_decipherPipe, + m_macPipe; + + Keyed_Filter *m_encipherFilter; + Keyed_Filter *m_decipherFilter; + MAC_Filter *m_cmac; + + int m_pageSize; + unsigned char m_page[SQLITE_MAX_PAGE_SIZE]; + void* m_db; + + InitializationVector GetIVForPage(u32bit page, bool useWriteKey); + void InitializeCodec(void *db); +}; + +#endif diff --git a/src/wrap/sqlite/codecext.cpp b/src/wrap/sqlite/codecext.cpp new file mode 100644 index 000000000..e542df975 --- /dev/null +++ b/src/wrap/sqlite/codecext.cpp @@ -0,0 +1,261 @@ +/* + * SQLite3 encryption extention codec + * (C) 2010 Olivier de Gaalon + * + * Distributed under the terms of the Botan license + */ + +#ifndef SQLITE_OMIT_DISKIO +#ifdef SQLITE_HAS_CODEC + +#include "codec.h" +#include "sqlite3.h" + +// Required to implement, called from pragma.c, guessing that "see" is related to the +// "SQLite Encryption Extension" (the semi-official, for-pay, encryption codec) +extern "C" +void sqlite3_activate_see(const char *info) { } + +// Free the encryption codec, called from pager.c (address passed in sqlite3PagerSetCodec) +extern "C" +void sqlite3PagerFreeCodec(void *pCodec) +{ + if (pCodec) + delete (Codec*) pCodec; +} + +// Report the page size to the codec, called from pager.c (address passed in sqlite3PagerSetCodec) +extern "C" +void sqlite3CodecSizeChange(void *pCodec, int pageSize, int nReserve) +{ + Codec* codec = (Codec*) pCodec; + codec->SetPageSize(pageSize); +} + +// Encrypt/Decrypt functionality, called by pager.c +extern "C" +void* sqlite3Codec(void* pCodec, void* data, Pgno nPageNum, int nMode) +{ + if (pCodec == NULL) //Db not encrypted + return data; + + Codec* codec = (Codec*) pCodec; + + try + { + switch(nMode) + { + case 0: // Undo a "case 7" journal file encryption + case 2: // Reload a page + case 3: // Load a page + if (codec->HasReadKey()) + codec->Decrypt(nPageNum, (unsigned char*) data); + break; + case 6: // Encrypt a page for the main database file + if (codec->HasWriteKey()) + data = codec->Encrypt(nPageNum, (unsigned char*) data, true); + break; + case 7: // Encrypt a page for the journal file + /* + *Under normal circumstances, the readkey is the same as the writekey. However, + *when the database is being rekeyed, the readkey is not the same as the writekey. + *(The writekey is the "destination key" for the rekey operation and the readkey + *is the key the db is currently encrypted with) + *Therefore, for case 7, when the rollback is being written, always encrypt using + *the database's readkey, which is guaranteed to be the same key that was used to + *read and write the original data. + */ + if (codec->HasReadKey()) + data = codec->Encrypt(nPageNum, (unsigned char*) data, false); + break; + } + } + catch(Botan::Exception e) + { + sqlite3Error((sqlite3*)codec->GetDB(), SQLITE_ERROR, "Botan Error: %s", e.what()); + } + + return data; +} + +//These functions are defined in pager.c +extern "C" void* sqlite3PagerGetCodec(Pager *pPager); +extern "C" void sqlite3PagerSetCodec( + Pager *pPager, + void *(*xCodec)(void*,void*,Pgno,int), + void (*xCodecSizeChng)(void*,int,int), + void (*xCodecFree)(void*), + void *pCodec +); + + +extern "C" +int sqlite3CodecAttach(sqlite3* db, int nDb, const void* zKey, int nKey) +{ + try { + if (zKey == NULL || nKey <= 0) + { + // No key specified, could mean either use the main db's encryption or no encryption + if (nDb != 0 && nKey < 0) + { + //Is an attached database, therefore use the key of main database, if main database is encrypted + Codec* mainCodec = (Codec*) sqlite3PagerGetCodec(sqlite3BtreePager(db->aDb[0].pBt)); + if (mainCodec != NULL) + { + Codec* codec = new Codec(*mainCodec, db); + sqlite3PagerSetCodec(sqlite3BtreePager(db->aDb[nDb].pBt), + sqlite3Codec, + sqlite3CodecSizeChange, + sqlite3PagerFreeCodec, codec); + } + } + } + else + { + // Key specified, setup encryption key for database + Codec* codec = new Codec(db); + codec->GenerateWriteKey((const char*) zKey, nKey); + codec->SetReadIsWrite(); + sqlite3PagerSetCodec(sqlite3BtreePager(db->aDb[nDb].pBt), + sqlite3Codec, + sqlite3CodecSizeChange, + sqlite3PagerFreeCodec, codec); + } + } + catch(Botan::Exception e) { + sqlite3Error(db, SQLITE_ERROR, "Botan Error: %s", e.what()); + return SQLITE_ERROR; + } + return SQLITE_OK; +} + +extern "C" +void sqlite3CodecGetKey(sqlite3* db, int nDb, void** zKey, int* nKey) +{ + // The unencrypted password is not stored for security reasons + // therefore always return NULL + *zKey = NULL; + *nKey = -1; +} + +extern "C" +int sqlite3_key(sqlite3 *db, const void *zKey, int nKey) +{ + // The key is only set for the main database, not the temp database + return sqlite3CodecAttach(db, 0, zKey, nKey); +} + +extern "C" +int sqlite3_rekey(sqlite3 *db, const void *zKey, int nKey) +{ + // Changes the encryption key for an existing database. + int rc = SQLITE_ERROR; + Btree* pbt = db->aDb[0].pBt; + Pager* pPager = sqlite3BtreePager(pbt); + Codec* codec = (Codec*) sqlite3PagerGetCodec(pPager); + + if ((zKey == NULL || nKey == 0) && codec == NULL) + { + // Database not encrypted and key not specified. Do nothing + return SQLITE_OK; + } + + if (codec == NULL) + { + // Database not encrypted, but key specified. Encrypt database + try { + codec = new Codec(db); + codec->GenerateWriteKey((const char*) zKey, nKey); + } catch (Botan::Exception e) { + sqlite3Error(db, SQLITE_ERROR, "Botan Error %s", e.what()); + return SQLITE_ERROR; + } + sqlite3PagerSetCodec(pPager, sqlite3Codec, sqlite3CodecSizeChange, sqlite3PagerFreeCodec, codec); + } + else if (zKey == NULL || nKey == 0) + { + // Database encrypted, but key not specified. Decrypt database + // Keep read key, drop write key + codec->DropWriteKey(); + } + else + { + // Database encrypted and key specified. Re-encrypt database with new key + // Keep read key, change write key to new key + try { + codec->GenerateWriteKey((const char*) zKey, nKey); + } catch (Botan::Exception e) { + sqlite3Error(db, SQLITE_ERROR, "Botan Error %s", e.what()); + return SQLITE_ERROR; + } + } + + // Start transaction + rc = sqlite3BtreeBeginTrans(pbt, 1); + if (rc == SQLITE_OK) + { + // Rewrite all pages using the new encryption key (if specified) + int nPageCount = -1; + int rc = sqlite3PagerPagecount(pPager, &nPageCount); + Pgno nPage = (Pgno) nPageCount; + int pageSize = sqlite3BtreeGetPageSize(pbt); + //Can't use SQLite3 macro here since pager is forward declared...sigh + Pgno nSkip = CODEC_PAGER_MJ_PGNO(pageSize); + DbPage *pPage; + + for (Pgno n = 1; rc == SQLITE_OK && n <= nPage; n++) + { + if (n == nSkip) + continue; + + rc = sqlite3PagerGet(pPager, n, &pPage); + + if (!rc) + { + rc = sqlite3PagerWrite(pPage); + sqlite3PagerUnref(pPage); + } + else + sqlite3Error(db, SQLITE_ERROR, "%s", "Error while rekeying database page. Transaction Canceled."); + } + } + else + sqlite3Error(db, SQLITE_ERROR, "%s", "Error beginning rekey transaction. Make sure that the current encryption key is correct."); + + if (rc == SQLITE_OK) + { + // All good, commit + rc = sqlite3BtreeCommit(pbt); + + if (rc == SQLITE_OK) + { + //Database rekeyed and committed successfully, update read key + if (codec->HasWriteKey()) + codec->SetReadIsWrite(); + else //No write key == no longer encrypted + sqlite3PagerSetCodec(pPager, NULL, NULL, NULL, NULL); + } + else + { + //FIXME: can't trigger this, not sure if rollback is needed, reference implementation didn't rollback + sqlite3Error(db, SQLITE_ERROR, "%s", "Could not commit rekey transaction."); + } + } + else + { + // Rollback, rekey failed + sqlite3BtreeRollback(pbt); + + // go back to read key + if (codec->HasReadKey()) + codec->SetWriteIsRead(); + else //Database wasn't encrypted to start with + sqlite3PagerSetCodec(pPager, NULL, NULL, NULL, NULL); + } + + return rc; +} + +#endif // SQLITE_HAS_CODEC + +#endif // SQLITE_OMIT_DISKIO diff --git a/src/wrap/sqlite/readme.txt b/src/wrap/sqlite/readme.txt new file mode 100644 index 000000000..e131f9e91 --- /dev/null +++ b/src/wrap/sqlite/readme.txt @@ -0,0 +1,36 @@ +Build instructions for Botan SQLite3 codec +--- + +1. Requires Botan 1.8.8 or later (earlier versions OK if you switch to + CBC mode from XTS) + +2. Download SQLite3 version 3.6.17 or later, get the version "as + extracted from the source control system", NOT the amalgamation. + +3. Apply the patch "sqlite.diff" [*]: + $ patch -p0 < ../sqlite.diff + patching file Makefile.in + patching file src/pager.c + + If the patch to pager.c fails for some reason (ie, changes in + SQLite3), all that need be done is remove the "static" keyword from + the functions sqlite3PagerSetCodec and sqlite3PagerGetCodec. + +5. Create a folder called "botan" in the SQLite3 src dir and copy + "codec.cpp", "codec.h", and "codecext.cpp" into it. + +6. As desired, edit the constants in codec.h to tweak the encryption + type to your needs. (Currently, Twofish/XTS with 256 bit key) + +7. Run ./configure in the SQLite3 root directory with the + "--disable-amalgamation" and (if desired) "--disable-shared" + arguments, and then run make. + +And to make sure it all worked... + +8. Make the test_sqlite.cpp file: + $ g++ test_sqlite.cpp -o test_sqlite -lbotan /path/to/libsqlite3.a +9. Run it + $ ./test_sqlite +10. Look for "All seems good" + diff --git a/src/wrap/sqlite/sqlite.diff b/src/wrap/sqlite/sqlite.diff new file mode 100644 index 000000000..1a3ef764c --- /dev/null +++ b/src/wrap/sqlite/sqlite.diff @@ -0,0 +1,77 @@ +--- Makefile.in.orig 2009-10-30 09:34:59.000000000 -0400 ++++ Makefile.in 2010-01-21 22:51:22.000000000 -0500 +@@ -133,7 +133,10 @@ + GCOV_LDFLAGS1 = -lgcov + USE_GCOV = @USE_GCOV@ + LTCOMPILE_EXTRAS += $(GCOV_CFLAGS$(USE_GCOV)) ++LTCOMPILE_EXTRAS += -DSQLITE_HAS_CODEC + LTLINK_EXTRAS += $(GCOV_LDFLAGS$(USE_GCOV)) ++LTLINK_EXTRAS += -lstdc++ ++LTLINK_EXTRAS += -lbotan + + + # The directory into which to store package information for +@@ -176,7 +179,8 @@ + table.lo tokenize.lo trigger.lo update.lo \ + util.lo vacuum.lo \ + vdbe.lo vdbeapi.lo vdbeaux.lo vdbeblob.lo vdbemem.lo \ +- walker.lo where.lo utf.lo vtab.lo ++ walker.lo where.lo utf.lo vtab.lo \ ++ codec.lo codecext.lo + + # Object files for the amalgamation. + # +@@ -275,7 +279,10 @@ + $(TOP)/src/vdbeInt.h \ + $(TOP)/src/vtab.c \ + $(TOP)/src/walker.c \ +- $(TOP)/src/where.c ++ $(TOP)/src/where.c \ ++ $(TOP)/src/botan/codec.cpp \ ++ $(TOP)/src/botan/codecext.cpp \ ++ $(TOP)/src/botan/codec.h + + # Generated source code files + # +@@ -411,6 +418,7 @@ + $(TOP)/src/sqlite3ext.h \ + $(TOP)/src/sqliteInt.h \ + $(TOP)/src/vdbe.h \ ++ $(TOP)/src/botan/codec.h \ + $(TOP)/src/vdbeInt.h \ + parse.h \ + config.h +@@ -622,6 +630,13 @@ + notify.lo: $(TOP)/src/notify.c $(HDR) + $(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/notify.c + ++codec.lo: $(TOP)/src/botan/codec.cpp $(HDR) $(TOP)/src/botan/codec.h ++ $(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/botan/codec.cpp ++ ++codecext.lo: $(TOP)/src/botan/codecext.cpp $(HDR) $(TOP)/src/botan/codec.h ++ $(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/botan/codecext.cpp ++ ++ + pager.lo: $(TOP)/src/pager.c $(HDR) $(TOP)/src/pager.h + $(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/pager.c + +--- src/pager.c.orig 2009-10-30 17:01:07.000000000 -0400 ++++ src/pager.c 2010-01-21 22:51:53.000000000 -0500 +@@ -5046,7 +5046,7 @@ + /* + ** Set or retrieve the codec for this pager + */ +-static void sqlite3PagerSetCodec( ++void sqlite3PagerSetCodec( + Pager *pPager, + void *(*xCodec)(void*,void*,Pgno,int), + void (*xCodecSizeChng)(void*,int,int), +@@ -5060,7 +5060,7 @@ + pPager->pCodec = pCodec; + pagerReportSize(pPager); + } +-static void *sqlite3PagerGetCodec(Pager *pPager){ ++void *sqlite3PagerGetCodec(Pager *pPager){ + return pPager->pCodec; + } + #endif diff --git a/src/wrap/sqlite/test_sqlite.cpp b/src/wrap/sqlite/test_sqlite.cpp new file mode 100644 index 000000000..8d8cad946 --- /dev/null +++ b/src/wrap/sqlite/test_sqlite.cpp @@ -0,0 +1,101 @@ +/* + * Quick and dirty test for SQLite3 encryption codec. + * (C) 2010 Olivier de Gaalon + * + * Distributed under the terms of the Botan license + */ + +#include <sqlite3.h> +#include <stdio.h> + +namespace SQL +{ + const char * CREATE_TABLE_TEST = + "create table 'test' (id INTEGER PRIMARY KEY, name TEXT, creationtime TEXT);"; + const char * CREATE_TABLE_TEST2 = + "create table 'test2' (id INTEGER PRIMARY KEY, name TEXT, creationtime TEXT);"; + const char * INSERT_INTO_TEST = + "INSERT INTO test (name, creationtime) VALUES ('widget', '1st time');\ + INSERT INTO test (name, creationtime) VALUES ('widget', '2nd time');\ + INSERT INTO test (name, creationtime) VALUES ('widget', '3rd time');\ + INSERT INTO test (name, creationtime) VALUES ('widget', '4th time');\ + INSERT INTO test (name, creationtime) VALUES ('widget', '5th time');"; + const char * INSERT_INTO_TEST2 = + "INSERT INTO test2 (name, creationtime) VALUES ('widget2', '1st time2');\ + INSERT INTO test2 (name, creationtime) VALUES ('widget2', '2nd time2');\ + INSERT INTO test2 (name, creationtime) VALUES ('widget2', '3rd time2');\ + INSERT INTO test2 (name, creationtime) VALUES ('widget2', '4th time2');\ + INSERT INTO test2 (name, creationtime) VALUES ('widget2', '5th time2');"; + const char * SELECT_FROM_TEST = + "SELECT * FROM test;"; + const char * SELECT_FROM_TEST2 = + "SELECT * FROM test2;"; +}; + +static int callback(void *NotUsed, int argc, char **argv, char **azColName){ + int i; + fprintf(stderr, "\t"); + for(i=0; i<argc; i++){ + fprintf(stderr, "%s = %s | ", azColName[i], argv[i] ? argv[i] : "NULL"); + } + fprintf(stderr, "\n"); + return 0; +} + +int main(int argc, char** argv) +{ + sqlite3 * db; + const char * key = "testkey"; + const char * dbname = "./testdb"; + int keylen = 7; + char * error=0; + + fprintf(stderr, "Creating Database \"%s\"\n", dbname); + int rc = sqlite3_open(dbname, &db); + if (rc != SQLITE_OK) { fprintf(stderr, "Can't open/create database: %s\n", sqlite3_errmsg(db)); return 1; } + + fprintf(stderr, "Keying Database with key \"%s\"\n", key); + rc = sqlite3_key(db, key, keylen); + if (rc != SQLITE_OK) { fprintf(stderr, "Can't key database: %s\n", sqlite3_errmsg(db)); return 1; } + + fprintf(stderr, "Creating table \"test\"\n"); + rc = sqlite3_exec(db, SQL::CREATE_TABLE_TEST, 0, 0, &error); + if (rc != SQLITE_OK) { fprintf(stderr, "SQL error: %s\n", error); return 1; } + + fprintf(stderr, "Creating table \"test2\"\n"); + rc = sqlite3_exec(db, SQL::CREATE_TABLE_TEST2, 0, 0, &error); + if (rc != SQLITE_OK) { fprintf(stderr, "SQL error: %s\n", error); return 1; } + + fprintf(stderr, "Inserting into table \"test\"\n"); + rc = sqlite3_exec(db, SQL::INSERT_INTO_TEST, 0, 0, &error); + if (rc != SQLITE_OK) { fprintf(stderr, "SQL error: %s\n", error); return 1; } + + fprintf(stderr, "Inserting into table \"test2\"\n"); + rc = sqlite3_exec(db, SQL::INSERT_INTO_TEST2, 0, 0, &error); + if (rc != SQLITE_OK) { fprintf(stderr, "SQL error: %s\n", error); return 1; } + + fprintf(stderr, "Closing Database \"%s\"\n", dbname); + sqlite3_close(db); + + fprintf(stderr, "Opening Database \"%s\"\n", dbname); + rc = sqlite3_open(dbname, &db); + if (rc != SQLITE_OK) { fprintf(stderr, "Can't open/create database: %s\n", sqlite3_errmsg(db)); return 1; } + + fprintf(stderr, "Keying Database with key \"%s\"\n", key); + rc = sqlite3_key(db, key, keylen); + if (rc != SQLITE_OK) { fprintf(stderr, "Can't key database: %s\n", sqlite3_errmsg(db)); return 1; } + + fprintf(stderr, "Selecting all from test\n"); + rc = sqlite3_exec(db, SQL::SELECT_FROM_TEST, callback, 0, &error); + if (rc != SQLITE_OK) { fprintf(stderr, "SQL error: %s\n", error); return 1; } + + fprintf(stderr, "Selecting all from test2\n"); + rc = sqlite3_exec(db, SQL::SELECT_FROM_TEST2, callback, 0, &error); + if (rc != SQLITE_OK) { fprintf(stderr, "SQL error: %s\n", error); return 1; } + + fprintf(stderr, "Closing Database \"%s\"\n", dbname); + sqlite3_close(db); + + fprintf(stderr, "All Seems Good \n"); + return 0; +} |