Botan
1.11.15
|
00001 /* 00002 * PKCS #5 PBES2 00003 * (C) 1999-2008,2014 Jack Lloyd 00004 * 00005 * Botan is released under the Simplified BSD License (see license.txt) 00006 */ 00007 00008 #include <botan/pbes2.h> 00009 #include <botan/internal/algo_registry.h> 00010 #include <botan/cipher_mode.h> 00011 #include <botan/pbkdf2.h> 00012 #include <botan/der_enc.h> 00013 #include <botan/ber_dec.h> 00014 #include <botan/parsing.h> 00015 #include <botan/alg_id.h> 00016 #include <botan/oids.h> 00017 #include <botan/rng.h> 00018 #include <algorithm> 00019 00020 namespace Botan { 00021 00022 namespace { 00023 00024 /* 00025 * Encode PKCS#5 PBES2 parameters 00026 */ 00027 std::vector<byte> encode_pbes2_params(const std::string& cipher, 00028 const std::string& prf, 00029 const secure_vector<byte>& salt, 00030 const secure_vector<byte>& iv, 00031 size_t iterations, 00032 size_t key_length) 00033 { 00034 return DER_Encoder() 00035 .start_cons(SEQUENCE) 00036 .encode( 00037 AlgorithmIdentifier("PKCS5.PBKDF2", 00038 DER_Encoder() 00039 .start_cons(SEQUENCE) 00040 .encode(salt, OCTET_STRING) 00041 .encode(iterations) 00042 .encode(key_length) 00043 .encode_if( 00044 prf != "HMAC(SHA-160)", 00045 AlgorithmIdentifier(prf, AlgorithmIdentifier::USE_NULL_PARAM)) 00046 .end_cons() 00047 .get_contents_unlocked() 00048 ) 00049 ) 00050 .encode( 00051 AlgorithmIdentifier(cipher, 00052 DER_Encoder().encode(iv, OCTET_STRING).get_contents_unlocked() 00053 ) 00054 ) 00055 .end_cons() 00056 .get_contents_unlocked(); 00057 } 00058 00059 } 00060 00061 /* 00062 * PKCS#5 v2.0 PBE Constructor 00063 */ 00064 std::pair<AlgorithmIdentifier, std::vector<byte>> 00065 pbes2_encrypt(const secure_vector<byte>& key_bits, 00066 const std::string& passphrase, 00067 std::chrono::milliseconds msec, 00068 const std::string& cipher, 00069 const std::string& digest, 00070 RandomNumberGenerator& rng) 00071 { 00072 const std::string prf = "HMAC(" + digest + ")"; 00073 00074 const std::vector<std::string> cipher_spec = split_on(cipher, '/'); 00075 if(cipher_spec.size() != 2) 00076 throw Decoding_Error("PBE-PKCS5 v2.0: Invalid cipher spec " + cipher); 00077 00078 const secure_vector<byte> salt = rng.random_vec(12); 00079 00080 if(cipher_spec[1] != "CBC" && cipher_spec[1] != "GCM") 00081 throw Decoding_Error("PBE-PKCS5 v2.0: Don't know param format for " + cipher); 00082 00083 std::unique_ptr<Cipher_Mode> enc(get_cipher_mode(cipher, ENCRYPTION)); 00084 00085 PKCS5_PBKDF2 pbkdf(Algo_Registry<MessageAuthenticationCode>::global_registry().make(prf)); 00086 00087 const size_t key_length = enc->key_spec().maximum_keylength(); 00088 size_t iterations = 0; 00089 00090 secure_vector<byte> iv = rng.random_vec(enc->default_nonce_length()); 00091 00092 enc->set_key(pbkdf.derive_key(key_length, passphrase, &salt[0], salt.size(), 00093 msec, iterations).bits_of()); 00094 00095 enc->start(iv); 00096 secure_vector<byte> buf = key_bits; 00097 enc->finish(buf); 00098 00099 AlgorithmIdentifier id( 00100 OIDS::lookup("PBE-PKCS5v20"), 00101 encode_pbes2_params(cipher, prf, salt, iv, iterations, key_length)); 00102 00103 return std::make_pair(id, unlock(buf)); 00104 } 00105 00106 secure_vector<byte> 00107 pbes2_decrypt(const secure_vector<byte>& key_bits, 00108 const std::string& passphrase, 00109 const std::vector<byte>& params) 00110 { 00111 AlgorithmIdentifier kdf_algo, enc_algo; 00112 00113 BER_Decoder(params) 00114 .start_cons(SEQUENCE) 00115 .decode(kdf_algo) 00116 .decode(enc_algo) 00117 .verify_end() 00118 .end_cons(); 00119 00120 AlgorithmIdentifier prf_algo; 00121 00122 if(kdf_algo.oid != OIDS::lookup("PKCS5.PBKDF2")) 00123 throw Decoding_Error("PBE-PKCS5 v2.0: Unknown KDF algorithm " + 00124 kdf_algo.oid.as_string()); 00125 00126 secure_vector<byte> salt; 00127 size_t iterations = 0, key_length = 0; 00128 00129 BER_Decoder(kdf_algo.parameters) 00130 .start_cons(SEQUENCE) 00131 .decode(salt, OCTET_STRING) 00132 .decode(iterations) 00133 .decode_optional(key_length, INTEGER, UNIVERSAL) 00134 .decode_optional(prf_algo, SEQUENCE, CONSTRUCTED, 00135 AlgorithmIdentifier("HMAC(SHA-160)", 00136 AlgorithmIdentifier::USE_NULL_PARAM)) 00137 .verify_end() 00138 .end_cons(); 00139 00140 const std::string cipher = OIDS::lookup(enc_algo.oid); 00141 const std::vector<std::string> cipher_spec = split_on(cipher, '/'); 00142 if(cipher_spec.size() != 2) 00143 throw Decoding_Error("PBE-PKCS5 v2.0: Invalid cipher spec " + cipher); 00144 if(cipher_spec[1] != "CBC" && cipher_spec[1] != "GCM") 00145 throw Decoding_Error("PBE-PKCS5 v2.0: Don't know param format for " + cipher); 00146 00147 if(salt.size() < 8) 00148 throw Decoding_Error("PBE-PKCS5 v2.0: Encoded salt is too small"); 00149 00150 secure_vector<byte> iv; 00151 BER_Decoder(enc_algo.parameters).decode(iv, OCTET_STRING).verify_end(); 00152 00153 const std::string prf = OIDS::lookup(prf_algo.oid); 00154 PKCS5_PBKDF2 pbkdf(Algo_Registry<MessageAuthenticationCode>::global_registry().make(prf)); 00155 00156 std::unique_ptr<Cipher_Mode> dec(get_cipher_mode(cipher, DECRYPTION)); 00157 00158 if(key_length == 0) 00159 key_length = dec->key_spec().maximum_keylength(); 00160 00161 dec->set_key(pbkdf.derive_key(key_length, passphrase, &salt[0], salt.size(), 00162 iterations).bits_of()); 00163 00164 dec->start(iv); 00165 00166 secure_vector<byte> buf = key_bits; 00167 dec->finish(buf); 00168 00169 return buf; 00170 } 00171 00172 }