Botan  1.11.15
src/lib/misc/pbes2/pbes2.cpp
Go to the documentation of this file.
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 }