mirror of
https://github.com/RGBCube/serenity
synced 2025-07-27 09:07:45 +00:00
LibCrypto+LibTLS: Reformat everything
I have no idea how I'll squash _this_ one...
This commit is contained in:
parent
a1e1570552
commit
05e2c7d9cf
14 changed files with 1434 additions and 1426 deletions
|
@ -31,29 +31,29 @@
|
|||
namespace Crypto {
|
||||
namespace PK {
|
||||
|
||||
enum class VerificationConsistency {
|
||||
Consistent,
|
||||
Inconsistent
|
||||
};
|
||||
enum class VerificationConsistency {
|
||||
Consistent,
|
||||
Inconsistent
|
||||
};
|
||||
|
||||
template <typename HashFunction>
|
||||
class Code {
|
||||
public:
|
||||
template <typename... Args>
|
||||
Code(Args... args)
|
||||
: m_hasher(args...)
|
||||
{
|
||||
}
|
||||
template<typename HashFunction>
|
||||
class Code {
|
||||
public:
|
||||
template<typename... Args>
|
||||
Code(Args... args)
|
||||
: m_hasher(args...)
|
||||
{
|
||||
}
|
||||
|
||||
virtual void encode(const ByteBuffer& in, ByteBuffer& out, size_t em_bits) = 0;
|
||||
virtual VerificationConsistency verify(const ByteBuffer& msg, const ByteBuffer& emsg, size_t em_bits) = 0;
|
||||
virtual void encode(const ByteBuffer& in, ByteBuffer& out, size_t em_bits) = 0;
|
||||
virtual VerificationConsistency verify(const ByteBuffer& msg, const ByteBuffer& emsg, size_t em_bits) = 0;
|
||||
|
||||
const HashFunction& hasher() const { return m_hasher; }
|
||||
HashFunction& hasher() { return m_hasher; }
|
||||
const HashFunction& hasher() const { return m_hasher; }
|
||||
HashFunction& hasher() { return m_hasher; }
|
||||
|
||||
protected:
|
||||
HashFunction m_hasher;
|
||||
};
|
||||
protected:
|
||||
HashFunction m_hasher;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -33,147 +33,148 @@ static constexpr u8 zeros[] { 0, 0, 0, 0, 0, 0, 0, 0 };
|
|||
namespace Crypto {
|
||||
namespace PK {
|
||||
|
||||
template <typename HashFunction, size_t SaltSize>
|
||||
class EMSA_PSS : public Code<HashFunction> {
|
||||
public:
|
||||
template <typename... Args>
|
||||
EMSA_PSS(Args... args)
|
||||
: Code<HashFunction>(args...)
|
||||
{
|
||||
m_buffer = ByteBuffer::wrap(m_data_buffer, sizeof(m_data_buffer));
|
||||
template<typename HashFunction, size_t SaltSize>
|
||||
class EMSA_PSS : public Code<HashFunction> {
|
||||
public:
|
||||
template<typename... Args>
|
||||
EMSA_PSS(Args... args)
|
||||
: Code<HashFunction>(args...)
|
||||
{
|
||||
m_buffer = ByteBuffer::wrap(m_data_buffer, sizeof(m_data_buffer));
|
||||
}
|
||||
|
||||
static constexpr auto SaltLength = SaltSize;
|
||||
|
||||
virtual void encode(const ByteBuffer& in, ByteBuffer& out, size_t em_bits) override
|
||||
{
|
||||
// FIXME: we're supposed to check if in.size() > HashFunction::input_limitation
|
||||
// however, all of our current hash functions can hash unlimited blocks
|
||||
auto& hash_fn = this->hasher();
|
||||
hash_fn.update(in);
|
||||
auto message_hash = hash_fn.digest();
|
||||
auto hash_length = hash_fn.DigestSize;
|
||||
auto em_length = (em_bits + 7) / 8;
|
||||
u8 salt[SaltLength];
|
||||
|
||||
arc4random_buf(salt, SaltLength);
|
||||
|
||||
if (em_length < hash_length + SaltLength + 2) {
|
||||
dbg() << "Ooops...encoding error";
|
||||
return;
|
||||
}
|
||||
|
||||
static constexpr auto SaltLength = SaltSize;
|
||||
m_buffer.overwrite(0, zeros, 8);
|
||||
m_buffer.overwrite(8, message_hash.data, HashFunction::DigestSize);
|
||||
m_buffer.overwrite(8 + HashFunction::DigestSize, salt, SaltLength);
|
||||
|
||||
virtual void encode(const ByteBuffer& in, ByteBuffer& out, size_t em_bits) override
|
||||
{
|
||||
// FIXME: we're supposed to check if in.size() > HashFunction::input_limitation
|
||||
// however, all of our current hash functions can hash unlimited blocks
|
||||
auto& hash_fn = this->hasher();
|
||||
hash_fn.update(in);
|
||||
auto message_hash = hash_fn.digest();
|
||||
auto hash_length = hash_fn.DigestSize;
|
||||
auto em_length = (em_bits + 7) / 8;
|
||||
u8 salt[SaltLength];
|
||||
hash_fn.update(m_buffer);
|
||||
auto hash = hash_fn.digest();
|
||||
|
||||
arc4random_buf(salt, SaltLength);
|
||||
u8 DB_data[em_length - HashFunction::DigestSize - 1];
|
||||
auto DB = ByteBuffer::wrap(DB_data, em_length - HashFunction::DigestSize - 1);
|
||||
auto DB_offset = 0;
|
||||
|
||||
if (em_length < hash_length + SaltLength + 2) {
|
||||
dbg() << "Ooops...encoding error";
|
||||
return;
|
||||
}
|
||||
for (size_t i = 0; i < em_length - SaltLength - HashFunction::DigestSize - 2; ++i)
|
||||
DB[DB_offset++] = 0;
|
||||
|
||||
m_buffer.overwrite(0, zeros, 8);
|
||||
m_buffer.overwrite(8, message_hash.data, HashFunction::DigestSize);
|
||||
m_buffer.overwrite(8 + HashFunction::DigestSize, salt, SaltLength);
|
||||
DB[DB_offset++] = 0x01;
|
||||
|
||||
hash_fn.update(m_buffer);
|
||||
auto hash = hash_fn.digest();
|
||||
DB.overwrite(DB_offset, salt, SaltLength);
|
||||
|
||||
u8 DB_data[em_length - HashFunction::DigestSize - 1];
|
||||
auto DB = ByteBuffer::wrap(DB_data, em_length - HashFunction::DigestSize - 1);
|
||||
auto DB_offset = 0;
|
||||
auto mask_length = em_length - HashFunction::DigestSize - 1;
|
||||
|
||||
for (size_t i = 0; i < em_length - SaltLength - HashFunction::DigestSize - 2; ++i)
|
||||
DB[DB_offset++] = 0;
|
||||
u8 DB_mask[mask_length];
|
||||
auto DB_mask_buffer = ByteBuffer::wrap(DB_mask, mask_length);
|
||||
// FIXME: we should probably allow reading from u8*
|
||||
auto hash_buffer = ByteBuffer::wrap(hash.data, HashFunction::DigestSize);
|
||||
MGF1(hash_buffer, mask_length, DB_mask_buffer);
|
||||
|
||||
DB[DB_offset++] = 0x01;
|
||||
for (size_t i = 0; i < DB.size(); ++i)
|
||||
DB_data[i] ^= DB_mask[i];
|
||||
|
||||
DB.overwrite(DB_offset, salt, SaltLength);
|
||||
auto count = (8 - (em_length * 8 - em_bits));
|
||||
DB_data[0] &= (0xff >> count) << count;
|
||||
|
||||
auto mask_length = em_length - HashFunction::DigestSize - 1;
|
||||
out.overwrite(0, DB.data(), DB.size());
|
||||
out.overwrite(DB.size(), hash.data, hash_fn.DigestSize);
|
||||
out[DB.size() + hash_fn.DigestSize] = 0xbc;
|
||||
}
|
||||
|
||||
u8 DB_mask[mask_length];
|
||||
auto DB_mask_buffer = ByteBuffer::wrap(DB_mask, mask_length);
|
||||
// FIXME: we should probably allow reading from u8*
|
||||
auto hash_buffer = ByteBuffer::wrap(hash.data, HashFunction::DigestSize);
|
||||
MGF1(hash_buffer, mask_length, DB_mask_buffer);
|
||||
virtual VerificationConsistency verify(const ByteBuffer& msg, const ByteBuffer& emsg, size_t em_bits) override
|
||||
{
|
||||
auto& hash_fn = this->hasher();
|
||||
hash_fn.update(msg);
|
||||
auto message_hash = hash_fn.digest();
|
||||
|
||||
for (size_t i = 0; i < DB.size(); ++i)
|
||||
DB_data[i] ^= DB_mask[i];
|
||||
if (emsg.size() < HashFunction::DigestSize + SaltLength + 2)
|
||||
return VerificationConsistency::Inconsistent;
|
||||
|
||||
auto count = (8 - (em_length * 8 - em_bits));
|
||||
DB_data[0] &= (0xff >> count) << count;
|
||||
if (emsg[emsg.size() - 1] != 0xbc)
|
||||
return VerificationConsistency::Inconsistent;
|
||||
|
||||
out.overwrite(0, DB.data(), DB.size());
|
||||
out.overwrite(DB.size(), hash.data, hash_fn.DigestSize);
|
||||
out[DB.size() + hash_fn.DigestSize] = 0xbc;
|
||||
auto mask_length = emsg.size() - HashFunction::DigestSize - 1;
|
||||
auto masked_DB = emsg.slice_view(0, mask_length);
|
||||
auto H = emsg.slice_view(mask_length, HashFunction::DigestSize);
|
||||
|
||||
auto length_to_check = 8 * emsg.size() - em_bits;
|
||||
auto octet = masked_DB[0];
|
||||
for (size_t i = 0; i < length_to_check; ++i)
|
||||
if ((octet >> (8 - i)) & 0x01)
|
||||
return VerificationConsistency::Inconsistent;
|
||||
|
||||
u8 DB_mask[mask_length];
|
||||
auto DB_mask_buffer = ByteBuffer::wrap(DB_mask, mask_length);
|
||||
MGF1(H, mask_length, DB_mask_buffer);
|
||||
|
||||
u8 DB[mask_length];
|
||||
|
||||
for (size_t i = 0; i < mask_length; ++i)
|
||||
DB[i] = masked_DB[i] ^ DB_mask[i];
|
||||
|
||||
DB[0] &= 0xff >> (8 - length_to_check);
|
||||
|
||||
auto check_octets = emsg.size() - HashFunction::DigestSize - SaltLength - 2;
|
||||
for (size_t i = 0; i < check_octets; ++i) {
|
||||
if (DB[i])
|
||||
return VerificationConsistency::Inconsistent;
|
||||
}
|
||||
|
||||
virtual VerificationConsistency verify(const ByteBuffer& msg, const ByteBuffer& emsg, size_t em_bits) override
|
||||
{
|
||||
auto& hash_fn = this->hasher();
|
||||
hash_fn.update(msg);
|
||||
auto message_hash = hash_fn.digest();
|
||||
if (DB[check_octets + 1] != 0x01)
|
||||
return VerificationConsistency::Inconsistent;
|
||||
|
||||
if (emsg.size() < HashFunction::DigestSize + SaltLength + 2)
|
||||
return VerificationConsistency::Inconsistent;
|
||||
auto* salt = DB + mask_length - SaltLength;
|
||||
u8 m_prime[8 + HashFunction::DigestSize + SaltLength] { 0, 0, 0, 0, 0, 0, 0, 0 };
|
||||
|
||||
if (emsg[emsg.size() - 1] != 0xbc)
|
||||
return VerificationConsistency::Inconsistent;
|
||||
auto m_prime_buffer = ByteBuffer::wrap(m_prime, sizeof(m_prime));
|
||||
|
||||
auto mask_length = emsg.size() - HashFunction::DigestSize - 1;
|
||||
auto masked_DB = emsg.slice_view(0, mask_length);
|
||||
auto H = emsg.slice_view(mask_length, HashFunction::DigestSize);
|
||||
m_prime_buffer.overwrite(8, message_hash.data, HashFunction::DigestSize);
|
||||
m_prime_buffer.overwrite(8 + HashFunction::DigestSize, salt, SaltLength);
|
||||
|
||||
auto length_to_check = 8 * emsg.size() - em_bits;
|
||||
auto octet = masked_DB[0];
|
||||
for (size_t i = 0; i < length_to_check; ++i)
|
||||
if ((octet >> (8 - i)) & 0x01)
|
||||
return VerificationConsistency::Inconsistent;
|
||||
hash_fn.update(m_prime_buffer);
|
||||
auto H_prime = hash_fn.digest();
|
||||
|
||||
u8 DB_mask[mask_length];
|
||||
auto DB_mask_buffer = ByteBuffer::wrap(DB_mask, mask_length);
|
||||
MGF1(H, mask_length, DB_mask_buffer);
|
||||
if (__builtin_memcmp(message_hash.data, H_prime.data, HashFunction::DigestSize))
|
||||
return VerificationConsistency::Inconsistent;
|
||||
|
||||
u8 DB[mask_length];
|
||||
return VerificationConsistency::Consistent;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < mask_length; ++i)
|
||||
DB[i] = masked_DB[i] ^ DB_mask[i];
|
||||
|
||||
DB[0] &= 0xff >> (8 - length_to_check);
|
||||
|
||||
auto check_octets = emsg.size() - HashFunction::DigestSize - SaltLength - 2;
|
||||
for (size_t i = 0; i < check_octets; ++i)
|
||||
if (DB[i])
|
||||
return VerificationConsistency::Inconsistent;
|
||||
|
||||
if (DB[check_octets + 1] != 0x01)
|
||||
return VerificationConsistency::Inconsistent;
|
||||
|
||||
auto* salt = DB + mask_length - SaltLength;
|
||||
u8 m_prime[8 + HashFunction::DigestSize + SaltLength] { 0, 0, 0, 0, 0, 0, 0, 0 };
|
||||
|
||||
auto m_prime_buffer = ByteBuffer::wrap(m_prime, sizeof(m_prime));
|
||||
|
||||
m_prime_buffer.overwrite(8, message_hash.data, HashFunction::DigestSize);
|
||||
m_prime_buffer.overwrite(8 + HashFunction::DigestSize, salt, SaltLength);
|
||||
|
||||
hash_fn.update(m_prime_buffer);
|
||||
auto H_prime = hash_fn.digest();
|
||||
|
||||
if (__builtin_memcmp(message_hash.data, H_prime.data, HashFunction::DigestSize))
|
||||
return VerificationConsistency::Inconsistent;
|
||||
|
||||
return VerificationConsistency::Consistent;
|
||||
void MGF1(const ByteBuffer& seed, size_t length, ByteBuffer& out)
|
||||
{
|
||||
auto& hash_fn = this->hasher();
|
||||
ByteBuffer T = ByteBuffer::create_zeroed(0);
|
||||
for (size_t counter = 0; counter < length / HashFunction::DigestSize - 1; ++counter) {
|
||||
hash_fn.update(seed);
|
||||
hash_fn.update((u8*)&counter, 4);
|
||||
T.append(hash_fn.digest().data, HashFunction::DigestSize);
|
||||
}
|
||||
out.overwrite(0, T.data(), length);
|
||||
}
|
||||
|
||||
void MGF1(const ByteBuffer& seed, size_t length, ByteBuffer& out)
|
||||
{
|
||||
auto& hash_fn = this->hasher();
|
||||
ByteBuffer T = ByteBuffer::create_zeroed(0);
|
||||
for (size_t counter = 0; counter < length / HashFunction::DigestSize - 1; ++counter) {
|
||||
hash_fn.update(seed);
|
||||
hash_fn.update((u8*)&counter, 4);
|
||||
T.append(hash_fn.digest().data, HashFunction::DigestSize);
|
||||
}
|
||||
out.overwrite(0, T.data(), length);
|
||||
}
|
||||
|
||||
private:
|
||||
u8 m_data_buffer[8 + HashFunction::DigestSize + SaltLength];
|
||||
ByteBuffer m_buffer;
|
||||
};
|
||||
private:
|
||||
u8 m_data_buffer[8 + HashFunction::DigestSize + SaltLength];
|
||||
ByteBuffer m_buffer;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -32,37 +32,37 @@
|
|||
namespace Crypto {
|
||||
namespace PK {
|
||||
|
||||
// FIXME: Fixing name up for grabs
|
||||
template <typename PrivKeyT, typename PubKeyT>
|
||||
class PKSystem {
|
||||
public:
|
||||
using PublicKeyType = PubKeyT;
|
||||
using PrivateKeyType = PrivKeyT;
|
||||
// FIXME: Fixing name up for grabs
|
||||
template<typename PrivKeyT, typename PubKeyT>
|
||||
class PKSystem {
|
||||
public:
|
||||
using PublicKeyType = PubKeyT;
|
||||
using PrivateKeyType = PrivKeyT;
|
||||
|
||||
PKSystem(PublicKeyType& pubkey, PrivateKeyType& privkey)
|
||||
: m_public_key(pubkey)
|
||||
, m_private_key(privkey)
|
||||
{
|
||||
}
|
||||
PKSystem(PublicKeyType& pubkey, PrivateKeyType& privkey)
|
||||
: m_public_key(pubkey)
|
||||
, m_private_key(privkey)
|
||||
{
|
||||
}
|
||||
|
||||
PKSystem()
|
||||
{
|
||||
}
|
||||
PKSystem()
|
||||
{
|
||||
}
|
||||
|
||||
virtual void encrypt(const ByteBuffer& in, ByteBuffer& out) = 0;
|
||||
virtual void decrypt(const ByteBuffer& in, ByteBuffer& out) = 0;
|
||||
virtual void encrypt(const ByteBuffer& in, ByteBuffer& out) = 0;
|
||||
virtual void decrypt(const ByteBuffer& in, ByteBuffer& out) = 0;
|
||||
|
||||
virtual void sign(const ByteBuffer& in, ByteBuffer& out) = 0;
|
||||
virtual void verify(const ByteBuffer& in, ByteBuffer& out) = 0;
|
||||
virtual void sign(const ByteBuffer& in, ByteBuffer& out) = 0;
|
||||
virtual void verify(const ByteBuffer& in, ByteBuffer& out) = 0;
|
||||
|
||||
virtual String class_name() const = 0;
|
||||
virtual String class_name() const = 0;
|
||||
|
||||
virtual size_t output_size() const = 0;
|
||||
virtual size_t output_size() const = 0;
|
||||
|
||||
protected:
|
||||
PublicKeyType m_public_key;
|
||||
PrivateKeyType m_private_key;
|
||||
};
|
||||
protected:
|
||||
PublicKeyType m_public_key;
|
||||
PrivateKeyType m_private_key;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -32,272 +32,272 @@
|
|||
namespace Crypto {
|
||||
namespace PK {
|
||||
|
||||
RSA::KeyPairType RSA::parse_rsa_key(const ByteBuffer& in)
|
||||
{
|
||||
// we are going to assign to at least one of these
|
||||
KeyPairType keypair;
|
||||
// TODO: move ASN parsing logic out
|
||||
u64 t, x, y, z, tmp_oid[16];
|
||||
u8 tmp_buf[4096] { 0 };
|
||||
UnsignedBigInteger n, e, d;
|
||||
ASN1::List pubkey_hash_oid[2], pubkey[2];
|
||||
RSA::KeyPairType RSA::parse_rsa_key(const ByteBuffer& in)
|
||||
{
|
||||
// we are going to assign to at least one of these
|
||||
KeyPairType keypair;
|
||||
// TODO: move ASN parsing logic out
|
||||
u64 t, x, y, z, tmp_oid[16];
|
||||
u8 tmp_buf[4096] { 0 };
|
||||
UnsignedBigInteger n, e, d;
|
||||
ASN1::List pubkey_hash_oid[2], pubkey[2];
|
||||
|
||||
ASN1::set(pubkey_hash_oid[0], ASN1::Kind::ObjectIdentifier, tmp_oid, sizeof(tmp_oid) / sizeof(tmp_oid[0]));
|
||||
ASN1::set(pubkey_hash_oid[1], ASN1::Kind::Null, nullptr, 0);
|
||||
ASN1::set(pubkey_hash_oid[0], ASN1::Kind::ObjectIdentifier, tmp_oid, sizeof(tmp_oid) / sizeof(tmp_oid[0]));
|
||||
ASN1::set(pubkey_hash_oid[1], ASN1::Kind::Null, nullptr, 0);
|
||||
|
||||
// DER is weird in that it stores pubkeys as bitstrings
|
||||
// we must first extract that crap
|
||||
ASN1::set(pubkey[0], ASN1::Kind::Sequence, &pubkey_hash_oid, 2);
|
||||
ASN1::set(pubkey[1], ASN1::Kind::Null, nullptr, 0);
|
||||
// DER is weird in that it stores pubkeys as bitstrings
|
||||
// we must first extract that crap
|
||||
ASN1::set(pubkey[0], ASN1::Kind::Sequence, &pubkey_hash_oid, 2);
|
||||
ASN1::set(pubkey[1], ASN1::Kind::Null, nullptr, 0);
|
||||
|
||||
dbg() << "we were offered " << in.size() << " bytes of input";
|
||||
dbg() << "we were offered " << in.size() << " bytes of input";
|
||||
|
||||
if (der_decode_sequence(in.data(), in.size(), pubkey, 2)) {
|
||||
// yay, now we have to reassemble the bitstring to a bytestring
|
||||
t = 0;
|
||||
y = 0;
|
||||
z = 0;
|
||||
x = 0;
|
||||
for (; x < pubkey[1].size; ++x) {
|
||||
y = (y << 1) | tmp_buf[x];
|
||||
if (++z == 8) {
|
||||
tmp_buf[t++] = (u8)y;
|
||||
y = 0;
|
||||
z = 0;
|
||||
}
|
||||
if (der_decode_sequence(in.data(), in.size(), pubkey, 2)) {
|
||||
// yay, now we have to reassemble the bitstring to a bytestring
|
||||
t = 0;
|
||||
y = 0;
|
||||
z = 0;
|
||||
x = 0;
|
||||
for (; x < pubkey[1].size; ++x) {
|
||||
y = (y << 1) | tmp_buf[x];
|
||||
if (++z == 8) {
|
||||
tmp_buf[t++] = (u8)y;
|
||||
y = 0;
|
||||
z = 0;
|
||||
}
|
||||
// now the buffer is correct (Sequence { Integer, Integer })
|
||||
if (!der_decode_sequence_many<2>(tmp_buf, t,
|
||||
ASN1::Kind::Integer, 1, &n,
|
||||
ASN1::Kind::Integer, 1, &e)) {
|
||||
// something was fucked up
|
||||
dbg() << "bad pubkey: " << e << " in " << n;
|
||||
return keypair;
|
||||
}
|
||||
// correct public key
|
||||
keypair.public_key.set(n, e);
|
||||
}
|
||||
// now the buffer is correct (Sequence { Integer, Integer })
|
||||
if (!der_decode_sequence_many<2>(tmp_buf, t,
|
||||
ASN1::Kind::Integer, 1, &n,
|
||||
ASN1::Kind::Integer, 1, &e)) {
|
||||
// something was fucked up
|
||||
dbg() << "bad pubkey: " << e << " in " << n;
|
||||
return keypair;
|
||||
}
|
||||
|
||||
// could be a private key
|
||||
if (!der_decode_sequence_many<1>(in.data(), in.size(),
|
||||
ASN1::Kind::Integer, 1, &n)) {
|
||||
// that's no key
|
||||
// that's a death star
|
||||
dbg() << "that's a death star";
|
||||
return keypair;
|
||||
}
|
||||
|
||||
if (n == 0) {
|
||||
// it is a private key
|
||||
UnsignedBigInteger zero;
|
||||
if (!der_decode_sequence_many<4>(in.data(), in.size(),
|
||||
ASN1::Kind::Integer, 1, &zero,
|
||||
ASN1::Kind::Integer, 1, &n,
|
||||
ASN1::Kind::Integer, 1, &e,
|
||||
ASN1::Kind::Integer, 1, &d)) {
|
||||
dbg() << "bad privkey " << n << " " << e << " " << d;
|
||||
return keypair;
|
||||
}
|
||||
keypair.private_key.set(n, d, e);
|
||||
return keypair;
|
||||
}
|
||||
if (n == 1) {
|
||||
// multiprime key, we don't know how to deal with this
|
||||
dbg() << "Unsupported key type";
|
||||
return keypair;
|
||||
}
|
||||
// it's a broken public key
|
||||
keypair.public_key.set(n, 65537);
|
||||
// correct public key
|
||||
keypair.public_key.set(n, e);
|
||||
return keypair;
|
||||
}
|
||||
|
||||
void RSA::encrypt(const ByteBuffer& in, ByteBuffer& out)
|
||||
{
|
||||
dbg() << "in size: " << in.size();
|
||||
auto in_integer = UnsignedBigInteger::import_data(in.data(), in.size());
|
||||
if (!(in_integer < m_public_key.modulus())) {
|
||||
dbg() << "value too large for key";
|
||||
out.clear();
|
||||
return;
|
||||
// could be a private key
|
||||
if (!der_decode_sequence_many<1>(in.data(), in.size(),
|
||||
ASN1::Kind::Integer, 1, &n)) {
|
||||
// that's no key
|
||||
// that's a death star
|
||||
dbg() << "that's a death star";
|
||||
return keypair;
|
||||
}
|
||||
|
||||
if (n == 0) {
|
||||
// it is a private key
|
||||
UnsignedBigInteger zero;
|
||||
if (!der_decode_sequence_many<4>(in.data(), in.size(),
|
||||
ASN1::Kind::Integer, 1, &zero,
|
||||
ASN1::Kind::Integer, 1, &n,
|
||||
ASN1::Kind::Integer, 1, &e,
|
||||
ASN1::Kind::Integer, 1, &d)) {
|
||||
dbg() << "bad privkey " << n << " " << e << " " << d;
|
||||
return keypair;
|
||||
}
|
||||
auto exp = NumberTheory::ModularPower(in_integer, m_public_key.public_exponent(), m_public_key.modulus());
|
||||
auto size = exp.export_data(out);
|
||||
// FIXME: We should probably not do this...
|
||||
if (size != out.size())
|
||||
out = out.slice(out.size() - size, size);
|
||||
keypair.private_key.set(n, d, e);
|
||||
return keypair;
|
||||
}
|
||||
|
||||
void RSA::decrypt(const ByteBuffer& in, ByteBuffer& out)
|
||||
{
|
||||
// FIXME: Actually use the private key properly
|
||||
|
||||
auto in_integer = UnsignedBigInteger::import_data(in.data(), in.size());
|
||||
auto exp = NumberTheory::ModularPower(in_integer, m_private_key.private_exponent(), m_private_key.modulus());
|
||||
auto size = exp.export_data(out);
|
||||
|
||||
auto align = m_private_key.length();
|
||||
auto aligned_size = (size + align - 1) / align * align;
|
||||
|
||||
for (auto i = size; i < aligned_size; ++i)
|
||||
out[out.size() - i - 1] = 0; // zero the non-aligned values
|
||||
out = out.slice(out.size() - aligned_size, aligned_size);
|
||||
if (n == 1) {
|
||||
// multiprime key, we don't know how to deal with this
|
||||
dbg() << "Unsupported key type";
|
||||
return keypair;
|
||||
}
|
||||
// it's a broken public key
|
||||
keypair.public_key.set(n, 65537);
|
||||
return keypair;
|
||||
}
|
||||
|
||||
void RSA::sign(const ByteBuffer& in, ByteBuffer& out)
|
||||
{
|
||||
auto in_integer = UnsignedBigInteger::import_data(in.data(), in.size());
|
||||
auto exp = NumberTheory::ModularPower(in_integer, m_private_key.private_exponent(), m_private_key.modulus());
|
||||
auto size = exp.export_data(out);
|
||||
void RSA::encrypt(const ByteBuffer& in, ByteBuffer& out)
|
||||
{
|
||||
dbg() << "in size: " << in.size();
|
||||
auto in_integer = UnsignedBigInteger::import_data(in.data(), in.size());
|
||||
if (!(in_integer < m_public_key.modulus())) {
|
||||
dbg() << "value too large for key";
|
||||
out.clear();
|
||||
return;
|
||||
}
|
||||
auto exp = NumberTheory::ModularPower(in_integer, m_public_key.public_exponent(), m_public_key.modulus());
|
||||
auto size = exp.export_data(out);
|
||||
// FIXME: We should probably not do this...
|
||||
if (size != out.size())
|
||||
out = out.slice(out.size() - size, size);
|
||||
}
|
||||
|
||||
void RSA::decrypt(const ByteBuffer& in, ByteBuffer& out)
|
||||
{
|
||||
// FIXME: Actually use the private key properly
|
||||
|
||||
auto in_integer = UnsignedBigInteger::import_data(in.data(), in.size());
|
||||
auto exp = NumberTheory::ModularPower(in_integer, m_private_key.private_exponent(), m_private_key.modulus());
|
||||
auto size = exp.export_data(out);
|
||||
|
||||
auto align = m_private_key.length();
|
||||
auto aligned_size = (size + align - 1) / align * align;
|
||||
|
||||
for (auto i = size; i < aligned_size; ++i)
|
||||
out[out.size() - i - 1] = 0; // zero the non-aligned values
|
||||
out = out.slice(out.size() - aligned_size, aligned_size);
|
||||
}
|
||||
|
||||
void RSA::sign(const ByteBuffer& in, ByteBuffer& out)
|
||||
{
|
||||
auto in_integer = UnsignedBigInteger::import_data(in.data(), in.size());
|
||||
auto exp = NumberTheory::ModularPower(in_integer, m_private_key.private_exponent(), m_private_key.modulus());
|
||||
auto size = exp.export_data(out);
|
||||
out = out.slice(out.size() - size, size);
|
||||
}
|
||||
|
||||
void RSA::verify(const ByteBuffer& in, ByteBuffer& out)
|
||||
{
|
||||
auto in_integer = UnsignedBigInteger::import_data(in.data(), in.size());
|
||||
auto exp = NumberTheory::ModularPower(in_integer, m_public_key.public_exponent(), m_public_key.modulus());
|
||||
auto size = exp.export_data(out);
|
||||
out = out.slice(out.size() - size, size);
|
||||
}
|
||||
|
||||
void RSA::import_private_key(const ByteBuffer& buffer, bool pem)
|
||||
{
|
||||
// so gods help me, I hate DER
|
||||
auto decoded_buffer = pem ? decode_pem(buffer) : buffer;
|
||||
auto key = parse_rsa_key(decoded_buffer);
|
||||
if (!key.private_key.length()) {
|
||||
dbg() << "We expected to see a private key, but we found none";
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
m_private_key = key.private_key;
|
||||
}
|
||||
|
||||
void RSA::import_public_key(const ByteBuffer& buffer, bool pem)
|
||||
{
|
||||
// so gods help me, I hate DER
|
||||
auto decoded_buffer = pem ? decode_pem(buffer) : buffer;
|
||||
auto key = parse_rsa_key(decoded_buffer);
|
||||
if (!key.public_key.length()) {
|
||||
dbg() << "We expected to see a public key, but we found none";
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
m_public_key = key.public_key;
|
||||
}
|
||||
|
||||
template<typename HashFunction>
|
||||
void RSA_EMSA_PSS<HashFunction>::sign(const ByteBuffer& in, ByteBuffer& out)
|
||||
{
|
||||
// -- encode via EMSA_PSS
|
||||
auto mod_bits = m_rsa.private_key().modulus().trimmed_length() * sizeof(u32) * 8;
|
||||
|
||||
u8 EM[mod_bits];
|
||||
auto EM_buf = ByteBuffer::wrap(EM, mod_bits);
|
||||
m_emsa_pss.encode(in, EM_buf, mod_bits - 1);
|
||||
|
||||
// -- sign via RSA
|
||||
m_rsa.sign(EM_buf, out);
|
||||
}
|
||||
|
||||
template<typename HashFunction>
|
||||
VerificationConsistency RSA_EMSA_PSS<HashFunction>::verify(const ByteBuffer& in)
|
||||
{
|
||||
auto mod_bytes = m_rsa.public_key().modulus().trimmed_length() * sizeof(u32);
|
||||
if (in.size() != mod_bytes)
|
||||
return VerificationConsistency::Inconsistent;
|
||||
|
||||
u8 EM[mod_bytes];
|
||||
auto EM_buf = ByteBuffer::wrap(EM, mod_bytes);
|
||||
|
||||
// -- verify via RSA
|
||||
m_rsa.verify(in, EM_buf);
|
||||
|
||||
// -- verify via EMSA_PSS
|
||||
return m_emsa_pss.verify(in, EM, mod_bytes * 8 - 1);
|
||||
}
|
||||
|
||||
void RSA_PKCS1_EME::encrypt(const ByteBuffer& in, ByteBuffer& out)
|
||||
{
|
||||
auto mod_len = (m_public_key.modulus().trimmed_length() * sizeof(u32) * 8 + 7) / 8;
|
||||
dbg() << "key size: " << mod_len;
|
||||
if (in.size() > mod_len - 11) {
|
||||
dbg() << "message too long :(";
|
||||
out.trim(0);
|
||||
return;
|
||||
}
|
||||
if (out.size() < mod_len) {
|
||||
dbg() << "output buffer too small";
|
||||
return;
|
||||
}
|
||||
|
||||
void RSA::verify(const ByteBuffer& in, ByteBuffer& out)
|
||||
{
|
||||
auto in_integer = UnsignedBigInteger::import_data(in.data(), in.size());
|
||||
auto exp = NumberTheory::ModularPower(in_integer, m_public_key.public_exponent(), m_public_key.modulus());
|
||||
auto size = exp.export_data(out);
|
||||
out = out.slice(out.size() - size, size);
|
||||
auto ps_length = mod_len - in.size() - 3;
|
||||
u8 ps[ps_length];
|
||||
|
||||
arc4random_buf(ps, ps_length);
|
||||
u8 paddings[] { 0x00, 0x02 };
|
||||
|
||||
out.overwrite(0, paddings, 2);
|
||||
out.overwrite(2, ps, ps_length);
|
||||
out.overwrite(2 + ps_length, paddings, 1);
|
||||
out.overwrite(3 + ps_length, in.data(), in.size());
|
||||
out.trim(3 + ps_length + in.size()); // should be a single block
|
||||
|
||||
dbg() << "padded output size: " << 3 + ps_length + in.size() << " buffer size: " << out.size();
|
||||
|
||||
RSA::encrypt(out, out);
|
||||
}
|
||||
void RSA_PKCS1_EME::decrypt(const ByteBuffer& in, ByteBuffer& out)
|
||||
{
|
||||
auto mod_len = (m_public_key.modulus().trimmed_length() * sizeof(u32) * 8 + 7) / 8;
|
||||
if (in.size() != mod_len) {
|
||||
dbg() << "decryption error: wrong amount of data: " << in.size();
|
||||
out.trim(0);
|
||||
return;
|
||||
}
|
||||
|
||||
void RSA::import_private_key(const ByteBuffer& buffer, bool pem)
|
||||
{
|
||||
// so gods help me, I hate DER
|
||||
auto decoded_buffer = pem ? decode_pem(buffer) : buffer;
|
||||
auto key = parse_rsa_key(decoded_buffer);
|
||||
if (!key.private_key.length()) {
|
||||
dbg() << "We expected to see a private key, but we found none";
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
m_private_key = key.private_key;
|
||||
RSA::decrypt(in, out);
|
||||
|
||||
if (out.size() < RSA::output_size()) {
|
||||
dbg() << "decryption error: not enough data after decryption: " << out.size();
|
||||
out.trim(0);
|
||||
return;
|
||||
}
|
||||
|
||||
void RSA::import_public_key(const ByteBuffer& buffer, bool pem)
|
||||
{
|
||||
// so gods help me, I hate DER
|
||||
auto decoded_buffer = pem ? decode_pem(buffer) : buffer;
|
||||
auto key = parse_rsa_key(decoded_buffer);
|
||||
if (!key.public_key.length()) {
|
||||
dbg() << "We expected to see a public key, but we found none";
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
m_public_key = key.public_key;
|
||||
if (out[0] != 0x00) {
|
||||
dbg() << "invalid padding byte 0 : " << out[0];
|
||||
return;
|
||||
}
|
||||
|
||||
template <typename HashFunction>
|
||||
void RSA_EMSA_PSS<HashFunction>::sign(const ByteBuffer& in, ByteBuffer& out)
|
||||
{
|
||||
// -- encode via EMSA_PSS
|
||||
auto mod_bits = m_rsa.private_key().modulus().trimmed_length() * sizeof(u32) * 8;
|
||||
|
||||
u8 EM[mod_bits];
|
||||
auto EM_buf = ByteBuffer::wrap(EM, mod_bits);
|
||||
m_emsa_pss.encode(in, EM_buf, mod_bits - 1);
|
||||
|
||||
// -- sign via RSA
|
||||
m_rsa.sign(EM_buf, out);
|
||||
if (out[1] != 0x02) {
|
||||
dbg() << "invalid padding byte 1" << out[1];
|
||||
return;
|
||||
}
|
||||
|
||||
template <typename HashFunction>
|
||||
VerificationConsistency RSA_EMSA_PSS<HashFunction>::verify(const ByteBuffer& in)
|
||||
{
|
||||
auto mod_bytes = m_rsa.public_key().modulus().trimmed_length() * sizeof(u32);
|
||||
if (in.size() != mod_bytes)
|
||||
return VerificationConsistency::Inconsistent;
|
||||
|
||||
u8 EM[mod_bytes];
|
||||
auto EM_buf = ByteBuffer::wrap(EM, mod_bytes);
|
||||
|
||||
// -- verify via RSA
|
||||
m_rsa.verify(in, EM_buf);
|
||||
|
||||
// -- verify via EMSA_PSS
|
||||
return m_emsa_pss.verify(in, EM, mod_bytes * 8 - 1);
|
||||
}
|
||||
|
||||
void RSA_PKCS1_EME::encrypt(const ByteBuffer& in, ByteBuffer& out)
|
||||
{
|
||||
auto mod_len = (m_public_key.modulus().trimmed_length() * sizeof(u32) * 8 + 7) / 8;
|
||||
dbg() << "key size: " << mod_len;
|
||||
if (in.size() > mod_len - 11) {
|
||||
dbg() << "message too long :(";
|
||||
out.trim(0);
|
||||
return;
|
||||
}
|
||||
if (out.size() < mod_len) {
|
||||
dbg() << "output buffer too small";
|
||||
return;
|
||||
}
|
||||
|
||||
auto ps_length = mod_len - in.size() - 3;
|
||||
u8 ps[ps_length];
|
||||
|
||||
arc4random_buf(ps, ps_length);
|
||||
u8 paddings[] { 0x00, 0x02 };
|
||||
|
||||
out.overwrite(0, paddings, 2);
|
||||
out.overwrite(2, ps, ps_length);
|
||||
out.overwrite(2 + ps_length, paddings, 1);
|
||||
out.overwrite(3 + ps_length, in.data(), in.size());
|
||||
out.trim(3 + ps_length + in.size()); // should be a single block
|
||||
|
||||
dbg() << "padded output size: " << 3 + ps_length + in.size() << " buffer size: " << out.size();
|
||||
|
||||
RSA::encrypt(out, out);
|
||||
}
|
||||
void RSA_PKCS1_EME::decrypt(const ByteBuffer& in, ByteBuffer& out)
|
||||
{
|
||||
auto mod_len = (m_public_key.modulus().trimmed_length() * sizeof(u32) * 8 + 7) / 8;
|
||||
if (in.size() != mod_len) {
|
||||
dbg() << "decryption error: wrong amount of data: " << in.size();
|
||||
out.trim(0);
|
||||
return;
|
||||
}
|
||||
|
||||
RSA::decrypt(in, out);
|
||||
|
||||
if (out.size() < RSA::output_size()) {
|
||||
dbg() << "decryption error: not enough data after decryption: " << out.size();
|
||||
out.trim(0);
|
||||
return;
|
||||
}
|
||||
|
||||
if (out[0] != 0x00) {
|
||||
dbg() << "invalid padding byte 0 : " << out[0];
|
||||
return;
|
||||
}
|
||||
|
||||
if (out[1] != 0x02) {
|
||||
dbg() << "invalid padding byte 1" << out[1];
|
||||
return;
|
||||
}
|
||||
|
||||
size_t offset = 2;
|
||||
while (offset < out.size() && out[offset])
|
||||
++offset;
|
||||
|
||||
if (offset == out.size()) {
|
||||
dbg() << "garbage data, no zero to split padding";
|
||||
return;
|
||||
}
|
||||
|
||||
size_t offset = 2;
|
||||
while (offset < out.size() && out[offset])
|
||||
++offset;
|
||||
|
||||
if (offset - 3 < 8) {
|
||||
dbg() << "PS too small";
|
||||
return;
|
||||
}
|
||||
|
||||
out = out.slice(offset, out.size() - offset);
|
||||
if (offset == out.size()) {
|
||||
dbg() << "garbage data, no zero to split padding";
|
||||
return;
|
||||
}
|
||||
|
||||
void RSA_PKCS1_EME::sign(const ByteBuffer&, ByteBuffer&)
|
||||
{
|
||||
dbg() << "FIXME: RSA_PKCS_EME::sign";
|
||||
}
|
||||
void RSA_PKCS1_EME::verify(const ByteBuffer&, ByteBuffer&)
|
||||
{
|
||||
dbg() << "FIXME: RSA_PKCS_EME::verify";
|
||||
++offset;
|
||||
|
||||
if (offset - 3 < 8) {
|
||||
dbg() << "PS too small";
|
||||
return;
|
||||
}
|
||||
|
||||
out = out.slice(offset, out.size() - offset);
|
||||
}
|
||||
|
||||
void RSA_PKCS1_EME::sign(const ByteBuffer&, ByteBuffer&)
|
||||
{
|
||||
dbg() << "FIXME: RSA_PKCS_EME::sign";
|
||||
}
|
||||
void RSA_PKCS1_EME::verify(const ByteBuffer&, ByteBuffer&)
|
||||
{
|
||||
dbg() << "FIXME: RSA_PKCS_EME::verify";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -34,201 +34,201 @@
|
|||
|
||||
namespace Crypto {
|
||||
namespace PK {
|
||||
template <typename Integer = u64>
|
||||
class RSAPublicKey {
|
||||
public:
|
||||
RSAPublicKey(const Integer& n, const Integer& e)
|
||||
: m_modulus(n)
|
||||
, m_public_exponent(e)
|
||||
{
|
||||
}
|
||||
template<typename Integer = u64>
|
||||
class RSAPublicKey {
|
||||
public:
|
||||
RSAPublicKey(const Integer& n, const Integer& e)
|
||||
: m_modulus(n)
|
||||
, m_public_exponent(e)
|
||||
{
|
||||
}
|
||||
|
||||
RSAPublicKey()
|
||||
: m_modulus(0)
|
||||
, m_public_exponent(0)
|
||||
{
|
||||
}
|
||||
RSAPublicKey()
|
||||
: m_modulus(0)
|
||||
, m_public_exponent(0)
|
||||
{
|
||||
}
|
||||
|
||||
//--stuff it should do
|
||||
//--stuff it should do
|
||||
|
||||
const Integer& modulus() const { return m_modulus; }
|
||||
const Integer& public_exponent() const { return m_public_exponent; }
|
||||
size_t length() const { return m_length; }
|
||||
void set_length(size_t length) { m_length = length; }
|
||||
const Integer& modulus() const { return m_modulus; }
|
||||
const Integer& public_exponent() const { return m_public_exponent; }
|
||||
size_t length() const { return m_length; }
|
||||
void set_length(size_t length) { m_length = length; }
|
||||
|
||||
void set(const Integer& n, const Integer& e)
|
||||
{
|
||||
m_modulus = n;
|
||||
m_public_exponent = e;
|
||||
m_length = (n.trimmed_length() * sizeof(u32));
|
||||
}
|
||||
void set(const Integer& n, const Integer& e)
|
||||
{
|
||||
m_modulus = n;
|
||||
m_public_exponent = e;
|
||||
m_length = (n.trimmed_length() * sizeof(u32));
|
||||
}
|
||||
|
||||
private:
|
||||
Integer m_modulus;
|
||||
Integer m_public_exponent;
|
||||
size_t m_length { 0 };
|
||||
};
|
||||
private:
|
||||
Integer m_modulus;
|
||||
Integer m_public_exponent;
|
||||
size_t m_length { 0 };
|
||||
};
|
||||
|
||||
template <typename Integer = UnsignedBigInteger>
|
||||
class RSAPrivateKey {
|
||||
public:
|
||||
RSAPrivateKey(const Integer& n, const Integer& d, const Integer& e)
|
||||
: m_modulus(n)
|
||||
, m_private_exponent(d)
|
||||
, m_public_exponent(e)
|
||||
{
|
||||
}
|
||||
template<typename Integer = UnsignedBigInteger>
|
||||
class RSAPrivateKey {
|
||||
public:
|
||||
RSAPrivateKey(const Integer& n, const Integer& d, const Integer& e)
|
||||
: m_modulus(n)
|
||||
, m_private_exponent(d)
|
||||
, m_public_exponent(e)
|
||||
{
|
||||
}
|
||||
|
||||
RSAPrivateKey()
|
||||
{
|
||||
}
|
||||
RSAPrivateKey()
|
||||
{
|
||||
}
|
||||
|
||||
//--stuff it should do
|
||||
const Integer& modulus() const { return m_modulus; }
|
||||
const Integer& private_exponent() const { return m_private_exponent; }
|
||||
const Integer& public_exponent() const { return m_public_exponent; }
|
||||
size_t length() const { return m_length; }
|
||||
void set_length(size_t length) { m_length = length; }
|
||||
//--stuff it should do
|
||||
const Integer& modulus() const { return m_modulus; }
|
||||
const Integer& private_exponent() const { return m_private_exponent; }
|
||||
const Integer& public_exponent() const { return m_public_exponent; }
|
||||
size_t length() const { return m_length; }
|
||||
void set_length(size_t length) { m_length = length; }
|
||||
|
||||
void set(const Integer& n, const Integer& d, const Integer& e)
|
||||
{
|
||||
m_modulus = n;
|
||||
m_private_exponent = d;
|
||||
m_public_exponent = e;
|
||||
m_length = (n.length() * sizeof(u32));
|
||||
}
|
||||
void set(const Integer& n, const Integer& d, const Integer& e)
|
||||
{
|
||||
m_modulus = n;
|
||||
m_private_exponent = d;
|
||||
m_public_exponent = e;
|
||||
m_length = (n.length() * sizeof(u32));
|
||||
}
|
||||
|
||||
private:
|
||||
Integer m_modulus;
|
||||
Integer m_private_exponent;
|
||||
Integer m_public_exponent;
|
||||
size_t m_length { 0 };
|
||||
};
|
||||
private:
|
||||
Integer m_modulus;
|
||||
Integer m_private_exponent;
|
||||
Integer m_public_exponent;
|
||||
size_t m_length { 0 };
|
||||
};
|
||||
|
||||
template <typename PubKey, typename PrivKey>
|
||||
struct RSAKeyPair {
|
||||
PubKey public_key;
|
||||
PrivKey private_key;
|
||||
};
|
||||
template<typename PubKey, typename PrivKey>
|
||||
struct RSAKeyPair {
|
||||
PubKey public_key;
|
||||
PrivKey private_key;
|
||||
};
|
||||
|
||||
using IntegerType = UnsignedBigInteger;
|
||||
class RSA : public PKSystem<RSAPrivateKey<IntegerType>, RSAPublicKey<IntegerType>> {
|
||||
template <typename T>
|
||||
friend class RSA_EMSA_PSS;
|
||||
using IntegerType = UnsignedBigInteger;
|
||||
class RSA : public PKSystem<RSAPrivateKey<IntegerType>, RSAPublicKey<IntegerType>> {
|
||||
template<typename T>
|
||||
friend class RSA_EMSA_PSS;
|
||||
|
||||
public:
|
||||
using KeyPairType = RSAKeyPair<PublicKeyType, PrivateKeyType>;
|
||||
public:
|
||||
using KeyPairType = RSAKeyPair<PublicKeyType, PrivateKeyType>;
|
||||
|
||||
static KeyPairType parse_rsa_key(const ByteBuffer&);
|
||||
static KeyPairType generate_key_pair(size_t bits = 256)
|
||||
{
|
||||
IntegerType e { 65537 }; // :P
|
||||
IntegerType p, q;
|
||||
IntegerType lambda;
|
||||
static KeyPairType parse_rsa_key(const ByteBuffer&);
|
||||
static KeyPairType generate_key_pair(size_t bits = 256)
|
||||
{
|
||||
IntegerType e { 65537 }; // :P
|
||||
IntegerType p, q;
|
||||
IntegerType lambda;
|
||||
|
||||
do {
|
||||
p = NumberTheory::random_big_prime(bits / 2);
|
||||
q = NumberTheory::random_big_prime(bits / 2);
|
||||
lambda = NumberTheory::LCM(p.sub(1), q.sub(1));
|
||||
dbg() << "checking combination p=" << p << ", q=" << q << ", lambda=" << lambda.length();
|
||||
} while (!(NumberTheory::GCD(e, lambda) == 1));
|
||||
do {
|
||||
p = NumberTheory::random_big_prime(bits / 2);
|
||||
q = NumberTheory::random_big_prime(bits / 2);
|
||||
lambda = NumberTheory::LCM(p.sub(1), q.sub(1));
|
||||
dbg() << "checking combination p=" << p << ", q=" << q << ", lambda=" << lambda.length();
|
||||
} while (!(NumberTheory::GCD(e, lambda) == 1));
|
||||
|
||||
auto n = p.multiply(q);
|
||||
auto n = p.multiply(q);
|
||||
|
||||
auto d = NumberTheory::ModularInverse(e, lambda);
|
||||
dbg() << "Your keys are Pub{n=" << n << ", e=" << e << "} and Priv{n=" << n << ", d=" << d << "}";
|
||||
RSAKeyPair<PublicKeyType, PrivateKeyType> keys {
|
||||
{ n, e },
|
||||
{ n, d, e }
|
||||
};
|
||||
keys.public_key.set_length(bits / 2 / 8);
|
||||
keys.private_key.set_length(bits / 2 / 8);
|
||||
return keys;
|
||||
}
|
||||
auto d = NumberTheory::ModularInverse(e, lambda);
|
||||
dbg() << "Your keys are Pub{n=" << n << ", e=" << e << "} and Priv{n=" << n << ", d=" << d << "}";
|
||||
RSAKeyPair<PublicKeyType, PrivateKeyType> keys {
|
||||
{ n, e },
|
||||
{ n, d, e }
|
||||
};
|
||||
keys.public_key.set_length(bits / 2 / 8);
|
||||
keys.private_key.set_length(bits / 2 / 8);
|
||||
return keys;
|
||||
}
|
||||
|
||||
RSA(IntegerType n, IntegerType d, IntegerType e)
|
||||
{
|
||||
m_public_key.set(n, e);
|
||||
m_private_key.set(n, d, e);
|
||||
}
|
||||
RSA(IntegerType n, IntegerType d, IntegerType e)
|
||||
{
|
||||
m_public_key.set(n, e);
|
||||
m_private_key.set(n, d, e);
|
||||
}
|
||||
|
||||
RSA(PublicKeyType& pubkey, PrivateKeyType& privkey)
|
||||
: PKSystem<RSAPrivateKey<IntegerType>, RSAPublicKey<IntegerType>>(pubkey, privkey)
|
||||
{
|
||||
}
|
||||
RSA(PublicKeyType& pubkey, PrivateKeyType& privkey)
|
||||
: PKSystem<RSAPrivateKey<IntegerType>, RSAPublicKey<IntegerType>>(pubkey, privkey)
|
||||
{
|
||||
}
|
||||
|
||||
RSA(const ByteBuffer& publicKeyPEM, const ByteBuffer& privateKeyPEM)
|
||||
{
|
||||
import_public_key(publicKeyPEM);
|
||||
import_private_key(privateKeyPEM);
|
||||
}
|
||||
RSA(const ByteBuffer& publicKeyPEM, const ByteBuffer& privateKeyPEM)
|
||||
{
|
||||
import_public_key(publicKeyPEM);
|
||||
import_private_key(privateKeyPEM);
|
||||
}
|
||||
|
||||
RSA(const StringView& privKeyPEM)
|
||||
{
|
||||
import_private_key(ByteBuffer::wrap(privKeyPEM.characters_without_null_termination(), privKeyPEM.length()));
|
||||
m_public_key.set(m_private_key.modulus(), m_private_key.public_exponent());
|
||||
}
|
||||
RSA(const StringView& privKeyPEM)
|
||||
{
|
||||
import_private_key(ByteBuffer::wrap(privKeyPEM.characters_without_null_termination(), privKeyPEM.length()));
|
||||
m_public_key.set(m_private_key.modulus(), m_private_key.public_exponent());
|
||||
}
|
||||
|
||||
// create our own keys
|
||||
RSA()
|
||||
{
|
||||
auto pair = generate_key_pair();
|
||||
m_public_key = pair.public_key;
|
||||
m_private_key = pair.private_key;
|
||||
}
|
||||
// create our own keys
|
||||
RSA()
|
||||
{
|
||||
auto pair = generate_key_pair();
|
||||
m_public_key = pair.public_key;
|
||||
m_private_key = pair.private_key;
|
||||
}
|
||||
|
||||
virtual void encrypt(const ByteBuffer& in, ByteBuffer& out) override;
|
||||
virtual void decrypt(const ByteBuffer& in, ByteBuffer& out) override;
|
||||
virtual void encrypt(const ByteBuffer& in, ByteBuffer& out) override;
|
||||
virtual void decrypt(const ByteBuffer& in, ByteBuffer& out) override;
|
||||
|
||||
virtual void sign(const ByteBuffer& in, ByteBuffer& out) override;
|
||||
virtual void verify(const ByteBuffer& in, ByteBuffer& out) override;
|
||||
virtual void sign(const ByteBuffer& in, ByteBuffer& out) override;
|
||||
virtual void verify(const ByteBuffer& in, ByteBuffer& out) override;
|
||||
|
||||
virtual String class_name() const override { return "RSA"; }
|
||||
virtual String class_name() const override { return "RSA"; }
|
||||
|
||||
virtual size_t output_size() const override { return m_public_key.length(); }
|
||||
virtual size_t output_size() const override { return m_public_key.length(); }
|
||||
|
||||
void import_public_key(const ByteBuffer& buffer, bool pem = true);
|
||||
void import_private_key(const ByteBuffer& buffer, bool pem = true);
|
||||
void import_public_key(const ByteBuffer& buffer, bool pem = true);
|
||||
void import_private_key(const ByteBuffer& buffer, bool pem = true);
|
||||
|
||||
const PrivateKeyType& private_key() const { return m_private_key; }
|
||||
const PublicKeyType& public_key() const { return m_public_key; }
|
||||
};
|
||||
const PrivateKeyType& private_key() const { return m_private_key; }
|
||||
const PublicKeyType& public_key() const { return m_public_key; }
|
||||
};
|
||||
|
||||
template <typename HashFunction>
|
||||
class RSA_EMSA_PSS {
|
||||
public:
|
||||
RSA_EMSA_PSS(RSA& rsa)
|
||||
: m_rsa(rsa)
|
||||
{
|
||||
}
|
||||
template<typename HashFunction>
|
||||
class RSA_EMSA_PSS {
|
||||
public:
|
||||
RSA_EMSA_PSS(RSA& rsa)
|
||||
: m_rsa(rsa)
|
||||
{
|
||||
}
|
||||
|
||||
void sign(const ByteBuffer& in, ByteBuffer& out);
|
||||
VerificationConsistency verify(const ByteBuffer& in);
|
||||
void sign(const ByteBuffer& in, ByteBuffer& out);
|
||||
VerificationConsistency verify(const ByteBuffer& in);
|
||||
|
||||
private:
|
||||
EMSA_PSS<HashFunction, HashFunction::DigestSize> m_emsa_pss;
|
||||
RSA m_rsa;
|
||||
};
|
||||
private:
|
||||
EMSA_PSS<HashFunction, HashFunction::DigestSize> m_emsa_pss;
|
||||
RSA m_rsa;
|
||||
};
|
||||
|
||||
class RSA_PKCS1_EME : public RSA {
|
||||
public:
|
||||
// forward all constructions to RSA
|
||||
template <typename... Args>
|
||||
RSA_PKCS1_EME(Args... args)
|
||||
: RSA(args...)
|
||||
{
|
||||
}
|
||||
class RSA_PKCS1_EME : public RSA {
|
||||
public:
|
||||
// forward all constructions to RSA
|
||||
template<typename... Args>
|
||||
RSA_PKCS1_EME(Args... args)
|
||||
: RSA(args...)
|
||||
{
|
||||
}
|
||||
|
||||
~RSA_PKCS1_EME() {}
|
||||
~RSA_PKCS1_EME() {}
|
||||
|
||||
virtual void encrypt(const ByteBuffer& in, ByteBuffer& out) override;
|
||||
virtual void decrypt(const ByteBuffer& in, ByteBuffer& out) override;
|
||||
virtual void encrypt(const ByteBuffer& in, ByteBuffer& out) override;
|
||||
virtual void decrypt(const ByteBuffer& in, ByteBuffer& out) override;
|
||||
|
||||
virtual void sign(const ByteBuffer&, ByteBuffer&) override;
|
||||
virtual void verify(const ByteBuffer&, ByteBuffer&) override;
|
||||
virtual void sign(const ByteBuffer&, ByteBuffer&) override;
|
||||
virtual void verify(const ByteBuffer&, ByteBuffer&) override;
|
||||
|
||||
virtual String class_name() const override { return "RSA_PKCS1-EME"; }
|
||||
virtual size_t output_size() const override { return m_public_key.length(); }
|
||||
};
|
||||
virtual String class_name() const override { return "RSA_PKCS1-EME"; }
|
||||
virtual size_t output_size() const override { return m_public_key.length(); }
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue