aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorJack Lloyd <[email protected]>2018-08-10 12:44:55 -0400
committerJack Lloyd <[email protected]>2018-08-10 12:44:55 -0400
commit87e4cd8c71511837b38406802f6e92e32b1890e9 (patch)
tree000aed5da6cfabd3009937a88cafb959f3988ea1 /src
parent256cfa3be098fb45d5c2de047f88786e88051e73 (diff)
Add functions to get size of PK ciphertext,plaintext
Needed for https://github.com/strongswan/strongswan/pull/109
Diffstat (limited to 'src')
-rw-r--r--src/lib/ffi/ffi.h16
-rw-r--r--src/lib/ffi/ffi_pk_op.cpp10
-rw-r--r--src/lib/prov/openssl/openssl_ec.cpp2
-rw-r--r--src/lib/prov/openssl/openssl_rsa.cpp4
-rw-r--r--src/lib/prov/pkcs11/p11_rsa.cpp4
-rw-r--r--src/lib/pubkey/dlies/dlies.cpp27
-rw-r--r--src/lib/pubkey/dlies/dlies.h4
-rw-r--r--src/lib/pubkey/ec_group/ec_group.cpp9
-rw-r--r--src/lib/pubkey/ec_group/ec_group.h2
-rw-r--r--src/lib/pubkey/ecies/ecies.cpp85
-rw-r--r--src/lib/pubkey/ecies/ecies.h16
-rw-r--r--src/lib/pubkey/elgamal/elgamal.cpp4
-rw-r--r--src/lib/pubkey/pk_ops.h4
-rw-r--r--src/lib/pubkey/pubkey.cpp10
-rw-r--r--src/lib/pubkey/pubkey.h19
-rw-r--r--src/lib/pubkey/rsa/rsa.cpp4
-rw-r--r--src/lib/pubkey/sm2/sm2_enc.cpp34
-rw-r--r--src/tests/test_ecies.cpp15
-rw-r--r--src/tests/test_ffi.cpp38
-rw-r--r--src/tests/test_pubkey.cpp8
20 files changed, 236 insertions, 79 deletions
diff --git a/src/lib/ffi/ffi.h b/src/lib/ffi/ffi.h
index 210c41eeb..19a65f946 100644
--- a/src/lib/ffi/ffi.h
+++ b/src/lib/ffi/ffi.h
@@ -1090,10 +1090,16 @@ BOTAN_PUBLIC_API(2,0) int botan_pk_op_encrypt_create(botan_pk_op_encrypt_t* op,
BOTAN_PUBLIC_API(2,0) int botan_pk_op_encrypt_destroy(botan_pk_op_encrypt_t op);
+BOTAN_PUBLIC_API(2,8) int botan_pk_op_encrypt_output_length(botan_pk_op_encrypt_t op,
+ size_t ptext_len,
+ size_t* ctext_len);
+
BOTAN_PUBLIC_API(2,0) int botan_pk_op_encrypt(botan_pk_op_encrypt_t op,
- botan_rng_t rng,
- uint8_t out[], size_t* out_len,
- const uint8_t plaintext[], size_t plaintext_len);
+ botan_rng_t rng,
+ uint8_t out[],
+ size_t* out_len,
+ const uint8_t plaintext[],
+ size_t plaintext_len);
/*
* Public Key Decryption
@@ -1106,6 +1112,10 @@ BOTAN_PUBLIC_API(2,0) int botan_pk_op_decrypt_create(botan_pk_op_decrypt_t* op,
uint32_t flags);
BOTAN_PUBLIC_API(2,0) int botan_pk_op_decrypt_destroy(botan_pk_op_decrypt_t op);
+BOTAN_PUBLIC_API(2,8) int botan_pk_op_decrypt_output_length(botan_pk_op_decrypt_t op,
+ size_t ctext_len,
+ size_t* ptext_len);
+
BOTAN_PUBLIC_API(2,0) int botan_pk_op_decrypt(botan_pk_op_decrypt_t op,
uint8_t out[], size_t* out_len,
const uint8_t ciphertext[], size_t ciphertext_len);
diff --git a/src/lib/ffi/ffi_pk_op.cpp b/src/lib/ffi/ffi_pk_op.cpp
index c714f7158..0f18fca3e 100644
--- a/src/lib/ffi/ffi_pk_op.cpp
+++ b/src/lib/ffi/ffi_pk_op.cpp
@@ -44,6 +44,11 @@ int botan_pk_op_encrypt_destroy(botan_pk_op_encrypt_t op)
return BOTAN_FFI_CHECKED_DELETE(op);
}
+int botan_pk_op_encrypt_output_length(botan_pk_op_encrypt_t op, size_t ptext_len, size_t* ctext_len)
+ {
+ return BOTAN_FFI_DO(Botan::PK_Encryptor, op, o, { *ctext_len = o.ciphertext_length(ptext_len); });
+ }
+
int botan_pk_op_encrypt(botan_pk_op_encrypt_t op,
botan_rng_t rng_obj,
uint8_t out[], size_t* out_len,
@@ -81,6 +86,11 @@ int botan_pk_op_decrypt_destroy(botan_pk_op_decrypt_t op)
return BOTAN_FFI_CHECKED_DELETE(op);
}
+int botan_pk_op_decrypt_output_length(botan_pk_op_decrypt_t op, size_t ctext_len, size_t* ptext_len)
+ {
+ return BOTAN_FFI_DO(Botan::PK_Decryptor, op, o, { *ptext_len = o.plaintext_length(ctext_len); });
+ }
+
int botan_pk_op_decrypt(botan_pk_op_decrypt_t op,
uint8_t out[], size_t* out_len,
const uint8_t ciphertext[], size_t ciphertext_len)
diff --git a/src/lib/prov/openssl/openssl_ec.cpp b/src/lib/prov/openssl/openssl_ec.cpp
index 33f277d5a..5da466c0c 100644
--- a/src/lib/prov/openssl/openssl_ec.cpp
+++ b/src/lib/prov/openssl/openssl_ec.cpp
@@ -232,7 +232,7 @@ class OpenSSL_ECDSA_Signing_Operation final : public PK_Ops::Signature_with_EMSA
m_order_bytes = (m_order_bits + 7) / 8;
}
- size_t signature_length() const { return 2*m_order_bytes; }
+ size_t signature_length() const override { return 2*m_order_bytes; }
secure_vector<uint8_t> raw_sign(const uint8_t msg[], size_t msg_len,
RandomNumberGenerator&) override
diff --git a/src/lib/prov/openssl/openssl_rsa.cpp b/src/lib/prov/openssl/openssl_rsa.cpp
index cf9c2b52b..8108526a1 100644
--- a/src/lib/prov/openssl/openssl_rsa.cpp
+++ b/src/lib/prov/openssl/openssl_rsa.cpp
@@ -57,6 +57,8 @@ class OpenSSL_RSA_Encryption_Operation final : public PK_Ops::Encryption
m_bits = 8 * (n_size() - pad_overhead) - 1;
}
+ size_t ciphertext_length(size_t) const override { return ::RSA_size(m_openssl_rsa.get()); }
+
size_t max_input_bits() const override { return m_bits; };
secure_vector<uint8_t> encrypt(const uint8_t msg[], size_t msg_len,
@@ -110,6 +112,8 @@ class OpenSSL_RSA_Decryption_Operation final : public PK_Ops::Decryption
throw OpenSSL_Error("d2i_RSAPrivateKey");
}
+ size_t plaintext_length(size_t) const override { return ::RSA_size(m_openssl_rsa.get()); }
+
secure_vector<uint8_t> decrypt(uint8_t& valid_mask,
const uint8_t msg[], size_t msg_len) override
{
diff --git a/src/lib/prov/pkcs11/p11_rsa.cpp b/src/lib/prov/pkcs11/p11_rsa.cpp
index 65bcd2d22..225e49bb2 100644
--- a/src/lib/prov/pkcs11/p11_rsa.cpp
+++ b/src/lib/prov/pkcs11/p11_rsa.cpp
@@ -131,6 +131,8 @@ class PKCS11_RSA_Decryption_Operation final : public PK_Ops::Decryption
m_bits = m_key.get_n().bits() - 1;
}
+ size_t plaintext_length(size_t) const override { return m_key.get_n().bytes(); }
+
secure_vector<uint8_t> decrypt(uint8_t& valid_mask, const uint8_t ciphertext[], size_t ciphertext_len) override
{
valid_mask = 0;
@@ -177,6 +179,8 @@ class PKCS11_RSA_Encryption_Operation final : public PK_Ops::Encryption
m_bits = 8 * (key.get_n().bytes() - m_mechanism.padding_size()) - 1;
}
+ size_t ciphertext_length(size_t) const override { return m_key.get_n().bytes(); }
+
size_t max_input_bits() const override
{
return m_bits;
diff --git a/src/lib/pubkey/dlies/dlies.cpp b/src/lib/pubkey/dlies/dlies.cpp
index a4603f0d7..5465401d1 100644
--- a/src/lib/pubkey/dlies/dlies.cpp
+++ b/src/lib/pubkey/dlies/dlies.cpp
@@ -97,20 +97,17 @@ std::vector<uint8_t> DLIES_Encryptor::enc(const uint8_t in[], size_t length,
/**
* Return the max size, in bytes, of a message
-* Not_Implemented if DLIES is used in XOR encryption mode
+* We assume DLIES is only used for key transport and limit the maximum size
+* to 512 bits
*/
size_t DLIES_Encryptor::maximum_input_size() const
{
- if(m_cipher)
- {
- // no limit in block cipher mode
- return std::numeric_limits<size_t>::max();
- }
- else
- {
- // No way to determine if the KDF will output enough bits for XORing with the plaintext?!
- throw Not_Implemented("Not implemented for XOR encryption mode");
- }
+ return 64;
+ }
+
+size_t DLIES_Encryptor::ciphertext_length(size_t ptext_len) const
+ {
+ return m_own_pub_key.size() + m_mac->output_length() + m_cipher->output_length(ptext_len);
}
DLIES_Decryptor::DLIES_Decryptor(const DH_PrivateKey& own_priv_key,
@@ -141,6 +138,14 @@ DLIES_Decryptor::DLIES_Decryptor(const DH_PrivateKey& own_priv_key,
DLIES_Decryptor(own_priv_key, rng, kdf, nullptr, 0, mac, mac_key_length)
{}
+size_t DLIES_Decryptor::plaintext_length(size_t ctext_len) const
+ {
+ if(ctext_len < m_pub_key_size + m_mac->output_length())
+ return 0; // will throw if attempted
+
+ return ctext_len - (m_pub_key_size + m_mac->output_length());
+ }
+
secure_vector<uint8_t> DLIES_Decryptor::do_decrypt(uint8_t& valid_mask,
const uint8_t msg[], size_t length) const
{
diff --git a/src/lib/pubkey/dlies/dlies.h b/src/lib/pubkey/dlies/dlies.h
index 8fa673491..640a8655e 100644
--- a/src/lib/pubkey/dlies/dlies.h
+++ b/src/lib/pubkey/dlies/dlies.h
@@ -79,6 +79,8 @@ class BOTAN_PUBLIC_API(2,0) DLIES_Encryptor final : public PK_Encryptor
size_t maximum_input_size() const override;
+ size_t ciphertext_length(size_t ptext_len) const override;
+
std::vector<uint8_t> m_other_pub_key;
std::vector<uint8_t> m_own_pub_key;
PK_Key_Agreement m_ka;
@@ -144,6 +146,8 @@ class BOTAN_PUBLIC_API(2,0) DLIES_Decryptor final : public PK_Decryptor
secure_vector<uint8_t> do_decrypt(uint8_t& valid_mask,
const uint8_t in[], size_t in_len) const override;
+ size_t plaintext_length(size_t ctext_len) const override;
+
const size_t m_pub_key_size;
PK_Key_Agreement m_ka;
std::unique_ptr<KDF> m_kdf;
diff --git a/src/lib/pubkey/ec_group/ec_group.cpp b/src/lib/pubkey/ec_group/ec_group.cpp
index 30a0bb141..f4419c7f0 100644
--- a/src/lib/pubkey/ec_group/ec_group.cpp
+++ b/src/lib/pubkey/ec_group/ec_group.cpp
@@ -526,6 +526,15 @@ const OID& EC_Group::get_curve_oid() const
return data().oid();
}
+size_t EC_Group::point_size(PointGFp::Compression_Type format) const
+ {
+ // Hybrid and standard format are (x,y), compressed is y, +1 format byte
+ if(format == PointGFp::COMPRESSED)
+ return (1 + get_p_bytes());
+ else
+ return (1 + 2*get_p_bytes());
+ }
+
PointGFp EC_Group::OS2ECP(const uint8_t bits[], size_t len) const
{
return Botan::OS2ECP(bits, len, data().curve());
diff --git a/src/lib/pubkey/ec_group/ec_group.h b/src/lib/pubkey/ec_group/ec_group.h
index f8c1c1a12..8a22cebce 100644
--- a/src/lib/pubkey/ec_group/ec_group.h
+++ b/src/lib/pubkey/ec_group/ec_group.h
@@ -302,6 +302,8 @@ class BOTAN_PUBLIC_API(2,0) EC_Group final
*/
PointGFp zero_point() const;
+ size_t point_size(PointGFp::Compression_Type format) const;
+
PointGFp OS2ECP(const uint8_t bits[], size_t len) const;
template<typename Alloc>
diff --git a/src/lib/pubkey/ecies/ecies.cpp b/src/lib/pubkey/ecies/ecies.cpp
index 793cca225..8f5c445ed 100644
--- a/src/lib/pubkey/ecies/ecies.cpp
+++ b/src/lib/pubkey/ecies/ecies.cpp
@@ -244,6 +244,8 @@ ECIES_Encryptor::ECIES_Encryptor(const PK_Key_Agreement_Key& private_key,
// convert only if necessary; m_eph_public_key_bin has been initialized with the uncompressed format
m_eph_public_key_bin = m_params.domain().OS2ECP(m_eph_public_key_bin).encode(ecies_params.compression_type());
}
+ m_mac = m_params.create_mac();
+ m_cipher = m_params.create_cipher(ENCRYPTION);
}
/*
@@ -254,6 +256,21 @@ ECIES_Encryptor::ECIES_Encryptor(RandomNumberGenerator& rng, const ECIES_System_
{
}
+size_t ECIES_Encryptor::maximum_input_size() const
+ {
+ /*
+ ECIES should just be used for key transport so this (arbitrary) limit
+ seems sufficient
+ */
+ return 64;
+ }
+
+size_t ECIES_Encryptor::ciphertext_length(size_t ptext_len) const
+ {
+ return m_eph_public_key_bin.size() +
+ m_mac->output_length() +
+ m_cipher->output_length(ptext_len);
+ }
/*
* ECIES Encryption according to ISO 18033-2
@@ -268,35 +285,31 @@ std::vector<uint8_t> ECIES_Encryptor::enc(const uint8_t data[], size_t length, R
const SymmetricKey secret_key = m_ka.derive_secret(m_eph_public_key_bin, m_other_point);
// encryption
- std::unique_ptr<Cipher_Mode> cipher = m_params.create_cipher(ENCRYPTION);
- BOTAN_ASSERT(cipher != nullptr, "Cipher is found");
- cipher->set_key(SymmetricKey(secret_key.begin(), m_params.dem_keylen()));
+ m_cipher->set_key(SymmetricKey(secret_key.begin(), m_params.dem_keylen()));
if(m_iv.size() != 0)
{
- cipher->start(m_iv.bits_of());
+ m_cipher->start(m_iv.bits_of());
}
secure_vector<uint8_t> encrypted_data(data, data + length);
- cipher->finish(encrypted_data);
+ m_cipher->finish(encrypted_data);
// concat elements
- std::unique_ptr<MessageAuthenticationCode> mac = m_params.create_mac();
- BOTAN_ASSERT(mac != nullptr, "MAC is found");
- secure_vector<uint8_t> out(m_eph_public_key_bin.size() + encrypted_data.size() + mac->output_length());
+ std::vector<uint8_t> out(m_eph_public_key_bin.size() + encrypted_data.size() + m_mac->output_length());
buffer_insert(out, 0, m_eph_public_key_bin);
buffer_insert(out, m_eph_public_key_bin.size(), encrypted_data);
// mac
- mac->set_key(secret_key.begin() + m_params.dem_keylen(), m_params.mac_keylen());
- mac->update(encrypted_data);
+ m_mac->set_key(secret_key.begin() + m_params.dem_keylen(), m_params.mac_keylen());
+ m_mac->update(encrypted_data);
if(!m_label.empty())
{
- mac->update(m_label);
+ m_mac->update(m_label);
}
- mac->final(out.data() + m_eph_public_key_bin.size() + encrypted_data.size());
+ m_mac->final(out.data() + m_eph_public_key_bin.size() + encrypted_data.size());
- return unlock(out);
+ return out;
}
@@ -317,6 +330,20 @@ ECIES_Decryptor::ECIES_Decryptor(const PK_Key_Agreement_Key& key,
throw Invalid_Argument("ECIES: gcd of cofactor and order must be 1 if check_mode is 0");
}
}
+
+ m_mac = m_params.create_mac();
+ m_cipher = m_params.create_cipher(DECRYPTION);
+ }
+
+size_t ECIES_Decryptor::plaintext_length(size_t ctext_len) const
+ {
+ const size_t point_size = m_params.domain().point_size(m_params.compression_type());
+ const size_t overhead = point_size + m_mac->output_length();
+
+ if(ctext_len < overhead)
+ return 0;
+
+ return m_cipher->output_length(ctext_len - overhead);
}
/**
@@ -324,25 +351,17 @@ ECIES_Decryptor::ECIES_Decryptor(const PK_Key_Agreement_Key& key,
*/
secure_vector<uint8_t> ECIES_Decryptor::do_decrypt(uint8_t& valid_mask, const uint8_t in[], size_t in_len) const
{
- size_t point_size = m_params.domain().get_p_bytes();
- if(m_params.compression_type() != PointGFp::COMPRESSED)
- {
- point_size *= 2; // uncompressed and hybrid contains x AND y
- }
- point_size += 1; // format byte
-
- std::unique_ptr<MessageAuthenticationCode> mac = m_params.create_mac();
- BOTAN_ASSERT(mac != nullptr, "MAC is found");
+ const size_t point_size = m_params.domain().point_size(m_params.compression_type());
- if(in_len < point_size + mac->output_length())
+ if(in_len < point_size + m_mac->output_length())
{
throw Decoding_Error("ECIES decryption: ciphertext is too short");
}
// extract data
const std::vector<uint8_t> other_public_key_bin(in, in + point_size); // the received (ephemeral) public key
- const std::vector<uint8_t> encrypted_data(in + point_size, in + in_len - mac->output_length());
- const std::vector<uint8_t> mac_data(in + in_len - mac->output_length(), in + in_len);
+ const std::vector<uint8_t> encrypted_data(in + point_size, in + in_len - m_mac->output_length());
+ const std::vector<uint8_t> mac_data(in + in_len - m_mac->output_length(), in + in_len);
// ISO 18033: step a
PointGFp other_public_key = m_params.domain().OS2ECP(other_public_key_bin);
@@ -358,25 +377,23 @@ secure_vector<uint8_t> ECIES_Decryptor::do_decrypt(uint8_t& valid_mask, const ui
const SymmetricKey secret_key = m_ka.derive_secret(other_public_key_bin, other_public_key);
// validate mac
- mac->set_key(secret_key.begin() + m_params.dem_keylen(), m_params.mac_keylen());
- mac->update(encrypted_data);
+ m_mac->set_key(secret_key.begin() + m_params.dem_keylen(), m_params.mac_keylen());
+ m_mac->update(encrypted_data);
if(!m_label.empty())
{
- mac->update(m_label);
+ m_mac->update(m_label);
}
- const secure_vector<uint8_t> calculated_mac = mac->final();
+ const secure_vector<uint8_t> calculated_mac = m_mac->final();
valid_mask = CT::expand_mask<uint8_t>(constant_time_compare(mac_data.data(), calculated_mac.data(), mac_data.size()));
if(valid_mask)
{
// decrypt data
- std::unique_ptr<Cipher_Mode> cipher = m_params.create_cipher(DECRYPTION);
- BOTAN_ASSERT(cipher != nullptr, "Cipher is found");
- cipher->set_key(SymmetricKey(secret_key.begin(), m_params.dem_keylen()));
+ m_cipher->set_key(SymmetricKey(secret_key.begin(), m_params.dem_keylen()));
if(m_iv.size() != 0)
{
- cipher->start(m_iv.bits_of());
+ m_cipher->start(m_iv.bits_of());
}
try
@@ -384,7 +401,7 @@ secure_vector<uint8_t> ECIES_Decryptor::do_decrypt(uint8_t& valid_mask, const ui
// the decryption can fail:
// e.g. Integrity_Failure is thrown if GCM is used and the message does not have a valid tag
secure_vector<uint8_t> decrypted_data(encrypted_data.begin(), encrypted_data.end());
- cipher->finish(decrypted_data);
+ m_cipher->finish(decrypted_data);
return decrypted_data;
}
catch(...)
diff --git a/src/lib/pubkey/ecies/ecies.h b/src/lib/pubkey/ecies/ecies.h
index f7d055dea..e36f94568 100644
--- a/src/lib/pubkey/ecies/ecies.h
+++ b/src/lib/pubkey/ecies/ecies.h
@@ -15,14 +15,13 @@
#include <botan/pubkey.h>
#include <botan/secmem.h>
#include <botan/symkey.h>
+#include <botan/mac.h>
#include <memory>
#include <string>
#include <vector>
-#include <limits>
namespace Botan {
-class MessageAuthenticationCode;
class RandomNumberGenerator;
enum class ECIES_Flags : uint32_t
@@ -254,13 +253,14 @@ class BOTAN_PUBLIC_API(2,0) ECIES_Encryptor final : public PK_Encryptor
private:
std::vector<uint8_t> enc(const uint8_t data[], size_t length, RandomNumberGenerator&) const override;
- inline size_t maximum_input_size() const override
- {
- return std::numeric_limits<size_t>::max();
- }
+ size_t maximum_input_size() const override;
+
+ size_t ciphertext_length(size_t ptext_len) const override;
const ECIES_KA_Operation m_ka;
const ECIES_System_Params m_params;
+ std::unique_ptr<MessageAuthenticationCode> m_mac;
+ std::unique_ptr<Cipher_Mode> m_cipher;
std::vector<uint8_t> m_eph_public_key_bin;
InitializationVector m_iv;
PointGFp m_other_point;
@@ -298,8 +298,12 @@ class BOTAN_PUBLIC_API(2,0) ECIES_Decryptor final : public PK_Decryptor
private:
secure_vector<uint8_t> do_decrypt(uint8_t& valid_mask, const uint8_t in[], size_t in_len) const override;
+ size_t plaintext_length(size_t ctext_len) const override;
+
const ECIES_KA_Operation m_ka;
const ECIES_System_Params m_params;
+ std::unique_ptr<MessageAuthenticationCode> m_mac;
+ std::unique_ptr<Cipher_Mode> m_cipher;
InitializationVector m_iv;
std::vector<uint8_t> m_label;
};
diff --git a/src/lib/pubkey/elgamal/elgamal.cpp b/src/lib/pubkey/elgamal/elgamal.cpp
index 1f62c2b1d..6c2d6bccc 100644
--- a/src/lib/pubkey/elgamal/elgamal.cpp
+++ b/src/lib/pubkey/elgamal/elgamal.cpp
@@ -75,6 +75,8 @@ class ElGamal_Encryption_Operation final : public PK_Ops::Encryption_with_EME
{
public:
+ size_t ciphertext_length(size_t) const override { return 2*m_group.p_bytes(); }
+
size_t max_raw_input_bits() const override { return m_group.p_bits() - 1; }
ElGamal_Encryption_Operation(const ElGamal_PublicKey& key, const std::string& eme);
@@ -124,6 +126,8 @@ class ElGamal_Decryption_Operation final : public PK_Ops::Decryption_with_EME
const std::string& eme,
RandomNumberGenerator& rng);
+ size_t plaintext_length(size_t) const override { return m_group.p_bytes(); }
+
secure_vector<uint8_t> raw_decrypt(const uint8_t msg[], size_t msg_len) override;
private:
const DL_Group m_group;
diff --git a/src/lib/pubkey/pk_ops.h b/src/lib/pubkey/pk_ops.h
index 3e38cc8ca..3f794f00d 100644
--- a/src/lib/pubkey/pk_ops.h
+++ b/src/lib/pubkey/pk_ops.h
@@ -42,6 +42,8 @@ class BOTAN_PUBLIC_API(2,0) Encryption
virtual size_t max_input_bits() const = 0;
+ virtual size_t ciphertext_length(size_t ptext_len) const = 0;
+
virtual ~Encryption() = default;
};
@@ -55,6 +57,8 @@ class BOTAN_PUBLIC_API(2,0) Decryption
const uint8_t ciphertext[],
size_t ciphertext_len) = 0;
+ virtual size_t plaintext_length(size_t ctext_len) const = 0;
+
virtual ~Decryption() = default;
};
diff --git a/src/lib/pubkey/pubkey.cpp b/src/lib/pubkey/pubkey.cpp
index 6296adbb2..fef81a620 100644
--- a/src/lib/pubkey/pubkey.cpp
+++ b/src/lib/pubkey/pubkey.cpp
@@ -96,6 +96,11 @@ PK_Encryptor_EME::PK_Encryptor_EME(const Public_Key& key,
PK_Encryptor_EME::~PK_Encryptor_EME() { /* for unique_ptr */ }
+size_t PK_Encryptor_EME::ciphertext_length(size_t ptext_len) const
+ {
+ return m_op->ciphertext_length(ptext_len);
+ }
+
std::vector<uint8_t>
PK_Encryptor_EME::enc(const uint8_t in[], size_t length, RandomNumberGenerator& rng) const
{
@@ -119,6 +124,11 @@ PK_Decryptor_EME::PK_Decryptor_EME(const Private_Key& key,
PK_Decryptor_EME::~PK_Decryptor_EME() { /* for unique_ptr */ }
+size_t PK_Decryptor_EME::plaintext_length(size_t ctext_len) const
+ {
+ return m_op->plaintext_length(ctext_len);
+ }
+
secure_vector<uint8_t> PK_Decryptor_EME::do_decrypt(uint8_t& valid_mask,
const uint8_t in[], size_t in_len) const
{
diff --git a/src/lib/pubkey/pubkey.h b/src/lib/pubkey/pubkey.h
index 8328861fd..a1404135d 100644
--- a/src/lib/pubkey/pubkey.h
+++ b/src/lib/pubkey/pubkey.h
@@ -66,6 +66,11 @@ class BOTAN_PUBLIC_API(2,0) PK_Encryptor
*/
virtual size_t maximum_input_size() const = 0;
+ /**
+ * Return an upper bound on the ciphertext length
+ */
+ virtual size_t ciphertext_length(size_t ctext_len) const = 0;
+
PK_Encryptor() = default;
virtual ~PK_Encryptor() = default;
@@ -140,6 +145,12 @@ class BOTAN_PUBLIC_API(2,0) PK_Decryptor
const uint8_t required_content_offsets[],
size_t required_contents) const;
+ /**
+ * Return an upper bound on the plaintext length for a particular
+ * ciphertext input length
+ */
+ virtual size_t plaintext_length(size_t ctext_len) const = 0;
+
PK_Decryptor() = default;
virtual ~PK_Decryptor() = default;
@@ -547,6 +558,12 @@ class BOTAN_PUBLIC_API(2,0) PK_Encryptor_EME final : public PK_Encryptor
PK_Encryptor_EME& operator=(const PK_Encryptor_EME&) = delete;
PK_Encryptor_EME(const PK_Encryptor_EME&) = delete;
+
+ /**
+ * Return an upper bound on the ciphertext length for a particular
+ * plaintext input length
+ */
+ size_t ciphertext_length(size_t ptext_len) const override;
private:
std::vector<uint8_t> enc(const uint8_t[], size_t,
RandomNumberGenerator& rng) const override;
@@ -586,6 +603,8 @@ class BOTAN_PUBLIC_API(2,0) PK_Decryptor_EME final : public PK_Decryptor
PK_Decryptor_EME(key, system_rng(), eme, provider) {}
#endif
+ size_t plaintext_length(size_t ptext_len) const override;
+
~PK_Decryptor_EME();
PK_Decryptor_EME& operator=(const PK_Decryptor_EME&) = delete;
PK_Decryptor_EME(const PK_Decryptor_EME&) = delete;
diff --git a/src/lib/pubkey/rsa/rsa.cpp b/src/lib/pubkey/rsa/rsa.cpp
index eefbea869..ec3c35ef1 100644
--- a/src/lib/pubkey/rsa/rsa.cpp
+++ b/src/lib/pubkey/rsa/rsa.cpp
@@ -328,6 +328,8 @@ class RSA_Decryption_Operation final : public PK_Ops::Decryption_with_EME,
{
}
+ size_t plaintext_length(size_t) const override { return m_mod_bytes; }
+
secure_vector<uint8_t> raw_decrypt(const uint8_t msg[], size_t msg_len) override
{
const BigInt m(msg, msg_len);
@@ -405,6 +407,8 @@ class RSA_Encryption_Operation final : public PK_Ops::Encryption_with_EME,
{
}
+ size_t ciphertext_length(size_t) const override { return m_n.bytes(); }
+
size_t max_raw_input_bits() const override { return get_max_input_bits(); }
secure_vector<uint8_t> raw_encrypt(const uint8_t msg[], size_t msg_len,
diff --git a/src/lib/pubkey/sm2/sm2_enc.cpp b/src/lib/pubkey/sm2/sm2_enc.cpp
index 3da4275b3..856cb5cbc 100644
--- a/src/lib/pubkey/sm2/sm2_enc.cpp
+++ b/src/lib/pubkey/sm2/sm2_enc.cpp
@@ -27,7 +27,10 @@ class SM2_Encryption_Operation final : public PK_Ops::Encryption
m_kdf_hash(kdf_hash),
m_ws(PointGFp::WORKSPACE_SIZE),
m_mul_public_point(key.public_point(), rng, m_ws)
- {}
+ {
+ std::unique_ptr<HashFunction> hash = HashFunction::create_or_throw(m_kdf_hash);
+ m_hash_size = hash->output_length();
+ }
size_t max_input_bits() const override
{
@@ -35,6 +38,14 @@ class SM2_Encryption_Operation final : public PK_Ops::Encryption
return 512;
}
+ size_t ciphertext_length(size_t ptext_len) const override
+ {
+ const size_t elem_size = m_group.get_order_bytes();
+ const size_t der_overhead = 12;
+
+ return der_overhead + 2*elem_size + m_hash_size + ptext_len;
+ }
+
secure_vector<uint8_t> encrypt(const uint8_t msg[],
size_t msg_len,
RandomNumberGenerator& rng) override
@@ -95,6 +106,7 @@ class SM2_Encryption_Operation final : public PK_Ops::Encryption
std::vector<BigInt> m_ws;
PointGFp_Var_Point_Precompute m_mul_public_point;
+ size_t m_hash_size;
};
class SM2_Decryption_Operation final : public PK_Ops::Decryption
@@ -106,7 +118,24 @@ class SM2_Decryption_Operation final : public PK_Ops::Decryption
m_key(key),
m_rng(rng),
m_kdf_hash(kdf_hash)
- {}
+ {
+ std::unique_ptr<HashFunction> hash = HashFunction::create_or_throw(m_kdf_hash);
+ m_hash_size = hash->output_length();
+ }
+
+ size_t plaintext_length(size_t ptext_len) const override
+ {
+ /*
+ * This ignores the DER encoding and so overestimates the
+ * plaintext length by 12 bytes or so
+ */
+ const size_t elem_size = m_key.domain().get_order_bytes();
+
+ if(ptext_len < 2*elem_size + m_hash_size)
+ return 0;
+
+ return ptext_len - (2*elem_size + m_hash_size);
+ }
secure_vector<uint8_t> decrypt(uint8_t& valid_mask,
const uint8_t ciphertext[],
@@ -202,6 +231,7 @@ class SM2_Decryption_Operation final : public PK_Ops::Decryption
RandomNumberGenerator& m_rng;
const std::string m_kdf_hash;
std::vector<BigInt> m_ws;
+ size_t m_hash_size;
};
}
diff --git a/src/tests/test_ecies.cpp b/src/tests/test_ecies.cpp
index 63619a8a4..8e167f5bb 100644
--- a/src/tests/test_ecies.cpp
+++ b/src/tests/test_ecies.cpp
@@ -279,10 +279,9 @@ Test::Result test_kdf_not_found()
"HMAC(SHA-512)", 20, Botan::PointGFp::Compression_Type::COMPRESSED,
flags);
- Botan::ECIES_Encryptor ecies_enc(private_key, ecies_params, Test::rng());
-
- result.test_throws("kdf not found", [ &ecies_enc ]()
+ result.test_throws("kdf not found", [&]()
{
+ Botan::ECIES_Encryptor ecies_enc(private_key, ecies_params, Test::rng());
ecies_enc.encrypt(std::vector<uint8_t>(8), Test::rng());
});
@@ -304,10 +303,9 @@ Test::Result test_mac_not_found()
"XYZMAC(SHA-512)", 20, Botan::PointGFp::Compression_Type::COMPRESSED,
flags);
- Botan::ECIES_Encryptor ecies_enc(private_key, ecies_params, Test::rng());
-
- result.test_throws("mac not found", [ &ecies_enc ]()
+ result.test_throws("mac not found", [&]()
{
+ Botan::ECIES_Encryptor ecies_enc(private_key, ecies_params, Test::rng());
ecies_enc.encrypt(std::vector<uint8_t>(8), Test::rng());
});
@@ -329,10 +327,9 @@ Test::Result test_cipher_not_found()
"HMAC(SHA-512)", 20, Botan::PointGFp::Compression_Type::COMPRESSED,
flags);
- Botan::ECIES_Encryptor ecies_enc(private_key, ecies_params, Test::rng());
-
- result.test_throws("cipher not found", [ &ecies_enc ]()
+ result.test_throws("cipher not found", [&]()
{
+ Botan::ECIES_Encryptor ecies_enc(private_key, ecies_params, Test::rng());
ecies_enc.encrypt(std::vector<uint8_t>(8), Test::rng());
});
diff --git a/src/tests/test_ffi.cpp b/src/tests/test_ffi.cpp
index 010b1b4eb..76f8635f1 100644
--- a/src/tests/test_ffi.cpp
+++ b/src/tests/test_ffi.cpp
@@ -1474,8 +1474,9 @@ class FFI_Unit_Tests final : public Test
std::vector<uint8_t> plaintext(32);
TEST_FFI_OK(botan_rng_get, (rng, plaintext.data(), plaintext.size()));
- std::vector<uint8_t> ciphertext(256); // TODO: no way to know this size from API
- size_t ctext_len = ciphertext.size();
+ size_t ctext_len;
+ TEST_FFI_OK(botan_pk_op_encrypt_output_length, (encrypt, plaintext.size(), &ctext_len));
+ std::vector<uint8_t> ciphertext(ctext_len);
if(TEST_FFI_OK(botan_pk_op_encrypt, (encrypt, rng,
ciphertext.data(), &ctext_len,
@@ -1486,8 +1487,9 @@ class FFI_Unit_Tests final : public Test
botan_pk_op_decrypt_t decrypt;
if(TEST_FFI_OK(botan_pk_op_decrypt_create, (&decrypt, priv, "OAEP(SHA-256)", 0)))
{
- std::vector<uint8_t> decrypted(256); // TODO as with above
- size_t decrypted_len = decrypted.size();
+ size_t decrypted_len;
+ TEST_FFI_OK(botan_pk_op_decrypt_output_length, (decrypt, ciphertext.size(), &decrypted_len));
+ std::vector<uint8_t> decrypted(decrypted_len);
TEST_FFI_OK(botan_pk_op_decrypt, (decrypt, decrypted.data(), &decrypted_len,
ciphertext.data(), ciphertext.size()));
decrypted.resize(decrypted_len);
@@ -1854,13 +1856,16 @@ class FFI_Unit_Tests final : public Test
std::vector<uint8_t> message(32);
- std::vector<uint8_t> ciphertext(4096);
+ std::vector<uint8_t> ciphertext;
TEST_FFI_OK(botan_rng_get, (rng, message.data(), message.size()));
botan_pk_op_encrypt_t enc;
if(TEST_FFI_OK(botan_pk_op_encrypt_create, (&enc, loaded_pubkey, "", 0)))
{
- size_t ctext_len = ciphertext.size();
+ size_t ctext_len;
+ TEST_FFI_OK(botan_pk_op_encrypt_output_length, (enc, message.size(), &ctext_len));
+
+ ciphertext.resize(ctext_len);
TEST_FFI_OK(botan_pk_op_encrypt, (enc, rng, ciphertext.data(), &ctext_len,
message.data(), message.size()));
ciphertext.resize(ctext_len);
@@ -2140,29 +2145,36 @@ class FFI_Unit_Tests final : public Test
botan_mp_destroy(y);
botan_mp_destroy(x);
-
std::vector<uint8_t> plaintext(16, 0xFF);
- std::vector<uint8_t> ciphertext(p_len*2, 0);
- std::vector<uint8_t> decryption(16, 0);
+ std::vector<uint8_t> ciphertext;
+ std::vector<uint8_t> decryption;
// Test encryption
botan_pk_op_encrypt_t op_enc;
- size_t ct_len = ciphertext.size();
if (TEST_FFI_OK(botan_pk_op_encrypt_create, (&op_enc, loaded_pubkey, "Raw", 0)))
{
- TEST_FFI_OK(botan_pk_op_encrypt, (op_enc, rng, ciphertext.data(), &ct_len, plaintext.data(), plaintext.size()));
+ size_t ctext_len;
+ TEST_FFI_OK(botan_pk_op_encrypt_output_length, (op_enc, plaintext.size(), &ctext_len));
+ ciphertext.resize(ctext_len);
+ TEST_FFI_OK(botan_pk_op_encrypt, (op_enc, rng, ciphertext.data(), &ctext_len, plaintext.data(), plaintext.size()));
+ ciphertext.resize(ctext_len);
TEST_FFI_OK(botan_pk_op_encrypt_destroy, (op_enc));
}
// Test decryption
botan_pk_op_decrypt_t op_dec;
- size_t pt_len = decryption.size();
if (TEST_FFI_OK(botan_pk_op_decrypt_create, (&op_dec, loaded_privkey, "Raw", 0)))
{
- TEST_FFI_OK(botan_pk_op_decrypt, (op_dec, decryption.data(), &pt_len, ciphertext.data(), ct_len));
+ size_t ptext_len;
+ TEST_FFI_OK(botan_pk_op_decrypt_output_length, (op_dec, ciphertext.size(), &ptext_len));
+ decryption.resize(ptext_len);
+ TEST_FFI_OK(botan_pk_op_decrypt, (op_dec, decryption.data(), &ptext_len, ciphertext.data(), ciphertext.size()));
+ decryption.resize(ptext_len);
TEST_FFI_OK(botan_pk_op_decrypt_destroy, (op_dec));
}
+ result.test_eq("decryption worked", decryption, plaintext);
+
TEST_FFI_OK(botan_pubkey_destroy, (loaded_pubkey));
TEST_FFI_OK(botan_pubkey_destroy, (pub));
TEST_FFI_OK(botan_privkey_destroy, (loaded_privkey));
diff --git a/src/tests/test_pubkey.cpp b/src/tests/test_pubkey.cpp
index 6b40e8d3c..bc2d19bb7 100644
--- a/src/tests/test_pubkey.cpp
+++ b/src/tests/test_pubkey.cpp
@@ -310,6 +310,10 @@ PK_Encryption_Decryption_Test::run_one_test(const std::string& pad_hdr, const Va
try
{
decrypted = decryptor->decrypt(ciphertext);
+
+ result.test_lte("Plaintext within length",
+ decrypted.size(),
+ decryptor->plaintext_length(ciphertext.size()));
}
catch(Botan::Exception& e)
{
@@ -358,6 +362,10 @@ PK_Encryption_Decryption_Test::run_one_test(const std::string& pad_hdr, const Va
const std::vector<uint8_t> generated_ciphertext =
encryptor->encrypt(plaintext, kat_rng ? *kat_rng : Test::rng());
+ result.test_lte("Ciphertext within length",
+ generated_ciphertext.size(),
+ encryptor->ciphertext_length(plaintext.size()));
+
if(enc_provider == "base")
{
result.test_eq(enc_provider, "generated ciphertext matches KAT",