secure_vector<uint8_t> rfc3394_keyunwrap(const secure_vector<uint8_t>& key, const SymmetricKey& kek) { BOTAN_ARG_CHECK(kek.size() == 16 || kek.size() == 24 || kek.size() == 32, "Invalid KEK length for NIST key wrap"); BOTAN_ARG_CHECK(key.size() >= 16 && key.size() % 8 == 0, "Bad input key size for NIST key unwrap"); const std::string cipher_name = "AES-" + std::to_string(8*kek.size()); std::unique_ptr<BlockCipher> aes(BlockCipher::create_or_throw(cipher_name)); aes->set_key(kek); return nist_key_unwrap(key.data(), key.size(), *aes); }
/* * Modified key schedule used for bcrypt password hashing */ void Blowfish::salted_set_key(const uint8_t key[], size_t length, const uint8_t salt[], size_t salt_length, size_t workfactor) { BOTAN_ARG_CHECK(salt_length > 0 && salt_length % 4 == 0, "Invalid salt length for Blowfish salted key schedule"); if(length > 72) { // Truncate longer passwords to the 72 char bcrypt limit length = 72; } m_P.resize(18); copy_mem(m_P.data(), P_INIT, 18); m_S.resize(1024); copy_mem(m_S.data(), S_INIT, 1024); key_expansion(key, length, salt, salt_length); if(workfactor > 0) { const size_t rounds = static_cast<size_t>(1) << workfactor; for(size_t r = 0; r != rounds; ++r) { key_expansion(key, length, nullptr, 0); key_expansion(salt, salt_length, nullptr, 0); } } }
std::string generate_passhash9(const std::string& pass, RandomNumberGenerator& rng, uint16_t work_factor, uint8_t alg_id) { BOTAN_ARG_CHECK(work_factor > 0 && work_factor < 512, "Invalid Passhash9 work factor"); std::unique_ptr<MessageAuthenticationCode> prf = get_pbkdf_prf(alg_id); if(!prf) throw Invalid_Argument("Passhash9: Algorithm id " + std::to_string(alg_id) + " is not defined"); PKCS5_PBKDF2 kdf(prf.release()); // takes ownership of pointer secure_vector<uint8_t> salt(SALT_BYTES); rng.randomize(salt.data(), salt.size()); const size_t kdf_iterations = WORK_FACTOR_SCALE * work_factor; secure_vector<uint8_t> blob; blob.push_back(alg_id); blob.push_back(get_byte(0, work_factor)); blob.push_back(get_byte(1, work_factor)); blob += salt; blob += kdf.derive_key(PASSHASH9_PBKDF_OUTPUT_LEN, pass, salt.data(), salt.size(), kdf_iterations).bits_of(); return MAGIC_PREFIX + base64_encode(blob); }
/* * Modified key schedule used for bcrypt password hashing */ void Blowfish::eks_key_schedule(const uint8_t key[], size_t length, const uint8_t salt[16], size_t workfactor) { /* * 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. * Bcrypt allows up to work factor 31 (2^31 iterations) */ BOTAN_ARG_CHECK(workfactor >= 4 && workfactor <= 18, "Invalid bcrypt work factor"); if(length > 72) { // Truncate longer passwords to the 72 char bcrypt limit length = 72; } m_P.resize(18); copy_mem(m_P.data(), P_INIT, 18); m_S.resize(1024); copy_mem(m_S.data(), S_INIT, 1024); key_expansion(key, length, salt); const uint8_t null_salt[16] = { 0 }; const size_t rounds = static_cast<size_t>(1) << workfactor; for(size_t r = 0; r != rounds; ++r) { key_expansion(key, length, null_salt); key_expansion(salt, 16, null_salt); } }
//static void SHA_3::expand(size_t bitrate, secure_vector<uint64_t>& S, uint8_t output[], size_t output_length) { BOTAN_ARG_CHECK(bitrate % 8 == 0); size_t Si = 0; for(size_t i = 0; i != output_length; ++i) { if(i > 0) { if(i % (bitrate / 8) == 0) { SHA_3::permute(S.data()); Si = 0; } else if(i % 8 == 0) { Si += 1; } } output[i] = get_byte(7 - (i % 8), S[Si]); } }
void X509_Time::encode_into(DER_Encoder& der) const { BOTAN_ARG_CHECK(m_tag == UTC_TIME || m_tag == GENERALIZED_TIME, "X509_Time: Bad encoding tag"); der.add_object(m_tag, UNIVERSAL, to_string()); }
//static void SHA_3::finish(size_t bitrate, secure_vector<uint64_t>& S, size_t S_pos, uint8_t init_pad, uint8_t fini_pad) { BOTAN_ARG_CHECK(bitrate % 64 == 0, "SHA-3 bitrate must be multiple of 64"); S[S_pos / 8] ^= static_cast<uint64_t>(init_pad) << (8 * (S_pos % 8)); S[(bitrate / 64) - 1] ^= static_cast<uint64_t>(fini_pad) << 56; SHA_3::permute(S.data()); }
secure_vector<uint8_t> rfc3394_keywrap(const secure_vector<uint8_t>& key, const SymmetricKey& kek) { BOTAN_ARG_CHECK(kek.size() == 16 || kek.size() == 24 || kek.size() == 32, "Invalid KEK length for NIST key wrap"); const std::string cipher_name = "AES-" + std::to_string(8*kek.size()); std::unique_ptr<BlockCipher> aes(BlockCipher::create_or_throw(cipher_name)); aes->set_key(kek); std::vector<uint8_t> wrapped = nist_key_wrap(key.data(), key.size(), *aes); return secure_vector<uint8_t>(wrapped.begin(), wrapped.end()); }
//static void SHA_3::expand(size_t bitrate, secure_vector<uint64_t>& S, uint8_t output[], size_t output_length) { BOTAN_ARG_CHECK(bitrate % 64 == 0, "SHA-3 bitrate must be multiple of 64"); const size_t byterate = bitrate / 8; while(output_length > 0) { const size_t copying = std::min(byterate, output_length); copy_out_vec_le(output, copying, S); output += copying; output_length -= copying; if(output_length > 0) { SHA_3::permute(S.data()); } } }
void X509_Time::set_to(const std::string& t_spec, ASN1_Tag spec_tag) { if(spec_tag == UTC_OR_GENERALIZED_TIME) { try { set_to(t_spec, GENERALIZED_TIME); return; } catch(Invalid_Argument&) {} // Not a generalized time. Continue try { set_to(t_spec, UTC_TIME); return; } catch(Invalid_Argument&) {} // Not a UTC time. Continue throw Invalid_Argument("Time string could not be parsed as GeneralizedTime or UTCTime."); } BOTAN_ASSERT(spec_tag == UTC_TIME || spec_tag == GENERALIZED_TIME, "Invalid tag."); BOTAN_ARG_CHECK(t_spec.size() > 0, "Time string must not be empty."); BOTAN_ARG_CHECK(t_spec.back() == 'Z', "Botan does not support times with timezones other than Z"); if(spec_tag == GENERALIZED_TIME) { BOTAN_ARG_CHECK(t_spec.size() == 15, "Invalid GeneralizedTime string"); } else if(spec_tag == UTC_TIME) { BOTAN_ARG_CHECK(t_spec.size() == 13, "Invalid UTCTime string"); } const size_t YEAR_SIZE = (spec_tag == UTC_TIME) ? 2 : 4; std::vector<std::string> params; std::string current; for(size_t j = 0; j != YEAR_SIZE; ++j) current += t_spec[j]; params.push_back(current); current.clear(); for(size_t j = YEAR_SIZE; j != t_spec.size() - 1; ++j) { current += t_spec[j]; if(current.size() == 2) { params.push_back(current); current.clear(); } } m_year = to_u32bit(params[0]); m_month = to_u32bit(params[1]); m_day = to_u32bit(params[2]); m_hour = to_u32bit(params[3]); m_minute = to_u32bit(params[4]); m_second = (params.size() == 6) ? to_u32bit(params[5]) : 0; m_tag = spec_tag; if(spec_tag == UTC_TIME) { if(m_year >= 50) m_year += 1900; else m_year += 2000; } if(!passes_sanity_check()) throw Invalid_Argument("Time " + t_spec + " does not seem to be valid"); }