/* * Encode two BigInt, with leading 0s if needed, and concatenate */ secure_vector<uint8_t> BigInt::encode_fixed_length_int_pair(const BigInt& n1, const BigInt& n2, size_t bytes) { if(n1.bytes() > bytes || n2.bytes() > bytes) throw Encoding_Error("encode_fixed_length_int_pair: values too large to encode properly"); secure_vector<uint8_t> output(2 * bytes); n1.binary_encode(output.data() , bytes); n2.binary_encode(output.data() + bytes, bytes); return output; }
/* * Default ElGamal Encrypt Operation */ SecureVector<byte> Default_ELG_Op::encrypt(const byte in[], u32bit length, const BigInt& k) const { BigInt m(in, length); if(m >= p) throw Invalid_Argument("Default_ELG_Op::encrypt: Input is too large"); BigInt a = powermod_g_p(k); BigInt b = mod_p.multiply(m, powermod_y_p(k)); SecureVector<byte> output(2*p.bytes()); a.binary_encode(output + (p.bytes() - a.bytes())); b.binary_encode(output + output.size() / 2 + (p.bytes() - b.bytes())); return output; }
//static void BigInt::encode_1363(uint8_t output[], size_t bytes, const BigInt& n) { if(n.bytes() > bytes) throw Encoding_Error("encode_1363: n is too large to encode properly"); n.binary_encode(output, bytes); }
SecureVector<byte> DSA_Signature_Operation::sign(const byte msg[], size_t msg_len, RandomNumberGenerator& rng) { rng.add_entropy(msg, msg_len); BigInt i(msg, msg_len); BigInt r = 0, s = 0; while(r == 0 || s == 0) { BigInt k; do k.randomize(rng, q.bits()); while(k >= q); r = mod_q.reduce(powermod_g_p(k)); s = mod_q.multiply(inverse_mod(k, q), mul_add(x, r, i)); } SecureVector<byte> output(2*q.bytes()); r.binary_encode(&output[output.size() / 2 - r.bytes()]); s.binary_encode(&output[output.size() - s.bytes()]); return output; }
SecureVector<byte> ECDSA_Signature_Operation::sign(const byte msg[], size_t msg_len, RandomNumberGenerator& rng) { rng.add_entropy(msg, msg_len); BigInt m(msg, msg_len); BigInt r = 0, s = 0; while(r == 0 || s == 0) { // This contortion is necessary for the tests BigInt k; k.randomize(rng, order.bits()); while(k >= order) k.randomize(rng, order.bits() - 1); PointGFp k_times_P = base_point * k; r = mod_order.reduce(k_times_P.get_affine_x()); s = mod_order.multiply(inverse_mod(k, order), mul_add(x, r, m)); } SecureVector<byte> output(2*order.bytes()); r.binary_encode(&output[output.size() / 2 - r.bytes()]); s.binary_encode(&output[output.size() - s.bytes()]); return output; }
/* * Encode a BigInt, with leading 0s if needed */ secure_vector<uint8_t> BigInt::encode_1363(const BigInt& n, size_t bytes) { if(n.bytes() > bytes) throw Encoding_Error("encode_1363: n is too large to encode properly"); secure_vector<uint8_t> output(bytes); n.binary_encode(output.data(), output.size()); return output; }
std::vector<byte> GOST_3410_PublicKey::x509_subject_public_key() const { const BigInt x = public_point().get_affine_x(); const BigInt y = public_point().get_affine_y(); size_t part_size = std::max(x.bytes(), y.bytes()); std::vector<byte> bits(2*part_size); x.binary_encode(&bits[part_size - x.bytes()]); y.binary_encode(&bits[2*part_size - y.bytes()]); // Keys are stored in little endian format (WTF) for(size_t i = 0; i != part_size / 2; ++i) { std::swap(bits[i], bits[part_size-1-i]); std::swap(bits[part_size+i], bits[2*part_size-1-i]); } return DER_Encoder().encode(bits, OCTET_STRING).get_contents_unlocked(); }
/************************************************* * Encode a BigInt, with leading 0s if needed * *************************************************/ SecureVector<byte> BigInt::encode_1363(const BigInt& n, u32bit bytes) { const u32bit n_bytes = n.bytes(); if(n_bytes > bytes) throw Encoding_Error("encode_1363: n is too large to encode properly"); const u32bit leading_0s = bytes - n_bytes; SecureVector<byte> output(bytes); encode(output + leading_0s, n, Binary); return output; }
bool SshEncryptionFacility::createAuthenticationKeyFromPKCS8(const QByteArray &privKeyFileContents, QList<BigInt> &pubKeyParams, QList<BigInt> &allKeyParams, QString &error) { try { Pipe pipe; pipe.process_msg(convertByteArray(privKeyFileContents), privKeyFileContents.size()); m_authKey.reset(PKCS8::load_key(pipe, m_rng, SshKeyPasswordRetriever())); if (auto * const dsaKey = dynamic_cast<DSA_PrivateKey *>(m_authKey.data())) { m_authKeyAlgoName = SshCapabilities::PubKeyDss; pubKeyParams << dsaKey->group_p() << dsaKey->group_q() << dsaKey->group_g() << dsaKey->get_y(); allKeyParams << pubKeyParams << dsaKey->get_x(); } else if (auto * const rsaKey = dynamic_cast<RSA_PrivateKey *>(m_authKey.data())) { m_authKeyAlgoName = SshCapabilities::PubKeyRsa; pubKeyParams << rsaKey->get_e() << rsaKey->get_n(); allKeyParams << pubKeyParams << rsaKey->get_p() << rsaKey->get_q() << rsaKey->get_d(); } else if (auto * const ecdsaKey = dynamic_cast<ECDSA_PrivateKey *>(m_authKey.data())) { const BigInt value = ecdsaKey->private_value(); m_authKeyAlgoName = SshCapabilities::ecdsaPubKeyAlgoForKeyWidth( static_cast<int>(value.bytes())); pubKeyParams << ecdsaKey->public_point().get_affine_x() << ecdsaKey->public_point().get_affine_y(); allKeyParams << pubKeyParams << value; } else { qCWarning(sshLog, "%s: Unexpected code flow, expected success or exception.", Q_FUNC_INFO); return false; } } catch (const Exception &ex) { error = QLatin1String(ex.what()); return false; } catch (const Decoding_Error &ex) { error = QLatin1String(ex.what()); return false; } return true; }
#include "catchy_tests.h" #if defined(BOTAN_HAS_BIGINT) #include <botan/bigint.h> using namespace Botan; TEST_CASE("Bigint basics", "[bigint]") { SECTION("in 0-bit border") { BigInt a(0u); CHECK_THAT(a.bits(), Equals(0)); CHECK_THAT(a.bytes(), Equals(0)); CHECK_THAT(a.to_u32bit(), Equals(0)); } SECTION("above 0-bit border") { BigInt a(1u); CHECK_THAT(a.bits(), Equals(1)); CHECK_THAT(a.bytes(), Equals(1)); CHECK_THAT(a.to_u32bit(), Equals(1)); } SECTION("in 8-bit border") { BigInt a(255u); CHECK_THAT(a.bits(), Equals(8)); CHECK_THAT(a.bytes(), Equals(1)); CHECK_THAT(a.to_u32bit(), Equals(255));
bool SshEncryptionFacility::createAuthenticationKeyFromOpenSSL(const QByteArray &privKeyFileContents, QList<BigInt> &pubKeyParams, QList<BigInt> &allKeyParams, QString &error) { try { bool syntaxOk = true; QList<QByteArray> lines = privKeyFileContents.split('\n'); while (lines.last().isEmpty()) lines.removeLast(); if (lines.count() < 3) { syntaxOk = false; } else if (lines.first() == PrivKeyFileStartLineRsa) { if (lines.last() != PrivKeyFileEndLineRsa) syntaxOk = false; else m_authKeyAlgoName = SshCapabilities::PubKeyRsa; } else if (lines.first() == PrivKeyFileStartLineDsa) { if (lines.last() != PrivKeyFileEndLineDsa) syntaxOk = false; else m_authKeyAlgoName = SshCapabilities::PubKeyDss; } else if (lines.first() == PrivKeyFileStartLineEcdsa) { if (lines.last() != PrivKeyFileEndLineEcdsa) syntaxOk = false; // m_authKeyAlgoName set below, as we don't know the size yet. } else { syntaxOk = false; } if (!syntaxOk) { error = SSH_TR("Unexpected format."); return false; } QByteArray privateKeyBlob; for (int i = 1; i < lines.size() - 1; ++i) privateKeyBlob += lines.at(i); privateKeyBlob = QByteArray::fromBase64(privateKeyBlob); BER_Decoder decoder(convertByteArray(privateKeyBlob), privateKeyBlob.size()); BER_Decoder sequence = decoder.start_cons(SEQUENCE); size_t version; sequence.decode (version); const size_t expectedVersion = m_authKeyAlgoName.isEmpty() ? 1 : 0; if (version != expectedVersion) { error = SSH_TR("Key encoding has version %1, expected %2.") .arg(version).arg(expectedVersion); return false; } if (m_authKeyAlgoName == SshCapabilities::PubKeyDss) { BigInt p, q, g, y, x; sequence.decode (p).decode (q).decode (g).decode (y).decode (x); DSA_PrivateKey * const dsaKey = new DSA_PrivateKey(m_rng, DL_Group(p, q, g), x); m_authKey.reset(dsaKey); pubKeyParams << p << q << g << y; allKeyParams << pubKeyParams << x; } else if (m_authKeyAlgoName == SshCapabilities::PubKeyRsa) { BigInt p, q, e, d, n; sequence.decode(n).decode(e).decode(d).decode(p).decode(q); RSA_PrivateKey * const rsaKey = new RSA_PrivateKey(m_rng, p, q, e, d, n); m_authKey.reset(rsaKey); pubKeyParams << e << n; allKeyParams << pubKeyParams << p << q << d; } else { BigInt privKey; sequence.decode_octet_string_bigint(privKey); m_authKeyAlgoName = SshCapabilities::ecdsaPubKeyAlgoForKeyWidth( static_cast<int>(privKey.bytes())); const EC_Group group(SshCapabilities::oid(m_authKeyAlgoName)); auto * const key = new ECDSA_PrivateKey(m_rng, group, privKey); m_authKey.reset(key); pubKeyParams << key->public_point().get_affine_x() << key->public_point().get_affine_y(); allKeyParams << pubKeyParams << privKey; } sequence.discard_remaining(); sequence.verify_end(); } catch (const Exception &ex) { error = QLatin1String(ex.what()); return false; } catch (const Decoding_Error &ex) { error = QLatin1String(ex.what()); return false; } return true; }