aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--checks/block.cpp115
-rw-r--r--checks/common.h12
-rw-r--r--checks/ecdsa.cpp71
-rw-r--r--checks/pk_valid.dat120
-rw-r--r--checks/validate.cpp138
-rwxr-xr-xconfigure.py64
-rw-r--r--doc/examples/bcrypt.cpp45
-rw-r--r--doc/examples/keywrap.cpp38
-rw-r--r--doc/log.txt9
-rw-r--r--readme.txt2
-rw-r--r--src/block/aes/aes.cpp4
-rw-r--r--src/block/blowfish/blowfish.cpp57
-rw-r--r--src/block/blowfish/blowfish.h19
-rw-r--r--src/block/mars/mars.cpp10
-rw-r--r--src/build-data/cc/sunstudio.txt4
-rw-r--r--src/cert/certstore/info.txt3
-rw-r--r--src/cert/x509cert/info.txt1
-rw-r--r--src/cert/x509cert/x509cert.cpp16
-rw-r--r--src/codec/pem/info.txt2
-rw-r--r--src/constructs/aont/package.cpp8
-rw-r--r--src/constructs/rfc3394/info.txt1
-rw-r--r--src/constructs/rfc3394/rfc3394.cpp122
-rw-r--r--src/constructs/rfc3394/rfc3394.h45
-rw-r--r--src/entropy/hres_timer/hres_timer.cpp2
-rw-r--r--src/filters/bzip2/bzip2.cpp24
-rw-r--r--src/filters/out_buf.cpp19
-rw-r--r--src/filters/zlib/zlib.cpp16
-rw-r--r--src/libstate/info.txt5
-rw-r--r--src/passhash/bcrypt/bcrypt.cpp154
-rw-r--r--src/passhash/bcrypt/bcrypt.h37
-rw-r--r--src/passhash/bcrypt/info.txt9
-rw-r--r--src/passhash/passhash9/info.txt (renamed from src/constructs/passhash/info.txt)0
-rw-r--r--src/passhash/passhash9/passhash9.cpp (renamed from src/constructs/passhash/passhash9.cpp)0
-rw-r--r--src/passhash/passhash9/passhash9.h (renamed from src/constructs/passhash/passhash9.h)0
-rw-r--r--src/ssl/info.txt2
-rw-r--r--src/stream/ctr/ctr.cpp4
36 files changed, 936 insertions, 242 deletions
diff --git a/checks/block.cpp b/checks/block.cpp
deleted file mode 100644
index 5d275615e..000000000
--- a/checks/block.cpp
+++ /dev/null
@@ -1,115 +0,0 @@
-/*
-* (C) 2009 Jack Lloyd
-*
-* Distributed under the terms of the Botan license
-*/
-
-
-/*
- We don't use the standard issue ECB filter, because we also want to check
- that the encryption and decryption operations are inverses (ie, it works).
-
- This class only works with NoPadding mode, unlike the regular ECB filters
-*/
-
-#include <iostream>
-#include <string>
-#include <cstdlib>
-#include <botan/filter.h>
-#include <botan/lookup.h>
-using namespace Botan;
-
-#include "common.h"
-
-class ECB_Encryption_ErrorCheck : public Filter
- {
- public:
- std::string name() const
- { return "ECB_ErrCheck(" + cipher->name() + ")"; }
-
- void write(const byte[], size_t);
-
- void end_msg();
-
- ECB_Encryption_ErrorCheck(const std::string& cipher_name,
- const std::string&,
- const SymmetricKey& key) :
- BLOCKSIZE(block_size_of(cipher_name))
- {
- const std::string HASH = "CRC32";
-
- cipher = get_block_cipher(cipher_name);
- input_hash = get_hash(HASH);
- decrypt_hash = get_hash(HASH);
- buffer.resize(BLOCKSIZE);
- cipher->set_key(key);
- position = 0;
- }
-
- ~ECB_Encryption_ErrorCheck()
- {
- delete cipher;
- delete input_hash;
- delete decrypt_hash;
- }
-
- private:
- const size_t BLOCKSIZE;
- BlockCipher* cipher;
- SecureVector<byte> buffer;
- size_t position;
- HashFunction* input_hash, *decrypt_hash;
- };
-
-void ECB_Encryption_ErrorCheck::write(const byte input[], size_t length)
- {
- input_hash->update(input, length);
- buffer.copy(position, input, length);
- if(position + length >= BLOCKSIZE)
- {
- cipher->encrypt(buffer);
- send(buffer, BLOCKSIZE);
- cipher->decrypt(buffer);
- decrypt_hash->update(&buffer[0], BLOCKSIZE);
- input += (BLOCKSIZE - position);
- length -= (BLOCKSIZE - position);
- while(length >= BLOCKSIZE)
- {
- cipher->encrypt(input, &buffer[0]);
- send(buffer, BLOCKSIZE);
- cipher->decrypt(buffer);
- decrypt_hash->update(&buffer[0], BLOCKSIZE);
- input += BLOCKSIZE;
- length -= BLOCKSIZE;
- }
- buffer.copy(input, length);
- position = 0;
- }
- position += length;
- }
-
-void ECB_Encryption_ErrorCheck::end_msg()
- {
- SecureVector<byte> hash1 = input_hash->final();
- SecureVector<byte> hash2 = decrypt_hash->final();
-
- if(hash1 != hash2)
- {
- std::cout << "In " << cipher->name()
- << " decryption check failed." << std::endl;
- }
-
- if(position)
- throw Encoding_Error("ECB: input was not in full blocks");
- }
-
-Filter* lookup_block(const std::string& algname, const std::string& key)
- {
- Filter* cipher = 0;
- try {
- cipher = new ECB_Encryption_ErrorCheck(algname, "NoPadding", key);
- }
- catch(Algorithm_Not_Found) {}
-
- return cipher;
- }
diff --git a/checks/common.h b/checks/common.h
index 148b89d93..33499a99d 100644
--- a/checks/common.h
+++ b/checks/common.h
@@ -25,18 +25,6 @@ std::vector<std::string> parse(const std::string& line);
Botan::Filter* lookup(const std::string& algname,
const std::vector<std::string>& params);
-Botan::Filter* lookup_block(const std::string&, const std::string&);
-Botan::Filter* lookup_cipher(const std::string&, const std::string&,
- const std::string&, bool);
-Botan::Filter* lookup_hash(const std::string&);
-Botan::Filter* lookup_mac(const std::string&, const std::string&);
-Botan::Filter* lookup_rng(const std::string&, const std::string&);
-Botan::Filter* lookup_encoder(const std::string&);
-Botan::Filter* lookup_pbkdf(const std::string&,
- const std::vector<std::string>&);
-Botan::Filter* lookup_kdf(const std::string&, const std::string&,
- const std::string&);
-
class Fixed_Output_RNG : public Botan::RandomNumberGenerator
{
public:
diff --git a/checks/ecdsa.cpp b/checks/ecdsa.cpp
index 1fa845094..346c0441c 100644
--- a/checks/ecdsa.cpp
+++ b/checks/ecdsa.cpp
@@ -48,55 +48,37 @@ void test_hash_larger_than_n(RandomNumberGenerator& rng)
{
std::cout << "." << std::flush;
- EC_Domain_Params dom_pars(OID("1.3.132.0.8"));
- // n:
- // 0x0100000000000000000001f4c8f927aed3ca752257 // 21 bytes
- // -> shouldn't work with SHA224 which outputs 23 bytes
+ EC_Domain_Params dom_pars(OID("1.3.132.0.8")); // secp160r1
+ // n = 0x0100000000000000000001f4c8f927aed3ca752257 (21 bytes)
+ // -> shouldn't work with SHA224 which outputs 28 bytes
+
ECDSA_PrivateKey priv_key(rng, dom_pars);
+
SecureVector<byte> message(20);
- for (unsigned i = 0; i != 20; ++i)
+ for(size_t i = 0; i != message.size(); ++i)
message[i] = i;
- for (int i = 0; i<3; i++)
- {
- //cout << "i = " << i << endl;
- std::string format;
- if(i==1)
- {
- format = "EMSA1_BSI(SHA-224)";
- }
- else
- {
- format = "EMSA1_BSI(SHA-1)";
- }
- PK_Signer pk_signer(priv_key, format);
- SecureVector<byte> signature;
- bool sig_exc = false;
- try
- {
- signature = pk_signer.sign_message(message, rng);
- }
- catch(Encoding_Error e)
- {
- sig_exc = true;
- }
- if(i==1)
- {
- CHECK(sig_exc);
- }
- if(i==0)
- {
- CHECK(!sig_exc);
- }
+ PK_Signer pk_signer_160(priv_key, "EMSA1_BSI(SHA-1)");
+ PK_Verifier pk_verifier_160(priv_key, "EMSA1_BSI(SHA-1)");
- if(i==0) // makes no sense to check for sha224
- {
- PK_Verifier pk_verifier(priv_key, format);
- bool ver = pk_verifier.verify_message(message, signature);
- CHECK(ver);
- }
+ PK_Signer pk_signer_224(priv_key, "EMSA1_BSI(SHA-224)");
+
+ // Verify we can sign and verify with SHA-160
+ SecureVector<byte> signature_160 = pk_signer_160.sign_message(message, rng);
+
+ CHECK(pk_verifier_160.verify_message(message, signature_160));
- } // for
+ bool signature_failed = false;
+ try
+ {
+ SecureVector<byte> signature_224 = pk_signer_224.sign_message(message, rng);
+ }
+ catch(Encoding_Error)
+ {
+ signature_failed = true;
+ }
+
+ CHECK(signature_failed);
// now check that verification alone fails
@@ -107,9 +89,6 @@ void test_hash_larger_than_n(RandomNumberGenerator& rng)
PK_Verifier pk_verifier(priv_key, "EMSA1_BSI(SHA-224)");
// verify against EMSA1_BSI
- // we make sure it doesn't fail because of the invalid signature,
- // but because of the Encoding_Error
-
if(pk_verifier.verify_message(message, signature))
std::cout << "Corrupt ECDSA signature verified, should not have\n";
}
diff --git a/checks/pk_valid.dat b/checks/pk_valid.dat
index bce2b0e04..7298b3730 100644
--- a/checks/pk_valid.dat
+++ b/checks/pk_valid.dat
@@ -4249,6 +4249,126 @@ x962_p239v1:\
2CB7F36803EBB9C427C58D8265F11FC5084747133078FC279DE874FBECB0\
2EEAE988104E9C2234A3C2BEB1F53BFA5DC11FF36A875D1E3CCB1F7E45CF
+brainpool160r1:\
+1CA8A0ACE60292D2813D992C4EC7A4BCDF611C0:\
+43727970746F2B2B20352E362E312045434453412074657374206D7367:\
+9CB692B33F02179D1A6F2A0669FD8DAAF17E4FC4:\
+672EAFD043D30BAE7CA826828333FA70F10A14C7\
+0F49C076BB26178277D8E490D0C77F7A9649DE31
+
+[ECDSA/EMSA1(SHA-224)]
+secp224r1:\
+42D126D0E51F3D6AA9B4D60BD1290853AA964A9C8698D5D5BDBAADEB:\
+45434453412074657374206D657373616765203230313130323135:\
+E1F6B207B4FC896879A51F65E85DB94CEB633FEC765739E689847D64:\
+A4C80AAF3D7B61200E66D6F41EC66D3D65E9E38DC06A88FE3B7F6C4C\
+8A5CEE4E04FE240464EA2DBB52489D3FAC1CDE6DA24A0E4C6598BCD2
+
+brainpool224r1:\
+47B5CCE9EED463CED28666DA57DA9D0A8BDD3F000CCFC0AE6054F1AD:\
+43727970746F2B2B20352E362E312045434453412074657374206D7367:\
+9E9D0C9E67FF5785C3AD89195567CD3990D54C628788F26DB926F5B6:\
+40369F41BD0D15C92DFB855779DBF439376FB6EDC4153E9B99019B79\
+40FEF076FC8D610EC12AFC9CC43A150BD0190E507622E6623906D6B8
+
+[ECDSA/EMSA1(SHA-256)]
+secp256r1:\
+368E89CC30AE7A3B4B4903C30C238C010257FE97DB85AF35982A7960A0DBD2F3:\
+43727970746F2B2B20352E362E312045434453412074657374206D7367:\
+E2AAB3BD3AB1999651CD903F5385B8EC2EDA84C43B7801F08608C179DD373369:\
+CBED1CE0D581020D2F89174EC2DE450C1D547BAC3DCEECCDD476A6AADF46D24F\
+C456F43F351605CC40FC2A000B4D291042B5AEEA7A783DF89FC86666D832DACF
+
+secp256r1:\
+6CC691616D2C996A8F00A31C2EBF4E35C5EFFEAAFA2266F800768D5BF8EA2C1B:\
+45434453412074657374206D657373616765203230313130323135:\
+C1DDAA59A4E0B5D95EB873C33BC465C6782EBF7BC43DB18058C9EC4816AD2A11:\
+A8369164EF54A67303760B77AA62C4DE8122396908EA5B06DBCC2BC48264C832\
+ADB3A8855019D5AFF789EC1F276AD38A03AAF41F88593B74E5CB9DF7E4BD4922
+
+brainpool256r1:\
+4EC702404A8047A08206721DE33F02E1F06B14E09A5582171EA9BB8AB3C9BC14:\
+43727970746F2B2B20352E362E312045434453412074657374206D7367:\
+A9952A1B896FB2C2AEA88EA578E2A5323114978A765E03E397969DC0F282708C:\
+54F843E89B084EEE1CFFED09F222DF041CD46DB0C48833667BA0790ECD603089\
+5304039A927714E79E5FCDB1D043E093FD85C8DD98B835CD6C7BB492C05357E5
+
+brainpool256r1:\
+416D7FCEB966DF966CAE7BE2608C5C4D8939A7B5B3CF6D3E441A64886AC5FAD7:\
+43727970746F2B2B20352E362E312045434453412074657374206D7367:\
+A07978494C1B301C1E44467853CD367624549E0E9F5092C0100A53F877AD2EF6:\
+93935B733CCC6A8702191664346135D1D6320D86A2346DFCA41AEDFBC4260435\
+A4A9C66485C02BC2DCC858364173FAE00EA02529BA21B56BBBB2EAA4B811416D
+
+[ECDSA/EMSA1(SHA-384)]
+secp384r1:\
+100CC52F0263DCB12FDB9E50D44A4C84831A98756265DF0CBFD092D27A739821\
+043BFE282E2C8FAD46948C1F0365DD0C:\
+45434453412074657374206D657373616765203230313130323135:\
+C27CC4947F7CA7AF386AF5BEA88582685A043BB3C83C0C8B2A4BB1E53A3971FA\
+8161168E332B2F3735A50BB3E8694F43:\
+C8B93B3C4B97B87A918522F423E26194F1AEA2B83FE890893C15928B79BCAC75\
+F66AB47309378A54771ED46AF6AA453BFD2404EECFCCE19ACE11E5D5883EE40A\
+300A42BD9AC79E77E507DE9EAE0B54034DB17355EE2111990ED226701D4ED7EC
+
+secp384r1:\
+4AF67D00B7A8D964B38CC52CBC808D4693595A5B330E0B3EA52BDCD619D41B85\
+6961BDAC571D9BC93D16A9B1C4D5CC2F:\
+45434453412074657374206D657373616765203230313130323135:\
+8C5D8DDCF8AF127174577A60F9B5512813E33EA8E45B471F343806FBF68663E9\
+915B81A33F6AD22007D57818023AF982:\
+FF83C10E8D84777D17B724957B83E1500F578F1096C48BE2BCACE73E6681CDD6\
+A34F66CA2AF31241FAF85AEE2528438DA6BED934D75ACCF2E41176D8B661AB58\
+B7B867D802C38B39E8227F9CF0865072D381948FFFF637D8FB9B37BEC6AE0772
+
+brainpool384r1:\
+19AD48ECFB30F115AEF41CAFD29B265A586399C0F95166017AA7DB894413A2AE\
+821B7BE4F4E7B6BBC22A4E2EB1CC0865:\
+43727970746F2B2B20352E362E312045434453412074657374206D7367:\
+83928FD1219F1C6D5B128C0ECD2E39A83399CE609382D41890D43FD476318E0C\
+26264E98E0D5A0DBCC28A8C01C2D63D7:\
+4B800A206ED7807C0F15798509164709E94ED73B5E02B10D65F45B6C2B7FD694\
+37F3B5D1342DAF0988CA100B8875C739\
+2CFA819E10B76CFE12B2C6485D8326B66E6256CD2F4A6DFEB9B2B7BDD732EA9E\
+9D5398DDECCBEAAF3FD53D554AA1FADD
+
+[ECDSA/EMSA1(SHA-512)]
+
+secp521r1:\
+1511908E830069DAD59E8BA8F1BD4045612A4844805F61F7ECD92A1DEE1877B7\
+E62A57860314820C97FFC972732E3C4C0AE837103692E85B3A11B49EB3E20EF1599:\
+45434453412F53484128353132292074657374206D6573736167652032303131\
+30323135:\
+01C352020AAA6D14B6FC2B78FD46209A9EEF6A357CD8B5D53738E3D655FE7A80\
+8396E1DC5742058D05F2D76C8CBF4832BE0580A6FD7B4C7426656D17680DEAAEEEC2:\
+0138A515C79EECAAB50139FB5D9EF5A771CC1C0999F2E54B5A1A9370EA8ADCFD\
+DDD6E9933A39EDA0862F3ECAEBD49EA5ED58D93DA8F72B1CFB11E52A1528AEC8\
+63870060D717B29AD6D36DE953A4753FAC58629429EF4DD8F98B5A4F5504C5B2\
+29C23C609905632CD8D839DC472693698D7A149E8F3F17462F86BA0A7A895D80\
+583A46E9
+
+brainpool512r1:\
+1433AE89858BE7DD9346AF015FEC69F0556982FFEB9CCEF7FB1CE71155F7620C\
+ED4A6ACD0F35461A17C8370C4E600BECBACC0F7C1D2D1A2C00203A0E6626C21C:\
+43727970746F2B2B20352E362E312045434453412074657374206D7367:\
+AA72BC70ABD9E078DDE47F5440E75A93F136F6EAA5267F591E0D3F562DE48BD8\
+FED21B9E3F6F5560250566A00C7AAE7E57770BFC7D18A3E7750DC6C7083CC5B0:\
+A058CD406C7F2D87FBBDDDD1870C67D1ACBD222D45A929565101842EDFAEFB89\
+3CF07AD22CAC0F3350A7D1300741AB5ECE38498F196690CBCEDBF8C866995E5C\
+17F48EA66EB70ADE68F6C16103BE54DD004230270E1F8CAC2D6BD47F717C0D1B\
+1E335FA4AAA5212321EE93E55FED129D781912A0D87B78A5B569DA272B3C9469
+
+brainpool512r1:\
+83DBEFECAF8CFF78C575BE9659C1A104767979497AD9B589B1B13705C71F1DEF\
+AF5CA76C8700236CE2392268E0133CAADE358E3D4F2E64CB4AB8517079E3EFA0:\
+43727970746F2B2B20352E362E312045434453412074657374206D7367:\
+A110CC7BEF64F5C0349344025B97B151C735408BD2BC0D0CC4E54642EA0DF33E\
+829E85916086B51624B830BB2CDF53DAD9003A6D194115051139DBC3E81DF197:\
+3254388208915E0EEB99DA89AA198C6FDB1A31B21D3B69EF8EFE4848AE78C32A\
+4C489347510A9DD04125BBE95F847E14A2DF3267A0A6D1B5EC442B130C9B5DD1\
+924FCD9F365897570329BFEC41FBAF42961210F3FF850DE5736FFBAAB09C5C03\
+E0058BD51C8A8EF0FF221F31CF93FE59572ADA3CFEC7016085258A45D1E8544C
+
# ECC verification format is group name:public key:message:signature
[GOST_3410_VA/EMSA1(GOST-34.11)]
gost_256A:\
diff --git a/checks/validate.cpp b/checks/validate.cpp
index dd23eadc3..9acf73419 100644
--- a/checks/validate.cpp
+++ b/checks/validate.cpp
@@ -23,10 +23,18 @@
#include <botan/passhash9.h>
#endif
+#if defined(BOTAN_HAS_BCRYPT)
+ #include <botan/bcrypt.h>
+#endif
+
#if defined(BOTAN_HAS_CRYPTO_BOX)
#include <botan/cryptobox.h>
#endif
+#if defined(BOTAN_HAS_RFC3394_KEYWRAP)
+ #include <botan/rfc3394.h>
+#endif
+
using namespace Botan;
#include "validate.h"
@@ -94,6 +102,124 @@ bool test_cryptobox(RandomNumberGenerator& rng)
return true;
}
+bool keywrap_test(const char* key_str,
+ const char* expected_str,
+ const char* kek_str)
+ {
+ std::cout << '.' << std::flush;
+
+ bool ok = true;
+
+ try
+ {
+ SymmetricKey key(key_str);
+ SymmetricKey expected(expected_str);
+ SymmetricKey kek(kek_str);
+
+ Algorithm_Factory& af = global_state().algorithm_factory();
+
+ SecureVector<byte> enc = rfc3394_keywrap(key.bits_of(), kek, af);
+
+ if(enc != expected.bits_of())
+ {
+ std::cout << "NIST key wrap encryption failure: "
+ << hex_encode(enc) << " != " << hex_encode(expected.bits_of()) << "\n";
+ ok = false;
+ }
+
+ SecureVector<byte> dec = rfc3394_keyunwrap(expected.bits_of(), kek, af);
+
+ if(dec != key.bits_of())
+ {
+ std::cout << "NIST key wrap decryption failure: "
+ << hex_encode(dec) << " != " << hex_encode(key.bits_of()) << "\n";
+ ok = false;
+ }
+ }
+ catch(std::exception& e)
+ {
+ std::cout << e.what() << "\n";
+ }
+
+ return ok;
+ }
+
+bool test_keywrap()
+ {
+ std::cout << "Testing NIST keywrap: " << std::flush;
+
+ bool ok = true;
+
+ ok &= keywrap_test("00112233445566778899AABBCCDDEEFF",
+ "1FA68B0A8112B447AEF34BD8FB5A7B829D3E862371D2CFE5",
+ "000102030405060708090A0B0C0D0E0F");
+
+ ok &= keywrap_test("00112233445566778899AABBCCDDEEFF",
+ "96778B25AE6CA435F92B5B97C050AED2468AB8A17AD84E5D",
+ "000102030405060708090A0B0C0D0E0F1011121314151617");
+
+ ok &= keywrap_test("00112233445566778899AABBCCDDEEFF",
+ "64E8C3F9CE0F5BA263E9777905818A2A93C8191E7D6E8AE7",
+ "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F");
+
+ ok &= keywrap_test("00112233445566778899AABBCCDDEEFF0001020304050607",
+ "031D33264E15D33268F24EC260743EDCE1C6C7DDEE725A936BA814915C6762D2",
+ "000102030405060708090A0B0C0D0E0F1011121314151617");
+
+ ok &= keywrap_test("00112233445566778899AABBCCDDEEFF0001020304050607",
+ "A8F9BC1612C68B3FF6E6F4FBE30E71E4769C8B80A32CB8958CD5D17D6B254DA1",
+ "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F");
+
+ ok &= keywrap_test("00112233445566778899AABBCCDDEEFF000102030405060708090A0B0C0D0E0F",
+ "28C9F404C4B810F4CBCCB35CFB87F8263F5786E2D80ED326CBC7F0E71A99F43BFB988B9B7A02DD21",
+ "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F");
+
+ std::cout << "\n";
+ return ok;
+ }
+
+bool test_bcrypt(RandomNumberGenerator& rng)
+ {
+#if defined(BOTAN_HAS_BCRYPT)
+ std::cout << "Testing Bcrypt: " << std::flush;
+
+ const std::string input = "abc";
+
+ // Generated by jBCrypt 0.3
+ const std::string fixed_hash =
+ "$2a$05$DfPyLs.G6.To9fXEFgUL1O6HpYw3jIXgPcl/L3Qt3jESuWmhxtmpS";
+
+ std::cout << "." << std::flush;
+
+ bool ok = true;
+
+ if(!check_bcrypt(input, fixed_hash))
+ {
+ std::cout << "Fixed bcrypt test failed\n";
+ ok = false;
+ }
+
+ std::cout << "." << std::flush;
+
+ for(u16bit level = 1; level != 5; ++level)
+ {
+ std::string gen_hash = generate_bcrypt(input, rng, level);
+
+ if(!check_bcrypt(input, gen_hash))
+ {
+ std::cout << "Gen and check for bcrypt failed: "
+ << gen_hash << " not valid\n";
+ ok = false;
+ }
+
+ std::cout << "." << std::flush;
+ }
+
+ std::cout << std::endl;
+ return ok;
+#endif
+ }
+
bool test_passhash(RandomNumberGenerator& rng)
{
#if defined(BOTAN_HAS_PASSHASH9)
@@ -265,6 +391,18 @@ u32bit do_validation_tests(const std::string& filename,
errors++;
}
+ if(should_pass && !test_bcrypt(rng))
+ {
+ std::cout << "BCrypt tests failed" << std::endl;
+ errors++;
+ }
+
+ if(should_pass && !test_keywrap())
+ {
+ std::cout << "NIST keywrap tests failed" << std::endl;
+ errors++;
+ }
+
if(should_pass && !test_cryptobox(rng))
{
std::cout << "Cryptobox tests failed" << std::endl;
diff --git a/configure.py b/configure.py
index f86da5709..fee244592 100755
--- a/configure.py
+++ b/configure.py
@@ -2,7 +2,7 @@
"""
Configuration program for botan (http://botan.randombit.net/)
- (C) 2009-2010 Jack Lloyd
+ (C) 2009-2011 Jack Lloyd
Distributed under the terms of the Botan license
Tested with
@@ -43,9 +43,9 @@ class BuildConfigurationInformation(object):
"""
version_major = 1
version_minor = 9
- version_patch = 14
- version_so_patch = 14
- version_suffix = '-dev'
+ version_patch = 15
+ version_so_patch = 15
+ version_suffix = ''
version_datestamp = 0
@@ -221,6 +221,10 @@ def process_command_line(args):
action='store_false', default=True,
help=SUPPRESS_HELP)
+ build_group.add_option('--link-method',
+ default=None,
+ help=SUPPRESS_HELP)
+
build_group.add_option('--distribution-info', metavar='STRING',
help='set distribution specific versioning',
default='unspecified')
@@ -1043,6 +1047,14 @@ def choose_modules_to_use(modules, archinfo, options):
def cannot_use_because(mod, reason):
not_using_because.setdefault(reason, []).append(mod)
+ for modname in options.enabled_modules:
+ if modname not in modules:
+ logging.warning("Unknown enabled module %s" % (modname))
+
+ for modname in options.disabled_modules:
+ if modname not in modules:
+ logging.warning("Unknown disabled module %s" % (modname))
+
for (modname, module) in modules.items():
if modname in options.disabled_modules:
cannot_use_because(modname, 'disabled by user')
@@ -1177,15 +1189,34 @@ Perform the filesystem operations needed to setup the build
def setup_build(build_config, options, template_vars):
"""
+ Choose the link method based on system availablity and user request
+ """
+ def choose_link_method(req_method):
+
+ def useable_methods():
+ if 'symlink' in os.__dict__:
+ yield 'symlink'
+ if 'link' in os.__dict__:
+ yield 'hardlink'
+ yield 'copy'
+
+ for method in useable_methods():
+ if req_method is None or req_method == method:
+ return method
+
+ logging.info('Could not use requested link method %s' % (req_method))
+ return 'copy'
+
+ """
Copy or link the file, depending on what the platform offers
"""
- def portable_symlink(filename, target_dir):
+ def portable_symlink(filename, target_dir, method):
if not os.access(filename, os.R_OK):
logging.warning('Missing file %s' % (filename))
return
- if 'symlink' in os.__dict__:
+ if method == 'symlink':
def count_dirs(dir, accum = 0):
if dir in ['', '/', os.path.curdir]:
return accum
@@ -1201,13 +1232,16 @@ def setup_build(build_config, options, template_vars):
os.symlink(source, target)
- elif 'link' in os.__dict__:
+ elif method == 'hardlink':
os.link(filename,
os.path.join(target_dir, os.path.basename(filename)))
- else:
+ elif method == 'copy':
shutil.copy(filename, target_dir)
+ else:
+ raise Exception('Unknown link method %s' % (method))
+
def choose_makefile_template(style):
if style == 'nmake':
return 'nmake.in'
@@ -1268,13 +1302,16 @@ def setup_build(build_config, options, template_vars):
finally:
f.close()
+ link_method = choose_link_method(options.link_method)
+ logging.info('Using %s to link files into build directory' % (link_method))
+
def link_headers(header_list, type, dir):
logging.debug('Linking %d %s header files in %s' % (
len(header_list), type, dir))
for header_file in header_list:
try:
- portable_symlink(header_file, dir)
+ portable_symlink(header_file, dir, link_method)
except OSError, e:
if e.errno != errno.EEXIST:
logging.error('Error linking %s into %s: %s' % (
@@ -1371,7 +1408,7 @@ def generate_amalgamation(build_config):
amalg_header = """/*
* Botan %s Amalgamation
-* (C) 1999-2009 Jack Lloyd and others
+* (C) 1999-2011 Jack Lloyd and others
*
* Distributed under the terms of the Botan license
*/
@@ -1473,7 +1510,12 @@ def main(argv = None):
if options.os is None:
options.os = platform.system().lower()
- logging.info('Guessing taget OS is %s (--os to set)' % (options.os))
+
+ if re.match('^cygwin_.*', options.os):
+ logging.debug("Converting '%s' to 'cygwin'", options.os)
+ options.os = 'cygwin'
+
+ logging.info('Guessing target OS is %s (--os to set)' % (options.os))
if options.compiler is None:
if options.os == 'windows':
diff --git a/doc/examples/bcrypt.cpp b/doc/examples/bcrypt.cpp
new file mode 100644
index 000000000..27a98cf33
--- /dev/null
+++ b/doc/examples/bcrypt.cpp
@@ -0,0 +1,45 @@
+/*
+* Bcrypt example
+* (C) 2011 Jack Lloyd
+*
+* Distributed under the terms of the Botan license
+*/
+
+#include <botan/botan.h>
+#include <botan/bcrypt.h>
+#include <iostream>
+
+using namespace Botan;
+
+int main(int argc, char* argv[])
+ {
+ if(argc != 2 && argc != 3)
+ {
+ std::cout << "Usage: " << argv[0] << " password\n"
+ << " " << argv[0] << " password passhash\n";
+ return 1;
+ }
+
+ LibraryInitializer init;
+
+ if(argc == 2)
+ {
+ AutoSeeded_RNG rng;
+
+ std::cout << generate_bcrypt(argv[1], rng, 12) << "\n";
+ }
+ else if(argc == 3)
+ {
+ if(strlen(argv[2]) != 60)
+ {
+ std::cout << "Note: hash " << argv[2]
+ << " has wrong length and cannot be valid\n";
+ }
+
+ const bool ok = check_bcrypt(argv[1], argv[2]);
+
+ std::cout << "Password is " << (ok ? "valid" : "NOT valid") << "\n";
+ }
+
+ return 0;
+ }
diff --git a/doc/examples/keywrap.cpp b/doc/examples/keywrap.cpp
new file mode 100644
index 000000000..730bcb6c9
--- /dev/null
+++ b/doc/examples/keywrap.cpp
@@ -0,0 +1,38 @@
+/*
+* NIST keywrap example
+* (C) 2011 Jack Lloyd
+*
+* Distributed under the terms of the Botan license
+*/
+
+#include <botan/botan.h>
+#include <botan/rfc3394.h>
+#include <botan/hex.h>
+#include <iostream>
+
+int main()
+ {
+ using namespace Botan;
+
+ LibraryInitializer init;
+
+ AutoSeeded_RNG rng;
+
+ // The key to encrypt
+ SymmetricKey key(rng, 24);
+
+ // The key encryption key
+ SymmetricKey kek(rng, 32);
+
+ std::cout << "Original: " << key.as_string() << "\n";
+
+ Algorithm_Factory& af = global_state().algorithm_factory();
+
+ SecureVector<byte> enc = rfc3394_keywrap(key.bits_of(), kek, af);
+
+ std::cout << "Encrypted: " << hex_encode(enc) << "\n";
+
+ SecureVector<byte> dec = rfc3394_keyunwrap(enc, kek, af);
+
+ std::cout << "Decrypted: " << hex_encode(dec) << "\n";
+ }
diff --git a/doc/log.txt b/doc/log.txt
index 3fa6e6d6b..9313ac2f6 100644
--- a/doc/log.txt
+++ b/doc/log.txt
@@ -1,5 +1,12 @@
-* 1.9.14-dev, ????-??-??
+* 1.9.15-dev, ????-??-??
+ - Pipe will delete empty output queues as soon as they are no longer
+ needed, even if earlier messages still have data unread.
+
+* 1.9.14, 2011-03-01
+ - Add support for bcrypt, OpenBSD's password hashing scheme
+ - Add support for NIST's AES key wrapping algorithm
+ - Fix an infinite loop in zlib filters introduced in 1.9.11 (PR 142)
* 1.9.13, 2011-02-19
- Update Keccak to the round 3 variant
diff --git a/readme.txt b/readme.txt
index 9f2b851e7..fde088312 100644
--- a/readme.txt
+++ b/readme.txt
@@ -1,4 +1,4 @@
-Botan 1.9.14-dev, ????-??-??
+Botan 1.9.15-dev, ????-??-??
http://botan.randombit.net/
Botan is a C++ class library for performing a wide variety of
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;
}