From 6f942d13e857617351a7a75b3d4e4eeb9a5b1772 Mon Sep 17 00:00:00 2001 From: Helder Eijs Date: Thu, 11 May 2023 23:12:21 +0200 Subject: [PATCH 01/18] Add unit test for AESNI --- src/AESNI.c | 56 +++++++++------ src/test/CMakeLists.txt | 12 +++- src/test/test_aesni.c | 150 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 194 insertions(+), 24 deletions(-) create mode 100644 src/test/test_aesni.c diff --git a/src/AESNI.c b/src/AESNI.c index 911ef819b..3cc716892 100644 --- a/src/AESNI.c +++ b/src/AESNI.c @@ -58,7 +58,7 @@ typedef struct { enum SubType { OnlySub, SubRotXor }; -static uint32_t sub_rot(uint32_t w, unsigned idx /** round/Nk **/, enum SubType subType) +STATIC uint32_t sub_rot(uint32_t w, unsigned idx /** round/Nk **/, enum SubType subType) { __m128i x, y, z; @@ -90,7 +90,7 @@ static uint32_t sub_rot(uint32_t w, unsigned idx /** round/Nk **/, enum SubType return (uint32_t)_mm_cvtsi128_si32(z); } -static int expand_key(__m128i *erk, __m128i *drk, const uint8_t *key, unsigned Nk, unsigned Nr) +STATIC int expand_key(__m128i *erk, __m128i *drk, const uint8_t *key, unsigned Nk, unsigned Nr) { uint32_t rk[4*(14+2)]; unsigned tot_words; @@ -137,26 +137,8 @@ static int expand_key(__m128i *erk, __m128i *drk, const uint8_t *key, unsigned N return 0; } -static int AESNI_encrypt(const BlockBase *bb, const uint8_t *in, uint8_t *out, size_t data_len) +STATIC int internal_AESNI_encrypt(__m128i r[], unsigned rounds, const uint8_t *in, uint8_t *out, size_t data_len) { - unsigned rounds; - __m128i r[14+1]; - const struct block_state *state; - unsigned k; - - if ((bb == NULL) || (in == NULL) || (out == NULL)) - return ERR_NULL; - - state = &((AESNI_State*)bb)->algo_state; - rounds = state->rounds; - - if (rounds > 14) - return ERR_NR_ROUNDS; - - for (k=0; k<=rounds; k++) { - r[k] = state->erk[k]; - } - /** Encrypt 8 blocks (128 bytes) in parallel, when possible **/ for (; data_len >= 8*16; data_len -= 8*16) { __m128i pt[8], data[8]; @@ -246,7 +228,7 @@ static int AESNI_encrypt(const BlockBase *bb, const uint8_t *in, uint8_t *out, s return 0; } -static int AESNI_decrypt(const BlockBase *bb, const uint8_t *in, uint8_t *out, size_t data_len) +static int AESNI_encrypt(const BlockBase *bb, const uint8_t *in, uint8_t *out, size_t data_len) { unsigned rounds; __m128i r[14+1]; @@ -263,9 +245,14 @@ static int AESNI_decrypt(const BlockBase *bb, const uint8_t *in, uint8_t *out, s return ERR_NR_ROUNDS; for (k=0; k<=rounds; k++) { - r[k] = state->drk[k]; + r[k] = state->erk[k]; } + return internal_AESNI_encrypt(r, rounds, in, out, data_len); +} + +STATIC int internal_AESNI_decrypt(__m128i r[], unsigned rounds, const uint8_t *in, uint8_t *out, size_t data_len) +{ /** Decrypt 8 blocks (128 bytes) in parallel, when possible **/ for (; data_len >= 8*16; data_len -= 8*16) { __m128i ct[8], data[8]; @@ -355,6 +342,29 @@ static int AESNI_decrypt(const BlockBase *bb, const uint8_t *in, uint8_t *out, s return 0; } +static int AESNI_decrypt(const BlockBase *bb, const uint8_t *in, uint8_t *out, size_t data_len) +{ + unsigned rounds; + __m128i r[14+1]; + const struct block_state *state; + unsigned k; + + if ((bb == NULL) || (in == NULL) || (out == NULL)) + return ERR_NULL; + + state = &((AESNI_State*)bb)->algo_state; + rounds = state->rounds; + + if (rounds > 14) + return ERR_NR_ROUNDS; + + for (k=0; k<=rounds; k++) { + r[k] = state->drk[k]; + } + + return internal_AESNI_decrypt(r, rounds, in, out, data_len); +} + EXPORT_SYM int AESNI_stop_operation(BlockBase *bb) { AESNI_State *state; diff --git a/src/test/CMakeLists.txt b/src/test/CMakeLists.txt index 0a2ea6377..075182a90 100644 --- a/src/test/CMakeLists.txt +++ b/src/test/CMakeLists.txt @@ -6,6 +6,7 @@ enable_testing() cmake_print_variables(CMAKE_CXX_COMPILER_ID CMAKE_CXX_COMPILER_VERSION CMAKE_SIZEOF_VOID_P SSE) option(SSE "Enable SSE instructions on Intel targets" ON) +option(AESNI "Enable AESNI instructions on Intel targets" ON) if (DEFINED ENV{PYTHON}) set(PYTHON $ENV{PYTHON}) @@ -62,10 +63,15 @@ else() if (SSE) message(STATUS "Using SSE instructions") add_compile_definitions(HAVE_X86INTRIN_H) - add_compile_definitions(HAVE_WMMINTRIN_H) add_compile_definitions(HAVE_TMMINTRIN_H) add_compile_options(-mssse3 -mpclmul) endif() + if (SSE OR AESNI) + add_compile_definitions(HAVE_WMMINTRIN_H) + endif() + if (AESNI) + add_compile_options(-maes) + endif() endif() # ------------------------------------------------------------------------- @@ -177,3 +183,7 @@ add_test(NAME test_ed25519 COMMAND test_ed25519) # ed448 add_executable(test_ed448 test_ed448.c ../ed448.c $) add_test(NAME test_ed448 COMMAND test_ed448) + +# aesni +add_executable(test_aesni test_aesni.c ../AESNI.c) +add_test(NAME test_aesni COMMAND test_aesni) diff --git a/src/test/test_aesni.c b/src/test/test_aesni.c new file mode 100644 index 000000000..46688b61a --- /dev/null +++ b/src/test/test_aesni.c @@ -0,0 +1,150 @@ +#include "common.h" +#include +#include + +enum SubType { OnlySub, SubRotXor }; +uint32_t sub_rot(uint32_t w, unsigned idx /** round/Nk **/, enum SubType subType); +int expand_key(__m128i *erk, __m128i *drk, const uint8_t *key, unsigned Nk, unsigned Nr); +int internal_AESNI_encrypt(__m128i r[], unsigned rounds, const uint8_t *in, uint8_t *out, size_t data_len); + +void test_sub_rot(void) +{ + uint32_t res[] = { + 0xC116EA4A, + 0xC116EA49, + 0xC116EA4F, + 0xC116EA43, + 0xC116EA5B, + 0xC116EA6B, + 0xC116EA0B, + 0xC116EACB, + 0xC116EA50, + 0xC116EA7D + }; + + for (int i=1; i<=10; i++) { + assert(res[i-1] == sub_rot(0xFFBBCCDD, i, SubRotXor)); + } + + assert(0x16EA4BC1 == sub_rot(0xFFBBCCDD, 4, OnlySub)); +} + +int m128i_m128i_differ(__m128i a, __m128i b) +{ + int mask; + __m128i result; + result = _mm_cmpeq_epi32(a, b); + mask = _mm_movemask_epi8(result); + return mask != 0xFFFF; +} + +int m128i_array_differ(__m128i a, const uint8_t *ref) +{ + uint8_t *array; + unsigned i; + array = (uint8_t*)align_alloc(16, 16); + _mm_storeu_si128((__m128i*)array, a); + for (i=0; i<16; i++) { + if (array[i] != ref[i]) + return -1; + } + align_free(array); + return 0; +} + +int array16_differ(const uint8_t *a, const uint8_t *b) +{ + unsigned i; + for (i=0; i<16; i++) { + if (a[i] != b[i]) + return -1; + } + return 0; +} + +void test_expand_key_128(void) +{ + uint8_t key[16] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 , 13, 14, 15 }; + __m128i *erk; + __m128i *drk; + const uint8_t drk_1[16] = { 19, 170, 41, 190, 156, 143, 175, 246, 247, 112, 245, 128, 0, 247, 191, 3 }; + const uint8_t drk_9[16] = { 140, 86, 223, 240, 130, 93, 211, 249, 128, 90, 211, 252, 134, 89, 215, 253 }; + const uint8_t erk_1[16] = {214, 170, 116, 253, 210, 175, 114, 250, 218, 166, 120, 241, 214, 171, 118, 254}; + const uint8_t erk_9[16] = {84, 153, 50, 209, 240, 133, 87, 104, 16, 147, 237, 156, 190, 44, 151, 78}; + + erk = (__m128i*)align_alloc(16*11, 16); + drk = (__m128i*)align_alloc(16*11, 16); + + expand_key(erk, drk, key, 4, 10); + + assert(m128i_m128i_differ(erk[0], drk[10]) == 0); + assert(m128i_m128i_differ(erk[10], drk[0]) == 0); + + assert(m128i_array_differ(erk[1], erk_1) == 0); + assert(m128i_array_differ(erk[9], erk_9) == 0); + assert(m128i_array_differ(drk[1], drk_1) == 0); + assert(m128i_array_differ(drk[9], drk_9) == 0); + + align_free(erk); + align_free(drk); +} + +void test_encrypt_128(void) +{ + uint8_t key[16] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 , 13, 14, 15 }; + uint8_t pt[16] = { 21, 23, 89, 2, 209, 2, 45, 1, 233, 190, 23, 1, 2, 2, 1, 5 }; + uint8_t ct[16]; + uint8_t ct_ref[16] = { 166, 206, 231, 70, 200, 68, 178, 80, 55, 156, 105, 27, 230, 75, 80, 178}; + uint8_t *pt_big, *ct_big; + __m128i *erk; + __m128i *drk; + int result; + int i; + + erk = (__m128i*)align_alloc(16*11, 16); + drk = (__m128i*)align_alloc(16*11, 16); + + expand_key(erk, drk, key, 4, 10); + + /* 1 block */ + result = internal_AESNI_encrypt(erk, 10, pt, ct, 16); + assert(result == 0); + assert(array16_differ(ct, ct_ref) == 0); + + /* 8 blocks */ + pt_big = malloc(16*8); + ct_big = malloc(16*8); + for (i=0; i<8; i++) + memcpy(pt_big + 16*i, pt, 16); + result = internal_AESNI_encrypt(erk, 10, pt_big, ct_big, 16*8); + for (i=0; i<8; i++) + assert(array16_differ(ct_big + 16*i, ct_ref) == 0); + free(pt_big); + free(ct_big); + + /* 8+1 blocks */ + pt_big = malloc(16*9); + ct_big = malloc(16*9); + for (i=0; i<9; i++) + memcpy(pt_big + 16*i, pt, 16); + result = internal_AESNI_encrypt(erk, 10, pt_big, ct_big, 16*9); + for (i=0; i<9; i++) + assert(array16_differ(ct_big + 16*i, ct_ref) == 0); + free(pt_big); + free(ct_big); + + /* partial block */ + result = internal_AESNI_encrypt(erk, 10, pt, ct, 15); + assert(result != 0); + + align_free(erk); + align_free(drk); +} + +int main(void) +{ + test_sub_rot(); + test_expand_key_128(); + test_encrypt_128(); + return 0; +} From b6fe8d11ba05e2019789919cc56bd9e6887987e3 Mon Sep 17 00:00:00 2001 From: Helder Eijs Date: Sat, 13 May 2023 09:45:41 +0200 Subject: [PATCH 02/18] Fixed GH#722: nonce attribute was not correctly set for XChaCha20_Poly1305 ciphers --- Changelog.rst | 4 ++++ lib/Crypto/Cipher/ChaCha20_Poly1305.py | 10 +++++----- lib/Crypto/SelfTest/Cipher/test_ChaCha20_Poly1305.py | 10 ++++++++-- 3 files changed, 17 insertions(+), 7 deletions(-) diff --git a/Changelog.rst b/Changelog.rst index 470f2835a..dd58ad432 100644 --- a/Changelog.rst +++ b/Changelog.rst @@ -8,6 +8,10 @@ New features --------------- * Added support for DER BOOLEAN encodings. + Resolved issues +--------------- +* GH#722: ``nonce`` attribute was not correctly set for XChaCha20_Poly1305 ciphers. Thanks to Liam Haber. + 3.17.0 (29 January 2023) ++++++++++++++++++++++++++ diff --git a/lib/Crypto/Cipher/ChaCha20_Poly1305.py b/lib/Crypto/Cipher/ChaCha20_Poly1305.py index d8f7ef1e8..55840a567 100644 --- a/lib/Crypto/Cipher/ChaCha20_Poly1305.py +++ b/lib/Crypto/Cipher/ChaCha20_Poly1305.py @@ -63,8 +63,6 @@ def __init__(self, key, nonce): See also `new()` at the module level.""" - self.nonce = _copy_bytes(None, None, nonce) - self._next = ("update", "encrypt", "decrypt", "digest", "verify") @@ -316,10 +314,10 @@ def new(**kwargs): nonce = get_random_bytes(12) if len(nonce) in (8, 12): - pass + chacha20_poly1305_nonce = nonce elif len(nonce) == 24: key = _HChaCha20(key, nonce[:16]) - nonce = b'\x00\x00\x00\x00' + nonce[16:] + chacha20_poly1305_nonce = b'\x00\x00\x00\x00' + nonce[16:] else: raise ValueError("Nonce must be 8, 12 or 24 bytes long") @@ -329,7 +327,9 @@ def new(**kwargs): if kwargs: raise TypeError("Unknown parameters: " + str(kwargs)) - return ChaCha20Poly1305Cipher(key, nonce) + cipher = ChaCha20Poly1305Cipher(key, chacha20_poly1305_nonce) + cipher.nonce = _copy_bytes(None, None, nonce) + return cipher # Size of a key (in bytes) diff --git a/lib/Crypto/SelfTest/Cipher/test_ChaCha20_Poly1305.py b/lib/Crypto/SelfTest/Cipher/test_ChaCha20_Poly1305.py index 67440d76b..9129c68de 100644 --- a/lib/Crypto/SelfTest/Cipher/test_ChaCha20_Poly1305.py +++ b/lib/Crypto/SelfTest/Cipher/test_ChaCha20_Poly1305.py @@ -37,7 +37,6 @@ from Crypto.Cipher import ChaCha20_Poly1305 from Crypto.Hash import SHAKE128 -from Crypto.Util._file_system import pycryptodome_filename from Crypto.Util.strxor import strxor @@ -326,6 +325,13 @@ def test_memoryview(self): class XChaCha20Poly1305Tests(unittest.TestCase): + def test_nonce(self): + # Nonce can only be 24 bytes + cipher = ChaCha20_Poly1305.new(key=b'Y' * 32, + nonce=b'H' * 24) + self.assertEqual(len(cipher.nonce), 24) + self.assertEqual(cipher.nonce, b'H' * 24) + def test_encrypt(self): # From https://tools.ietf.org/html/draft-arciszewski-xchacha-03 # Section A.3.1 @@ -599,7 +605,7 @@ class TestVectorsRFC(unittest.TestCase): ) ] - test_vectors = [[unhexlify(x.replace(" ","").replace(":","")) for x in tv] for tv in test_vectors_hex] + test_vectors = [[unhexlify(x.replace(" ", "").replace(":", "")) for x in tv] for tv in test_vectors_hex] def runTest(self): for assoc_data, pt, ct, mac, key, nonce in self.test_vectors: From 56ec867f1ee155c782a0d80de2309fb4fdf9edde Mon Sep 17 00:00:00 2001 From: William Barnhart Date: Tue, 14 Mar 2023 12:36:50 -0400 Subject: [PATCH 03/18] Fix documentation for SIV and GCM ciphers Closes https://github.com/Legrandin/pycryptodome/issues/717. --- lib/Crypto/Cipher/AES.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/Crypto/Cipher/AES.py b/lib/Crypto/Cipher/AES.py index ebb27d2ee..40441f4c5 100644 --- a/lib/Crypto/Cipher/AES.py +++ b/lib/Crypto/Cipher/AES.py @@ -38,8 +38,8 @@ MODE_OPENPGP = 7 #: OpenPGP mode (:ref:`openpgp_mode`) MODE_CCM = 8 #: Counter with CBC-MAC (:ref:`ccm_mode`) MODE_EAX = 9 #: :ref:`eax_mode` -MODE_SIV = 10 #: Galois Counter Mode (:ref:`gcm_mode`) -MODE_GCM = 11 #: Synthetic Initialization Vector (:ref:`siv_mode`) +MODE_SIV = 10 #: Synthetic Initialization Vector (:ref:`siv_mode`) +MODE_GCM = 11 #: Galois Counter Mode (:ref:`gcm_mode`) MODE_OCB = 12 #: Offset Code Book (:ref:`ocb_mode`) From 09f0ac570c6a47984c692eb82695d493de971117 Mon Sep 17 00:00:00 2001 From: Helder Eijs Date: Sat, 13 May 2023 22:45:52 +0200 Subject: [PATCH 04/18] Fix GH#739: OID encoding for arc 2 didn't accept children larger than 39 --- Changelog.rst | 1 + lib/Crypto/SelfTest/Util/test_asn1.py | 29 +++++++++++---- lib/Crypto/Util/asn1.py | 51 ++++++++++++++++++--------- 3 files changed, 58 insertions(+), 23 deletions(-) diff --git a/Changelog.rst b/Changelog.rst index dd58ad432..39202ec8a 100644 --- a/Changelog.rst +++ b/Changelog.rst @@ -11,6 +11,7 @@ New features Resolved issues --------------- * GH#722: ``nonce`` attribute was not correctly set for XChaCha20_Poly1305 ciphers. Thanks to Liam Haber. +* GH#739: OID encoding for arc 2 didn't accept children larger than 39. Thanks to James. 3.17.0 (29 January 2023) ++++++++++++++++++++++++++ diff --git a/lib/Crypto/SelfTest/Util/test_asn1.py b/lib/Crypto/SelfTest/Util/test_asn1.py index c678a956d..e441ba0a3 100644 --- a/lib/Crypto/SelfTest/Util/test_asn1.py +++ b/lib/Crypto/SelfTest/Util/test_asn1.py @@ -614,35 +614,50 @@ class DerObjectIdTests(unittest.TestCase): def testInit1(self): der = DerObjectId("1.1") - self.assertEqual(der.encode(), b('\x06\x01)')) + self.assertEqual(der.encode(), b'\x06\x01)') def testEncode1(self): der = DerObjectId('1.2.840.113549.1.1.1') - self.assertEqual(der.encode(), b('\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x01\x01')) - # + self.assertEqual(der.encode(), b'\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x01\x01') + der = DerObjectId() der.value = '1.2.840.113549.1.1.1' - self.assertEqual(der.encode(), b('\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x01\x01')) + self.assertEqual(der.encode(), b'\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x01\x01') + + der = DerObjectId('2.999.1234') + self.assertEqual(der.encode(), b'\x06\x04\x88\x37\x89\x52') + + def testEncode2(self): + der = DerObjectId('3.4') + self.assertRaises(ValueError, der.encode) + + der = DerObjectId('1.40') + self.assertRaises(ValueError, der.encode) #### def testDecode1(self): # Empty sequence der = DerObjectId() - der.decode(b('\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x01\x01')) + der.decode(b'\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x01\x01') self.assertEqual(der.value, '1.2.840.113549.1.1.1') def testDecode2(self): # Verify that decode returns the object der = DerObjectId() self.assertEqual(der, - der.decode(b('\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x01\x01'))) + der.decode(b'\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x01\x01')) def testDecode3(self): der = DerObjectId() - der.decode(b('\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x00\x01')) + der.decode(b'\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x00\x01') self.assertEqual(der.value, '1.2.840.113549.1.0.1') + def testDecode4(self): + der = DerObjectId() + der.decode(b'\x06\x04\x88\x37\x89\x52') + self.assertEqual(der.value, '2.999.1234') + class DerBitStringTests(unittest.TestCase): diff --git a/lib/Crypto/Util/asn1.py b/lib/Crypto/Util/asn1.py index 59d5956b1..1f7efe276 100644 --- a/lib/Crypto/Util/asn1.py +++ b/lib/Crypto/Util/asn1.py @@ -34,7 +34,8 @@ # - https://letsencrypt.org/docs/a-warm-welcome-to-asn1-and-der/ # - https://www.zytrax.com/tech/survival/asn1.html # - https://www.oss.com/asn1/resources/books-whitepapers-pubs/larmouth-asn1-book.pdf - +# - https://www.itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf +# - https://misc.daniel-marschall.de/asn.1/oid-converter/online.php def _is_number(x, only_non_negative=False): test = 0 @@ -747,19 +748,25 @@ def encode(self): binary string.""" comps = [int(x) for x in self.value.split(".")] + if len(comps) < 2: raise ValueError("Not a valid Object Identifier string") - self.payload = bchr(40*comps[0]+comps[1]) - for v in comps[2:]: - if v == 0: - enc = [0] - else: - enc = [] - while v: - enc.insert(0, (v & 0x7F) | 0x80) - v >>= 7 - enc[-1] &= 0x7F - self.payload += b''.join([bchr(x) for x in enc]) + if comps[0] > 2: + raise ValueError("First component must be 0, 1 or 2") + if comps[0] < 2 and comps[1] > 39: + raise ValueError("Second component must be 39 at most") + + subcomps = [40 * comps[0] + comps[1]] + comps[2:] + + encoding = [] + for v in reversed(subcomps): + encoding.append(v & 0x7F) + v >>= 7 + while v: + encoding.append((v & 0x7F) | 0x80) + v >>= 7 + + self.payload = b''.join([bchr(x) for x in reversed(encoding)]) return DerObject.encode(self) def decode(self, der_encoded, strict=False): @@ -786,15 +793,27 @@ def _decodeFromStream(self, s, strict): # Derive self.value from self.payload p = BytesIO_EOF(self.payload) - comps = [str(x) for x in divmod(p.read_byte(), 40)] + + subcomps = [] v = 0 while p.remaining_data(): c = p.read_byte() - v = v*128 + (c & 0x7F) + v = (v << 7) + (c & 0x7F) if not (c & 0x80): - comps.append(str(v)) + subcomps.append(v) v = 0 - self.value = '.'.join(comps) + + if len(subcomps) == 0: + raise ValueError("Empty payload") + + if subcomps[0] < 40: + subcomps[:1] = [0, subcomps[0]] + elif subcomps[0] < 80: + subcomps[:1] = [1, subcomps[0] - 40] + else: + subcomps[:1] = [2, subcomps[0] - 80] + + self.value = ".".join([str(x) for x in subcomps]) class DerBitString(DerObject): From 7e9183b5663744e9e4ab5046d50f71883bbc9736 Mon Sep 17 00:00:00 2001 From: Helder Eijs Date: Sun, 14 May 2023 23:00:41 +0200 Subject: [PATCH 05/18] Enable compiling on Windows ARM64 (see GH PR 579) --- Changelog.rst | 1 + src/multiply.h | 14 +++++++++++--- src/multiply_64.c | 2 +- 3 files changed, 13 insertions(+), 4 deletions(-) diff --git a/Changelog.rst b/Changelog.rst index 39202ec8a..138c6e6ed 100644 --- a/Changelog.rst +++ b/Changelog.rst @@ -7,6 +7,7 @@ Changelog New features --------------- * Added support for DER BOOLEAN encodings. +* The library now compiles on Windows ARM64. Thanks to Niyas Sait. Resolved issues --------------- diff --git a/src/multiply.h b/src/multiply.h index f7bc2e5f4..75cd448bd 100644 --- a/src/multiply.h +++ b/src/multiply.h @@ -15,10 +15,18 @@ oh = (uint64_t)(pr >> 64); \ } while (0) -#elif defined(_MSC_VER) && defined(_WIN64) +#elif defined(_MSC_VER) && (defined(_M_X64) || defined(__x86_64__)) -#include -#define DP_MULT(a,b,ol,oh) do { ol = UnsignedMultiply128(a,b,&oh); } while (0) +#include +#define DP_MULT(a,b,ol,oh) do { ol = _umul128(a,b,&oh); } while (0) + +#elif defined(_MSC_VER) && defined(_M_ARM64) + +#include +#define DP_MULT(a,b,ol,oh) do { \ + ol = ((uint64_t)(a))*(b); \ + oh = __umulh(a, b); \ +} while (0) #else diff --git a/src/multiply_64.c b/src/multiply_64.c index e9d517613..cb34ff1f4 100644 --- a/src/multiply_64.c +++ b/src/multiply_64.c @@ -38,7 +38,7 @@ /** * Add a 64-bit value x to y/sum_mid/sum_hi */ -#if defined(_WIN64) && (_MSC_VER>=1900) +#if defined(_MSC_VER) && (_MSC_VER>=1900) && (defined(_M_X64) || defined(__x86_64__)) #include #define ADD192(y, x) do { \ From d6a35eb714e363b033c84417b3ddd36cf81f7723 Mon Sep 17 00:00:00 2001 From: Marti Raudsepp Date: Mon, 6 Feb 2023 18:38:23 +0200 Subject: [PATCH 06/18] Add changelog URL to package metadata This changelog link will be visible on the package's PyPI page. Also Renovate bot uses this link to provide quicker access to the changelog for a dependency update. --- setup.cfg | 1 + 1 file changed, 1 insertion(+) diff --git a/setup.cfg b/setup.cfg index 1b7c57a96..8ad4965aa 100644 --- a/setup.cfg +++ b/setup.cfg @@ -4,6 +4,7 @@ max-line-length = 110 [metadata] project_urls = Source=https://github.com/Legrandin/pycryptodome/ + Changelog=https://www.pycryptodome.org/src/changelog [bdist_wheel] py-limited-api = cp35 From 29b11716501508a3f14bc83efebf28d647eebae5 Mon Sep 17 00:00:00 2001 From: Michal Ambroz <723625+xambroz@users.noreply.github.com> Date: Fri, 3 Feb 2023 05:24:42 +0100 Subject: [PATCH 07/18] use assertTrue instead of deprecated failUnless --- lib/Crypto/SelfTest/PublicKey/test_ECC_25519.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/Crypto/SelfTest/PublicKey/test_ECC_25519.py b/lib/Crypto/SelfTest/PublicKey/test_ECC_25519.py index 4ddf3cfc7..9f14131ff 100644 --- a/lib/Crypto/SelfTest/PublicKey/test_ECC_25519.py +++ b/lib/Crypto/SelfTest/PublicKey/test_ECC_25519.py @@ -105,13 +105,13 @@ def test_equal(self): def test_pai(self): pai = EccPoint(0, 1, curve="Ed25519") - self.failUnless(pai.is_point_at_infinity()) + self.assertTrue(pai.is_point_at_infinity()) self.assertEqual(pai, pai.point_at_infinity()) def test_negate(self): negG = -self.pointG sum = self.pointG + negG - self.failUnless(sum.is_point_at_infinity()) + self.assertTrue(sum.is_point_at_infinity()) def test_addition(self): self.assertEqual(self.pointG + self.pointG2, self.pointG3) From d64618b16a86912dfa262bbfb0f89bba6f758bbe Mon Sep 17 00:00:00 2001 From: Michal Ambroz <723625+xambroz@users.noreply.github.com> Date: Fri, 3 Feb 2023 05:26:11 +0100 Subject: [PATCH 08/18] use assertTrue instead of deprecated failUnless --- lib/Crypto/SelfTest/PublicKey/test_ECC_448.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/Crypto/SelfTest/PublicKey/test_ECC_448.py b/lib/Crypto/SelfTest/PublicKey/test_ECC_448.py index c0778df3d..178c3a90c 100644 --- a/lib/Crypto/SelfTest/PublicKey/test_ECC_448.py +++ b/lib/Crypto/SelfTest/PublicKey/test_ECC_448.py @@ -105,13 +105,13 @@ def test_equal(self): def test_pai(self): pai = EccPoint(0, 1, curve="Ed448") - self.failUnless(pai.is_point_at_infinity()) + self.assertTrue(pai.is_point_at_infinity()) self.assertEqual(pai, pai.point_at_infinity()) def test_negate(self): negG = -self.pointG sum = self.pointG + negG - self.failUnless(sum.is_point_at_infinity()) + self.assertTrue(sum.is_point_at_infinity()) def test_addition(self): self.assertEqual(self.pointG + self.pointG2, self.pointG3) From 2b11e5b3adb3d09b42df4e639653e5b65cec0469 Mon Sep 17 00:00:00 2001 From: Helder Eijs Date: Tue, 16 May 2023 00:18:05 +0200 Subject: [PATCH 09/18] Correctly check that the scalar matches the point when importing an ECC private key --- Changelog.rst | 1 + lib/Crypto/PublicKey/ECC.py | 4 ++-- lib/Crypto/SelfTest/PublicKey/test_import_ECC.py | 10 ++++++++++ 3 files changed, 13 insertions(+), 2 deletions(-) diff --git a/Changelog.rst b/Changelog.rst index 138c6e6ed..169cd4307 100644 --- a/Changelog.rst +++ b/Changelog.rst @@ -13,6 +13,7 @@ New features --------------- * GH#722: ``nonce`` attribute was not correctly set for XChaCha20_Poly1305 ciphers. Thanks to Liam Haber. * GH#739: OID encoding for arc 2 didn't accept children larger than 39. Thanks to James. +* Correctly check that the scalar matches the point when importing an ECC private key. 3.17.0 (29 January 2023) ++++++++++++++++++++++++++ diff --git a/lib/Crypto/PublicKey/ECC.py b/lib/Crypto/PublicKey/ECC.py index c44408631..1d104a91a 100644 --- a/lib/Crypto/PublicKey/ECC.py +++ b/lib/Crypto/PublicKey/ECC.py @@ -1396,8 +1396,8 @@ def _import_rfc5915_der(encoded, passphrase, curve_oid=None): d = Integer.from_bytes(scalar_bytes) # Decode public key (if any) - if len(private_key) == 4: - public_key_enc = DerBitString(explicit=1).decode(private_key[3]).value + if len(private_key) > 2: + public_key_enc = DerBitString(explicit=1).decode(private_key[-1]).value public_key = _import_public_der(public_key_enc, curve_oid=curve_oid) point_x = public_key.pointQ.x point_y = public_key.pointQ.y diff --git a/lib/Crypto/SelfTest/PublicKey/test_import_ECC.py b/lib/Crypto/SelfTest/PublicKey/test_import_ECC.py index f9222c86d..eb53c5761 100644 --- a/lib/Crypto/SelfTest/PublicKey/test_import_ECC.py +++ b/lib/Crypto/SelfTest/PublicKey/test_import_ECC.py @@ -183,6 +183,16 @@ class TestImport(unittest.TestCase): def test_empty(self): self.assertRaises(ValueError, ECC.import_key, b"") + def test_mismatch(self): + # The private key does not match the public key + mismatch = """-----BEGIN PRIVATE KEY----- +MIG2AgEAMBAGByqGSM49AgEGBSuBBAAiBIGeMIGbAgEBBDAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJChZANiAAQarFRaqflo +I+d61SRvU8Za2EurxtW20eZzca7dnNYMYf3boIkDuAUU7FfO7l0/4iGzzvfUinng +o4N+LZfQYcTxmdwlkWOrfzCjtHDix6EznPO/LlxTsV+zfTJ/ijTjeXk= +-----END PRIVATE KEY-----""" + self.assertRaises(ValueError, ECC.import_key, mismatch) + class TestImport_P192(unittest.TestCase): From 72051edac8e386cbcc39baa71af4526c76d5df8a Mon Sep 17 00:00:00 2001 From: Helder Eijs Date: Tue, 16 May 2023 00:18:05 +0200 Subject: [PATCH 10/18] =?UTF-8?q?Add=20DerSequence(=E2=80=A6,=20explicit?= =?UTF-8?q?=3D=E2=80=A6)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Allow encoding of a DER SEQUENCE with an EXPLICIT tag --- lib/Crypto/Util/asn1.py | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/lib/Crypto/Util/asn1.py b/lib/Crypto/Util/asn1.py index 1f7efe276..a646eacb4 100644 --- a/lib/Crypto/Util/asn1.py +++ b/lib/Crypto/Util/asn1.py @@ -481,7 +481,7 @@ class DerSequence(DerObject): """ - def __init__(self, startSeq=None, implicit=None): + def __init__(self, startSeq=None, implicit=None, explicit=None): """Initialize the DER object as a SEQUENCE. :Parameters: @@ -489,12 +489,19 @@ def __init__(self, startSeq=None, implicit=None): A sequence whose element are either integers or other DER objects. - implicit : integer - The IMPLICIT tag to use for the encoded object. + implicit : integer or byte + The IMPLICIT tag number (< 0x1F) to use for the encoded object. It overrides the universal tag for SEQUENCE (16). + It cannot be combined with the ``explicit`` parameter. + By default, there is no IMPLICIT tag. + + explicit : integer or byte + The EXPLICIT tag number (< 0x1F) to use for the encoded object. + It cannot be combined with the ``implicit`` parameter. + By default, there is no EXPLICIT tag. """ - DerObject.__init__(self, 0x10, b'', implicit, True) + DerObject.__init__(self, 0x10, b'', implicit, True, explicit) if startSeq is None: self._seq = [] else: From bfb5ce3f67ac4d19101aa1aafb1c3adff2f48566 Mon Sep 17 00:00:00 2001 From: Helder Eijs Date: Wed, 17 May 2023 00:05:10 +0200 Subject: [PATCH 11/18] Update Changelog --- Changelog.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/Changelog.rst b/Changelog.rst index 169cd4307..0f0a39878 100644 --- a/Changelog.rst +++ b/Changelog.rst @@ -12,6 +12,7 @@ New features Resolved issues --------------- * GH#722: ``nonce`` attribute was not correctly set for XChaCha20_Poly1305 ciphers. Thanks to Liam Haber. +* GH#728: Workaround for a possible x86 emulator bug in Windows for ARM64. * GH#739: OID encoding for arc 2 didn't accept children larger than 39. Thanks to James. * Correctly check that the scalar matches the point when importing an ECC private key. From 6487836db7c4f0c7eb50dc57a65b6c30952d65db Mon Sep 17 00:00:00 2001 From: Helder Eijs Date: Wed, 17 May 2023 15:14:45 +0200 Subject: [PATCH 12/18] Update to MacOS 12 for wheels --- .github/workflows/wheels.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/wheels.yml b/.github/workflows/wheels.yml index ca9e4ebdd..f7307a278 100644 --- a/.github/workflows/wheels.yml +++ b/.github/workflows/wheels.yml @@ -30,7 +30,7 @@ jobs: runs-on: ${{ matrix.os }} strategy: matrix: - os: [ubuntu-20.04, windows-latest, macos-10.15] + os: [ubuntu-20.04, windows-latest, macos-12] if: github.actor == 'Legrandin' @@ -79,7 +79,7 @@ jobs: runs-on: ${{ matrix.os }} strategy: matrix: - os: [ubuntu-20.04, windows-latest, macos-10.15] + os: [ubuntu-20.04, windows-latest, macos-12] python-version: ['3.5'] if: github.actor == 'Legrandin' @@ -117,7 +117,7 @@ jobs: runs-on: ${{ matrix.os }} strategy: matrix: - os: [ ubuntu-20.04, windows-latest, macos-10.15 ] + os: [ ubuntu-20.04, windows-latest, macos-12 ] arch: [ multi-arch ] # Python 2 on Windows requires manual toolchain setup (per-arch) due to newer MSVC used here exclude: From fd4df5959bd53b65565173b23e75dabe24e102b2 Mon Sep 17 00:00:00 2001 From: Helder Eijs Date: Wed, 17 May 2023 15:24:18 +0200 Subject: [PATCH 13/18] Update msvc-dev-cmd --- .github/workflows/integration.yml | 4 ++-- .github/workflows/wheels.yml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/integration.yml b/.github/workflows/integration.yml index c3faa317f..a55bdbf01 100644 --- a/.github/workflows/integration.yml +++ b/.github/workflows/integration.yml @@ -58,7 +58,7 @@ jobs: - name: Install MSVC if: matrix.os == 'windows-latest' && matrix.python-version == '2.7' - uses: ilammy/msvc-dev-cmd@f456b805b3f63911738cb71d4f255e4e129c7e7a + uses: ilammy/msvc-dev-cmd@a742a854f54111d83b78e97091b5d85ccdaa3e89 - name: Prepare environmental variables if: matrix.os == 'windows-latest' && matrix.python-version == '2.7' @@ -125,7 +125,7 @@ jobs: with: python-version: "3.11" - name: Install MSVC - uses: ilammy/msvc-dev-cmd@f456b805b3f63911738cb71d4f255e4e129c7e7a + uses: ilammy/msvc-dev-cmd@a742a854f54111d83b78e97091b5d85ccdaa3e89 with: arch: ${{ matrix.arch }} - name: Test Windows 32 and 64 diff --git a/.github/workflows/wheels.yml b/.github/workflows/wheels.yml index f7307a278..a19591116 100644 --- a/.github/workflows/wheels.yml +++ b/.github/workflows/wheels.yml @@ -136,7 +136,7 @@ jobs: - name: Install MSVC if: runner.os == 'Windows' - uses: ilammy/msvc-dev-cmd@v1 + uses: ilammy/msvc-dev-cmd@a742a854f54111d83b78e97091b5d85ccdaa3e89 with: toolset: 14.0 arch: ${{ matrix.arch }} From e8f55cb40c0982f2dceda77b074974701a3fd107 Mon Sep 17 00:00:00 2001 From: Helder Eijs Date: Wed, 17 May 2023 22:38:25 +0200 Subject: [PATCH 14/18] Bump version --- Changelog.rst | 2 +- lib/Crypto/__init__.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Changelog.rst b/Changelog.rst index 0f0a39878..94909e5d1 100644 --- a/Changelog.rst +++ b/Changelog.rst @@ -1,7 +1,7 @@ Changelog ========= -3.18.0 (under development) +3.18.0 (18 May 2023) ++++++++++++++++++++++++++ New features diff --git a/lib/Crypto/__init__.py b/lib/Crypto/__init__.py index abb496db2..bfd02cd14 100644 --- a/lib/Crypto/__init__.py +++ b/lib/Crypto/__init__.py @@ -1,6 +1,6 @@ __all__ = ['Cipher', 'Hash', 'Protocol', 'PublicKey', 'Util', 'Signature', 'IO', 'Math'] -version_info = (3, 18, '0b0') +version_info = (3, 18, '0') __version__ = ".".join([str(x) for x in version_info]) From a75c4643703625a2a6a8fd9e3ebf7605c6752cbf Mon Sep 17 00:00:00 2001 From: Helder Eijs Date: Wed, 17 May 2023 22:48:57 +0200 Subject: [PATCH 15/18] Use ilammy/msvc-dev-cmd@v1 --- .github/workflows/integration.yml | 4 ++-- .github/workflows/wheels.yml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/integration.yml b/.github/workflows/integration.yml index a55bdbf01..1359544b4 100644 --- a/.github/workflows/integration.yml +++ b/.github/workflows/integration.yml @@ -58,7 +58,7 @@ jobs: - name: Install MSVC if: matrix.os == 'windows-latest' && matrix.python-version == '2.7' - uses: ilammy/msvc-dev-cmd@a742a854f54111d83b78e97091b5d85ccdaa3e89 + uses: ilammy/msvc-dev-cmd@v1 - name: Prepare environmental variables if: matrix.os == 'windows-latest' && matrix.python-version == '2.7' @@ -125,7 +125,7 @@ jobs: with: python-version: "3.11" - name: Install MSVC - uses: ilammy/msvc-dev-cmd@a742a854f54111d83b78e97091b5d85ccdaa3e89 + uses: ilammy/msvc-dev-cmd@v1 with: arch: ${{ matrix.arch }} - name: Test Windows 32 and 64 diff --git a/.github/workflows/wheels.yml b/.github/workflows/wheels.yml index a19591116..f7307a278 100644 --- a/.github/workflows/wheels.yml +++ b/.github/workflows/wheels.yml @@ -136,7 +136,7 @@ jobs: - name: Install MSVC if: runner.os == 'Windows' - uses: ilammy/msvc-dev-cmd@a742a854f54111d83b78e97091b5d85ccdaa3e89 + uses: ilammy/msvc-dev-cmd@v1 with: toolset: 14.0 arch: ${{ matrix.arch }} From 768437fcfb247858f65875e8c50335bea205390a Mon Sep 17 00:00:00 2001 From: Helder Eijs Date: Fri, 19 May 2023 08:30:46 +0200 Subject: [PATCH 16/18] Fix Changelog formatting --- Changelog.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Changelog.rst b/Changelog.rst index 94909e5d1..091ae0a0b 100644 --- a/Changelog.rst +++ b/Changelog.rst @@ -9,7 +9,7 @@ New features * Added support for DER BOOLEAN encodings. * The library now compiles on Windows ARM64. Thanks to Niyas Sait. - Resolved issues +Resolved issues --------------- * GH#722: ``nonce`` attribute was not correctly set for XChaCha20_Poly1305 ciphers. Thanks to Liam Haber. * GH#728: Workaround for a possible x86 emulator bug in Windows for ARM64. From 4582ac91a83aa14527013c218a66f7138eda7fc7 Mon Sep 17 00:00:00 2001 From: Helder Eijs Date: Sat, 3 Jun 2023 19:58:01 +0200 Subject: [PATCH 17/18] Use sanitizer in Linux builds --- .github/workflows/integration.yml | 2 +- src/test/CMakeLists.txt | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/integration.yml b/.github/workflows/integration.yml index 1359544b4..44850cf84 100644 --- a/.github/workflows/integration.yml +++ b/.github/workflows/integration.yml @@ -101,7 +101,7 @@ jobs: - name: Install dependencies run: | sudo apt-get update - sudo apt-get install libc6-dev-i386 + sudo apt-get install libc6-dev-i386 libubsan1 - name: Test Linux x32 and x64 run: | cd src/test diff --git a/src/test/CMakeLists.txt b/src/test/CMakeLists.txt index 075182a90..aacb60857 100644 --- a/src/test/CMakeLists.txt +++ b/src/test/CMakeLists.txt @@ -44,6 +44,8 @@ else() # https://gcc.gnu.org/bugzilla/show_bug.cgi?id=40838 add_compile_options(-mstackrealign) endif() + add_compile_options(-fsanitize=undefined) + link_libraries(-lubsan) endif() if (CMAKE_SIZEOF_VOID_P EQUAL 8) From ca85cd2913570bae9a1bda31faea155a20fbb329 Mon Sep 17 00:00:00 2001 From: Helder Eijs Date: Sat, 3 Jun 2023 23:17:44 +0200 Subject: [PATCH 18/18] Use gcc address sanitizer --- src/test/CMakeLists.txt | 3 +- src/test/test_ec_ws.c | 111 ++++++++++++++++++++++++++++++++++++++- src/test/test_mod25519.c | 2 + src/test/test_mont.c | 2 + 4 files changed, 115 insertions(+), 3 deletions(-) diff --git a/src/test/CMakeLists.txt b/src/test/CMakeLists.txt index aacb60857..b04d03ba3 100644 --- a/src/test/CMakeLists.txt +++ b/src/test/CMakeLists.txt @@ -44,8 +44,9 @@ else() # https://gcc.gnu.org/bugzilla/show_bug.cgi?id=40838 add_compile_options(-mstackrealign) endif() - add_compile_options(-fsanitize=undefined) + add_compile_options(-fsanitize=undefined -fsanitize=address) link_libraries(-lubsan) + add_link_options(-fsanitize=address) endif() if (CMAKE_SIZEOF_VOID_P EQUAL 8) diff --git a/src/test/test_ec_ws.c b/src/test/test_ec_ws.c index 478df2533..3a6cef13b 100644 --- a/src/test/test_ec_ws.c +++ b/src/test/test_ec_ws.c @@ -175,7 +175,7 @@ void test_ec_full_double(void) mont_context_free(ctx); } -void test_ec_mix_add(void) +void test_ec_mix_add_1(void) { Workplace *wp; MontContext *ctx; @@ -219,9 +219,40 @@ void test_ec_mix_add(void) mont_to_bytes(buffer, 32, z1, ctx); assert(0 == memcmp(buffer, "\x7f\x3f\xac\x7e\x49\x3e\x61\x4b\x52\xd8\x49\x31\x8b\x57\xa7\xec\x89\x50\x27\xdb\x75\xbe\xa6\x61\x3c\x54\x42\x89\xb3\x9f\x31\x46", 32)); + free(x1); + free(y1); + free(z1); + free(x2); + free(y2); + + free(b); + free_workplace(wp); + mont_context_free(ctx); +} + +void test_ec_mix_add_2(void) +{ + Workplace *wp; + MontContext *ctx; + const uint8_t modulus[32] = {0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; + uint64_t *x1, *y1, *z1; + uint64_t *x2, *y2; + uint64_t *b; + uint8_t buffer[32]; + + mont_context_init(&ctx, modulus, sizeof(modulus)); + wp = new_workplace(ctx); + mont_from_bytes(&b, (uint8_t*)"\x5a\xc6\x35\xd8\xaa\x3a\x93\xe7\xb3\xeb\xbd\x55\x76\x98\x86\xbc\x65\x1d\x06\xb0\xcc\x53\xb0\xf6\x3b\xce\x3c\x3e\x27\xd2\x60\x4b", 32, ctx); + /* Projective input point is point-at-infinity */ + mont_number(&x1, 1, ctx); mont_set(x1, 0, ctx); + mont_number(&y1, 1, ctx); mont_set(y1, 1, ctx); + mont_number(&z1, 1, ctx); mont_set(z1, 0, ctx); mont_from_bytes(&x2, (uint8_t*)"\xf2\x49\x10\x4d\x0e\x6f\x8f\x29\xe6\x01\x62\x77\x78\x0c\xda\x84\xdc\x84\xb8\x3b\xc3\xd8\x99\xdf\xb7\x36\xca\x08\x31\xfb\xe8\xcf", 32, ctx); @@ -235,6 +266,79 @@ void test_ec_mix_add(void) mont_to_bytes(buffer, 32, y1, ctx); assert(0 == memcmp(buffer, (uint8_t*)"\xb5\x7e\x12\xfc\xdb\x03\x1f\x59\xca\xb8\x1b\x1c\x6b\x1e\x1c\x07\xe4\x51\x2e\x52\xce\x83\x2f\x1a\x0c\xed\xef\xff\x8b\x43\x40\xe9", 32)); + free(x1); + free(y1); + free(z1); + free(x2); + free(y2); + + free(b); + free_workplace(wp); + mont_context_free(ctx); +} + +void test_ec_mix_add_3(void) +{ + Workplace *wp; + MontContext *ctx; + const uint8_t modulus[32] = {0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; + uint64_t *x1, *y1, *z1; + uint64_t *x2, *y2; + uint64_t *b; + uint8_t buffer[32]; + + mont_context_init(&ctx, modulus, sizeof(modulus)); + wp = new_workplace(ctx); + mont_from_bytes(&b, (uint8_t*)"\x5a\xc6\x35\xd8\xaa\x3a\x93\xe7\xb3\xeb\xbd\x55\x76\x98\x86\xbc\x65\x1d\x06\xb0\xcc\x53\xb0\xf6\x3b\xce\x3c\x3e\x27\xd2\x60\x4b", 32, ctx); + + /* Affine and projective are actually the same point (doubling) */ + mont_from_bytes(&x1, (uint8_t*)"\xc6\x4c\x90\xad\x8d\x5c\x1d\x96\xd6\x4b\x63\x46\x4a\x8b\x57\x91\xbf\x48\xa6\xb4\xb9\xbc\xd6\xad\x79\xc6\x3a\x13\xbf\xb7\x78\x5b", 32, ctx); + mont_from_bytes(&y1, (uint8_t*)"\xe4\x98\x64\xd0\x22\x85\x75\x8a\x11\x79\x68\x2e\x06\x92\x3d\xf7\x62\xa8\x85\xea\xda\xe6\xd9\xb0\x5a\x4f\x0c\x43\x1d\x51\x77\xe4", 32, ctx); + mont_from_bytes(&z1, (uint8_t*)"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0a", 32, ctx); + + mont_from_bytes(&x2, (uint8_t*)"\xfa\x3a\xdb\x43\xa7\xbc\x69\x5c\xc8\xa1\x23\x87\x07\x74\x55\x8e\x93\x20\xdd\x79\x5f\x5f\xaf\x11\x58\xfa\x39\x01\xf9\x92\x58\xd5", 32, ctx); + mont_from_bytes(&y2, (uint8_t*)"\xe3\xa8\xd6\xe0\xd0\x40\x8b\xc1\xce\x8c\x24\x04\x9a\x41\xd2\xff\x23\x77\x40\x98\x49\x17\x15\xc4\xd5\xd4\xb4\x6d\x1c\x88\x25\x96", 32, ctx); + + ec_mix_add(x1, y1, z1, x1, y1, z1, x2, y2, b, wp, ctx); + + mont_to_bytes(buffer, 32, x1, ctx); + assert(0 == memcmp(buffer, "\x96\x0f\x82\x08\x3a\x75\xf9\xaf\x9a\xab\x06\x05\x27\x0e\x2d\xa8\xb3\x20\x7e\x8d\xf2\xf0\x00\x4d\xb3\x19\x16\xc9\xea\xc5\x0f\x02", 32)); + mont_to_bytes(buffer, 32, y1, ctx); + assert(0 == memcmp(buffer, "\x20\xe6\xe3\x02\xc6\x57\xfa\x95\x30\x39\xa9\x25\xf1\x9d\xc3\xcb\x0f\x59\xa7\x01\x46\xc8\xac\xe2\x09\x54\x3a\x25\x2a\x18\x96\xba", 32)); + mont_to_bytes(buffer, 32, z1, ctx); + assert(0 == memcmp(buffer, "\xb4\x2f\x0b\xc1\x61\x03\x91\xe4\x11\xf1\x4c\x65\xef\x13\xd4\x57\xb1\x41\xb2\x54\xc3\x86\x08\xea\xc6\x5c\xf1\x61\x9d\x37\x6b\x77", 32)); + + free(x1); + free(y1); + free(z1); + free(x2); + free(y2); + + free(b); + free_workplace(wp); + mont_context_free(ctx); +} + +void test_ec_mix_add_4(void) +{ + Workplace *wp; + MontContext *ctx; + const uint8_t modulus[32] = {0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; + uint64_t *x1, *y1, *z1; + uint64_t *x2, *y2; + uint64_t *b; + uint8_t buffer[32]; + + mont_context_init(&ctx, modulus, sizeof(modulus)); + wp = new_workplace(ctx); + mont_from_bytes(&b, (uint8_t*)"\x5a\xc6\x35\xd8\xaa\x3a\x93\xe7\xb3\xeb\xbd\x55\x76\x98\x86\xbc\x65\x1d\x06\xb0\xcc\x53\xb0\xf6\x3b\xce\x3c\x3e\x27\xd2\x60\x4b", 32, ctx); + /* Affine and projective are actually the same point (doubling) */ mont_from_bytes(&x1, (uint8_t*)"\xc6\x4c\x90\xad\x8d\x5c\x1d\x96\xd6\x4b\x63\x46\x4a\x8b\x57\x91\xbf\x48\xa6\xb4\xb9\xbc\xd6\xad\x79\xc6\x3a\x13\xbf\xb7\x78\x5b", 32, ctx); mont_from_bytes(&y1, (uint8_t*)"\xe4\x98\x64\xd0\x22\x85\x75\x8a\x11\x79\x68\x2e\x06\x92\x3d\xf7\x62\xa8\x85\xea\xda\xe6\xd9\xb0\x5a\x4f\x0c\x43\x1d\x51\x77\xe4", 32, ctx); @@ -926,7 +1030,10 @@ void test_ec_ws_neg(void) int main(void) { test_ec_projective_to_affine(); test_ec_full_double(); - test_ec_mix_add(); + test_ec_mix_add_1(); + test_ec_mix_add_2(); + test_ec_mix_add_3(); + test_ec_mix_add_4(); test_ec_full_add(); test_ec_scalar(); test_ec_scalar_g_p256(); diff --git a/src/test/test_mod25519.c b/src/test/test_mod25519.c index 4a13494c5..a54de186b 100644 --- a/src/test/test_mod25519.c +++ b/src/test/test_mod25519.c @@ -188,6 +188,8 @@ void test_tole25p5_to_behex(void) convert_le25p5_to_behex(&out, in); res = strcmp(out, "0000000000000000000000000000000000000000000000000000000000000000"); assert(res == 0); + + free(out); } void test_reduce(void) diff --git a/src/test/test_mont.c b/src/test/test_mont.c index a83373ab9..9086c6855 100644 --- a/src/test/test_mont.c +++ b/src/test/test_mont.c @@ -424,6 +424,8 @@ void test_mod_select(void) res = mod_select(f, d, e, 0, ctx->words); assert(res == 0); assert(memcmp(e, f, sizeof f) == 0); + + mont_context_free(ctx); } int main(void) {