diff options
author | Jack Lloyd <[email protected]> | 2016-02-28 02:43:57 -0500 |
---|---|---|
committer | Jack Lloyd <[email protected]> | 2016-03-20 09:38:17 -0400 |
commit | ada363473a9491a3b07e3bb6fa2b5fd9f12aec98 (patch) | |
tree | 0dc7eefb24c3d9983e45dd6e2e7f0876179c8c11 /src/lib/pubkey/pubkey.cpp | |
parent | f70a9de37d22282d8cca465632efd0044ab9008c (diff) |
Add PK_Decryptor::decrypt_or_random
Performs content checks on the value (expected length, expected bytes)
and in constant time returns either the decrypted value or a random value.
Diffstat (limited to 'src/lib/pubkey/pubkey.cpp')
-rw-r--r-- | src/lib/pubkey/pubkey.cpp | 85 |
1 files changed, 82 insertions, 3 deletions
diff --git a/src/lib/pubkey/pubkey.cpp b/src/lib/pubkey/pubkey.cpp index d3b711f1e..86665ed93 100644 --- a/src/lib/pubkey/pubkey.cpp +++ b/src/lib/pubkey/pubkey.cpp @@ -5,10 +5,11 @@ */ #include <botan/pubkey.h> -#include <botan/internal/algo_registry.h> #include <botan/der_enc.h> #include <botan/ber_dec.h> #include <botan/bigint.h> +#include <botan/internal/algo_registry.h> +#include <botan/internal/ct_utils.h> namespace Botan { @@ -30,6 +31,83 @@ T* get_pk_op(const std::string& what, const Key& key, const std::string& pad, } +secure_vector<byte> PK_Decryptor::decrypt(const byte in[], size_t length) const + { + byte valid_mask = 0; + + secure_vector<byte> decoded = do_decrypt(valid_mask, in, length); + + if(valid_mask == 0) + throw Decoding_Error("Invalid public key ciphertext, cannot decrypt"); + + return decoded; + } + +secure_vector<byte> +PK_Decryptor::decrypt_or_random(const byte in[], + size_t length, + size_t expected_pt_len, + RandomNumberGenerator& rng, + const byte required_content_bytes[], + const byte required_content_offsets[], + size_t required_contents_length) const + { + const secure_vector<byte> fake_pms = rng.random_vec(expected_pt_len); + //secure_vector<byte> decoded(expected_pt_len); + + CT::poison(in, length); + + byte valid_mask = 0; + secure_vector<byte> decoded = do_decrypt(valid_mask, in, length); + + valid_mask &= CT::is_equal(decoded.size(), expected_pt_len); + + // fixme + decoded.resize(expected_pt_len); + + for(size_t i = 0; i != required_contents_length; ++i) + { + /* + These values are chosen by the application and for TLS are constants, + so this early failure via assert is fine since we know 0,1 < 48 + + If there is a protocol that has content checks on the key where + the expected offsets are controllable by the attacker this could + still leak. + + Alternately could always reduce the offset modulo the length? + */ + + const byte exp = required_content_bytes[i]; + const byte off = required_content_offsets[i]; + + BOTAN_ASSERT(off < expected_pt_len, "Offset in range of plaintext"); + + valid_mask &= CT::is_equal(decoded[off], exp); + } + + CT::conditional_copy_mem(valid_mask, + /*output*/decoded.data(), + /*from0*/decoded.data(), + /*from1*/fake_pms.data(), + expected_pt_len); + + CT::unpoison(in, length); + CT::unpoison(decoded.data(), decoded.size()); + + return decoded; + } + +secure_vector<byte> +PK_Decryptor::decrypt_or_random(const byte in[], + size_t length, + size_t expected_pt_len, + RandomNumberGenerator& rng) const + { + return decrypt_or_random(in, length, expected_pt_len, rng, + nullptr, nullptr, 0); + } + PK_Encryptor_EME::PK_Encryptor_EME(const Public_Key& key, const std::string& padding, const std::string& provider) @@ -54,9 +132,10 @@ PK_Decryptor_EME::PK_Decryptor_EME(const Private_Key& key, const std::string& pa m_op.reset(get_pk_op<PK_Ops::Decryption>("Decryption", key, padding, provider)); } -secure_vector<byte> PK_Decryptor_EME::dec(const byte msg[], size_t length) const +secure_vector<byte> PK_Decryptor_EME::do_decrypt(byte& valid_mask, + const byte in[], size_t in_len) const { - return m_op->decrypt(msg, length); + return m_op->decrypt(valid_mask, in, in_len); } PK_KEM_Encryptor::PK_KEM_Encryptor(const Public_Key& key, |