From 8e3549acc05b1bae3edf2db3ebe14978aa07db5f Mon Sep 17 00:00:00 2001 From: Rafal Skowronski Date: Mon, 5 Jul 2021 11:44:20 +0200 Subject: [PATCH] compatible with 2.18.1 --- news.rst | 6 + src/build-data/version.txt | 8 + src/lib/pubkey/curve25519/curve25519.cpp | 262 ++++++++++++++++++++++ src/lib/pubkey/curve25519/curve25519.h | 27 +++ src/lib/pubkey/ed25519/ed25519_fe.h | 15 +- src/lib/pubkey/ed25519/ed25519_internal.h | 28 ++- src/lib/pubkey/ed25519/ge.cpp | 12 + src/python/botan2.py | 4 + src/scripts/test_cli.py | 12 +- src/scripts/test_python.py | 4 +- 10 files changed, 360 insertions(+), 18 deletions(-) diff --git a/news.rst b/news.rst index b70969205df..556fd3031ac 100644 --- a/news.rst +++ b/news.rst @@ -1,6 +1,7 @@ Release Notes ======================================== +<<<<<<< HEAD Version 2.18.1, 2021-05-09 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -87,6 +88,11 @@ Version 2.17.1, 2020-11-07 * Re-enable support for the x86 CLMUL instruction on Visual C++, which was accidentally disabled starting in 2.12.0. (GH #2460) +======= +Version 3.0.0, Not Yet Released +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +>>>>>>> c9fcd92e4 (Bump version to 3.0.0-alpha0) Version 2.17.0, 2020-11-05 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/build-data/version.txt b/src/build-data/version.txt index d0c70ce70ea..55cd913682c 100644 --- a/src/build-data/version.txt +++ b/src/build-data/version.txt @@ -1,9 +1,17 @@ +<<<<<<< HEAD release_major = 2 release_minor = 18 release_patch = 1 release_suffix = '' release_so_abi_rev = 18 +======= +release_major = 3 +release_minor = 0 +release_patch = 0 +release_suffix = '-alpha0' +release_so_abi_rev = 0 +>>>>>>> c9fcd92e4 (Bump version to 3.0.0-alpha0) # These are set by the distribution script release_vc_rev = None diff --git a/src/lib/pubkey/curve25519/curve25519.cpp b/src/lib/pubkey/curve25519/curve25519.cpp index 515fdc5e684..7020890f556 100644 --- a/src/lib/pubkey/curve25519/curve25519.cpp +++ b/src/lib/pubkey/curve25519/curve25519.cpp @@ -6,13 +6,83 @@ */ #include +#include #include #include #include #include namespace Botan { +/** + * Ed25519 signing operation ('C25519' - signs with a Curve25519 key) + */ + class Ed25519_C25519_Sign_Operation : public PK_Ops::Signature + { + public: + Ed25519_C25519_Sign_Operation(const Curve25519_PrivateKey& key) : m_key(key) + { + } +size_t signature_length() const override + { + return 64; + } + void update(const uint8_t msg[], size_t msg_len) override + { + m_msg.insert(m_msg.end(), msg, msg + msg_len); + } + + secure_vector sign(RandomNumberGenerator& rng) override + { + secure_vector sig(64); + std::vector rand; + rand.resize(64); + rng.randomize(rand.data(), 64); + secure_vector privKey25519RAW; + + BER_Decoder(m_key.private_key_bits()).decode(privKey25519RAW, Botan::ASN1_Tag::OCTET_STRING).discard_remaining(); + + curve25519_sign(sig.data(), privKey25519RAW.data(), m_msg.data(), m_msg.size(), rand.data()); + + m_msg.clear(); + return sig; + + } + + private: + std::vector m_msg; + const Curve25519_PrivateKey& m_key; + }; + /** + * Ed255190_C25519 verifying operation + */ + class Ed25519_C25519_Verify_Operation : public PK_Ops::Verification + { + public: + Ed25519_C25519_Verify_Operation(const Curve25519_PublicKey& key) : m_key(key) + { + } + + void update(const uint8_t msg[], size_t msg_len) override + { + m_msg.insert(m_msg.end(), msg, msg + msg_len); + } + + bool is_valid_signature(const uint8_t sig[], size_t sig_len) override + { + if (sig_len != 64) + return false; + + bool ok = curve25519_verify(sig, m_key.public_key_bits().data(), m_msg.data(), m_msg.size()); + m_msg.clear(); + return ok; + } + + private: + std::vector m_msg; + const Curve25519_PublicKey& m_key; + }; + void curve25519_basepoint(uint8_t mypublic[32], const uint8_t secret[32]) { const uint8_t basepoint[32] = { 9 }; @@ -59,6 +129,18 @@ std::vector Curve25519_PublicKey::public_key_bits() const { return m_public; } +std::unique_ptr +Curve25519_PublicKey::create_verification_op(const std::string& params, + const std::string& provider) const +{ + if (provider == "base" || provider.empty()) + { + if (params == "" || params == "Pure") + return std::unique_ptr(new Ed25519_C25519_Verify_Operation(*this)); + + } + throw Provider_Not_Found(algo_name(), provider); +} Curve25519_PrivateKey::Curve25519_PrivateKey(const secure_vector& secret_key) { @@ -139,5 +221,185 @@ Curve25519_PrivateKey::create_key_agreement_op(RandomNumberGenerator& /*rng*/, return std::unique_ptr(new Curve25519_KA_Operation(*this, params)); throw Provider_Not_Found(algo_name(), provider); } +std::unique_ptr +Curve25519_PrivateKey::create_signature_op(RandomNumberGenerator&, + const std::string& params, + const std::string& provider) const +{ + if (provider == "base" || provider.empty()) + { + if (params == "Pure") + return std::unique_ptr(new Ed25519_C25519_Sign_Operation(*this)); + + } + throw Provider_Not_Found(algo_name(), provider); +} + +void clamp(unsigned char* a) +{ + a[0] &= 248; a[31] &= 127; a[31] |= 64; +} +int curve25519_sign(unsigned char* signature_out, + const unsigned char* curve25519_privkey, + const unsigned char* msg, const size_t msg_len, + const unsigned char* random) +{ + std::vector privkey(32); + std::memcpy(privkey.data(), curve25519_privkey, 32); + clamp(privkey.data()); + + ge_p3 ed_pubkey_point; /* Ed25519 pubkey point */ + unsigned char ed_pubkey[32]; /* Ed25519 encoded pubkey */ + unsigned char *sigbuf; /* working buffer */ + unsigned char sign_bit = 0; + + if ((sigbuf = (unsigned char*)malloc(msg_len + 128)) == 0) { + memset(signature_out, 0, 64); + return -1; + } + + /* Convert the Curve25519 privkey to an Ed25519 public key */ + ge_scalarmult_base(ed_pubkey, privkey.data()); + sign_bit = ed_pubkey[31] & 0x80; + + /* Perform an Ed25519 signature with explicit private key */ + ed25519_sign_modified(signature_out, msg, msg_len, privkey.data(), + ed_pubkey, random); + + /* Encode the sign bit into signature (in unused high bit of S) */ + signature_out[63] &= 0x7F; /* bit should be zero already, but just in case */ + signature_out[63] |= sign_bit; + + free(sigbuf); + return 0; +} + +int ed25519_sign_modified( + unsigned char *signature_out, + const unsigned char *m, size_t mlen, + const unsigned char *sk, const unsigned char* pk, + const unsigned char* random +) +{ + unsigned char nonce[64]; + unsigned char hram[64]; + unsigned char * sigbuf; + + SHA_512 sha; + ge_p3 R; + int count = 0; + + if ((sigbuf = (unsigned char*)malloc(mlen+128)) == 0) { + memset(signature_out, 0, 64); + return -1; + } + memmove(sigbuf + 64, m, mlen); + memmove(sigbuf + 32, sk, 32); + sigbuf[0] = 0xFE; + for (count = 1; count < 32; count++) + sigbuf[count] = 0xFF; + + /* add suffix of random data */ + memmove(sigbuf + mlen + 64, random, 64); + sha.update(sigbuf, mlen + 128); + sha.final(nonce); + memmove(sigbuf + 32, pk, 32); + + sc_reduce(nonce); + ge_scalarmult_base(sigbuf, nonce); + + sha.update(sigbuf, mlen + 64); + sha.final(hram); + + sc_reduce(hram); + sc_muladd(sigbuf + 32, hram, sk, nonce); + memmove(signature_out, sigbuf, 64); + + free(sigbuf); + return 0; +} + +int ed25519_verify_modified( + const unsigned char *m, size_t mlen, const unsigned char *sig, + const unsigned char *pk +) +{ + unsigned char pkcopy[32]; + unsigned char rcopy[32]; + unsigned char scopy[32]; + unsigned char h[64]; + unsigned char rcheck[32]; + unsigned char *verifybuf = NULL; + ge_p3 A; + ge_p2 R; + + std::unique_ptr hash(HashFunction::create("SHA-512")); + int retvalue = 0; + + if (sig[63] & 224) + goto exit; + + if (ge_frombytes_negate_vartime(&A, pk) != 0) + goto exit; + + if ((verifybuf = (unsigned char*) malloc(mlen+64)) == 0) { + goto exit; + } + + memmove(pkcopy, pk, 32); + memmove(rcopy, sig, 32); + memmove(scopy, sig + 32, 32); + memmove(verifybuf, sig, 64); + memmove(verifybuf+64, m, mlen); + memmove(verifybuf + 32, pkcopy, 32); + + hash->update(verifybuf, mlen+64); + hash->final(h); + + sc_reduce(h); + + ge_double_scalarmult_vartime(rcheck, h, &A, scopy); + + if (constant_time_compare(rcheck, rcopy, 32)) { + retvalue = 1; + } + +exit: + if (verifybuf != NULL) { + free(verifybuf); + } + + return retvalue; +} + + +int curve25519_verify(const unsigned char* signature, + const unsigned char* curve25519_pubkey, + const unsigned char* msg, const size_t msg_len) +{ + fe u; + fe y; + unsigned char ed_pubkey[32]; + unsigned char loc_signature[64]; + int result; + + fe_frombytes(u, curve25519_pubkey); + + /* Convert montgomery x-coordinate into an edwards y - coordinate: + y = (u - 1) / (u + 1) */ + fe_montx_to_edy(&y, u); + fe_tobytes(ed_pubkey, y); + + ed_pubkey[31] &= 0x7F; + ed_pubkey[31] |= (signature[63] & 0x80); + memmove(loc_signature, signature, 64); + loc_signature[63] &= 0x7F; + + result = ed25519_verify_modified(msg, msg_len, loc_signature, ed_pubkey); + +err: + + return result; +} } diff --git a/src/lib/pubkey/curve25519/curve25519.h b/src/lib/pubkey/curve25519/curve25519.h index c2f8f42b33c..59fd22e32ed 100644 --- a/src/lib/pubkey/curve25519/curve25519.h +++ b/src/lib/pubkey/curve25519/curve25519.h @@ -49,6 +49,10 @@ class BOTAN_PUBLIC_API(2,0) Curve25519_PublicKey : public virtual Public_Key */ explicit Curve25519_PublicKey(const secure_vector& pub) : m_public(pub.begin(), pub.end()) {} + + std::unique_ptr + create_verification_op(const std::string& params, + const std::string& provider) const override; protected: Curve25519_PublicKey() = default; @@ -94,6 +98,10 @@ class BOTAN_PUBLIC_API(2,0) Curve25519_PrivateKey final : public Curve25519_Publ create_key_agreement_op(RandomNumberGenerator& rng, const std::string& params, const std::string& provider) const override; + std::unique_ptr + create_signature_op(RandomNumberGenerator& rng, + const std::string& params, + const std::string& provider) const override; private: secure_vector m_private; @@ -119,5 +127,24 @@ void BOTAN_PUBLIC_API(2,0) curve25519_basepoint(uint8_t mypublic[32], const uint8_t secret[32]); } +namespace Botan { + /* returns 0 on success */ + int curve25519_sign(unsigned char* signature_out, /* 64 bytes */ + const unsigned char* curve25519_privkey, /* 32 bytes */ + const unsigned char* msg, const size_t msg_len, + const unsigned char * random); /* 64 bytes */ + + /* returns 0 on success */ + int curve25519_verify(const unsigned char* signature, /* 64 bytes */ + const unsigned char* curve25519_pubkey, /* 32 bytes */ + const unsigned char* msg, const size_t msg_len); + + int ed25519_sign_modified( + unsigned char *sm, + const unsigned char *m, size_t mlen, + const unsigned char *sk, const unsigned char* pk, + const unsigned char* random + ); +} #endif diff --git a/src/lib/pubkey/ed25519/ed25519_fe.h b/src/lib/pubkey/ed25519/ed25519_fe.h index bcdc36a5e24..acb24788388 100644 --- a/src/lib/pubkey/ed25519/ed25519_fe.h +++ b/src/lib/pubkey/ed25519/ed25519_fe.h @@ -221,7 +221,20 @@ inline void fe_pow22523(fe& x, const fe& y) { x = FE_25519::pow_22523(y); } - +inline void fe_montx_to_edy(fe *y, const fe u) +{ + /* + y = (u - 1) / (u + 1) + NOTE: u=-1 is converted to y=0 since fe_invert is mod-exp + */ + fe one, um1, up1; + + fe_1(one); + fe_sub(um1, u, one); + fe_add(up1, u, one); + fe_invert(up1, up1); + fe_mul(*y, um1, up1); +} } #endif diff --git a/src/lib/pubkey/ed25519/ed25519_internal.h b/src/lib/pubkey/ed25519/ed25519_internal.h index cb67a43fd29..3054cf7682c 100644 --- a/src/lib/pubkey/ed25519/ed25519_internal.h +++ b/src/lib/pubkey/ed25519/ed25519_internal.h @@ -8,6 +8,7 @@ * Botan is released under the Simplified BSD License (see license.txt) */ + #ifndef BOTAN_ED25519_INT_H_ #define BOTAN_ED25519_INT_H_ @@ -16,6 +17,22 @@ namespace Botan { + #ifndef gePoints + #define gePoints + typedef struct + { + fe X; + fe Y; + fe Z; + fe T; + } ge_p3; + typedef struct + { + fe X; + fe Y; + fe Z; + } ge_p2; + #endif inline uint64_t load_3(const uint8_t in[3]) { return static_cast(in[0]) | @@ -90,17 +107,11 @@ where d = -121665/121666. ge_p3 (extended): (X:Y:Z:T) satisfying x=X/Z, y=Y/Z, XY=ZT */ -typedef struct - { - fe X; - fe Y; - fe Z; - fe T; - } ge_p3; + + int ge_frombytes_negate_vartime(ge_p3*, const uint8_t*); void ge_scalarmult_base(uint8_t out[32], const uint8_t in[32]); - void ge_double_scalarmult_vartime(uint8_t out[32], const uint8_t a[], const ge_p3* A, @@ -110,7 +121,6 @@ void ge_double_scalarmult_vartime(uint8_t out[32], The set of scalars is \Z/l where l = 2^252 + 27742317777372353535851937790883648493. */ - void sc_reduce(uint8_t*); void sc_muladd(uint8_t*, const uint8_t*, const uint8_t*, const uint8_t*); diff --git a/src/lib/pubkey/ed25519/ge.cpp b/src/lib/pubkey/ed25519/ge.cpp index 7d3fae2fbc2..e9bf20b4866 100644 --- a/src/lib/pubkey/ed25519/ge.cpp +++ b/src/lib/pubkey/ed25519/ge.cpp @@ -22,12 +22,24 @@ namespace { ge_p1p1 (completed): ((X:Z),(Y:T)) satisfying x=X/Z, y=Y/T ge_precomp (Duif): (y+x,y-x,2dxy) */ + + +#ifndef gePoints +#define gePoints typedef struct + { + fe X; + fe Y; + fe Z; + fe T; + } ge_p3; + typedef struct { fe X; fe Y; fe Z; } ge_p2; +#endif typedef struct { diff --git a/src/python/botan2.py b/src/python/botan2.py index 6ae1bd6da32..358d3bc59fc 100755 --- a/src/python/botan2.py +++ b/src/python/botan2.py @@ -55,11 +55,15 @@ def _load_botan_dll(expected_version): possible_dll_names = [] if platform in ['win32', 'cygwin', 'msys']: + possible_dll_names.append('botan-3.dll') possible_dll_names.append('botan.dll') elif platform in ['darwin', 'macos']: + possible_dll_names.append('libbotan-3.dylib') possible_dll_names.append('libbotan-2.dylib') else: # assumed to be some Unix/Linux system + possible_dll_names.append('libbotan-3.so') + possible_dll_names += ['libbotan-3.so.%d' % (v) for v in reversed(range(0, 10))] possible_dll_names.append('libbotan-2.so') possible_dll_names += ['libbotan-2.so.%d' % (v) for v in reversed(range(13, 20))] diff --git a/src/scripts/test_cli.py b/src/scripts/test_cli.py index 4e0f8ab830d..71abdc2e89f 100755 --- a/src/scripts/test_cli.py +++ b/src/scripts/test_cli.py @@ -119,11 +119,11 @@ def cli_config_tests(_tmp_dir): if len(prefix) < 4 or prefix[0] != '/': logging.error("Bad prefix %s" % (prefix)) - if ("-I%s/include/botan-2" % (prefix)) not in cflags: + if ("-I%s/include/botan-3" % (prefix)) not in cflags: logging.error("Bad cflags %s" % (cflags)) if not ldflags.endswith(("-L%s/lib" % (prefix))): logging.error("Bad ldflags %s" % (ldflags)) - if "-lbotan-2" not in libs: + if "-lbotan-3" not in libs: logging.error("Bad libs %s" % (libs)) def cli_help_tests(_tmp_dir): @@ -136,12 +136,12 @@ def cli_help_tests(_tmp_dir): def cli_version_tests(_tmp_dir): output = test_cli("version", None, None) - version_re = re.compile(r'[0-9]\.[0-9]+\.[0-9]') + version_re = re.compile(r'[0-9]\.[0-9]+\.[0-9](\-[a-z]+[0-9]+)?') if not version_re.match(output): logging.error("Unexpected version output %s" % (output)) output = test_cli("version", ["--full"], None, None) - version_full_re = re.compile(r'Botan [0-9]\.[0-9]+\.[0-9] \(.* revision .*, distribution .*\)$') + version_full_re = re.compile(r'Botan [0-9]\.[0-9]+\.[0-9](\-[a-z]+[0-9]+)? \(.* revision .*, distribution .*\)$') if not version_full_re.match(output): logging.error("Unexpected version output %s" % (output)) @@ -913,7 +913,7 @@ def cli_tls_http_server_tests(tmp_dir): body = str(resp.read()) - if body.find('TLS negotiation with Botan 2.') < 0: + if body.find('TLS negotiation with Botan 3.') < 0: logging.error('Unexpected response body') conn.request("POST", "/logout") @@ -1157,7 +1157,7 @@ def cli_speed_pbkdf_tests(_tmp_dir): def cli_speed_table_tests(_tmp_dir): msec = 1 - version_re = re.compile(r'^Botan 2\.[0-9]+\.[0-9] \(.*, revision .*, distribution .*\)') + version_re = re.compile(r'^Botan 3\.[0-9]+\.[0-9](\-.*[0-9]+)? \(.*, revision .*, distribution .*\)') cpuid_re = re.compile(r'^CPUID: [a-z_0-9 ]*$') format_re = re.compile(r'^AES-128 .* buffer size [0-9]+ bytes: [0-9]+\.[0-9]+ MiB\/sec .*\([0-9]+\.[0-9]+ MiB in [0-9]+\.[0-9]+ ms\)') tbl_hdr_re = re.compile(r'^algo +operation +1024 bytes$') diff --git a/src/scripts/test_python.py b/src/scripts/test_python.py index 2202c0e4bcb..e4f115d0c84 100644 --- a/src/scripts/test_python.py +++ b/src/scripts/test_python.py @@ -23,8 +23,8 @@ def test_version(self): version_str = botan2.version_string() self.assertTrue(version_str.startswith('Botan ')) - self.assertEqual(botan2.version_major(), 2) - self.assertGreaterEqual(botan2.version_minor(), 8) + self.assertEqual(botan2.version_major(), 3) + self.assertGreaterEqual(botan2.version_minor(), 0) self.assertGreaterEqual(botan2.ffi_api_version(), 20180713)