aboutsummaryrefslogtreecommitdiffstats
path: root/src/lib/pubkey/pubkey.cpp
diff options
context:
space:
mode:
authorJack Lloyd <[email protected]>2016-02-28 02:43:57 -0500
committerJack Lloyd <[email protected]>2016-03-20 09:38:17 -0400
commitada363473a9491a3b07e3bb6fa2b5fd9f12aec98 (patch)
tree0dc7eefb24c3d9983e45dd6e2e7f0876179c8c11 /src/lib/pubkey/pubkey.cpp
parentf70a9de37d22282d8cca465632efd0044ab9008c (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.cpp85
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,