From 9eeeead8fbbee1d21809b6c2a11cee6000e7d4be Mon Sep 17 00:00:00 2001 From: ARROWBOW Date: Sat, 29 Jan 2022 20:32:03 +0800 Subject: [PATCH] Delete Crypto directory --- Crypto/Cipher/AES.py | 250 --- Crypto/Cipher/AES.pyi | 47 - Crypto/Cipher/ARC2.py | 175 -- Crypto/Cipher/ARC2.pyi | 35 - Crypto/Cipher/ARC4.py | 137 -- Crypto/Cipher/ARC4.pyi | 16 - Crypto/Cipher/Blowfish.py | 159 -- Crypto/Cipher/Blowfish.pyi | 35 - Crypto/Cipher/CAST.py | 159 -- Crypto/Cipher/CAST.pyi | 35 - Crypto/Cipher/ChaCha20.py | 287 ---- Crypto/Cipher/ChaCha20.pyi | 25 - Crypto/Cipher/ChaCha20_Poly1305.py | 336 ---- Crypto/Cipher/ChaCha20_Poly1305.pyi | 28 - Crypto/Cipher/DES.py | 158 -- Crypto/Cipher/DES.pyi | 35 - Crypto/Cipher/DES3.py | 187 --- Crypto/Cipher/DES3.pyi | 37 - Crypto/Cipher/PKCS1_OAEP.py | 239 --- Crypto/Cipher/PKCS1_OAEP.pyi | 35 - Crypto/Cipher/PKCS1_v1_5.py | 199 --- Crypto/Cipher/PKCS1_v1_5.pyi | 17 - Crypto/Cipher/Salsa20.py | 167 -- Crypto/Cipher/Salsa20.pyi | 27 - Crypto/Cipher/_ARC4.abi3.so | Bin 13768 -> 0 bytes Crypto/Cipher/_EKSBlowfish.py | 131 -- Crypto/Cipher/_EKSBlowfish.pyi | 15 - Crypto/Cipher/_Salsa20.abi3.so | Bin 26784 -> 0 bytes Crypto/Cipher/__init__.py | 79 - Crypto/Cipher/__init__.pyi | 0 Crypto/Cipher/__pycache__/AES.cpython-36.pyc | Bin 8161 -> 0 bytes .../__pycache__/__init__.cpython-36.pyc | Bin 1724 -> 0 bytes .../__pycache__/_mode_cbc.cpython-36.pyc | Bin 7595 -> 0 bytes .../__pycache__/_mode_ccm.cpython-36.pyc | Bin 18154 -> 0 bytes .../__pycache__/_mode_cfb.cpython-36.pyc | Bin 7915 -> 0 bytes .../__pycache__/_mode_ctr.cpython-36.pyc | Bin 11164 -> 0 bytes .../__pycache__/_mode_eax.cpython-36.pyc | Bin 12265 -> 0 bytes .../__pycache__/_mode_ecb.cpython-36.pyc | Bin 5989 -> 0 bytes .../__pycache__/_mode_gcm.cpython-36.pyc | Bin 17122 -> 0 bytes .../__pycache__/_mode_ocb.cpython-36.pyc | Bin 14585 -> 0 bytes .../__pycache__/_mode_ofb.cpython-36.pyc | Bin 7482 -> 0 bytes .../__pycache__/_mode_openpgp.cpython-36.pyc | Bin 4791 -> 0 bytes .../__pycache__/_mode_siv.cpython-36.pyc | Bin 11836 -> 0 bytes Crypto/Cipher/_chacha20.abi3.so | Bin 28224 -> 0 bytes Crypto/Cipher/_mode_cbc.py | 293 ---- Crypto/Cipher/_mode_cbc.pyi | 25 - Crypto/Cipher/_mode_ccm.py | 650 -------- Crypto/Cipher/_mode_ccm.pyi | 47 - Crypto/Cipher/_mode_cfb.py | 293 ---- Crypto/Cipher/_mode_cfb.pyi | 26 - Crypto/Cipher/_mode_ctr.py | 393 ----- Crypto/Cipher/_mode_ctr.pyi | 27 - Crypto/Cipher/_mode_eax.py | 408 ----- Crypto/Cipher/_mode_eax.pyi | 45 - Crypto/Cipher/_mode_ecb.py | 220 --- Crypto/Cipher/_mode_ecb.pyi | 19 - Crypto/Cipher/_mode_gcm.py | 620 ------- Crypto/Cipher/_mode_gcm.pyi | 45 - Crypto/Cipher/_mode_ocb.py | 525 ------ Crypto/Cipher/_mode_ocb.pyi | 36 - Crypto/Cipher/_mode_ofb.py | 282 ---- Crypto/Cipher/_mode_ofb.pyi | 25 - Crypto/Cipher/_mode_openpgp.py | 206 --- Crypto/Cipher/_mode_openpgp.pyi | 20 - Crypto/Cipher/_mode_siv.py | 392 ----- Crypto/Cipher/_mode_siv.pyi | 38 - Crypto/Cipher/_raw_aes.abi3.so | Bin 66256 -> 0 bytes Crypto/Cipher/_raw_aesni.abi3.so | Bin 101136 -> 0 bytes Crypto/Cipher/_raw_arc2.abi3.so | Bin 43776 -> 0 bytes Crypto/Cipher/_raw_blowfish.abi3.so | Bin 70472 -> 0 bytes Crypto/Cipher/_raw_cast.abi3.so | Bin 42976 -> 0 bytes Crypto/Cipher/_raw_cbc.abi3.so | Bin 20712 -> 0 bytes Crypto/Cipher/_raw_cfb.abi3.so | Bin 25440 -> 0 bytes Crypto/Cipher/_raw_ctr.abi3.so | Bin 28600 -> 0 bytes Crypto/Cipher/_raw_des.abi3.so | Bin 75672 -> 0 bytes Crypto/Cipher/_raw_des3.abi3.so | Bin 76480 -> 0 bytes Crypto/Cipher/_raw_ecb.abi3.so | Bin 12440 -> 0 bytes Crypto/Cipher/_raw_eksblowfish.abi3.so | Bin 167560 -> 0 bytes Crypto/Cipher/_raw_ocb.abi3.so | Bin 37344 -> 0 bytes Crypto/Cipher/_raw_ofb.abi3.so | Bin 15368 -> 0 bytes Crypto/Hash/BLAKE2b.py | 247 --- Crypto/Hash/BLAKE2b.pyi | 31 - Crypto/Hash/BLAKE2s.py | 247 --- Crypto/Hash/BLAKE2s.pyi | 26 - Crypto/Hash/CMAC.py | 302 ---- Crypto/Hash/CMAC.pyi | 30 - Crypto/Hash/HMAC.py | 213 --- Crypto/Hash/HMAC.pyi | 25 - Crypto/Hash/MD2.py | 166 -- Crypto/Hash/MD2.pyi | 19 - Crypto/Hash/MD4.py | 185 --- Crypto/Hash/MD4.pyi | 19 - Crypto/Hash/MD5.py | 184 --- Crypto/Hash/MD5.pyi | 19 - Crypto/Hash/Poly1305.py | 217 --- Crypto/Hash/Poly1305.pyi | 24 - Crypto/Hash/RIPEMD.py | 26 - Crypto/Hash/RIPEMD.pyi | 3 - Crypto/Hash/RIPEMD160.py | 169 -- Crypto/Hash/RIPEMD160.pyi | 19 - Crypto/Hash/SHA.py | 24 - Crypto/Hash/SHA.pyi | 4 - Crypto/Hash/SHA1.py | 185 --- Crypto/Hash/SHA1.pyi | 19 - Crypto/Hash/SHA224.py | 186 --- Crypto/Hash/SHA224.pyi | 19 - Crypto/Hash/SHA256.py | 185 --- Crypto/Hash/SHA256.pyi | 18 - Crypto/Hash/SHA384.py | 186 --- Crypto/Hash/SHA384.pyi | 19 - Crypto/Hash/SHA3_224.py | 147 -- Crypto/Hash/SHA3_224.pyi | 16 - Crypto/Hash/SHA3_256.py | 147 -- Crypto/Hash/SHA3_256.pyi | 16 - Crypto/Hash/SHA3_384.py | 147 -- Crypto/Hash/SHA3_384.pyi | 16 - Crypto/Hash/SHA3_512.py | 148 -- Crypto/Hash/SHA3_512.pyi | 16 - Crypto/Hash/SHA512.py | 204 --- Crypto/Hash/SHA512.pyi | 22 - Crypto/Hash/SHAKE128.py | 127 -- Crypto/Hash/SHAKE128.pyi | 13 - Crypto/Hash/SHAKE256.py | 127 -- Crypto/Hash/SHAKE256.pyi | 13 - Crypto/Hash/_BLAKE2b.abi3.so | Bin 21888 -> 0 bytes Crypto/Hash/_BLAKE2s.abi3.so | Bin 21712 -> 0 bytes Crypto/Hash/_MD2.abi3.so | Bin 20128 -> 0 bytes Crypto/Hash/_MD4.abi3.so | Bin 25576 -> 0 bytes Crypto/Hash/_MD5.abi3.so | Bin 31704 -> 0 bytes Crypto/Hash/_RIPEMD160.abi3.so | Bin 55608 -> 0 bytes Crypto/Hash/_SHA1.abi3.so | Bin 74416 -> 0 bytes Crypto/Hash/_SHA224.abi3.so | Bin 43792 -> 0 bytes Crypto/Hash/_SHA256.abi3.so | Bin 43872 -> 0 bytes Crypto/Hash/_SHA384.abi3.so | Bin 50520 -> 0 bytes Crypto/Hash/_SHA512.abi3.so | Bin 50624 -> 0 bytes Crypto/Hash/__init__.py | 22 - Crypto/Hash/__init__.pyi | 0 .../Hash/__pycache__/BLAKE2s.cpython-36.pyc | Bin 7236 -> 0 bytes Crypto/Hash/__pycache__/CMAC.cpython-36.pyc | Bin 7730 -> 0 bytes Crypto/Hash/__pycache__/HMAC.cpython-36.pyc | Bin 5361 -> 0 bytes Crypto/Hash/__pycache__/MD5.cpython-36.pyc | Bin 5420 -> 0 bytes Crypto/Hash/__pycache__/SHA1.cpython-36.pyc | Bin 5445 -> 0 bytes Crypto/Hash/__pycache__/SHA256.cpython-36.pyc | Bin 5560 -> 0 bytes .../Hash/__pycache__/__init__.cpython-36.pyc | Bin 288 -> 0 bytes Crypto/Hash/_ghash_clmul.abi3.so | Bin 50160 -> 0 bytes Crypto/Hash/_ghash_portable.abi3.so | Bin 17432 -> 0 bytes Crypto/Hash/_keccak.abi3.so | Bin 33776 -> 0 bytes Crypto/Hash/_poly1305.abi3.so | Bin 33360 -> 0 bytes Crypto/Hash/keccak.py | 173 -- Crypto/Hash/keccak.pyi | 23 - Crypto/IO/PEM.py | 189 --- Crypto/IO/PEM.pyi | 10 - Crypto/IO/PKCS8.py | 231 --- Crypto/IO/PKCS8.pyi | 14 - Crypto/IO/_PBES.py | 435 ----- Crypto/IO/_PBES.pyi | 19 - Crypto/IO/__init__.py | 31 - Crypto/Math/Numbers.py | 42 - Crypto/Math/Numbers.pyi | 4 - Crypto/Math/Primality.py | 369 ----- Crypto/Math/Primality.pyi | 18 - Crypto/Math/_IntegerBase.py | 392 ----- Crypto/Math/_IntegerBase.pyi | 61 - Crypto/Math/_IntegerCustom.py | 111 -- Crypto/Math/_IntegerCustom.pyi | 8 - Crypto/Math/_IntegerGMP.py | 708 -------- Crypto/Math/_IntegerGMP.pyi | 3 - Crypto/Math/_IntegerNative.py | 380 ----- Crypto/Math/_IntegerNative.pyi | 3 - Crypto/Math/__init__.py | 0 Crypto/Math/_modexp.abi3.so | Bin 241256 -> 0 bytes Crypto/Protocol/KDF.py | 574 ------- Crypto/Protocol/KDF.pyi | 24 - Crypto/Protocol/SecretSharing.py | 278 ---- Crypto/Protocol/SecretSharing.pyi | 22 - Crypto/Protocol/__init__.py | 31 - Crypto/Protocol/__init__.pyi | 1 - .../Protocol/__pycache__/KDF.cpython-36.pyc | Bin 18158 -> 0 bytes .../__pycache__/__init__.cpython-36.pyc | Bin 204 -> 0 bytes Crypto/Protocol/_scrypt.abi3.so | Bin 25024 -> 0 bytes Crypto/PublicKey/DSA.py | 682 -------- Crypto/PublicKey/DSA.pyi | 31 - Crypto/PublicKey/ECC.py | 1182 ------------- Crypto/PublicKey/ECC.pyi | 62 - Crypto/PublicKey/ElGamal.py | 286 ---- Crypto/PublicKey/ElGamal.pyi | 18 - Crypto/PublicKey/RSA.py | 799 --------- Crypto/PublicKey/RSA.pyi | 51 - Crypto/PublicKey/__init__.py | 95 -- Crypto/PublicKey/__init__.pyi | 0 Crypto/PublicKey/_ec_ws.abi3.so | Bin 1019608 -> 0 bytes Crypto/PublicKey/_openssh.py | 135 -- Crypto/PublicKey/_openssh.pyi | 7 - Crypto/Random/__init__.py | 57 - Crypto/Random/__init__.pyi | 19 - .../__pycache__/__init__.cpython-36.pyc | Bin 1346 -> 0 bytes Crypto/Random/random.py | 138 -- Crypto/Random/random.pyi | 20 - Crypto/SelfTest/Cipher/__init__.py | 60 - .../__pycache__/__init__.cpython-36.pyc | Bin 1845 -> 0 bytes .../Cipher/__pycache__/common.cpython-36.pyc | Bin 12232 -> 0 bytes .../__pycache__/test_AES.cpython-36.pyc | Bin 61291 -> 0 bytes .../__pycache__/test_ARC2.cpython-36.pyc | Bin 4207 -> 0 bytes .../__pycache__/test_ARC4.cpython-36.pyc | Bin 19295 -> 0 bytes .../__pycache__/test_Blowfish.cpython-36.pyc | Bin 5646 -> 0 bytes .../__pycache__/test_CAST.cpython-36.pyc | Bin 2246 -> 0 bytes .../__pycache__/test_CBC.cpython-36.pyc | Bin 15613 -> 0 bytes .../__pycache__/test_CCM.cpython-36.pyc | Bin 26796 -> 0 bytes .../__pycache__/test_CFB.cpython-36.pyc | Bin 11278 -> 0 bytes .../__pycache__/test_CTR.cpython-36.pyc | Bin 15376 -> 0 bytes .../__pycache__/test_ChaCha20.cpython-36.pyc | Bin 15428 -> 0 bytes .../test_ChaCha20_Poly1305.cpython-36.pyc | Bin 22682 -> 0 bytes .../__pycache__/test_DES.cpython-36.pyc | Bin 12019 -> 0 bytes .../__pycache__/test_DES3.cpython-36.pyc | Bin 4423 -> 0 bytes .../__pycache__/test_EAX.cpython-36.pyc | Bin 22251 -> 0 bytes .../__pycache__/test_GCM.cpython-36.pyc | Bin 26176 -> 0 bytes .../__pycache__/test_OCB.cpython-36.pyc | Bin 19096 -> 0 bytes .../__pycache__/test_OFB.cpython-36.pyc | Bin 6812 -> 0 bytes .../__pycache__/test_OpenPGP.cpython-36.pyc | Bin 5984 -> 0 bytes .../__pycache__/test_SIV.cpython-36.pyc | Bin 16462 -> 0 bytes .../__pycache__/test_Salsa20.cpython-36.pyc | Bin 14278 -> 0 bytes .../__pycache__/test_pkcs1_15.cpython-36.pyc | Bin 8850 -> 0 bytes .../test_pkcs1_oaep.cpython-36.pyc | Bin 19328 -> 0 bytes Crypto/SelfTest/Cipher/common.py | 512 ------ Crypto/SelfTest/Cipher/test_AES.py | 1351 --------------- Crypto/SelfTest/Cipher/test_ARC2.py | 167 -- Crypto/SelfTest/Cipher/test_ARC4.py | 466 ------ Crypto/SelfTest/Cipher/test_Blowfish.py | 160 -- Crypto/SelfTest/Cipher/test_CAST.py | 101 -- Crypto/SelfTest/Cipher/test_CBC.py | 555 ------- Crypto/SelfTest/Cipher/test_CCM.py | 930 ----------- Crypto/SelfTest/Cipher/test_CFB.py | 411 ----- Crypto/SelfTest/Cipher/test_CTR.py | 471 ------ Crypto/SelfTest/Cipher/test_ChaCha20.py | 529 ------ .../SelfTest/Cipher/test_ChaCha20_Poly1305.py | 770 --------- Crypto/SelfTest/Cipher/test_DES.py | 374 ----- Crypto/SelfTest/Cipher/test_DES3.py | 195 --- Crypto/SelfTest/Cipher/test_EAX.py | 772 --------- Crypto/SelfTest/Cipher/test_GCM.py | 950 ----------- Crypto/SelfTest/Cipher/test_OCB.py | 742 --------- Crypto/SelfTest/Cipher/test_OFB.py | 238 --- Crypto/SelfTest/Cipher/test_OpenPGP.py | 218 --- Crypto/SelfTest/Cipher/test_SIV.py | 551 ------- Crypto/SelfTest/Cipher/test_Salsa20.py | 367 ---- Crypto/SelfTest/Cipher/test_pkcs1_15.py | 252 --- Crypto/SelfTest/Cipher/test_pkcs1_oaep.py | 506 ------ Crypto/SelfTest/Hash/__init__.py | 61 - .../Hash/__pycache__/__init__.cpython-36.pyc | Bin 1855 -> 0 bytes .../Hash/__pycache__/common.cpython-36.pyc | Bin 7206 -> 0 bytes .../__pycache__/test_BLAKE2.cpython-36.pyc | Bin 12558 -> 0 bytes .../Hash/__pycache__/test_CMAC.cpython-36.pyc | Bin 9188 -> 0 bytes .../Hash/__pycache__/test_HMAC.cpython-36.pyc | Bin 9411 -> 0 bytes .../Hash/__pycache__/test_MD2.cpython-36.pyc | Bin 1399 -> 0 bytes .../Hash/__pycache__/test_MD4.cpython-36.pyc | Bin 1425 -> 0 bytes .../Hash/__pycache__/test_MD5.cpython-36.pyc | Bin 2306 -> 0 bytes .../__pycache__/test_Poly1305.cpython-36.pyc | Bin 13401 -> 0 bytes .../__pycache__/test_RIPEMD160.cpython-36.pyc | Bin 1572 -> 0 bytes .../Hash/__pycache__/test_SHA1.cpython-36.pyc | Bin 1550 -> 0 bytes .../__pycache__/test_SHA224.cpython-36.pyc | Bin 1404 -> 0 bytes .../__pycache__/test_SHA256.cpython-36.pyc | Bin 2278 -> 0 bytes .../__pycache__/test_SHA384.cpython-36.pyc | Bin 1523 -> 0 bytes .../__pycache__/test_SHA3_224.cpython-36.pyc | Bin 1971 -> 0 bytes .../__pycache__/test_SHA3_256.cpython-36.pyc | Bin 1971 -> 0 bytes .../__pycache__/test_SHA3_384.cpython-36.pyc | Bin 1971 -> 0 bytes .../__pycache__/test_SHA3_512.cpython-36.pyc | Bin 1972 -> 0 bytes .../__pycache__/test_SHA512.cpython-36.pyc | Bin 3694 -> 0 bytes .../__pycache__/test_SHAKE.cpython-36.pyc | Bin 4036 -> 0 bytes .../__pycache__/test_keccak.cpython-36.pyc | Bin 6582 -> 0 bytes Crypto/SelfTest/Hash/common.py | 290 ---- Crypto/SelfTest/Hash/test_BLAKE2.py | 482 ------ Crypto/SelfTest/Hash/test_CMAC.py | 448 ----- Crypto/SelfTest/Hash/test_HMAC.py | 402 ----- Crypto/SelfTest/Hash/test_MD2.py | 62 - Crypto/SelfTest/Hash/test_MD4.py | 64 - Crypto/SelfTest/Hash/test_MD5.py | 94 -- Crypto/SelfTest/Hash/test_Poly1305.py | 542 ------ Crypto/SelfTest/Hash/test_RIPEMD160.py | 71 - Crypto/SelfTest/Hash/test_SHA1.py | 84 - Crypto/SelfTest/Hash/test_SHA224.py | 63 - Crypto/SelfTest/Hash/test_SHA256.py | 94 -- Crypto/SelfTest/Hash/test_SHA384.py | 61 - Crypto/SelfTest/Hash/test_SHA3_224.py | 79 - Crypto/SelfTest/Hash/test_SHA3_256.py | 80 - Crypto/SelfTest/Hash/test_SHA3_384.py | 79 - Crypto/SelfTest/Hash/test_SHA3_512.py | 79 - Crypto/SelfTest/Hash/test_SHA512.py | 140 -- Crypto/SelfTest/Hash/test_SHAKE.py | 143 -- Crypto/SelfTest/Hash/test_keccak.py | 250 --- Crypto/SelfTest/IO/__init__.py | 47 - .../IO/__pycache__/__init__.cpython-36.pyc | Bin 675 -> 0 bytes .../IO/__pycache__/test_PBES.cpython-36.pyc | Bin 2436 -> 0 bytes .../IO/__pycache__/test_PKCS8.cpython-36.pyc | Bin 14466 -> 0 bytes Crypto/SelfTest/IO/test_PBES.py | 93 -- Crypto/SelfTest/IO/test_PKCS8.py | 423 ----- Crypto/SelfTest/Math/__init__.py | 49 - .../Math/__pycache__/__init__.cpython-36.pyc | Bin 744 -> 0 bytes .../__pycache__/test_Numbers.cpython-36.pyc | Bin 37961 -> 0 bytes .../__pycache__/test_Primality.cpython-36.pyc | Bin 3951 -> 0 bytes .../__pycache__/test_modexp.cpython-36.pyc | Bin 6302 -> 0 bytes Crypto/SelfTest/Math/test_Numbers.py | 774 --------- Crypto/SelfTest/Math/test_Primality.py | 118 -- Crypto/SelfTest/Math/test_modexp.py | 201 --- Crypto/SelfTest/Protocol/__init__.py | 44 - .../__pycache__/__init__.cpython-36.pyc | Bin 790 -> 0 bytes .../__pycache__/test_KDF.cpython-36.pyc | Bin 28548 -> 0 bytes .../test_SecretSharing.cpython-36.pyc | Bin 8037 -> 0 bytes .../__pycache__/test_rfc1751.cpython-36.pyc | Bin 1627 -> 0 bytes Crypto/SelfTest/Protocol/test_KDF.py | 732 -------- .../SelfTest/Protocol/test_SecretSharing.py | 267 --- Crypto/SelfTest/Protocol/test_rfc1751.py | 62 - Crypto/SelfTest/PublicKey/__init__.py | 54 - .../__pycache__/__init__.cpython-36.pyc | Bin 1035 -> 0 bytes .../__pycache__/test_DSA.cpython-36.pyc | Bin 8834 -> 0 bytes .../__pycache__/test_ECC.cpython-36.pyc | Bin 27502 -> 0 bytes .../__pycache__/test_ElGamal.cpython-36.pyc | Bin 7369 -> 0 bytes .../__pycache__/test_RSA.cpython-36.pyc | Bin 9965 -> 0 bytes .../test_import_DSA.cpython-36.pyc | Bin 23462 -> 0 bytes .../test_import_ECC.cpython-36.pyc | Bin 38554 -> 0 bytes .../test_import_RSA.cpython-36.pyc | Bin 23528 -> 0 bytes Crypto/SelfTest/PublicKey/test_DSA.py | 247 --- Crypto/SelfTest/PublicKey/test_ECC.py | 859 ---------- Crypto/SelfTest/PublicKey/test_ElGamal.py | 217 --- Crypto/SelfTest/PublicKey/test_RSA.py | 317 ---- Crypto/SelfTest/PublicKey/test_import_DSA.py | 554 ------- Crypto/SelfTest/PublicKey/test_import_ECC.py | 1346 --------------- Crypto/SelfTest/PublicKey/test_import_RSA.py | 585 ------- Crypto/SelfTest/Random/__init__.py | 39 - .../__pycache__/__init__.cpython-36.pyc | Bin 676 -> 0 bytes .../__pycache__/test_random.cpython-36.pyc | Bin 3289 -> 0 bytes Crypto/SelfTest/Random/test_random.py | 167 -- Crypto/SelfTest/Signature/__init__.py | 39 - .../__pycache__/__init__.cpython-36.pyc | Bin 748 -> 0 bytes .../__pycache__/test_dss.cpython-36.pyc | Bin 39159 -> 0 bytes .../__pycache__/test_pkcs1_15.cpython-36.pyc | Bin 12385 -> 0 bytes .../__pycache__/test_pss.cpython-36.pyc | Bin 15025 -> 0 bytes Crypto/SelfTest/Signature/test_dss.py | 1132 ------------- Crypto/SelfTest/Signature/test_pkcs1_15.py | 348 ---- Crypto/SelfTest/Signature/test_pss.py | 377 ----- Crypto/SelfTest/Util/__init__.py | 46 - .../Util/__pycache__/__init__.cpython-36.pyc | Bin 963 -> 0 bytes .../__pycache__/test_Counter.cpython-36.pyc | Bin 2116 -> 0 bytes .../__pycache__/test_Padding.cpython-36.pyc | Bin 5348 -> 0 bytes .../Util/__pycache__/test_asn1.cpython-36.pyc | Bin 22936 -> 0 bytes .../__pycache__/test_number.cpython-36.pyc | Bin 4887 -> 0 bytes .../__pycache__/test_rfc1751.cpython-36.pyc | Bin 1617 -> 0 bytes .../__pycache__/test_strxor.cpython-36.pyc | Bin 9187 -> 0 bytes Crypto/SelfTest/Util/test_Counter.py | 67 - Crypto/SelfTest/Util/test_Padding.py | 154 -- Crypto/SelfTest/Util/test_asn1.py | 784 --------- Crypto/SelfTest/Util/test_number.py | 144 -- Crypto/SelfTest/Util/test_rfc1751.py | 38 - Crypto/SelfTest/Util/test_strxor.py | 280 ---- Crypto/SelfTest/__init__.py | 97 -- Crypto/SelfTest/__main__.py | 38 - Crypto/SelfTest/loader.py | 206 --- Crypto/SelfTest/st_common.py | 55 - Crypto/Signature/DSS.py | 416 ----- Crypto/Signature/DSS.pyi | 27 - Crypto/Signature/PKCS1_PSS.py | 55 - Crypto/Signature/PKCS1_PSS.pyi | 7 - Crypto/Signature/PKCS1_v1_5.py | 53 - Crypto/Signature/PKCS1_v1_5.pyi | 6 - Crypto/Signature/__init__.py | 36 - Crypto/Signature/pkcs1_15.py | 222 --- Crypto/Signature/pkcs1_15.pyi | 17 - Crypto/Signature/pss.py | 386 ----- Crypto/Signature/pss.pyi | 30 - Crypto/Util/Counter.py | 77 - Crypto/Util/Counter.pyi | 5 - Crypto/Util/Padding.py | 108 -- Crypto/Util/Padding.pyi | 6 - Crypto/Util/RFC1751.py | 386 ----- Crypto/Util/RFC1751.pyi | 7 - Crypto/Util/__init__.py | 41 - .../Util/__pycache__/__init__.cpython-36.pyc | Bin 1116 -> 0 bytes .../__pycache__/_cpu_features.cpython-36.pyc | Bin 695 -> 0 bytes .../__pycache__/_file_system.cpython-36.pyc | Bin 850 -> 0 bytes .../Util/__pycache__/_raw_api.cpython-36.pyc | Bin 8300 -> 0 bytes Crypto/Util/__pycache__/number.cpython-36.pyc | Bin 112019 -> 0 bytes .../Util/__pycache__/py3compat.cpython-36.pyc | Bin 4712 -> 0 bytes Crypto/Util/__pycache__/strxor.cpython-36.pyc | Bin 3001 -> 0 bytes Crypto/Util/_cpu_features.py | 46 - Crypto/Util/_cpu_features.pyi | 2 - Crypto/Util/_cpuid_c.abi3.so | Bin 12776 -> 0 bytes Crypto/Util/_file_system.py | 54 - Crypto/Util/_file_system.pyi | 4 - Crypto/Util/_raw_api.py | 307 ---- Crypto/Util/_raw_api.pyi | 27 - Crypto/Util/_strxor.abi3.so | Bin 14960 -> 0 bytes Crypto/Util/asn1.py | 940 ----------- Crypto/Util/asn1.pyi | 74 - Crypto/Util/number.py | 1469 ----------------- Crypto/Util/number.pyi | 19 - Crypto/Util/py3compat.py | 160 -- Crypto/Util/py3compat.pyi | 31 - Crypto/Util/strxor.py | 137 -- Crypto/Util/strxor.pyi | 6 - Crypto/__init__.py | 6 - Crypto/__init__.pyi | 4 - Crypto/__pycache__/__init__.cpython-36.pyc | Bin 457 -> 0 bytes Crypto/py.typed | 0 401 files changed, 51105 deletions(-) delete mode 100644 Crypto/Cipher/AES.py delete mode 100644 Crypto/Cipher/AES.pyi delete mode 100644 Crypto/Cipher/ARC2.py delete mode 100644 Crypto/Cipher/ARC2.pyi delete mode 100644 Crypto/Cipher/ARC4.py delete mode 100644 Crypto/Cipher/ARC4.pyi delete mode 100644 Crypto/Cipher/Blowfish.py delete mode 100644 Crypto/Cipher/Blowfish.pyi delete mode 100644 Crypto/Cipher/CAST.py delete mode 100644 Crypto/Cipher/CAST.pyi delete mode 100644 Crypto/Cipher/ChaCha20.py delete mode 100644 Crypto/Cipher/ChaCha20.pyi delete mode 100644 Crypto/Cipher/ChaCha20_Poly1305.py delete mode 100644 Crypto/Cipher/ChaCha20_Poly1305.pyi delete mode 100644 Crypto/Cipher/DES.py delete mode 100644 Crypto/Cipher/DES.pyi delete mode 100644 Crypto/Cipher/DES3.py delete mode 100644 Crypto/Cipher/DES3.pyi delete mode 100644 Crypto/Cipher/PKCS1_OAEP.py delete mode 100644 Crypto/Cipher/PKCS1_OAEP.pyi delete mode 100644 Crypto/Cipher/PKCS1_v1_5.py delete mode 100644 Crypto/Cipher/PKCS1_v1_5.pyi delete mode 100644 Crypto/Cipher/Salsa20.py delete mode 100644 Crypto/Cipher/Salsa20.pyi delete mode 100644 Crypto/Cipher/_ARC4.abi3.so delete mode 100644 Crypto/Cipher/_EKSBlowfish.py delete mode 100644 Crypto/Cipher/_EKSBlowfish.pyi delete mode 100644 Crypto/Cipher/_Salsa20.abi3.so delete mode 100644 Crypto/Cipher/__init__.py delete mode 100644 Crypto/Cipher/__init__.pyi delete mode 100644 Crypto/Cipher/__pycache__/AES.cpython-36.pyc delete mode 100644 Crypto/Cipher/__pycache__/__init__.cpython-36.pyc delete mode 100644 Crypto/Cipher/__pycache__/_mode_cbc.cpython-36.pyc delete mode 100644 Crypto/Cipher/__pycache__/_mode_ccm.cpython-36.pyc delete mode 100644 Crypto/Cipher/__pycache__/_mode_cfb.cpython-36.pyc delete mode 100644 Crypto/Cipher/__pycache__/_mode_ctr.cpython-36.pyc delete mode 100644 Crypto/Cipher/__pycache__/_mode_eax.cpython-36.pyc delete mode 100644 Crypto/Cipher/__pycache__/_mode_ecb.cpython-36.pyc delete mode 100644 Crypto/Cipher/__pycache__/_mode_gcm.cpython-36.pyc delete mode 100644 Crypto/Cipher/__pycache__/_mode_ocb.cpython-36.pyc delete mode 100644 Crypto/Cipher/__pycache__/_mode_ofb.cpython-36.pyc delete mode 100644 Crypto/Cipher/__pycache__/_mode_openpgp.cpython-36.pyc delete mode 100644 Crypto/Cipher/__pycache__/_mode_siv.cpython-36.pyc delete mode 100644 Crypto/Cipher/_chacha20.abi3.so delete mode 100644 Crypto/Cipher/_mode_cbc.py delete mode 100644 Crypto/Cipher/_mode_cbc.pyi delete mode 100644 Crypto/Cipher/_mode_ccm.py delete mode 100644 Crypto/Cipher/_mode_ccm.pyi delete mode 100644 Crypto/Cipher/_mode_cfb.py delete mode 100644 Crypto/Cipher/_mode_cfb.pyi delete mode 100644 Crypto/Cipher/_mode_ctr.py delete mode 100644 Crypto/Cipher/_mode_ctr.pyi delete mode 100644 Crypto/Cipher/_mode_eax.py delete mode 100644 Crypto/Cipher/_mode_eax.pyi delete mode 100644 Crypto/Cipher/_mode_ecb.py delete mode 100644 Crypto/Cipher/_mode_ecb.pyi delete mode 100644 Crypto/Cipher/_mode_gcm.py delete mode 100644 Crypto/Cipher/_mode_gcm.pyi delete mode 100644 Crypto/Cipher/_mode_ocb.py delete mode 100644 Crypto/Cipher/_mode_ocb.pyi delete mode 100644 Crypto/Cipher/_mode_ofb.py delete mode 100644 Crypto/Cipher/_mode_ofb.pyi delete mode 100644 Crypto/Cipher/_mode_openpgp.py delete mode 100644 Crypto/Cipher/_mode_openpgp.pyi delete mode 100644 Crypto/Cipher/_mode_siv.py delete mode 100644 Crypto/Cipher/_mode_siv.pyi delete mode 100644 Crypto/Cipher/_raw_aes.abi3.so delete mode 100644 Crypto/Cipher/_raw_aesni.abi3.so delete mode 100644 Crypto/Cipher/_raw_arc2.abi3.so delete mode 100644 Crypto/Cipher/_raw_blowfish.abi3.so delete mode 100644 Crypto/Cipher/_raw_cast.abi3.so delete mode 100644 Crypto/Cipher/_raw_cbc.abi3.so delete mode 100644 Crypto/Cipher/_raw_cfb.abi3.so delete mode 100644 Crypto/Cipher/_raw_ctr.abi3.so delete mode 100644 Crypto/Cipher/_raw_des.abi3.so delete mode 100644 Crypto/Cipher/_raw_des3.abi3.so delete mode 100644 Crypto/Cipher/_raw_ecb.abi3.so delete mode 100644 Crypto/Cipher/_raw_eksblowfish.abi3.so delete mode 100644 Crypto/Cipher/_raw_ocb.abi3.so delete mode 100644 Crypto/Cipher/_raw_ofb.abi3.so delete mode 100644 Crypto/Hash/BLAKE2b.py delete mode 100644 Crypto/Hash/BLAKE2b.pyi delete mode 100644 Crypto/Hash/BLAKE2s.py delete mode 100644 Crypto/Hash/BLAKE2s.pyi delete mode 100644 Crypto/Hash/CMAC.py delete mode 100644 Crypto/Hash/CMAC.pyi delete mode 100644 Crypto/Hash/HMAC.py delete mode 100644 Crypto/Hash/HMAC.pyi delete mode 100644 Crypto/Hash/MD2.py delete mode 100644 Crypto/Hash/MD2.pyi delete mode 100644 Crypto/Hash/MD4.py delete mode 100644 Crypto/Hash/MD4.pyi delete mode 100644 Crypto/Hash/MD5.py delete mode 100644 Crypto/Hash/MD5.pyi delete mode 100644 Crypto/Hash/Poly1305.py delete mode 100644 Crypto/Hash/Poly1305.pyi delete mode 100644 Crypto/Hash/RIPEMD.py delete mode 100644 Crypto/Hash/RIPEMD.pyi delete mode 100644 Crypto/Hash/RIPEMD160.py delete mode 100644 Crypto/Hash/RIPEMD160.pyi delete mode 100644 Crypto/Hash/SHA.py delete mode 100644 Crypto/Hash/SHA.pyi delete mode 100644 Crypto/Hash/SHA1.py delete mode 100644 Crypto/Hash/SHA1.pyi delete mode 100644 Crypto/Hash/SHA224.py delete mode 100644 Crypto/Hash/SHA224.pyi delete mode 100644 Crypto/Hash/SHA256.py delete mode 100644 Crypto/Hash/SHA256.pyi delete mode 100644 Crypto/Hash/SHA384.py delete mode 100644 Crypto/Hash/SHA384.pyi delete mode 100644 Crypto/Hash/SHA3_224.py delete mode 100644 Crypto/Hash/SHA3_224.pyi delete mode 100644 Crypto/Hash/SHA3_256.py delete mode 100644 Crypto/Hash/SHA3_256.pyi delete mode 100644 Crypto/Hash/SHA3_384.py delete mode 100644 Crypto/Hash/SHA3_384.pyi delete mode 100644 Crypto/Hash/SHA3_512.py delete mode 100644 Crypto/Hash/SHA3_512.pyi delete mode 100644 Crypto/Hash/SHA512.py delete mode 100644 Crypto/Hash/SHA512.pyi delete mode 100644 Crypto/Hash/SHAKE128.py delete mode 100644 Crypto/Hash/SHAKE128.pyi delete mode 100644 Crypto/Hash/SHAKE256.py delete mode 100644 Crypto/Hash/SHAKE256.pyi delete mode 100644 Crypto/Hash/_BLAKE2b.abi3.so delete mode 100644 Crypto/Hash/_BLAKE2s.abi3.so delete mode 100644 Crypto/Hash/_MD2.abi3.so delete mode 100644 Crypto/Hash/_MD4.abi3.so delete mode 100644 Crypto/Hash/_MD5.abi3.so delete mode 100644 Crypto/Hash/_RIPEMD160.abi3.so delete mode 100644 Crypto/Hash/_SHA1.abi3.so delete mode 100644 Crypto/Hash/_SHA224.abi3.so delete mode 100644 Crypto/Hash/_SHA256.abi3.so delete mode 100644 Crypto/Hash/_SHA384.abi3.so delete mode 100644 Crypto/Hash/_SHA512.abi3.so delete mode 100644 Crypto/Hash/__init__.py delete mode 100644 Crypto/Hash/__init__.pyi delete mode 100644 Crypto/Hash/__pycache__/BLAKE2s.cpython-36.pyc delete mode 100644 Crypto/Hash/__pycache__/CMAC.cpython-36.pyc delete mode 100644 Crypto/Hash/__pycache__/HMAC.cpython-36.pyc delete mode 100644 Crypto/Hash/__pycache__/MD5.cpython-36.pyc delete mode 100644 Crypto/Hash/__pycache__/SHA1.cpython-36.pyc delete mode 100644 Crypto/Hash/__pycache__/SHA256.cpython-36.pyc delete mode 100644 Crypto/Hash/__pycache__/__init__.cpython-36.pyc delete mode 100644 Crypto/Hash/_ghash_clmul.abi3.so delete mode 100644 Crypto/Hash/_ghash_portable.abi3.so delete mode 100644 Crypto/Hash/_keccak.abi3.so delete mode 100644 Crypto/Hash/_poly1305.abi3.so delete mode 100644 Crypto/Hash/keccak.py delete mode 100644 Crypto/Hash/keccak.pyi delete mode 100644 Crypto/IO/PEM.py delete mode 100644 Crypto/IO/PEM.pyi delete mode 100644 Crypto/IO/PKCS8.py delete mode 100644 Crypto/IO/PKCS8.pyi delete mode 100644 Crypto/IO/_PBES.py delete mode 100644 Crypto/IO/_PBES.pyi delete mode 100644 Crypto/IO/__init__.py delete mode 100644 Crypto/Math/Numbers.py delete mode 100644 Crypto/Math/Numbers.pyi delete mode 100644 Crypto/Math/Primality.py delete mode 100644 Crypto/Math/Primality.pyi delete mode 100644 Crypto/Math/_IntegerBase.py delete mode 100644 Crypto/Math/_IntegerBase.pyi delete mode 100644 Crypto/Math/_IntegerCustom.py delete mode 100644 Crypto/Math/_IntegerCustom.pyi delete mode 100644 Crypto/Math/_IntegerGMP.py delete mode 100644 Crypto/Math/_IntegerGMP.pyi delete mode 100644 Crypto/Math/_IntegerNative.py delete mode 100644 Crypto/Math/_IntegerNative.pyi delete mode 100644 Crypto/Math/__init__.py delete mode 100644 Crypto/Math/_modexp.abi3.so delete mode 100644 Crypto/Protocol/KDF.py delete mode 100644 Crypto/Protocol/KDF.pyi delete mode 100644 Crypto/Protocol/SecretSharing.py delete mode 100644 Crypto/Protocol/SecretSharing.pyi delete mode 100644 Crypto/Protocol/__init__.py delete mode 100644 Crypto/Protocol/__init__.pyi delete mode 100644 Crypto/Protocol/__pycache__/KDF.cpython-36.pyc delete mode 100644 Crypto/Protocol/__pycache__/__init__.cpython-36.pyc delete mode 100644 Crypto/Protocol/_scrypt.abi3.so delete mode 100644 Crypto/PublicKey/DSA.py delete mode 100644 Crypto/PublicKey/DSA.pyi delete mode 100644 Crypto/PublicKey/ECC.py delete mode 100644 Crypto/PublicKey/ECC.pyi delete mode 100644 Crypto/PublicKey/ElGamal.py delete mode 100644 Crypto/PublicKey/ElGamal.pyi delete mode 100644 Crypto/PublicKey/RSA.py delete mode 100644 Crypto/PublicKey/RSA.pyi delete mode 100644 Crypto/PublicKey/__init__.py delete mode 100644 Crypto/PublicKey/__init__.pyi delete mode 100644 Crypto/PublicKey/_ec_ws.abi3.so delete mode 100644 Crypto/PublicKey/_openssh.py delete mode 100644 Crypto/PublicKey/_openssh.pyi delete mode 100644 Crypto/Random/__init__.py delete mode 100644 Crypto/Random/__init__.pyi delete mode 100644 Crypto/Random/__pycache__/__init__.cpython-36.pyc delete mode 100644 Crypto/Random/random.py delete mode 100644 Crypto/Random/random.pyi delete mode 100644 Crypto/SelfTest/Cipher/__init__.py delete mode 100644 Crypto/SelfTest/Cipher/__pycache__/__init__.cpython-36.pyc delete mode 100644 Crypto/SelfTest/Cipher/__pycache__/common.cpython-36.pyc delete mode 100644 Crypto/SelfTest/Cipher/__pycache__/test_AES.cpython-36.pyc delete mode 100644 Crypto/SelfTest/Cipher/__pycache__/test_ARC2.cpython-36.pyc delete mode 100644 Crypto/SelfTest/Cipher/__pycache__/test_ARC4.cpython-36.pyc delete mode 100644 Crypto/SelfTest/Cipher/__pycache__/test_Blowfish.cpython-36.pyc delete mode 100644 Crypto/SelfTest/Cipher/__pycache__/test_CAST.cpython-36.pyc delete mode 100644 Crypto/SelfTest/Cipher/__pycache__/test_CBC.cpython-36.pyc delete mode 100644 Crypto/SelfTest/Cipher/__pycache__/test_CCM.cpython-36.pyc delete mode 100644 Crypto/SelfTest/Cipher/__pycache__/test_CFB.cpython-36.pyc delete mode 100644 Crypto/SelfTest/Cipher/__pycache__/test_CTR.cpython-36.pyc delete mode 100644 Crypto/SelfTest/Cipher/__pycache__/test_ChaCha20.cpython-36.pyc delete mode 100644 Crypto/SelfTest/Cipher/__pycache__/test_ChaCha20_Poly1305.cpython-36.pyc delete mode 100644 Crypto/SelfTest/Cipher/__pycache__/test_DES.cpython-36.pyc delete mode 100644 Crypto/SelfTest/Cipher/__pycache__/test_DES3.cpython-36.pyc delete mode 100644 Crypto/SelfTest/Cipher/__pycache__/test_EAX.cpython-36.pyc delete mode 100644 Crypto/SelfTest/Cipher/__pycache__/test_GCM.cpython-36.pyc delete mode 100644 Crypto/SelfTest/Cipher/__pycache__/test_OCB.cpython-36.pyc delete mode 100644 Crypto/SelfTest/Cipher/__pycache__/test_OFB.cpython-36.pyc delete mode 100644 Crypto/SelfTest/Cipher/__pycache__/test_OpenPGP.cpython-36.pyc delete mode 100644 Crypto/SelfTest/Cipher/__pycache__/test_SIV.cpython-36.pyc delete mode 100644 Crypto/SelfTest/Cipher/__pycache__/test_Salsa20.cpython-36.pyc delete mode 100644 Crypto/SelfTest/Cipher/__pycache__/test_pkcs1_15.cpython-36.pyc delete mode 100644 Crypto/SelfTest/Cipher/__pycache__/test_pkcs1_oaep.cpython-36.pyc delete mode 100644 Crypto/SelfTest/Cipher/common.py delete mode 100644 Crypto/SelfTest/Cipher/test_AES.py delete mode 100644 Crypto/SelfTest/Cipher/test_ARC2.py delete mode 100644 Crypto/SelfTest/Cipher/test_ARC4.py delete mode 100644 Crypto/SelfTest/Cipher/test_Blowfish.py delete mode 100644 Crypto/SelfTest/Cipher/test_CAST.py delete mode 100644 Crypto/SelfTest/Cipher/test_CBC.py delete mode 100644 Crypto/SelfTest/Cipher/test_CCM.py delete mode 100644 Crypto/SelfTest/Cipher/test_CFB.py delete mode 100644 Crypto/SelfTest/Cipher/test_CTR.py delete mode 100644 Crypto/SelfTest/Cipher/test_ChaCha20.py delete mode 100644 Crypto/SelfTest/Cipher/test_ChaCha20_Poly1305.py delete mode 100644 Crypto/SelfTest/Cipher/test_DES.py delete mode 100644 Crypto/SelfTest/Cipher/test_DES3.py delete mode 100644 Crypto/SelfTest/Cipher/test_EAX.py delete mode 100644 Crypto/SelfTest/Cipher/test_GCM.py delete mode 100644 Crypto/SelfTest/Cipher/test_OCB.py delete mode 100644 Crypto/SelfTest/Cipher/test_OFB.py delete mode 100644 Crypto/SelfTest/Cipher/test_OpenPGP.py delete mode 100644 Crypto/SelfTest/Cipher/test_SIV.py delete mode 100644 Crypto/SelfTest/Cipher/test_Salsa20.py delete mode 100644 Crypto/SelfTest/Cipher/test_pkcs1_15.py delete mode 100644 Crypto/SelfTest/Cipher/test_pkcs1_oaep.py delete mode 100644 Crypto/SelfTest/Hash/__init__.py delete mode 100644 Crypto/SelfTest/Hash/__pycache__/__init__.cpython-36.pyc delete mode 100644 Crypto/SelfTest/Hash/__pycache__/common.cpython-36.pyc delete mode 100644 Crypto/SelfTest/Hash/__pycache__/test_BLAKE2.cpython-36.pyc delete mode 100644 Crypto/SelfTest/Hash/__pycache__/test_CMAC.cpython-36.pyc delete mode 100644 Crypto/SelfTest/Hash/__pycache__/test_HMAC.cpython-36.pyc delete mode 100644 Crypto/SelfTest/Hash/__pycache__/test_MD2.cpython-36.pyc delete mode 100644 Crypto/SelfTest/Hash/__pycache__/test_MD4.cpython-36.pyc delete mode 100644 Crypto/SelfTest/Hash/__pycache__/test_MD5.cpython-36.pyc delete mode 100644 Crypto/SelfTest/Hash/__pycache__/test_Poly1305.cpython-36.pyc delete mode 100644 Crypto/SelfTest/Hash/__pycache__/test_RIPEMD160.cpython-36.pyc delete mode 100644 Crypto/SelfTest/Hash/__pycache__/test_SHA1.cpython-36.pyc delete mode 100644 Crypto/SelfTest/Hash/__pycache__/test_SHA224.cpython-36.pyc delete mode 100644 Crypto/SelfTest/Hash/__pycache__/test_SHA256.cpython-36.pyc delete mode 100644 Crypto/SelfTest/Hash/__pycache__/test_SHA384.cpython-36.pyc delete mode 100644 Crypto/SelfTest/Hash/__pycache__/test_SHA3_224.cpython-36.pyc delete mode 100644 Crypto/SelfTest/Hash/__pycache__/test_SHA3_256.cpython-36.pyc delete mode 100644 Crypto/SelfTest/Hash/__pycache__/test_SHA3_384.cpython-36.pyc delete mode 100644 Crypto/SelfTest/Hash/__pycache__/test_SHA3_512.cpython-36.pyc delete mode 100644 Crypto/SelfTest/Hash/__pycache__/test_SHA512.cpython-36.pyc delete mode 100644 Crypto/SelfTest/Hash/__pycache__/test_SHAKE.cpython-36.pyc delete mode 100644 Crypto/SelfTest/Hash/__pycache__/test_keccak.cpython-36.pyc delete mode 100644 Crypto/SelfTest/Hash/common.py delete mode 100644 Crypto/SelfTest/Hash/test_BLAKE2.py delete mode 100644 Crypto/SelfTest/Hash/test_CMAC.py delete mode 100644 Crypto/SelfTest/Hash/test_HMAC.py delete mode 100644 Crypto/SelfTest/Hash/test_MD2.py delete mode 100644 Crypto/SelfTest/Hash/test_MD4.py delete mode 100644 Crypto/SelfTest/Hash/test_MD5.py delete mode 100644 Crypto/SelfTest/Hash/test_Poly1305.py delete mode 100644 Crypto/SelfTest/Hash/test_RIPEMD160.py delete mode 100644 Crypto/SelfTest/Hash/test_SHA1.py delete mode 100644 Crypto/SelfTest/Hash/test_SHA224.py delete mode 100644 Crypto/SelfTest/Hash/test_SHA256.py delete mode 100644 Crypto/SelfTest/Hash/test_SHA384.py delete mode 100644 Crypto/SelfTest/Hash/test_SHA3_224.py delete mode 100644 Crypto/SelfTest/Hash/test_SHA3_256.py delete mode 100644 Crypto/SelfTest/Hash/test_SHA3_384.py delete mode 100644 Crypto/SelfTest/Hash/test_SHA3_512.py delete mode 100644 Crypto/SelfTest/Hash/test_SHA512.py delete mode 100644 Crypto/SelfTest/Hash/test_SHAKE.py delete mode 100644 Crypto/SelfTest/Hash/test_keccak.py delete mode 100644 Crypto/SelfTest/IO/__init__.py delete mode 100644 Crypto/SelfTest/IO/__pycache__/__init__.cpython-36.pyc delete mode 100644 Crypto/SelfTest/IO/__pycache__/test_PBES.cpython-36.pyc delete mode 100644 Crypto/SelfTest/IO/__pycache__/test_PKCS8.cpython-36.pyc delete mode 100644 Crypto/SelfTest/IO/test_PBES.py delete mode 100644 Crypto/SelfTest/IO/test_PKCS8.py delete mode 100644 Crypto/SelfTest/Math/__init__.py delete mode 100644 Crypto/SelfTest/Math/__pycache__/__init__.cpython-36.pyc delete mode 100644 Crypto/SelfTest/Math/__pycache__/test_Numbers.cpython-36.pyc delete mode 100644 Crypto/SelfTest/Math/__pycache__/test_Primality.cpython-36.pyc delete mode 100644 Crypto/SelfTest/Math/__pycache__/test_modexp.cpython-36.pyc delete mode 100644 Crypto/SelfTest/Math/test_Numbers.py delete mode 100644 Crypto/SelfTest/Math/test_Primality.py delete mode 100644 Crypto/SelfTest/Math/test_modexp.py delete mode 100644 Crypto/SelfTest/Protocol/__init__.py delete mode 100644 Crypto/SelfTest/Protocol/__pycache__/__init__.cpython-36.pyc delete mode 100644 Crypto/SelfTest/Protocol/__pycache__/test_KDF.cpython-36.pyc delete mode 100644 Crypto/SelfTest/Protocol/__pycache__/test_SecretSharing.cpython-36.pyc delete mode 100644 Crypto/SelfTest/Protocol/__pycache__/test_rfc1751.cpython-36.pyc delete mode 100644 Crypto/SelfTest/Protocol/test_KDF.py delete mode 100644 Crypto/SelfTest/Protocol/test_SecretSharing.py delete mode 100644 Crypto/SelfTest/Protocol/test_rfc1751.py delete mode 100644 Crypto/SelfTest/PublicKey/__init__.py delete mode 100644 Crypto/SelfTest/PublicKey/__pycache__/__init__.cpython-36.pyc delete mode 100644 Crypto/SelfTest/PublicKey/__pycache__/test_DSA.cpython-36.pyc delete mode 100644 Crypto/SelfTest/PublicKey/__pycache__/test_ECC.cpython-36.pyc delete mode 100644 Crypto/SelfTest/PublicKey/__pycache__/test_ElGamal.cpython-36.pyc delete mode 100644 Crypto/SelfTest/PublicKey/__pycache__/test_RSA.cpython-36.pyc delete mode 100644 Crypto/SelfTest/PublicKey/__pycache__/test_import_DSA.cpython-36.pyc delete mode 100644 Crypto/SelfTest/PublicKey/__pycache__/test_import_ECC.cpython-36.pyc delete mode 100644 Crypto/SelfTest/PublicKey/__pycache__/test_import_RSA.cpython-36.pyc delete mode 100644 Crypto/SelfTest/PublicKey/test_DSA.py delete mode 100644 Crypto/SelfTest/PublicKey/test_ECC.py delete mode 100644 Crypto/SelfTest/PublicKey/test_ElGamal.py delete mode 100644 Crypto/SelfTest/PublicKey/test_RSA.py delete mode 100644 Crypto/SelfTest/PublicKey/test_import_DSA.py delete mode 100644 Crypto/SelfTest/PublicKey/test_import_ECC.py delete mode 100644 Crypto/SelfTest/PublicKey/test_import_RSA.py delete mode 100644 Crypto/SelfTest/Random/__init__.py delete mode 100644 Crypto/SelfTest/Random/__pycache__/__init__.cpython-36.pyc delete mode 100644 Crypto/SelfTest/Random/__pycache__/test_random.cpython-36.pyc delete mode 100644 Crypto/SelfTest/Random/test_random.py delete mode 100644 Crypto/SelfTest/Signature/__init__.py delete mode 100644 Crypto/SelfTest/Signature/__pycache__/__init__.cpython-36.pyc delete mode 100644 Crypto/SelfTest/Signature/__pycache__/test_dss.cpython-36.pyc delete mode 100644 Crypto/SelfTest/Signature/__pycache__/test_pkcs1_15.cpython-36.pyc delete mode 100644 Crypto/SelfTest/Signature/__pycache__/test_pss.cpython-36.pyc delete mode 100644 Crypto/SelfTest/Signature/test_dss.py delete mode 100644 Crypto/SelfTest/Signature/test_pkcs1_15.py delete mode 100644 Crypto/SelfTest/Signature/test_pss.py delete mode 100644 Crypto/SelfTest/Util/__init__.py delete mode 100644 Crypto/SelfTest/Util/__pycache__/__init__.cpython-36.pyc delete mode 100644 Crypto/SelfTest/Util/__pycache__/test_Counter.cpython-36.pyc delete mode 100644 Crypto/SelfTest/Util/__pycache__/test_Padding.cpython-36.pyc delete mode 100644 Crypto/SelfTest/Util/__pycache__/test_asn1.cpython-36.pyc delete mode 100644 Crypto/SelfTest/Util/__pycache__/test_number.cpython-36.pyc delete mode 100644 Crypto/SelfTest/Util/__pycache__/test_rfc1751.cpython-36.pyc delete mode 100644 Crypto/SelfTest/Util/__pycache__/test_strxor.cpython-36.pyc delete mode 100644 Crypto/SelfTest/Util/test_Counter.py delete mode 100644 Crypto/SelfTest/Util/test_Padding.py delete mode 100644 Crypto/SelfTest/Util/test_asn1.py delete mode 100644 Crypto/SelfTest/Util/test_number.py delete mode 100644 Crypto/SelfTest/Util/test_rfc1751.py delete mode 100644 Crypto/SelfTest/Util/test_strxor.py delete mode 100644 Crypto/SelfTest/__init__.py delete mode 100644 Crypto/SelfTest/__main__.py delete mode 100644 Crypto/SelfTest/loader.py delete mode 100644 Crypto/SelfTest/st_common.py delete mode 100644 Crypto/Signature/DSS.py delete mode 100644 Crypto/Signature/DSS.pyi delete mode 100644 Crypto/Signature/PKCS1_PSS.py delete mode 100644 Crypto/Signature/PKCS1_PSS.pyi delete mode 100644 Crypto/Signature/PKCS1_v1_5.py delete mode 100644 Crypto/Signature/PKCS1_v1_5.pyi delete mode 100644 Crypto/Signature/__init__.py delete mode 100644 Crypto/Signature/pkcs1_15.py delete mode 100644 Crypto/Signature/pkcs1_15.pyi delete mode 100644 Crypto/Signature/pss.py delete mode 100644 Crypto/Signature/pss.pyi delete mode 100644 Crypto/Util/Counter.py delete mode 100644 Crypto/Util/Counter.pyi delete mode 100644 Crypto/Util/Padding.py delete mode 100644 Crypto/Util/Padding.pyi delete mode 100644 Crypto/Util/RFC1751.py delete mode 100644 Crypto/Util/RFC1751.pyi delete mode 100644 Crypto/Util/__init__.py delete mode 100644 Crypto/Util/__pycache__/__init__.cpython-36.pyc delete mode 100644 Crypto/Util/__pycache__/_cpu_features.cpython-36.pyc delete mode 100644 Crypto/Util/__pycache__/_file_system.cpython-36.pyc delete mode 100644 Crypto/Util/__pycache__/_raw_api.cpython-36.pyc delete mode 100644 Crypto/Util/__pycache__/number.cpython-36.pyc delete mode 100644 Crypto/Util/__pycache__/py3compat.cpython-36.pyc delete mode 100644 Crypto/Util/__pycache__/strxor.cpython-36.pyc delete mode 100644 Crypto/Util/_cpu_features.py delete mode 100644 Crypto/Util/_cpu_features.pyi delete mode 100644 Crypto/Util/_cpuid_c.abi3.so delete mode 100644 Crypto/Util/_file_system.py delete mode 100644 Crypto/Util/_file_system.pyi delete mode 100644 Crypto/Util/_raw_api.py delete mode 100644 Crypto/Util/_raw_api.pyi delete mode 100644 Crypto/Util/_strxor.abi3.so delete mode 100644 Crypto/Util/asn1.py delete mode 100644 Crypto/Util/asn1.pyi delete mode 100644 Crypto/Util/number.py delete mode 100644 Crypto/Util/number.pyi delete mode 100644 Crypto/Util/py3compat.py delete mode 100644 Crypto/Util/py3compat.pyi delete mode 100644 Crypto/Util/strxor.py delete mode 100644 Crypto/Util/strxor.pyi delete mode 100644 Crypto/__init__.py delete mode 100644 Crypto/__init__.pyi delete mode 100644 Crypto/__pycache__/__init__.cpython-36.pyc delete mode 100644 Crypto/py.typed diff --git a/Crypto/Cipher/AES.py b/Crypto/Cipher/AES.py deleted file mode 100644 index 1237a8c..0000000 --- a/Crypto/Cipher/AES.py +++ /dev/null @@ -1,250 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Cipher/AES.py : AES -# -# =================================================================== -# The contents of this file are dedicated to the public domain. To -# the extent that dedication to the public domain is not available, -# everyone is granted a worldwide, perpetual, royalty-free, -# non-exclusive license to exercise all rights associated with the -# contents of this file for any purpose whatsoever. -# No rights are reserved. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS -# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN -# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# =================================================================== -""" -Module's constants for the modes of operation supported with AES: - -:var MODE_ECB: :ref:`Electronic Code Book (ECB) ` -:var MODE_CBC: :ref:`Cipher-Block Chaining (CBC) ` -:var MODE_CFB: :ref:`Cipher FeedBack (CFB) ` -:var MODE_OFB: :ref:`Output FeedBack (OFB) ` -:var MODE_CTR: :ref:`CounTer Mode (CTR) ` -:var MODE_OPENPGP: :ref:`OpenPGP Mode ` -:var MODE_CCM: :ref:`Counter with CBC-MAC (CCM) Mode ` -:var MODE_EAX: :ref:`EAX Mode ` -:var MODE_GCM: :ref:`Galois Counter Mode (GCM) ` -:var MODE_SIV: :ref:`Syntethic Initialization Vector (SIV) ` -:var MODE_OCB: :ref:`Offset Code Book (OCB) ` -""" - -import sys - -from Crypto.Cipher import _create_cipher -from Crypto.Util._raw_api import (load_pycryptodome_raw_lib, - VoidPointer, SmartPointer, - c_size_t, c_uint8_ptr) - -from Crypto.Util import _cpu_features -from Crypto.Random import get_random_bytes - - -_cproto = """ - int AES_start_operation(const uint8_t key[], - size_t key_len, - void **pResult); - int AES_encrypt(const void *state, - const uint8_t *in, - uint8_t *out, - size_t data_len); - int AES_decrypt(const void *state, - const uint8_t *in, - uint8_t *out, - size_t data_len); - int AES_stop_operation(void *state); - """ - - -# Load portable AES -_raw_aes_lib = load_pycryptodome_raw_lib("Crypto.Cipher._raw_aes", - _cproto) - -# Try to load AES with AES NI instructions -try: - _raw_aesni_lib = None - if _cpu_features.have_aes_ni(): - _raw_aesni_lib = load_pycryptodome_raw_lib("Crypto.Cipher._raw_aesni", - _cproto.replace("AES", - "AESNI")) -# _raw_aesni may not have been compiled in -except OSError: - pass - - -def _create_base_cipher(dict_parameters): - """This method instantiates and returns a handle to a low-level - base cipher. It will absorb named parameters in the process.""" - - use_aesni = dict_parameters.pop("use_aesni", True) - - try: - key = dict_parameters.pop("key") - except KeyError: - raise TypeError("Missing 'key' parameter") - - if len(key) not in key_size: - raise ValueError("Incorrect AES key length (%d bytes)" % len(key)) - - if use_aesni and _raw_aesni_lib: - start_operation = _raw_aesni_lib.AESNI_start_operation - stop_operation = _raw_aesni_lib.AESNI_stop_operation - else: - start_operation = _raw_aes_lib.AES_start_operation - stop_operation = _raw_aes_lib.AES_stop_operation - - cipher = VoidPointer() - result = start_operation(c_uint8_ptr(key), - c_size_t(len(key)), - cipher.address_of()) - if result: - raise ValueError("Error %X while instantiating the AES cipher" - % result) - return SmartPointer(cipher.get(), stop_operation) - - -def _derive_Poly1305_key_pair(key, nonce): - """Derive a tuple (r, s, nonce) for a Poly1305 MAC. - - If nonce is ``None``, a new 16-byte nonce is generated. - """ - - if len(key) != 32: - raise ValueError("Poly1305 with AES requires a 32-byte key") - - if nonce is None: - nonce = get_random_bytes(16) - elif len(nonce) != 16: - raise ValueError("Poly1305 with AES requires a 16-byte nonce") - - s = new(key[:16], MODE_ECB).encrypt(nonce) - return key[16:], s, nonce - - -def new(key, mode, *args, **kwargs): - """Create a new AES cipher. - - :param key: - The secret key to use in the symmetric cipher. - - It must be 16, 24 or 32 bytes long (respectively for *AES-128*, - *AES-192* or *AES-256*). - - For ``MODE_SIV`` only, it doubles to 32, 48, or 64 bytes. - :type key: bytes/bytearray/memoryview - - :param mode: - The chaining mode to use for encryption or decryption. - If in doubt, use ``MODE_EAX``. - :type mode: One of the supported ``MODE_*`` constants - - :Keyword Arguments: - * **iv** (*bytes*, *bytearray*, *memoryview*) -- - (Only applicable for ``MODE_CBC``, ``MODE_CFB``, ``MODE_OFB``, - and ``MODE_OPENPGP`` modes). - - The initialization vector to use for encryption or decryption. - - For ``MODE_CBC``, ``MODE_CFB``, and ``MODE_OFB`` it must be 16 bytes long. - - For ``MODE_OPENPGP`` mode only, - it must be 16 bytes long for encryption - and 18 bytes for decryption (in the latter case, it is - actually the *encrypted* IV which was prefixed to the ciphertext). - - If not provided, a random byte string is generated (you must then - read its value with the :attr:`iv` attribute). - - * **nonce** (*bytes*, *bytearray*, *memoryview*) -- - (Only applicable for ``MODE_CCM``, ``MODE_EAX``, ``MODE_GCM``, - ``MODE_SIV``, ``MODE_OCB``, and ``MODE_CTR``). - - A value that must never be reused for any other encryption done - with this key (except possibly for ``MODE_SIV``, see below). - - For ``MODE_EAX``, ``MODE_GCM`` and ``MODE_SIV`` there are no - restrictions on its length (recommended: **16** bytes). - - For ``MODE_CCM``, its length must be in the range **[7..13]**. - Bear in mind that with CCM there is a trade-off between nonce - length and maximum message size. Recommendation: **11** bytes. - - For ``MODE_OCB``, its length must be in the range **[1..15]** - (recommended: **15**). - - For ``MODE_CTR``, its length must be in the range **[0..15]** - (recommended: **8**). - - For ``MODE_SIV``, the nonce is optional, if it is not specified, - then no nonce is being used, which renders the encryption - deterministic. - - If not provided, for modes other than ``MODE_SIV```, a random - byte string of the recommended length is used (you must then - read its value with the :attr:`nonce` attribute). - - * **segment_size** (*integer*) -- - (Only ``MODE_CFB``).The number of **bits** the plaintext and ciphertext - are segmented in. It must be a multiple of 8. - If not specified, it will be assumed to be 8. - - * **mac_len** : (*integer*) -- - (Only ``MODE_EAX``, ``MODE_GCM``, ``MODE_OCB``, ``MODE_CCM``) - Length of the authentication tag, in bytes. - - It must be even and in the range **[4..16]**. - The recommended value (and the default, if not specified) is **16**. - - * **msg_len** : (*integer*) -- - (Only ``MODE_CCM``). Length of the message to (de)cipher. - If not specified, ``encrypt`` must be called with the entire message. - Similarly, ``decrypt`` can only be called once. - - * **assoc_len** : (*integer*) -- - (Only ``MODE_CCM``). Length of the associated data. - If not specified, all associated data is buffered internally, - which may represent a problem for very large messages. - - * **initial_value** : (*integer* or *bytes/bytearray/memoryview*) -- - (Only ``MODE_CTR``). - The initial value for the counter. If not present, the cipher will - start counting from 0. The value is incremented by one for each block. - The counter number is encoded in big endian mode. - - * **counter** : (*object*) -- - Instance of ``Crypto.Util.Counter``, which allows full customization - of the counter block. This parameter is incompatible to both ``nonce`` - and ``initial_value``. - - * **use_aesni** : (*boolean*) -- - Use Intel AES-NI hardware extensions (default: use if available). - - :Return: an AES object, of the applicable mode. - """ - - kwargs["add_aes_modes"] = True - return _create_cipher(sys.modules[__name__], key, mode, *args, **kwargs) - - -MODE_ECB = 1 -MODE_CBC = 2 -MODE_CFB = 3 -MODE_OFB = 5 -MODE_CTR = 6 -MODE_OPENPGP = 7 -MODE_CCM = 8 -MODE_EAX = 9 -MODE_SIV = 10 -MODE_GCM = 11 -MODE_OCB = 12 - -# Size of a data block (in bytes) -block_size = 16 -# Size of a key (in bytes) -key_size = (16, 24, 32) diff --git a/Crypto/Cipher/AES.pyi b/Crypto/Cipher/AES.pyi deleted file mode 100644 index 8f655cf..0000000 --- a/Crypto/Cipher/AES.pyi +++ /dev/null @@ -1,47 +0,0 @@ -from typing import Union, Tuple, Optional, Dict - -from Crypto.Cipher._mode_ecb import EcbMode -from Crypto.Cipher._mode_cbc import CbcMode -from Crypto.Cipher._mode_cfb import CfbMode -from Crypto.Cipher._mode_ofb import OfbMode -from Crypto.Cipher._mode_ctr import CtrMode -from Crypto.Cipher._mode_openpgp import OpenPgpMode -from Crypto.Cipher._mode_ccm import CcmMode -from Crypto.Cipher._mode_eax import EaxMode -from Crypto.Cipher._mode_gcm import GcmMode -from Crypto.Cipher._mode_siv import SivMode -from Crypto.Cipher._mode_ocb import OcbMode - -AESMode = int - -MODE_ECB: AESMode -MODE_CBC: AESMode -MODE_CFB: AESMode -MODE_OFB: AESMode -MODE_CTR: AESMode -MODE_OPENPGP: AESMode -MODE_CCM: AESMode -MODE_EAX: AESMode -MODE_GCM: AESMode -MODE_SIV: AESMode -MODE_OCB: AESMode - -Buffer = Union[bytes, bytearray, memoryview] - -def new(key: Buffer, - mode: AESMode, - iv : Buffer = ..., - IV : Buffer = ..., - nonce : Buffer = ..., - segment_size : int = ..., - mac_len : int = ..., - assoc_len : int = ..., - initial_value : Union[int, Buffer] = ..., - counter : Dict = ..., - use_aesni : bool = ...) -> \ - Union[EcbMode, CbcMode, CfbMode, OfbMode, CtrMode, - OpenPgpMode, CcmMode, EaxMode, GcmMode, - SivMode, OcbMode]: ... - -block_size: int -key_size: Tuple[int, int, int] diff --git a/Crypto/Cipher/ARC2.py b/Crypto/Cipher/ARC2.py deleted file mode 100644 index 0ba7e33..0000000 --- a/Crypto/Cipher/ARC2.py +++ /dev/null @@ -1,175 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Cipher/ARC2.py : ARC2.py -# -# =================================================================== -# The contents of this file are dedicated to the public domain. To -# the extent that dedication to the public domain is not available, -# everyone is granted a worldwide, perpetual, royalty-free, -# non-exclusive license to exercise all rights associated with the -# contents of this file for any purpose whatsoever. -# No rights are reserved. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS -# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN -# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# =================================================================== -""" -Module's constants for the modes of operation supported with ARC2: - -:var MODE_ECB: :ref:`Electronic Code Book (ECB) ` -:var MODE_CBC: :ref:`Cipher-Block Chaining (CBC) ` -:var MODE_CFB: :ref:`Cipher FeedBack (CFB) ` -:var MODE_OFB: :ref:`Output FeedBack (OFB) ` -:var MODE_CTR: :ref:`CounTer Mode (CTR) ` -:var MODE_OPENPGP: :ref:`OpenPGP Mode ` -:var MODE_EAX: :ref:`EAX Mode ` -""" - -import sys - -from Crypto.Cipher import _create_cipher -from Crypto.Util.py3compat import byte_string -from Crypto.Util._raw_api import (load_pycryptodome_raw_lib, - VoidPointer, SmartPointer, - c_size_t, c_uint8_ptr) - -_raw_arc2_lib = load_pycryptodome_raw_lib( - "Crypto.Cipher._raw_arc2", - """ - int ARC2_start_operation(const uint8_t key[], - size_t key_len, - size_t effective_key_len, - void **pResult); - int ARC2_encrypt(const void *state, - const uint8_t *in, - uint8_t *out, - size_t data_len); - int ARC2_decrypt(const void *state, - const uint8_t *in, - uint8_t *out, - size_t data_len); - int ARC2_stop_operation(void *state); - """ - ) - - -def _create_base_cipher(dict_parameters): - """This method instantiates and returns a handle to a low-level - base cipher. It will absorb named parameters in the process.""" - - try: - key = dict_parameters.pop("key") - except KeyError: - raise TypeError("Missing 'key' parameter") - - effective_keylen = dict_parameters.pop("effective_keylen", 1024) - - if len(key) not in key_size: - raise ValueError("Incorrect ARC2 key length (%d bytes)" % len(key)) - - if not (40 <= effective_keylen <= 1024): - raise ValueError("'effective_key_len' must be at least 40 and no larger than 1024 " - "(not %d)" % effective_keylen) - - start_operation = _raw_arc2_lib.ARC2_start_operation - stop_operation = _raw_arc2_lib.ARC2_stop_operation - - cipher = VoidPointer() - result = start_operation(c_uint8_ptr(key), - c_size_t(len(key)), - c_size_t(effective_keylen), - cipher.address_of()) - if result: - raise ValueError("Error %X while instantiating the ARC2 cipher" - % result) - - return SmartPointer(cipher.get(), stop_operation) - - -def new(key, mode, *args, **kwargs): - """Create a new RC2 cipher. - - :param key: - The secret key to use in the symmetric cipher. - Its length can vary from 5 to 128 bytes; the actual search space - (and the cipher strength) can be reduced with the ``effective_keylen`` parameter. - :type key: bytes, bytearray, memoryview - - :param mode: - The chaining mode to use for encryption or decryption. - :type mode: One of the supported ``MODE_*`` constants - - :Keyword Arguments: - * **iv** (*bytes*, *bytearray*, *memoryview*) -- - (Only applicable for ``MODE_CBC``, ``MODE_CFB``, ``MODE_OFB``, - and ``MODE_OPENPGP`` modes). - - The initialization vector to use for encryption or decryption. - - For ``MODE_CBC``, ``MODE_CFB``, and ``MODE_OFB`` it must be 8 bytes long. - - For ``MODE_OPENPGP`` mode only, - it must be 8 bytes long for encryption - and 10 bytes for decryption (in the latter case, it is - actually the *encrypted* IV which was prefixed to the ciphertext). - - If not provided, a random byte string is generated (you must then - read its value with the :attr:`iv` attribute). - - * **nonce** (*bytes*, *bytearray*, *memoryview*) -- - (Only applicable for ``MODE_EAX`` and ``MODE_CTR``). - - A value that must never be reused for any other encryption done - with this key. - - For ``MODE_EAX`` there are no - restrictions on its length (recommended: **16** bytes). - - For ``MODE_CTR``, its length must be in the range **[0..7]**. - - If not provided for ``MODE_EAX``, a random byte string is generated (you - can read it back via the ``nonce`` attribute). - - * **effective_keylen** (*integer*) -- - Optional. Maximum strength in bits of the actual key used by the ARC2 algorithm. - If the supplied ``key`` parameter is longer (in bits) of the value specified - here, it will be weakened to match it. - If not specified, no limitation is applied. - - * **segment_size** (*integer*) -- - (Only ``MODE_CFB``).The number of **bits** the plaintext and ciphertext - are segmented in. It must be a multiple of 8. - If not specified, it will be assumed to be 8. - - * **mac_len** : (*integer*) -- - (Only ``MODE_EAX``) - Length of the authentication tag, in bytes. - It must be no longer than 8 (default). - - * **initial_value** : (*integer*) -- - (Only ``MODE_CTR``). The initial value for the counter within - the counter block. By default it is **0**. - - :Return: an ARC2 object, of the applicable mode. - """ - - return _create_cipher(sys.modules[__name__], key, mode, *args, **kwargs) - -MODE_ECB = 1 -MODE_CBC = 2 -MODE_CFB = 3 -MODE_OFB = 5 -MODE_CTR = 6 -MODE_OPENPGP = 7 -MODE_EAX = 9 - -# Size of a data block (in bytes) -block_size = 8 -# Size of a key (in bytes) -key_size = range(5, 128 + 1) diff --git a/Crypto/Cipher/ARC2.pyi b/Crypto/Cipher/ARC2.pyi deleted file mode 100644 index 055c424..0000000 --- a/Crypto/Cipher/ARC2.pyi +++ /dev/null @@ -1,35 +0,0 @@ -from typing import Union, Dict, Iterable - -from Crypto.Cipher._mode_ecb import EcbMode -from Crypto.Cipher._mode_cbc import CbcMode -from Crypto.Cipher._mode_cfb import CfbMode -from Crypto.Cipher._mode_ofb import OfbMode -from Crypto.Cipher._mode_ctr import CtrMode -from Crypto.Cipher._mode_openpgp import OpenPgpMode -from Crypto.Cipher._mode_eax import EaxMode - -ARC2Mode = int - -MODE_ECB: ARC2Mode -MODE_CBC: ARC2Mode -MODE_CFB: ARC2Mode -MODE_OFB: ARC2Mode -MODE_CTR: ARC2Mode -MODE_OPENPGP: ARC2Mode -MODE_EAX: ARC2Mode - -Buffer = Union[bytes, bytearray, memoryview] - -def new(key: Buffer, - mode: ARC2Mode, - iv : Buffer = ..., - IV : Buffer = ..., - nonce : Buffer = ..., - segment_size : int = ..., - mac_len : int = ..., - initial_value : Union[int, Buffer] = ..., - counter : Dict = ...) -> \ - Union[EcbMode, CbcMode, CfbMode, OfbMode, CtrMode, OpenPgpMode]: ... - -block_size: int -key_size: Iterable[int] diff --git a/Crypto/Cipher/ARC4.py b/Crypto/Cipher/ARC4.py deleted file mode 100644 index 7150ea6..0000000 --- a/Crypto/Cipher/ARC4.py +++ /dev/null @@ -1,137 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Cipher/ARC4.py : ARC4 -# -# =================================================================== -# The contents of this file are dedicated to the public domain. To -# the extent that dedication to the public domain is not available, -# everyone is granted a worldwide, perpetual, royalty-free, -# non-exclusive license to exercise all rights associated with the -# contents of this file for any purpose whatsoever. -# No rights are reserved. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS -# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN -# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# =================================================================== - -from Crypto.Util.py3compat import b - -from Crypto.Util._raw_api import (load_pycryptodome_raw_lib, VoidPointer, - create_string_buffer, get_raw_buffer, - SmartPointer, c_size_t, c_uint8_ptr) - - -_raw_arc4_lib = load_pycryptodome_raw_lib("Crypto.Cipher._ARC4", """ - int ARC4_stream_encrypt(void *rc4State, const uint8_t in[], - uint8_t out[], size_t len); - int ARC4_stream_init(uint8_t *key, size_t keylen, - void **pRc4State); - int ARC4_stream_destroy(void *rc4State); - """) - - -class ARC4Cipher: - """ARC4 cipher object. Do not create it directly. Use - :func:`Crypto.Cipher.ARC4.new` instead. - """ - - def __init__(self, key, *args, **kwargs): - """Initialize an ARC4 cipher object - - See also `new()` at the module level.""" - - if len(args) > 0: - ndrop = args[0] - args = args[1:] - else: - ndrop = kwargs.pop('drop', 0) - - if len(key) not in key_size: - raise ValueError("Incorrect ARC4 key length (%d bytes)" % - len(key)) - - self._state = VoidPointer() - result = _raw_arc4_lib.ARC4_stream_init(c_uint8_ptr(key), - c_size_t(len(key)), - self._state.address_of()) - if result != 0: - raise ValueError("Error %d while creating the ARC4 cipher" - % result) - self._state = SmartPointer(self._state.get(), - _raw_arc4_lib.ARC4_stream_destroy) - - if ndrop > 0: - # This is OK even if the cipher is used for decryption, - # since encrypt and decrypt are actually the same thing - # with ARC4. - self.encrypt(b'\x00' * ndrop) - - self.block_size = 1 - self.key_size = len(key) - - def encrypt(self, plaintext): - """Encrypt a piece of data. - - :param plaintext: The data to encrypt, of any size. - :type plaintext: bytes, bytearray, memoryview - :returns: the encrypted byte string, of equal length as the - plaintext. - """ - - ciphertext = create_string_buffer(len(plaintext)) - result = _raw_arc4_lib.ARC4_stream_encrypt(self._state.get(), - c_uint8_ptr(plaintext), - ciphertext, - c_size_t(len(plaintext))) - if result: - raise ValueError("Error %d while encrypting with RC4" % result) - return get_raw_buffer(ciphertext) - - def decrypt(self, ciphertext): - """Decrypt a piece of data. - - :param ciphertext: The data to decrypt, of any size. - :type ciphertext: bytes, bytearray, memoryview - :returns: the decrypted byte string, of equal length as the - ciphertext. - """ - - try: - return self.encrypt(ciphertext) - except ValueError as e: - raise ValueError(str(e).replace("enc", "dec")) - - -def new(key, *args, **kwargs): - """Create a new ARC4 cipher. - - :param key: - The secret key to use in the symmetric cipher. - Its length must be in the range ``[5..256]``. - The recommended length is 16 bytes. - :type key: bytes, bytearray, memoryview - - :Keyword Arguments: - * *drop* (``integer``) -- - The amount of bytes to discard from the initial part of the keystream. - In fact, such part has been found to be distinguishable from random - data (while it shouldn't) and also correlated to key. - - The recommended value is 3072_ bytes. The default value is 0. - - :Return: an `ARC4Cipher` object - - .. _3072: http://eprint.iacr.org/2002/067.pdf - """ - return ARC4Cipher(key, *args, **kwargs) - -# Size of a data block (in bytes) -block_size = 1 -# Size of a key (in bytes) -key_size = range(5, 256+1) diff --git a/Crypto/Cipher/ARC4.pyi b/Crypto/Cipher/ARC4.pyi deleted file mode 100644 index 2e75d6f..0000000 --- a/Crypto/Cipher/ARC4.pyi +++ /dev/null @@ -1,16 +0,0 @@ -from typing import Any, Union, Iterable - -Buffer = Union[bytes, bytearray, memoryview] - -class ARC4Cipher: - block_size: int - key_size: int - - def __init__(self, key: Buffer, *args: Any, **kwargs: Any) -> None: ... - def encrypt(self, plaintext: Buffer) -> bytes: ... - def decrypt(self, ciphertext: Buffer) -> bytes: ... - -def new(key: Buffer, drop : int = ...) -> ARC4Cipher: ... - -block_size: int -key_size: Iterable[int] diff --git a/Crypto/Cipher/Blowfish.py b/Crypto/Cipher/Blowfish.py deleted file mode 100644 index 6005ffe..0000000 --- a/Crypto/Cipher/Blowfish.py +++ /dev/null @@ -1,159 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Cipher/Blowfish.py : Blowfish -# -# =================================================================== -# The contents of this file are dedicated to the public domain. To -# the extent that dedication to the public domain is not available, -# everyone is granted a worldwide, perpetual, royalty-free, -# non-exclusive license to exercise all rights associated with the -# contents of this file for any purpose whatsoever. -# No rights are reserved. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS -# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN -# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# =================================================================== -""" -Module's constants for the modes of operation supported with Blowfish: - -:var MODE_ECB: :ref:`Electronic Code Book (ECB) ` -:var MODE_CBC: :ref:`Cipher-Block Chaining (CBC) ` -:var MODE_CFB: :ref:`Cipher FeedBack (CFB) ` -:var MODE_OFB: :ref:`Output FeedBack (OFB) ` -:var MODE_CTR: :ref:`CounTer Mode (CTR) ` -:var MODE_OPENPGP: :ref:`OpenPGP Mode ` -:var MODE_EAX: :ref:`EAX Mode ` -""" - -import sys - -from Crypto.Cipher import _create_cipher -from Crypto.Util._raw_api import (load_pycryptodome_raw_lib, - VoidPointer, SmartPointer, c_size_t, - c_uint8_ptr) - -_raw_blowfish_lib = load_pycryptodome_raw_lib( - "Crypto.Cipher._raw_blowfish", - """ - int Blowfish_start_operation(const uint8_t key[], - size_t key_len, - void **pResult); - int Blowfish_encrypt(const void *state, - const uint8_t *in, - uint8_t *out, - size_t data_len); - int Blowfish_decrypt(const void *state, - const uint8_t *in, - uint8_t *out, - size_t data_len); - int Blowfish_stop_operation(void *state); - """ - ) - - -def _create_base_cipher(dict_parameters): - """This method instantiates and returns a smart pointer to - a low-level base cipher. It will absorb named parameters in - the process.""" - - try: - key = dict_parameters.pop("key") - except KeyError: - raise TypeError("Missing 'key' parameter") - - if len(key) not in key_size: - raise ValueError("Incorrect Blowfish key length (%d bytes)" % len(key)) - - start_operation = _raw_blowfish_lib.Blowfish_start_operation - stop_operation = _raw_blowfish_lib.Blowfish_stop_operation - - void_p = VoidPointer() - result = start_operation(c_uint8_ptr(key), - c_size_t(len(key)), - void_p.address_of()) - if result: - raise ValueError("Error %X while instantiating the Blowfish cipher" - % result) - return SmartPointer(void_p.get(), stop_operation) - - -def new(key, mode, *args, **kwargs): - """Create a new Blowfish cipher - - :param key: - The secret key to use in the symmetric cipher. - Its length can vary from 5 to 56 bytes. - :type key: bytes, bytearray, memoryview - - :param mode: - The chaining mode to use for encryption or decryption. - :type mode: One of the supported ``MODE_*`` constants - - :Keyword Arguments: - * **iv** (*bytes*, *bytearray*, *memoryview*) -- - (Only applicable for ``MODE_CBC``, ``MODE_CFB``, ``MODE_OFB``, - and ``MODE_OPENPGP`` modes). - - The initialization vector to use for encryption or decryption. - - For ``MODE_CBC``, ``MODE_CFB``, and ``MODE_OFB`` it must be 8 bytes long. - - For ``MODE_OPENPGP`` mode only, - it must be 8 bytes long for encryption - and 10 bytes for decryption (in the latter case, it is - actually the *encrypted* IV which was prefixed to the ciphertext). - - If not provided, a random byte string is generated (you must then - read its value with the :attr:`iv` attribute). - - * **nonce** (*bytes*, *bytearray*, *memoryview*) -- - (Only applicable for ``MODE_EAX`` and ``MODE_CTR``). - - A value that must never be reused for any other encryption done - with this key. - - For ``MODE_EAX`` there are no - restrictions on its length (recommended: **16** bytes). - - For ``MODE_CTR``, its length must be in the range **[0..7]**. - - If not provided for ``MODE_EAX``, a random byte string is generated (you - can read it back via the ``nonce`` attribute). - - * **segment_size** (*integer*) -- - (Only ``MODE_CFB``).The number of **bits** the plaintext and ciphertext - are segmented in. It must be a multiple of 8. - If not specified, it will be assumed to be 8. - - * **mac_len** : (*integer*) -- - (Only ``MODE_EAX``) - Length of the authentication tag, in bytes. - It must be no longer than 8 (default). - - * **initial_value** : (*integer*) -- - (Only ``MODE_CTR``). The initial value for the counter within - the counter block. By default it is **0**. - - :Return: a Blowfish object, of the applicable mode. - """ - - return _create_cipher(sys.modules[__name__], key, mode, *args, **kwargs) - -MODE_ECB = 1 -MODE_CBC = 2 -MODE_CFB = 3 -MODE_OFB = 5 -MODE_CTR = 6 -MODE_OPENPGP = 7 -MODE_EAX = 9 - -# Size of a data block (in bytes) -block_size = 8 -# Size of a key (in bytes) -key_size = range(4, 56 + 1) diff --git a/Crypto/Cipher/Blowfish.pyi b/Crypto/Cipher/Blowfish.pyi deleted file mode 100644 index eff9da9..0000000 --- a/Crypto/Cipher/Blowfish.pyi +++ /dev/null @@ -1,35 +0,0 @@ -from typing import Union, Dict, Iterable - -from Crypto.Cipher._mode_ecb import EcbMode -from Crypto.Cipher._mode_cbc import CbcMode -from Crypto.Cipher._mode_cfb import CfbMode -from Crypto.Cipher._mode_ofb import OfbMode -from Crypto.Cipher._mode_ctr import CtrMode -from Crypto.Cipher._mode_openpgp import OpenPgpMode -from Crypto.Cipher._mode_eax import EaxMode - -BlowfishMode = int - -MODE_ECB: BlowfishMode -MODE_CBC: BlowfishMode -MODE_CFB: BlowfishMode -MODE_OFB: BlowfishMode -MODE_CTR: BlowfishMode -MODE_OPENPGP: BlowfishMode -MODE_EAX: BlowfishMode - -Buffer = Union[bytes, bytearray, memoryview] - -def new(key: Buffer, - mode: BlowfishMode, - iv : Buffer = ..., - IV : Buffer = ..., - nonce : Buffer = ..., - segment_size : int = ..., - mac_len : int = ..., - initial_value : Union[int, Buffer] = ..., - counter : Dict = ...) -> \ - Union[EcbMode, CbcMode, CfbMode, OfbMode, CtrMode, OpenPgpMode]: ... - -block_size: int -key_size: Iterable[int] diff --git a/Crypto/Cipher/CAST.py b/Crypto/Cipher/CAST.py deleted file mode 100644 index c7e82c1..0000000 --- a/Crypto/Cipher/CAST.py +++ /dev/null @@ -1,159 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Cipher/CAST.py : CAST -# -# =================================================================== -# The contents of this file are dedicated to the public domain. To -# the extent that dedication to the public domain is not available, -# everyone is granted a worldwide, perpetual, royalty-free, -# non-exclusive license to exercise all rights associated with the -# contents of this file for any purpose whatsoever. -# No rights are reserved. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS -# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN -# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# =================================================================== -""" -Module's constants for the modes of operation supported with CAST: - -:var MODE_ECB: :ref:`Electronic Code Book (ECB) ` -:var MODE_CBC: :ref:`Cipher-Block Chaining (CBC) ` -:var MODE_CFB: :ref:`Cipher FeedBack (CFB) ` -:var MODE_OFB: :ref:`Output FeedBack (OFB) ` -:var MODE_CTR: :ref:`CounTer Mode (CTR) ` -:var MODE_OPENPGP: :ref:`OpenPGP Mode ` -:var MODE_EAX: :ref:`EAX Mode ` -""" - -import sys - -from Crypto.Cipher import _create_cipher -from Crypto.Util.py3compat import byte_string -from Crypto.Util._raw_api import (load_pycryptodome_raw_lib, - VoidPointer, SmartPointer, - c_size_t, c_uint8_ptr) - -_raw_cast_lib = load_pycryptodome_raw_lib( - "Crypto.Cipher._raw_cast", - """ - int CAST_start_operation(const uint8_t key[], - size_t key_len, - void **pResult); - int CAST_encrypt(const void *state, - const uint8_t *in, - uint8_t *out, - size_t data_len); - int CAST_decrypt(const void *state, - const uint8_t *in, - uint8_t *out, - size_t data_len); - int CAST_stop_operation(void *state); - """) - - -def _create_base_cipher(dict_parameters): - """This method instantiates and returns a handle to a low-level - base cipher. It will absorb named parameters in the process.""" - - try: - key = dict_parameters.pop("key") - except KeyError: - raise TypeError("Missing 'key' parameter") - - if len(key) not in key_size: - raise ValueError("Incorrect CAST key length (%d bytes)" % len(key)) - - start_operation = _raw_cast_lib.CAST_start_operation - stop_operation = _raw_cast_lib.CAST_stop_operation - - cipher = VoidPointer() - result = start_operation(c_uint8_ptr(key), - c_size_t(len(key)), - cipher.address_of()) - if result: - raise ValueError("Error %X while instantiating the CAST cipher" - % result) - - return SmartPointer(cipher.get(), stop_operation) - - -def new(key, mode, *args, **kwargs): - """Create a new CAST cipher - - :param key: - The secret key to use in the symmetric cipher. - Its length can vary from 5 to 16 bytes. - :type key: bytes, bytearray, memoryview - - :param mode: - The chaining mode to use for encryption or decryption. - :type mode: One of the supported ``MODE_*`` constants - - :Keyword Arguments: - * **iv** (*bytes*, *bytearray*, *memoryview*) -- - (Only applicable for ``MODE_CBC``, ``MODE_CFB``, ``MODE_OFB``, - and ``MODE_OPENPGP`` modes). - - The initialization vector to use for encryption or decryption. - - For ``MODE_CBC``, ``MODE_CFB``, and ``MODE_OFB`` it must be 8 bytes long. - - For ``MODE_OPENPGP`` mode only, - it must be 8 bytes long for encryption - and 10 bytes for decryption (in the latter case, it is - actually the *encrypted* IV which was prefixed to the ciphertext). - - If not provided, a random byte string is generated (you must then - read its value with the :attr:`iv` attribute). - - * **nonce** (*bytes*, *bytearray*, *memoryview*) -- - (Only applicable for ``MODE_EAX`` and ``MODE_CTR``). - - A value that must never be reused for any other encryption done - with this key. - - For ``MODE_EAX`` there are no - restrictions on its length (recommended: **16** bytes). - - For ``MODE_CTR``, its length must be in the range **[0..7]**. - - If not provided for ``MODE_EAX``, a random byte string is generated (you - can read it back via the ``nonce`` attribute). - - * **segment_size** (*integer*) -- - (Only ``MODE_CFB``).The number of **bits** the plaintext and ciphertext - are segmented in. It must be a multiple of 8. - If not specified, it will be assumed to be 8. - - * **mac_len** : (*integer*) -- - (Only ``MODE_EAX``) - Length of the authentication tag, in bytes. - It must be no longer than 8 (default). - - * **initial_value** : (*integer*) -- - (Only ``MODE_CTR``). The initial value for the counter within - the counter block. By default it is **0**. - - :Return: a CAST object, of the applicable mode. - """ - - return _create_cipher(sys.modules[__name__], key, mode, *args, **kwargs) - -MODE_ECB = 1 -MODE_CBC = 2 -MODE_CFB = 3 -MODE_OFB = 5 -MODE_CTR = 6 -MODE_OPENPGP = 7 -MODE_EAX = 9 - -# Size of a data block (in bytes) -block_size = 8 -# Size of a key (in bytes) -key_size = range(5, 16 + 1) diff --git a/Crypto/Cipher/CAST.pyi b/Crypto/Cipher/CAST.pyi deleted file mode 100644 index a0cb6af..0000000 --- a/Crypto/Cipher/CAST.pyi +++ /dev/null @@ -1,35 +0,0 @@ -from typing import Union, Dict, Iterable - -from Crypto.Cipher._mode_ecb import EcbMode -from Crypto.Cipher._mode_cbc import CbcMode -from Crypto.Cipher._mode_cfb import CfbMode -from Crypto.Cipher._mode_ofb import OfbMode -from Crypto.Cipher._mode_ctr import CtrMode -from Crypto.Cipher._mode_openpgp import OpenPgpMode -from Crypto.Cipher._mode_eax import EaxMode - -CASTMode = int - -MODE_ECB: CASTMode -MODE_CBC: CASTMode -MODE_CFB: CASTMode -MODE_OFB: CASTMode -MODE_CTR: CASTMode -MODE_OPENPGP: CASTMode -MODE_EAX: CASTMode - -Buffer = Union[bytes, bytearray, memoryview] - -def new(key: Buffer, - mode: CASTMode, - iv : Buffer = ..., - IV : Buffer = ..., - nonce : Buffer = ..., - segment_size : int = ..., - mac_len : int = ..., - initial_value : Union[int, Buffer] = ..., - counter : Dict = ...) -> \ - Union[EcbMode, CbcMode, CfbMode, OfbMode, CtrMode, OpenPgpMode]: ... - -block_size: int -key_size : Iterable[int] diff --git a/Crypto/Cipher/ChaCha20.py b/Crypto/Cipher/ChaCha20.py deleted file mode 100644 index 9bd2252..0000000 --- a/Crypto/Cipher/ChaCha20.py +++ /dev/null @@ -1,287 +0,0 @@ -# =================================================================== -# -# Copyright (c) 2014, Legrandin -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# =================================================================== - -from Crypto.Random import get_random_bytes - -from Crypto.Util.py3compat import _copy_bytes -from Crypto.Util._raw_api import (load_pycryptodome_raw_lib, - create_string_buffer, - get_raw_buffer, VoidPointer, - SmartPointer, c_size_t, - c_uint8_ptr, c_ulong, - is_writeable_buffer) - -_raw_chacha20_lib = load_pycryptodome_raw_lib("Crypto.Cipher._chacha20", - """ - int chacha20_init(void **pState, - const uint8_t *key, - size_t keySize, - const uint8_t *nonce, - size_t nonceSize); - - int chacha20_destroy(void *state); - - int chacha20_encrypt(void *state, - const uint8_t in[], - uint8_t out[], - size_t len); - - int chacha20_seek(void *state, - unsigned long block_high, - unsigned long block_low, - unsigned offset); - int hchacha20( const uint8_t key[32], - const uint8_t nonce16[16], - uint8_t subkey[32]); - """) - - -def _HChaCha20(key, nonce): - - assert(len(key) == 32) - assert(len(nonce) == 16) - - subkey = bytearray(32) - result = _raw_chacha20_lib.hchacha20( - c_uint8_ptr(key), - c_uint8_ptr(nonce), - c_uint8_ptr(subkey)) - if result: - raise ValueError("Error %d when deriving subkey with HChaCha20" % result) - - return subkey - - -class ChaCha20Cipher(object): - """ChaCha20 (or XChaCha20) cipher object. - Do not create it directly. Use :py:func:`new` instead. - - :var nonce: The nonce with length 8, 12 or 24 bytes - :vartype nonce: bytes - """ - - block_size = 1 - - def __init__(self, key, nonce): - """Initialize a ChaCha20/XChaCha20 cipher object - - See also `new()` at the module level.""" - - self.nonce = _copy_bytes(None, None, nonce) - - # XChaCha20 requires a key derivation with HChaCha20 - # See 2.3 in https://tools.ietf.org/html/draft-arciszewski-xchacha-03 - if len(nonce) == 24: - key = _HChaCha20(key, nonce[:16]) - nonce = b'\x00' * 4 + nonce[16:] - self._name = "XChaCha20" - else: - self._name = "ChaCha20" - nonce = self.nonce - - self._next = ( self.encrypt, self.decrypt ) - - self._state = VoidPointer() - result = _raw_chacha20_lib.chacha20_init( - self._state.address_of(), - c_uint8_ptr(key), - c_size_t(len(key)), - nonce, - c_size_t(len(nonce))) - if result: - raise ValueError("Error %d instantiating a %s cipher" % (result, - self._name)) - self._state = SmartPointer(self._state.get(), - _raw_chacha20_lib.chacha20_destroy) - - def encrypt(self, plaintext, output=None): - """Encrypt a piece of data. - - Args: - plaintext(bytes/bytearray/memoryview): The data to encrypt, of any size. - Keyword Args: - output(bytes/bytearray/memoryview): The location where the ciphertext - is written to. If ``None``, the ciphertext is returned. - Returns: - If ``output`` is ``None``, the ciphertext is returned as ``bytes``. - Otherwise, ``None``. - """ - - if self.encrypt not in self._next: - raise TypeError("Cipher object can only be used for decryption") - self._next = ( self.encrypt, ) - return self._encrypt(plaintext, output) - - def _encrypt(self, plaintext, output): - """Encrypt without FSM checks""" - - if output is None: - ciphertext = create_string_buffer(len(plaintext)) - else: - ciphertext = output - - if not is_writeable_buffer(output): - raise TypeError("output must be a bytearray or a writeable memoryview") - - if len(plaintext) != len(output): - raise ValueError("output must have the same length as the input" - " (%d bytes)" % len(plaintext)) - - result = _raw_chacha20_lib.chacha20_encrypt( - self._state.get(), - c_uint8_ptr(plaintext), - c_uint8_ptr(ciphertext), - c_size_t(len(plaintext))) - if result: - raise ValueError("Error %d while encrypting with %s" % (result, self._name)) - - if output is None: - return get_raw_buffer(ciphertext) - else: - return None - - def decrypt(self, ciphertext, output=None): - """Decrypt a piece of data. - - Args: - ciphertext(bytes/bytearray/memoryview): The data to decrypt, of any size. - Keyword Args: - output(bytes/bytearray/memoryview): The location where the plaintext - is written to. If ``None``, the plaintext is returned. - Returns: - If ``output`` is ``None``, the plaintext is returned as ``bytes``. - Otherwise, ``None``. - """ - - if self.decrypt not in self._next: - raise TypeError("Cipher object can only be used for encryption") - self._next = ( self.decrypt, ) - - try: - return self._encrypt(ciphertext, output) - except ValueError as e: - raise ValueError(str(e).replace("enc", "dec")) - - def seek(self, position): - """Seek to a certain position in the key stream. - - Args: - position (integer): - The absolute position within the key stream, in bytes. - """ - - position, offset = divmod(position, 64) - block_low = position & 0xFFFFFFFF - block_high = position >> 32 - - result = _raw_chacha20_lib.chacha20_seek( - self._state.get(), - c_ulong(block_high), - c_ulong(block_low), - offset - ) - if result: - raise ValueError("Error %d while seeking with %s" % (result, self._name)) - - -def _derive_Poly1305_key_pair(key, nonce): - """Derive a tuple (r, s, nonce) for a Poly1305 MAC. - - If nonce is ``None``, a new 12-byte nonce is generated. - """ - - if len(key) != 32: - raise ValueError("Poly1305 with ChaCha20 requires a 32-byte key") - - if nonce is None: - padded_nonce = nonce = get_random_bytes(12) - elif len(nonce) == 8: - # See RFC7538, 2.6: [...] ChaCha20 as specified here requires a 96-bit - # nonce. So if the provided nonce is only 64-bit, then the first 32 - # bits of the nonce will be set to a constant number. - # This will usually be zero, but for protocols with multiple senders it may be - # different for each sender, but should be the same for all - # invocations of the function with the same key by a particular - # sender. - padded_nonce = b'\x00\x00\x00\x00' + nonce - elif len(nonce) == 12: - padded_nonce = nonce - else: - raise ValueError("Poly1305 with ChaCha20 requires an 8- or 12-byte nonce") - - rs = new(key=key, nonce=padded_nonce).encrypt(b'\x00' * 32) - return rs[:16], rs[16:], nonce - - -def new(**kwargs): - """Create a new ChaCha20 or XChaCha20 cipher - - Keyword Args: - key (bytes/bytearray/memoryview): The secret key to use. - It must be 32 bytes long. - nonce (bytes/bytearray/memoryview): A mandatory value that - must never be reused for any other encryption - done with this key. - - For ChaCha20, it must be 8 or 12 bytes long. - - For XChaCha20, it must be 24 bytes long. - - If not provided, 8 bytes will be randomly generated - (you can find them back in the ``nonce`` attribute). - - :Return: a :class:`Crypto.Cipher.ChaCha20.ChaCha20Cipher` object - """ - - try: - key = kwargs.pop("key") - except KeyError as e: - raise TypeError("Missing parameter %s" % e) - - nonce = kwargs.pop("nonce", None) - if nonce is None: - nonce = get_random_bytes(8) - - if len(key) != 32: - raise ValueError("ChaCha20/XChaCha20 key must be 32 bytes long") - - if len(nonce) not in (8, 12, 24): - raise ValueError("Nonce must be 8/12 bytes(ChaCha20) or 24 bytes (XChaCha20)") - - if kwargs: - raise TypeError("Unknown parameters: " + str(kwargs)) - - return ChaCha20Cipher(key, nonce) - -# Size of a data block (in bytes) -block_size = 1 - -# Size of a key (in bytes) -key_size = 32 diff --git a/Crypto/Cipher/ChaCha20.pyi b/Crypto/Cipher/ChaCha20.pyi deleted file mode 100644 index 3d00a1d..0000000 --- a/Crypto/Cipher/ChaCha20.pyi +++ /dev/null @@ -1,25 +0,0 @@ -from typing import Union, overload - -Buffer = Union[bytes, bytearray, memoryview] - -def _HChaCha20(key: Buffer, nonce: Buffer) -> bytearray: ... - -class ChaCha20Cipher: - block_size: int - nonce: bytes - - def __init__(self, key: Buffer, nonce: Buffer) -> None: ... - @overload - def encrypt(self, plaintext: Buffer) -> bytes: ... - @overload - def encrypt(self, plaintext: Buffer, output: Union[bytearray, memoryview]) -> None: ... - @overload - def decrypt(self, plaintext: Buffer) -> bytes: ... - @overload - def decrypt(self, plaintext: Buffer, output: Union[bytearray, memoryview]) -> None: ... - def seek(self, position: int) -> None: ... - -def new(key: Buffer, nonce: Buffer = ...) -> ChaCha20Cipher: ... - -block_size: int -key_size: int diff --git a/Crypto/Cipher/ChaCha20_Poly1305.py b/Crypto/Cipher/ChaCha20_Poly1305.py deleted file mode 100644 index 21ddca3..0000000 --- a/Crypto/Cipher/ChaCha20_Poly1305.py +++ /dev/null @@ -1,336 +0,0 @@ -# =================================================================== -# -# Copyright (c) 2018, Helder Eijs -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# =================================================================== - -from binascii import unhexlify - -from Crypto.Cipher import ChaCha20 -from Crypto.Cipher.ChaCha20 import _HChaCha20 -from Crypto.Hash import Poly1305, BLAKE2s - -from Crypto.Random import get_random_bytes - -from Crypto.Util.number import long_to_bytes -from Crypto.Util.py3compat import _copy_bytes, bord -from Crypto.Util._raw_api import is_buffer - - -def _enum(**enums): - return type('Enum', (), enums) - - -_CipherStatus = _enum(PROCESSING_AUTH_DATA=1, - PROCESSING_CIPHERTEXT=2, - PROCESSING_DONE=3) - - -class ChaCha20Poly1305Cipher(object): - """ChaCha20-Poly1305 and XChaCha20-Poly1305 cipher object. - Do not create it directly. Use :py:func:`new` instead. - - :var nonce: The nonce with length 8, 12 or 24 bytes - :vartype nonce: byte string - """ - - def __init__(self, key, nonce): - """Initialize a ChaCha20-Poly1305 AEAD cipher object - - See also `new()` at the module level.""" - - self.nonce = _copy_bytes(None, None, nonce) - - self._next = (self.update, self.encrypt, self.decrypt, self.digest, - self.verify) - - self._authenticator = Poly1305.new(key=key, nonce=nonce, cipher=ChaCha20) - - self._cipher = ChaCha20.new(key=key, nonce=nonce) - self._cipher.seek(64) # Block counter starts at 1 - - self._len_aad = 0 - self._len_ct = 0 - self._mac_tag = None - self._status = _CipherStatus.PROCESSING_AUTH_DATA - - def update(self, data): - """Protect the associated data. - - Associated data (also known as *additional authenticated data* - AAD) - is the piece of the message that must stay in the clear, while - still allowing the receiver to verify its integrity. - An example is packet headers. - - The associated data (possibly split into multiple segments) is - fed into :meth:`update` before any call to :meth:`decrypt` or :meth:`encrypt`. - If there is no associated data, :meth:`update` is not called. - - :param bytes/bytearray/memoryview assoc_data: - A piece of associated data. There are no restrictions on its size. - """ - - if self.update not in self._next: - raise TypeError("update() method cannot be called") - - self._len_aad += len(data) - self._authenticator.update(data) - - def _pad_aad(self): - - assert(self._status == _CipherStatus.PROCESSING_AUTH_DATA) - if self._len_aad & 0x0F: - self._authenticator.update(b'\x00' * (16 - (self._len_aad & 0x0F))) - self._status = _CipherStatus.PROCESSING_CIPHERTEXT - - def encrypt(self, plaintext, output=None): - """Encrypt a piece of data. - - Args: - plaintext(bytes/bytearray/memoryview): The data to encrypt, of any size. - Keyword Args: - output(bytes/bytearray/memoryview): The location where the ciphertext - is written to. If ``None``, the ciphertext is returned. - Returns: - If ``output`` is ``None``, the ciphertext is returned as ``bytes``. - Otherwise, ``None``. - """ - - if self.encrypt not in self._next: - raise TypeError("encrypt() method cannot be called") - - if self._status == _CipherStatus.PROCESSING_AUTH_DATA: - self._pad_aad() - - self._next = (self.encrypt, self.digest) - - result = self._cipher.encrypt(plaintext, output=output) - self._len_ct += len(plaintext) - if output is None: - self._authenticator.update(result) - else: - self._authenticator.update(output) - return result - - def decrypt(self, ciphertext, output=None): - """Decrypt a piece of data. - - Args: - ciphertext(bytes/bytearray/memoryview): The data to decrypt, of any size. - Keyword Args: - output(bytes/bytearray/memoryview): The location where the plaintext - is written to. If ``None``, the plaintext is returned. - Returns: - If ``output`` is ``None``, the plaintext is returned as ``bytes``. - Otherwise, ``None``. - """ - - if self.decrypt not in self._next: - raise TypeError("decrypt() method cannot be called") - - if self._status == _CipherStatus.PROCESSING_AUTH_DATA: - self._pad_aad() - - self._next = (self.decrypt, self.verify) - - self._len_ct += len(ciphertext) - self._authenticator.update(ciphertext) - return self._cipher.decrypt(ciphertext, output=output) - - def _compute_mac(self): - """Finalize the cipher (if not done already) and return the MAC.""" - - if self._mac_tag: - assert(self._status == _CipherStatus.PROCESSING_DONE) - return self._mac_tag - - assert(self._status != _CipherStatus.PROCESSING_DONE) - - if self._status == _CipherStatus.PROCESSING_AUTH_DATA: - self._pad_aad() - - if self._len_ct & 0x0F: - self._authenticator.update(b'\x00' * (16 - (self._len_ct & 0x0F))) - - self._status = _CipherStatus.PROCESSING_DONE - - self._authenticator.update(long_to_bytes(self._len_aad, 8)[::-1]) - self._authenticator.update(long_to_bytes(self._len_ct, 8)[::-1]) - self._mac_tag = self._authenticator.digest() - return self._mac_tag - - def digest(self): - """Compute the *binary* authentication tag (MAC). - - :Return: the MAC tag, as 16 ``bytes``. - """ - - if self.digest not in self._next: - raise TypeError("digest() method cannot be called") - self._next = (self.digest,) - - return self._compute_mac() - - def hexdigest(self): - """Compute the *printable* authentication tag (MAC). - - This method is like :meth:`digest`. - - :Return: the MAC tag, as a hexadecimal string. - """ - return "".join(["%02x" % bord(x) for x in self.digest()]) - - def verify(self, received_mac_tag): - """Validate the *binary* authentication tag (MAC). - - The receiver invokes this method at the very end, to - check if the associated data (if any) and the decrypted - messages are valid. - - :param bytes/bytearray/memoryview received_mac_tag: - This is the 16-byte *binary* MAC, as received from the sender. - :Raises ValueError: - if the MAC does not match. The message has been tampered with - or the key is incorrect. - """ - - if self.verify not in self._next: - raise TypeError("verify() cannot be called" - " when encrypting a message") - self._next = (self.verify,) - - secret = get_random_bytes(16) - - self._compute_mac() - - mac1 = BLAKE2s.new(digest_bits=160, key=secret, - data=self._mac_tag) - mac2 = BLAKE2s.new(digest_bits=160, key=secret, - data=received_mac_tag) - - if mac1.digest() != mac2.digest(): - raise ValueError("MAC check failed") - - def hexverify(self, hex_mac_tag): - """Validate the *printable* authentication tag (MAC). - - This method is like :meth:`verify`. - - :param string hex_mac_tag: - This is the *printable* MAC. - :Raises ValueError: - if the MAC does not match. The message has been tampered with - or the key is incorrect. - """ - - self.verify(unhexlify(hex_mac_tag)) - - def encrypt_and_digest(self, plaintext): - """Perform :meth:`encrypt` and :meth:`digest` in one step. - - :param plaintext: The data to encrypt, of any size. - :type plaintext: bytes/bytearray/memoryview - :return: a tuple with two ``bytes`` objects: - - - the ciphertext, of equal length as the plaintext - - the 16-byte MAC tag - """ - - return self.encrypt(plaintext), self.digest() - - def decrypt_and_verify(self, ciphertext, received_mac_tag): - """Perform :meth:`decrypt` and :meth:`verify` in one step. - - :param ciphertext: The piece of data to decrypt. - :type ciphertext: bytes/bytearray/memoryview - :param bytes received_mac_tag: - This is the 16-byte *binary* MAC, as received from the sender. - :return: the decrypted data (as ``bytes``) - :raises ValueError: - if the MAC does not match. The message has been tampered with - or the key is incorrect. - """ - - plaintext = self.decrypt(ciphertext) - self.verify(received_mac_tag) - return plaintext - - -def new(**kwargs): - """Create a new ChaCha20-Poly1305 or XChaCha20-Poly1305 AEAD cipher. - - :keyword key: The secret key to use. It must be 32 bytes long. - :type key: byte string - - :keyword nonce: - A value that must never be reused for any other encryption - done with this key. - - For ChaCha20-Poly1305, it must be 8 or 12 bytes long. - - For XChaCha20-Poly1305, it must be 24 bytes long. - - If not provided, 12 ``bytes`` will be generated randomly - (you can find them back in the ``nonce`` attribute). - :type nonce: bytes, bytearray, memoryview - - :Return: a :class:`Crypto.Cipher.ChaCha20.ChaCha20Poly1305Cipher` object - """ - - try: - key = kwargs.pop("key") - except KeyError as e: - raise TypeError("Missing parameter %s" % e) - - self._len_ct += len(plaintext) - - if len(key) != 32: - raise ValueError("Key must be 32 bytes long") - - nonce = kwargs.pop("nonce", None) - if nonce is None: - nonce = get_random_bytes(12) - - if len(nonce) in (8, 12): - pass - elif len(nonce) == 24: - key = _HChaCha20(key, nonce[:16]) - nonce = b'\x00\x00\x00\x00' + nonce[16:] - else: - raise ValueError("Nonce must be 8, 12 or 24 bytes long") - - if not is_buffer(nonce): - raise TypeError("nonce must be bytes, bytearray or memoryview") - - if kwargs: - raise TypeError("Unknown parameters: " + str(kwargs)) - - return ChaCha20Poly1305Cipher(key, nonce) - - -# Size of a key (in bytes) -key_size = 32 diff --git a/Crypto/Cipher/ChaCha20_Poly1305.pyi b/Crypto/Cipher/ChaCha20_Poly1305.pyi deleted file mode 100644 index ef0450f..0000000 --- a/Crypto/Cipher/ChaCha20_Poly1305.pyi +++ /dev/null @@ -1,28 +0,0 @@ -from typing import Union, Tuple, overload - -Buffer = Union[bytes, bytearray, memoryview] - -class ChaCha20Poly1305Cipher: - nonce: bytes - - def __init__(self, key: Buffer, nonce: Buffer) -> None: ... - def update(self, data: Buffer) -> None: ... - @overload - def encrypt(self, plaintext: Buffer) -> bytes: ... - @overload - def encrypt(self, plaintext: Buffer, output: Union[bytearray, memoryview]) -> None: ... - @overload - def decrypt(self, plaintext: Buffer) -> bytes: ... - @overload - def decrypt(self, plaintext: Buffer, output: Union[bytearray, memoryview]) -> None: ... - def digest(self) -> bytes: ... - def hexdigest(self) -> str: ... - def verify(self, received_mac_tag: Buffer) -> None: ... - def hexverify(self, received_mac_tag: str) -> None: ... - def encrypt_and_digest(self, plaintext: Buffer) -> Tuple[bytes, bytes]: ... - def decrypt_and_verify(self, ciphertext: Buffer, received_mac_tag: Buffer) -> bytes: ... - -def new(key: Buffer, nonce: Buffer = ...) -> ChaCha20Poly1305Cipher: ... - -block_size: int -key_size: int diff --git a/Crypto/Cipher/DES.py b/Crypto/Cipher/DES.py deleted file mode 100644 index 5cc286a..0000000 --- a/Crypto/Cipher/DES.py +++ /dev/null @@ -1,158 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Cipher/DES.py : DES -# -# =================================================================== -# The contents of this file are dedicated to the public domain. To -# the extent that dedication to the public domain is not available, -# everyone is granted a worldwide, perpetual, royalty-free, -# non-exclusive license to exercise all rights associated with the -# contents of this file for any purpose whatsoever. -# No rights are reserved. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS -# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN -# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# =================================================================== -""" -Module's constants for the modes of operation supported with Single DES: - -:var MODE_ECB: :ref:`Electronic Code Book (ECB) ` -:var MODE_CBC: :ref:`Cipher-Block Chaining (CBC) ` -:var MODE_CFB: :ref:`Cipher FeedBack (CFB) ` -:var MODE_OFB: :ref:`Output FeedBack (OFB) ` -:var MODE_CTR: :ref:`CounTer Mode (CTR) ` -:var MODE_OPENPGP: :ref:`OpenPGP Mode ` -:var MODE_EAX: :ref:`EAX Mode ` -""" - -import sys - -from Crypto.Cipher import _create_cipher -from Crypto.Util.py3compat import byte_string -from Crypto.Util._raw_api import (load_pycryptodome_raw_lib, - VoidPointer, SmartPointer, - c_size_t, c_uint8_ptr) - -_raw_des_lib = load_pycryptodome_raw_lib( - "Crypto.Cipher._raw_des", - """ - int DES_start_operation(const uint8_t key[], - size_t key_len, - void **pResult); - int DES_encrypt(const void *state, - const uint8_t *in, - uint8_t *out, - size_t data_len); - int DES_decrypt(const void *state, - const uint8_t *in, - uint8_t *out, - size_t data_len); - int DES_stop_operation(void *state); - """) - - -def _create_base_cipher(dict_parameters): - """This method instantiates and returns a handle to a low-level - base cipher. It will absorb named parameters in the process.""" - - try: - key = dict_parameters.pop("key") - except KeyError: - raise TypeError("Missing 'key' parameter") - - if len(key) != key_size: - raise ValueError("Incorrect DES key length (%d bytes)" % len(key)) - - start_operation = _raw_des_lib.DES_start_operation - stop_operation = _raw_des_lib.DES_stop_operation - - cipher = VoidPointer() - result = start_operation(c_uint8_ptr(key), - c_size_t(len(key)), - cipher.address_of()) - if result: - raise ValueError("Error %X while instantiating the DES cipher" - % result) - return SmartPointer(cipher.get(), stop_operation) - - -def new(key, mode, *args, **kwargs): - """Create a new DES cipher. - - :param key: - The secret key to use in the symmetric cipher. - It must be 8 byte long. The parity bits will be ignored. - :type key: bytes/bytearray/memoryview - - :param mode: - The chaining mode to use for encryption or decryption. - :type mode: One of the supported ``MODE_*`` constants - - :Keyword Arguments: - * **iv** (*byte string*) -- - (Only applicable for ``MODE_CBC``, ``MODE_CFB``, ``MODE_OFB``, - and ``MODE_OPENPGP`` modes). - - The initialization vector to use for encryption or decryption. - - For ``MODE_CBC``, ``MODE_CFB``, and ``MODE_OFB`` it must be 8 bytes long. - - For ``MODE_OPENPGP`` mode only, - it must be 8 bytes long for encryption - and 10 bytes for decryption (in the latter case, it is - actually the *encrypted* IV which was prefixed to the ciphertext). - - If not provided, a random byte string is generated (you must then - read its value with the :attr:`iv` attribute). - - * **nonce** (*byte string*) -- - (Only applicable for ``MODE_EAX`` and ``MODE_CTR``). - - A value that must never be reused for any other encryption done - with this key. - - For ``MODE_EAX`` there are no - restrictions on its length (recommended: **16** bytes). - - For ``MODE_CTR``, its length must be in the range **[0..7]**. - - If not provided for ``MODE_EAX``, a random byte string is generated (you - can read it back via the ``nonce`` attribute). - - * **segment_size** (*integer*) -- - (Only ``MODE_CFB``).The number of **bits** the plaintext and ciphertext - are segmented in. It must be a multiple of 8. - If not specified, it will be assumed to be 8. - - * **mac_len** : (*integer*) -- - (Only ``MODE_EAX``) - Length of the authentication tag, in bytes. - It must be no longer than 8 (default). - - * **initial_value** : (*integer*) -- - (Only ``MODE_CTR``). The initial value for the counter within - the counter block. By default it is **0**. - - :Return: a DES object, of the applicable mode. - """ - - return _create_cipher(sys.modules[__name__], key, mode, *args, **kwargs) - -MODE_ECB = 1 -MODE_CBC = 2 -MODE_CFB = 3 -MODE_OFB = 5 -MODE_CTR = 6 -MODE_OPENPGP = 7 -MODE_EAX = 9 - -# Size of a data block (in bytes) -block_size = 8 -# Size of a key (in bytes) -key_size = 8 diff --git a/Crypto/Cipher/DES.pyi b/Crypto/Cipher/DES.pyi deleted file mode 100644 index 1047f13..0000000 --- a/Crypto/Cipher/DES.pyi +++ /dev/null @@ -1,35 +0,0 @@ -from typing import Union, Dict, Iterable - -from Crypto.Cipher._mode_ecb import EcbMode -from Crypto.Cipher._mode_cbc import CbcMode -from Crypto.Cipher._mode_cfb import CfbMode -from Crypto.Cipher._mode_ofb import OfbMode -from Crypto.Cipher._mode_ctr import CtrMode -from Crypto.Cipher._mode_openpgp import OpenPgpMode -from Crypto.Cipher._mode_eax import EaxMode - -DESMode = int - -MODE_ECB: DESMode -MODE_CBC: DESMode -MODE_CFB: DESMode -MODE_OFB: DESMode -MODE_CTR: DESMode -MODE_OPENPGP: DESMode -MODE_EAX: DESMode - -Buffer = Union[bytes, bytearray, memoryview] - -def new(key: Buffer, - mode: DESMode, - iv : Buffer = ..., - IV : Buffer = ..., - nonce : Buffer = ..., - segment_size : int = ..., - mac_len : int = ..., - initial_value : Union[int, Buffer] = ..., - counter : Dict = ...) -> \ - Union[EcbMode, CbcMode, CfbMode, OfbMode, CtrMode, OpenPgpMode]: ... - -block_size: int -key_size: int diff --git a/Crypto/Cipher/DES3.py b/Crypto/Cipher/DES3.py deleted file mode 100644 index c0d9367..0000000 --- a/Crypto/Cipher/DES3.py +++ /dev/null @@ -1,187 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Cipher/DES3.py : DES3 -# -# =================================================================== -# The contents of this file are dedicated to the public domain. To -# the extent that dedication to the public domain is not available, -# everyone is granted a worldwide, perpetual, royalty-free, -# non-exclusive license to exercise all rights associated with the -# contents of this file for any purpose whatsoever. -# No rights are reserved. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS -# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN -# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# =================================================================== -""" -Module's constants for the modes of operation supported with Triple DES: - -:var MODE_ECB: :ref:`Electronic Code Book (ECB) ` -:var MODE_CBC: :ref:`Cipher-Block Chaining (CBC) ` -:var MODE_CFB: :ref:`Cipher FeedBack (CFB) ` -:var MODE_OFB: :ref:`Output FeedBack (OFB) ` -:var MODE_CTR: :ref:`CounTer Mode (CTR) ` -:var MODE_OPENPGP: :ref:`OpenPGP Mode ` -:var MODE_EAX: :ref:`EAX Mode ` -""" - -import sys - -from Crypto.Cipher import _create_cipher -from Crypto.Util.py3compat import byte_string, bchr, bord, bstr -from Crypto.Util._raw_api import (load_pycryptodome_raw_lib, - VoidPointer, SmartPointer, - c_size_t) - -_raw_des3_lib = load_pycryptodome_raw_lib( - "Crypto.Cipher._raw_des3", - """ - int DES3_start_operation(const uint8_t key[], - size_t key_len, - void **pResult); - int DES3_encrypt(const void *state, - const uint8_t *in, - uint8_t *out, - size_t data_len); - int DES3_decrypt(const void *state, - const uint8_t *in, - uint8_t *out, - size_t data_len); - int DES3_stop_operation(void *state); - """) - - -def adjust_key_parity(key_in): - """Set the parity bits in a TDES key. - - :param key_in: the TDES key whose bits need to be adjusted - :type key_in: byte string - - :returns: a copy of ``key_in``, with the parity bits correctly set - :rtype: byte string - - :raises ValueError: if the TDES key is not 16 or 24 bytes long - :raises ValueError: if the TDES key degenerates into Single DES - """ - - def parity_byte(key_byte): - parity = 1 - for i in range(1, 8): - parity ^= (key_byte >> i) & 1 - return (key_byte & 0xFE) | parity - - if len(key_in) not in key_size: - raise ValueError("Not a valid TDES key") - - key_out = b"".join([ bchr(parity_byte(bord(x))) for x in key_in ]) - - if key_out[:8] == key_out[8:16] or key_out[-16:-8] == key_out[-8:]: - raise ValueError("Triple DES key degenerates to single DES") - - return key_out - - -def _create_base_cipher(dict_parameters): - """This method instantiates and returns a handle to a low-level base cipher. - It will absorb named parameters in the process.""" - - try: - key_in = dict_parameters.pop("key") - except KeyError: - raise TypeError("Missing 'key' parameter") - - key = adjust_key_parity(bstr(key_in)) - - start_operation = _raw_des3_lib.DES3_start_operation - stop_operation = _raw_des3_lib.DES3_stop_operation - - cipher = VoidPointer() - result = start_operation(key, - c_size_t(len(key)), - cipher.address_of()) - if result: - raise ValueError("Error %X while instantiating the TDES cipher" - % result) - return SmartPointer(cipher.get(), stop_operation) - - -def new(key, mode, *args, **kwargs): - """Create a new Triple DES cipher. - - :param key: - The secret key to use in the symmetric cipher. - It must be 16 or 24 byte long. The parity bits will be ignored. - :type key: bytes/bytearray/memoryview - - :param mode: - The chaining mode to use for encryption or decryption. - :type mode: One of the supported ``MODE_*`` constants - - :Keyword Arguments: - * **iv** (*bytes*, *bytearray*, *memoryview*) -- - (Only applicable for ``MODE_CBC``, ``MODE_CFB``, ``MODE_OFB``, - and ``MODE_OPENPGP`` modes). - - The initialization vector to use for encryption or decryption. - - For ``MODE_CBC``, ``MODE_CFB``, and ``MODE_OFB`` it must be 8 bytes long. - - For ``MODE_OPENPGP`` mode only, - it must be 8 bytes long for encryption - and 10 bytes for decryption (in the latter case, it is - actually the *encrypted* IV which was prefixed to the ciphertext). - - If not provided, a random byte string is generated (you must then - read its value with the :attr:`iv` attribute). - - * **nonce** (*bytes*, *bytearray*, *memoryview*) -- - (Only applicable for ``MODE_EAX`` and ``MODE_CTR``). - - A value that must never be reused for any other encryption done - with this key. - - For ``MODE_EAX`` there are no - restrictions on its length (recommended: **16** bytes). - - For ``MODE_CTR``, its length must be in the range **[0..7]**. - - If not provided for ``MODE_EAX``, a random byte string is generated (you - can read it back via the ``nonce`` attribute). - - * **segment_size** (*integer*) -- - (Only ``MODE_CFB``).The number of **bits** the plaintext and ciphertext - are segmented in. It must be a multiple of 8. - If not specified, it will be assumed to be 8. - - * **mac_len** : (*integer*) -- - (Only ``MODE_EAX``) - Length of the authentication tag, in bytes. - It must be no longer than 8 (default). - - * **initial_value** : (*integer*) -- - (Only ``MODE_CTR``). The initial value for the counter within - the counter block. By default it is **0**. - - :Return: a Triple DES object, of the applicable mode. - """ - - return _create_cipher(sys.modules[__name__], key, mode, *args, **kwargs) - -MODE_ECB = 1 -MODE_CBC = 2 -MODE_CFB = 3 -MODE_OFB = 5 -MODE_CTR = 6 -MODE_OPENPGP = 7 -MODE_EAX = 9 - -# Size of a data block (in bytes) -block_size = 8 -# Size of a key (in bytes) -key_size = (16, 24) diff --git a/Crypto/Cipher/DES3.pyi b/Crypto/Cipher/DES3.pyi deleted file mode 100644 index a89db9c..0000000 --- a/Crypto/Cipher/DES3.pyi +++ /dev/null @@ -1,37 +0,0 @@ -from typing import Union, Dict, Tuple - -from Crypto.Cipher._mode_ecb import EcbMode -from Crypto.Cipher._mode_cbc import CbcMode -from Crypto.Cipher._mode_cfb import CfbMode -from Crypto.Cipher._mode_ofb import OfbMode -from Crypto.Cipher._mode_ctr import CtrMode -from Crypto.Cipher._mode_openpgp import OpenPgpMode -from Crypto.Cipher._mode_eax import EaxMode - -def adjust_key_parity(key_in: bytes) -> bytes: ... - -DES3Mode = int - -MODE_ECB: DES3Mode -MODE_CBC: DES3Mode -MODE_CFB: DES3Mode -MODE_OFB: DES3Mode -MODE_CTR: DES3Mode -MODE_OPENPGP: DES3Mode -MODE_EAX: DES3Mode - -Buffer = Union[bytes, bytearray, memoryview] - -def new(key: Buffer, - mode: DES3Mode, - iv : Buffer = ..., - IV : Buffer = ..., - nonce : Buffer = ..., - segment_size : int = ..., - mac_len : int = ..., - initial_value : Union[int, Buffer] = ..., - counter : Dict = ...) -> \ - Union[EcbMode, CbcMode, CfbMode, OfbMode, CtrMode, OpenPgpMode]: ... - -block_size: int -key_size: Tuple[int, int] diff --git a/Crypto/Cipher/PKCS1_OAEP.py b/Crypto/Cipher/PKCS1_OAEP.py deleted file mode 100644 index 4fdf76d..0000000 --- a/Crypto/Cipher/PKCS1_OAEP.py +++ /dev/null @@ -1,239 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Cipher/PKCS1_OAEP.py : PKCS#1 OAEP -# -# =================================================================== -# The contents of this file are dedicated to the public domain. To -# the extent that dedication to the public domain is not available, -# everyone is granted a worldwide, perpetual, royalty-free, -# non-exclusive license to exercise all rights associated with the -# contents of this file for any purpose whatsoever. -# No rights are reserved. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS -# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN -# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# =================================================================== - -from Crypto.Signature.pss import MGF1 -import Crypto.Hash.SHA1 - -from Crypto.Util.py3compat import bord, _copy_bytes -import Crypto.Util.number -from Crypto.Util.number import ceil_div, bytes_to_long, long_to_bytes -from Crypto.Util.strxor import strxor -from Crypto import Random - -class PKCS1OAEP_Cipher: - """Cipher object for PKCS#1 v1.5 OAEP. - Do not create directly: use :func:`new` instead.""" - - def __init__(self, key, hashAlgo, mgfunc, label, randfunc): - """Initialize this PKCS#1 OAEP cipher object. - - :Parameters: - key : an RSA key object - If a private half is given, both encryption and decryption are possible. - If a public half is given, only encryption is possible. - hashAlgo : hash object - The hash function to use. This can be a module under `Crypto.Hash` - or an existing hash object created from any of such modules. If not specified, - `Crypto.Hash.SHA1` is used. - mgfunc : callable - A mask generation function that accepts two parameters: a string to - use as seed, and the lenth of the mask to generate, in bytes. - If not specified, the standard MGF1 consistent with ``hashAlgo`` is used (a safe choice). - label : bytes/bytearray/memoryview - A label to apply to this particular encryption. If not specified, - an empty string is used. Specifying a label does not improve - security. - randfunc : callable - A function that returns random bytes. - - :attention: Modify the mask generation function only if you know what you are doing. - Sender and receiver must use the same one. - """ - self._key = key - - if hashAlgo: - self._hashObj = hashAlgo - else: - self._hashObj = Crypto.Hash.SHA1 - - if mgfunc: - self._mgf = mgfunc - else: - self._mgf = lambda x,y: MGF1(x,y,self._hashObj) - - self._label = _copy_bytes(None, None, label) - self._randfunc = randfunc - - def can_encrypt(self): - """Legacy function to check if you can call :meth:`encrypt`. - - .. deprecated:: 3.0""" - return self._key.can_encrypt() - - def can_decrypt(self): - """Legacy function to check if you can call :meth:`decrypt`. - - .. deprecated:: 3.0""" - return self._key.can_decrypt() - - def encrypt(self, message): - """Encrypt a message with PKCS#1 OAEP. - - :param message: - The message to encrypt, also known as plaintext. It can be of - variable length, but not longer than the RSA modulus (in bytes) - minus 2, minus twice the hash output size. - For instance, if you use RSA 2048 and SHA-256, the longest message - you can encrypt is 190 byte long. - :type message: bytes/bytearray/memoryview - - :returns: The ciphertext, as large as the RSA modulus. - :rtype: bytes - - :raises ValueError: - if the message is too long. - """ - - # See 7.1.1 in RFC3447 - modBits = Crypto.Util.number.size(self._key.n) - k = ceil_div(modBits, 8) # Convert from bits to bytes - hLen = self._hashObj.digest_size - mLen = len(message) - - # Step 1b - ps_len = k - mLen - 2 * hLen - 2 - if ps_len < 0: - raise ValueError("Plaintext is too long.") - # Step 2a - lHash = self._hashObj.new(self._label).digest() - # Step 2b - ps = b'\x00' * ps_len - # Step 2c - db = lHash + ps + b'\x01' + _copy_bytes(None, None, message) - # Step 2d - ros = self._randfunc(hLen) - # Step 2e - dbMask = self._mgf(ros, k-hLen-1) - # Step 2f - maskedDB = strxor(db, dbMask) - # Step 2g - seedMask = self._mgf(maskedDB, hLen) - # Step 2h - maskedSeed = strxor(ros, seedMask) - # Step 2i - em = b'\x00' + maskedSeed + maskedDB - # Step 3a (OS2IP) - em_int = bytes_to_long(em) - # Step 3b (RSAEP) - m_int = self._key._encrypt(em_int) - # Step 3c (I2OSP) - c = long_to_bytes(m_int, k) - return c - - def decrypt(self, ciphertext): - """Decrypt a message with PKCS#1 OAEP. - - :param ciphertext: The encrypted message. - :type ciphertext: bytes/bytearray/memoryview - - :returns: The original message (plaintext). - :rtype: bytes - - :raises ValueError: - if the ciphertext has the wrong length, or if decryption - fails the integrity check (in which case, the decryption - key is probably wrong). - :raises TypeError: - if the RSA key has no private half (i.e. you are trying - to decrypt using a public key). - """ - - # See 7.1.2 in RFC3447 - modBits = Crypto.Util.number.size(self._key.n) - k = ceil_div(modBits,8) # Convert from bits to bytes - hLen = self._hashObj.digest_size - - # Step 1b and 1c - if len(ciphertext) != k or k Any: ... - -class HashLikeModule(Protocol): - digest_size : int - @staticmethod - def new(data: Optional[bytes] = ...) -> Any: ... - -HashLike = Union[HashLikeClass, HashLikeModule] - -Buffer = Union[bytes, bytearray, memoryview] - -class PKCS1OAEP_Cipher: - def __init__(self, - key: RsaKey, - hashAlgo: HashLike, - mgfunc: Callable[[bytes, int], bytes], - label: Buffer, - randfunc: Callable[[int], bytes]) -> None: ... - def can_encrypt(self) -> bool: ... - def can_decrypt(self) -> bool: ... - def encrypt(self, message: Buffer) -> bytes: ... - def decrypt(self, ciphertext: Buffer) -> bytes: ... - -def new(key: RsaKey, - hashAlgo: Optional[HashLike] = ..., - mgfunc: Optional[Callable[[bytes, int], bytes]] = ..., - label: Optional[Buffer] = ..., - randfunc: Optional[Callable[[int], bytes]] = ...) -> PKCS1OAEP_Cipher: ... diff --git a/Crypto/Cipher/PKCS1_v1_5.py b/Crypto/Cipher/PKCS1_v1_5.py deleted file mode 100644 index 1b9912f..0000000 --- a/Crypto/Cipher/PKCS1_v1_5.py +++ /dev/null @@ -1,199 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Cipher/PKCS1-v1_5.py : PKCS#1 v1.5 -# -# =================================================================== -# The contents of this file are dedicated to the public domain. To -# the extent that dedication to the public domain is not available, -# everyone is granted a worldwide, perpetual, royalty-free, -# non-exclusive license to exercise all rights associated with the -# contents of this file for any purpose whatsoever. -# No rights are reserved. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS -# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN -# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# =================================================================== - -__all__ = [ 'new', 'PKCS115_Cipher' ] - -from Crypto.Util.number import ceil_div, bytes_to_long, long_to_bytes -from Crypto.Util.py3compat import bord, _copy_bytes -import Crypto.Util.number -from Crypto import Random - -class PKCS115_Cipher: - """This cipher can perform PKCS#1 v1.5 RSA encryption or decryption. - Do not instantiate directly. Use :func:`Crypto.Cipher.PKCS1_v1_5.new` instead.""" - - def __init__(self, key, randfunc): - """Initialize this PKCS#1 v1.5 cipher object. - - :Parameters: - key : an RSA key object - If a private half is given, both encryption and decryption are possible. - If a public half is given, only encryption is possible. - randfunc : callable - Function that returns random bytes. - """ - - self._key = key - self._randfunc = randfunc - - def can_encrypt(self): - """Return True if this cipher object can be used for encryption.""" - return self._key.can_encrypt() - - def can_decrypt(self): - """Return True if this cipher object can be used for decryption.""" - return self._key.can_decrypt() - - def encrypt(self, message): - """Produce the PKCS#1 v1.5 encryption of a message. - - This function is named ``RSAES-PKCS1-V1_5-ENCRYPT``, and it is specified in - `section 7.2.1 of RFC8017 - `_. - - :param message: - The message to encrypt, also known as plaintext. It can be of - variable length, but not longer than the RSA modulus (in bytes) minus 11. - :type message: bytes/bytearray/memoryview - - :Returns: A byte string, the ciphertext in which the message is encrypted. - It is as long as the RSA modulus (in bytes). - - :Raises ValueError: - If the RSA key length is not sufficiently long to deal with the given - message. - """ - - # See 7.2.1 in RFC8017 - modBits = Crypto.Util.number.size(self._key.n) - k = ceil_div(modBits,8) # Convert from bits to bytes - mLen = len(message) - - # Step 1 - if mLen > k - 11: - raise ValueError("Plaintext is too long.") - # Step 2a - ps = [] - while len(ps) != k - mLen - 3: - new_byte = self._randfunc(1) - if bord(new_byte[0]) == 0x00: - continue - ps.append(new_byte) - ps = b"".join(ps) - assert(len(ps) == k - mLen - 3) - # Step 2b - em = b'\x00\x02' + ps + b'\x00' + _copy_bytes(None, None, message) - # Step 3a (OS2IP) - em_int = bytes_to_long(em) - # Step 3b (RSAEP) - m_int = self._key._encrypt(em_int) - # Step 3c (I2OSP) - c = long_to_bytes(m_int, k) - return c - - def decrypt(self, ciphertext, sentinel): - r"""Decrypt a PKCS#1 v1.5 ciphertext. - - This function is named ``RSAES-PKCS1-V1_5-DECRYPT``, and is specified in - `section 7.2.2 of RFC8017 - `_. - - :param ciphertext: - The ciphertext that contains the message to recover. - :type ciphertext: bytes/bytearray/memoryview - - :param sentinel: - The object to return whenever an error is detected. - :type sentinel: any type - - :Returns: A byte string. It is either the original message or the ``sentinel`` (in case of an error). - - :Raises ValueError: - If the ciphertext length is incorrect - :Raises TypeError: - If the RSA key has no private half (i.e. it cannot be used for - decyption). - - .. warning:: - You should **never** let the party who submitted the ciphertext know that - this function returned the ``sentinel`` value. - Armed with such knowledge (for a fair amount of carefully crafted but invalid ciphertexts), - an attacker is able to recontruct the plaintext of any other encryption that were carried out - with the same RSA public key (see `Bleichenbacher's`__ attack). - - In general, it should not be possible for the other party to distinguish - whether processing at the server side failed because the value returned - was a ``sentinel`` as opposed to a random, invalid message. - - In fact, the second option is not that unlikely: encryption done according to PKCS#1 v1.5 - embeds no good integrity check. There is roughly one chance - in 2\ :sup:`16` for a random ciphertext to be returned as a valid message - (although random looking). - - It is therefore advisabled to: - - 1. Select as ``sentinel`` a value that resembles a plausable random, invalid message. - 2. Not report back an error as soon as you detect a ``sentinel`` value. - Put differently, you should not explicitly check if the returned value is the ``sentinel`` or not. - 3. Cover all possible errors with a single, generic error indicator. - 4. Embed into the definition of ``message`` (at the protocol level) a digest (e.g. ``SHA-1``). - It is recommended for it to be the rightmost part ``message``. - 5. Where possible, monitor the number of errors due to ciphertexts originating from the same party, - and slow down the rate of the requests from such party (or even blacklist it altogether). - - **If you are designing a new protocol, consider using the more robust PKCS#1 OAEP.** - - .. __: http://www.bell-labs.com/user/bleichen/papers/pkcs.ps - - """ - - # See 7.2.1 in RFC3447 - modBits = Crypto.Util.number.size(self._key.n) - k = ceil_div(modBits,8) # Convert from bits to bytes - - # Step 1 - if len(ciphertext) != k: - raise ValueError("Ciphertext with incorrect length.") - # Step 2a (O2SIP) - ct_int = bytes_to_long(ciphertext) - # Step 2b (RSADP) - m_int = self._key._decrypt(ct_int) - # Complete step 2c (I2OSP) - em = long_to_bytes(m_int, k) - # Step 3 - sep = em.find(b'\x00', 2) - if not em.startswith(b'\x00\x02') or sep < 10: - return sentinel - # Step 4 - return em[sep + 1:] - - -def new(key, randfunc=None): - """Create a cipher for performing PKCS#1 v1.5 encryption or decryption. - - :param key: - The key to use to encrypt or decrypt the message. This is a `Crypto.PublicKey.RSA` object. - Decryption is only possible if *key* is a private RSA key. - :type key: RSA key object - - :param randfunc: - Function that return random bytes. - The default is :func:`Crypto.Random.get_random_bytes`. - :type randfunc: callable - - :returns: A cipher object `PKCS115_Cipher`. - """ - - if randfunc is None: - randfunc = Random.get_random_bytes - return PKCS115_Cipher(key, randfunc) - diff --git a/Crypto/Cipher/PKCS1_v1_5.pyi b/Crypto/Cipher/PKCS1_v1_5.pyi deleted file mode 100644 index d640736..0000000 --- a/Crypto/Cipher/PKCS1_v1_5.pyi +++ /dev/null @@ -1,17 +0,0 @@ -from typing import Callable, Union, Any, Optional - -from Crypto.PublicKey.RSA import RsaKey - -Buffer = Union[bytes, bytearray, memoryview] - -class PKCS115_Cipher: - def __init__(self, - key: RsaKey, - randfunc: Callable[[int], bytes]) -> None: ... - def can_encrypt(self) -> bool: ... - def can_decrypt(self) -> bool: ... - def encrypt(self, message: Buffer) -> bytes: ... - def decrypt(self, ciphertext: Buffer, sentinel: Buffer) -> bytes: ... - -def new(key: RsaKey, - randfunc: Optional[Callable[[int], bytes]] = ...) -> PKCS115_Cipher: ... diff --git a/Crypto/Cipher/Salsa20.py b/Crypto/Cipher/Salsa20.py deleted file mode 100644 index 62d0b29..0000000 --- a/Crypto/Cipher/Salsa20.py +++ /dev/null @@ -1,167 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Cipher/Salsa20.py : Salsa20 stream cipher (http://cr.yp.to/snuffle.html) -# -# Contributed by Fabrizio Tarizzo . -# -# =================================================================== -# The contents of this file are dedicated to the public domain. To -# the extent that dedication to the public domain is not available, -# everyone is granted a worldwide, perpetual, royalty-free, -# non-exclusive license to exercise all rights associated with the -# contents of this file for any purpose whatsoever. -# No rights are reserved. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS -# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN -# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# =================================================================== - -from Crypto.Util.py3compat import _copy_bytes -from Crypto.Util._raw_api import (load_pycryptodome_raw_lib, - create_string_buffer, - get_raw_buffer, VoidPointer, - SmartPointer, c_size_t, - c_uint8_ptr, is_writeable_buffer) - -from Crypto.Random import get_random_bytes - -_raw_salsa20_lib = load_pycryptodome_raw_lib("Crypto.Cipher._Salsa20", - """ - int Salsa20_stream_init(uint8_t *key, size_t keylen, - uint8_t *nonce, size_t nonce_len, - void **pSalsaState); - int Salsa20_stream_destroy(void *salsaState); - int Salsa20_stream_encrypt(void *salsaState, - const uint8_t in[], - uint8_t out[], size_t len); - """) - - -class Salsa20Cipher: - """Salsa20 cipher object. Do not create it directly. Use :py:func:`new` - instead. - - :var nonce: The nonce with length 8 - :vartype nonce: byte string - """ - - def __init__(self, key, nonce): - """Initialize a Salsa20 cipher object - - See also `new()` at the module level.""" - - if len(key) not in key_size: - raise ValueError("Incorrect key length for Salsa20 (%d bytes)" % len(key)) - - if len(nonce) != 8: - raise ValueError("Incorrect nonce length for Salsa20 (%d bytes)" % - len(nonce)) - - self.nonce = _copy_bytes(None, None, nonce) - - self._state = VoidPointer() - result = _raw_salsa20_lib.Salsa20_stream_init( - c_uint8_ptr(key), - c_size_t(len(key)), - c_uint8_ptr(nonce), - c_size_t(len(nonce)), - self._state.address_of()) - if result: - raise ValueError("Error %d instantiating a Salsa20 cipher") - self._state = SmartPointer(self._state.get(), - _raw_salsa20_lib.Salsa20_stream_destroy) - - self.block_size = 1 - self.key_size = len(key) - - def encrypt(self, plaintext, output=None): - """Encrypt a piece of data. - - Args: - plaintext(bytes/bytearray/memoryview): The data to encrypt, of any size. - Keyword Args: - output(bytes/bytearray/memoryview): The location where the ciphertext - is written to. If ``None``, the ciphertext is returned. - Returns: - If ``output`` is ``None``, the ciphertext is returned as ``bytes``. - Otherwise, ``None``. - """ - - if output is None: - ciphertext = create_string_buffer(len(plaintext)) - else: - ciphertext = output - - if not is_writeable_buffer(output): - raise TypeError("output must be a bytearray or a writeable memoryview") - - if len(plaintext) != len(output): - raise ValueError("output must have the same length as the input" - " (%d bytes)" % len(plaintext)) - - result = _raw_salsa20_lib.Salsa20_stream_encrypt( - self._state.get(), - c_uint8_ptr(plaintext), - c_uint8_ptr(ciphertext), - c_size_t(len(plaintext))) - if result: - raise ValueError("Error %d while encrypting with Salsa20" % result) - - if output is None: - return get_raw_buffer(ciphertext) - else: - return None - - def decrypt(self, ciphertext, output=None): - """Decrypt a piece of data. - - Args: - ciphertext(bytes/bytearray/memoryview): The data to decrypt, of any size. - Keyword Args: - output(bytes/bytearray/memoryview): The location where the plaintext - is written to. If ``None``, the plaintext is returned. - Returns: - If ``output`` is ``None``, the plaintext is returned as ``bytes``. - Otherwise, ``None``. - """ - - try: - return self.encrypt(ciphertext, output=output) - except ValueError as e: - raise ValueError(str(e).replace("enc", "dec")) - - -def new(key, nonce=None): - """Create a new Salsa20 cipher - - :keyword key: The secret key to use. It must be 16 or 32 bytes long. - :type key: bytes/bytearray/memoryview - - :keyword nonce: - A value that must never be reused for any other encryption - done with this key. It must be 8 bytes long. - - If not provided, a random byte string will be generated (you can read - it back via the ``nonce`` attribute of the returned object). - :type nonce: bytes/bytearray/memoryview - - :Return: a :class:`Crypto.Cipher.Salsa20.Salsa20Cipher` object - """ - - if nonce is None: - nonce = get_random_bytes(8) - - return Salsa20Cipher(key, nonce) - -# Size of a data block (in bytes) -block_size = 1 - -# Size of a key (in bytes) -key_size = (16, 32) - diff --git a/Crypto/Cipher/Salsa20.pyi b/Crypto/Cipher/Salsa20.pyi deleted file mode 100644 index 9178f0d..0000000 --- a/Crypto/Cipher/Salsa20.pyi +++ /dev/null @@ -1,27 +0,0 @@ -from typing import Union, Tuple, Optional, overload - - -Buffer = Union[bytes, bytearray, memoryview] - -class Salsa20Cipher: - nonce: bytes - block_size: int - key_size: int - - def __init__(self, - key: Buffer, - nonce: Buffer) -> None: ... - @overload - def encrypt(self, plaintext: Buffer) -> bytes: ... - @overload - def encrypt(self, plaintext: Buffer, output: Union[bytearray, memoryview]) -> None: ... - @overload - def decrypt(self, plaintext: Buffer) -> bytes: ... - @overload - def decrypt(self, plaintext: Buffer, output: Union[bytearray, memoryview]) -> None: ... - -def new(key: Buffer, nonce: Optional[Buffer] = ...) -> Salsa20Cipher: ... - -block_size: int -key_size: Tuple[int, int] - diff --git a/Crypto/Cipher/_ARC4.abi3.so b/Crypto/Cipher/_ARC4.abi3.so deleted file mode 100644 index bc11d1ab868d03c537abefbe7de3d2e825c8096e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 13768 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 L)q0bGiDZ8RSQ*@K diff --git a/Crypto/Cipher/_EKSBlowfish.py b/Crypto/Cipher/_EKSBlowfish.py deleted file mode 100644 index a844fae..0000000 --- a/Crypto/Cipher/_EKSBlowfish.py +++ /dev/null @@ -1,131 +0,0 @@ -# =================================================================== -# -# Copyright (c) 2019, Legrandin -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# =================================================================== - -import sys - -from Crypto.Cipher import _create_cipher -from Crypto.Util._raw_api import (load_pycryptodome_raw_lib, - VoidPointer, SmartPointer, c_size_t, - c_uint8_ptr, c_uint) - -_raw_blowfish_lib = load_pycryptodome_raw_lib( - "Crypto.Cipher._raw_eksblowfish", - """ - int EKSBlowfish_start_operation(const uint8_t key[], - size_t key_len, - const uint8_t salt[16], - size_t salt_len, - unsigned cost, - unsigned invert, - void **pResult); - int EKSBlowfish_encrypt(const void *state, - const uint8_t *in, - uint8_t *out, - size_t data_len); - int EKSBlowfish_decrypt(const void *state, - const uint8_t *in, - uint8_t *out, - size_t data_len); - int EKSBlowfish_stop_operation(void *state); - """ - ) - - -def _create_base_cipher(dict_parameters): - """This method instantiates and returns a smart pointer to - a low-level base cipher. It will absorb named parameters in - the process.""" - - try: - key = dict_parameters.pop("key") - salt = dict_parameters.pop("salt") - cost = dict_parameters.pop("cost") - except KeyError as e: - raise TypeError("Missing EKSBlowfish parameter: " + str(e)) - invert = dict_parameters.pop("invert", True) - - if len(key) not in key_size: - raise ValueError("Incorrect EKSBlowfish key length (%d bytes)" % len(key)) - - start_operation = _raw_blowfish_lib.EKSBlowfish_start_operation - stop_operation = _raw_blowfish_lib.EKSBlowfish_stop_operation - - void_p = VoidPointer() - result = start_operation(c_uint8_ptr(key), - c_size_t(len(key)), - c_uint8_ptr(salt), - c_size_t(len(salt)), - c_uint(cost), - c_uint(int(invert)), - void_p.address_of()) - if result: - raise ValueError("Error %X while instantiating the EKSBlowfish cipher" - % result) - return SmartPointer(void_p.get(), stop_operation) - - -def new(key, mode, salt, cost, invert): - """Create a new EKSBlowfish cipher - - Args: - - key (bytes, bytearray, memoryview): - The secret key to use in the symmetric cipher. - Its length can vary from 0 to 72 bytes. - - mode (one of the supported ``MODE_*`` constants): - The chaining mode to use for encryption or decryption. - - salt (bytes, bytearray, memoryview): - The salt that bcrypt uses to thwart rainbow table attacks - - cost (integer): - The complexity factor in bcrypt - - invert (bool): - If ``False``, in the inner loop use ``ExpandKey`` first over the salt - and then over the key, as defined in - the `original bcrypt specification `_. - If ``True``, reverse the order, as in the first implementation of - `bcrypt` in OpenBSD. - - :Return: an EKSBlowfish object - """ - - kwargs = { 'salt':salt, 'cost':cost, 'invert':invert } - return _create_cipher(sys.modules[__name__], key, mode, **kwargs) - - -MODE_ECB = 1 - -# Size of a data block (in bytes) -block_size = 8 -# Size of a key (in bytes) -key_size = range(0, 72 + 1) diff --git a/Crypto/Cipher/_EKSBlowfish.pyi b/Crypto/Cipher/_EKSBlowfish.pyi deleted file mode 100644 index 95db379..0000000 --- a/Crypto/Cipher/_EKSBlowfish.pyi +++ /dev/null @@ -1,15 +0,0 @@ -from typing import Union, Iterable - -from Crypto.Cipher._mode_ecb import EcbMode - -MODE_ECB: int - -Buffer = Union[bytes, bytearray, memoryview] - -def new(key: Buffer, - mode: int, - salt: Buffer, - cost: int) -> EcbMode: ... - -block_size: int -key_size: Iterable[int] diff --git a/Crypto/Cipher/_Salsa20.abi3.so b/Crypto/Cipher/_Salsa20.abi3.so deleted file mode 100644 index 2cefcf3d9ef0b76c4b260bcabd486ab22afeb3e9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 26784 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 aM0uR?c>nlIG^zeC*P8m*#wo;+;=cjEqOz#~ diff --git a/Crypto/Cipher/__init__.py b/Crypto/Cipher/__init__.py deleted file mode 100644 index ba2d485..0000000 --- a/Crypto/Cipher/__init__.py +++ /dev/null @@ -1,79 +0,0 @@ -# -# A block cipher is instantiated as a combination of: -# 1. A base cipher (such as AES) -# 2. A mode of operation (such as CBC) -# -# Both items are implemented as C modules. -# -# The API of #1 is (replace "AES" with the name of the actual cipher): -# - AES_start_operaion(key) --> base_cipher_state -# - AES_encrypt(base_cipher_state, in, out, length) -# - AES_decrypt(base_cipher_state, in, out, length) -# - AES_stop_operation(base_cipher_state) -# -# Where base_cipher_state is AES_State, a struct with BlockBase (set of -# pointers to encrypt/decrypt/stop) followed by cipher-specific data. -# -# The API of #2 is (replace "CBC" with the name of the actual mode): -# - CBC_start_operation(base_cipher_state) --> mode_state -# - CBC_encrypt(mode_state, in, out, length) -# - CBC_decrypt(mode_state, in, out, length) -# - CBC_stop_operation(mode_state) -# -# where mode_state is a a pointer to base_cipher_state plus mode-specific data. - -import os - -from Crypto.Cipher._mode_ecb import _create_ecb_cipher -from Crypto.Cipher._mode_cbc import _create_cbc_cipher -from Crypto.Cipher._mode_cfb import _create_cfb_cipher -from Crypto.Cipher._mode_ofb import _create_ofb_cipher -from Crypto.Cipher._mode_ctr import _create_ctr_cipher -from Crypto.Cipher._mode_openpgp import _create_openpgp_cipher -from Crypto.Cipher._mode_ccm import _create_ccm_cipher -from Crypto.Cipher._mode_eax import _create_eax_cipher -from Crypto.Cipher._mode_siv import _create_siv_cipher -from Crypto.Cipher._mode_gcm import _create_gcm_cipher -from Crypto.Cipher._mode_ocb import _create_ocb_cipher - -_modes = { 1:_create_ecb_cipher, - 2:_create_cbc_cipher, - 3:_create_cfb_cipher, - 5:_create_ofb_cipher, - 6:_create_ctr_cipher, - 7:_create_openpgp_cipher, - 9:_create_eax_cipher - } - -_extra_modes = { 8:_create_ccm_cipher, - 10:_create_siv_cipher, - 11:_create_gcm_cipher, - 12:_create_ocb_cipher - } - -def _create_cipher(factory, key, mode, *args, **kwargs): - - kwargs["key"] = key - - modes = dict(_modes) - if kwargs.pop("add_aes_modes", False): - modes.update(_extra_modes) - if not mode in modes: - raise ValueError("Mode not supported") - - if args: - if mode in (8, 9, 10, 11, 12): - if len(args) > 1: - raise TypeError("Too many arguments for this mode") - kwargs["nonce"] = args[0] - elif mode in (2, 3, 5, 7): - if len(args) > 1: - raise TypeError("Too many arguments for this mode") - kwargs["IV"] = args[0] - elif mode == 6: - if len(args) > 0: - raise TypeError("Too many arguments for this mode") - elif mode == 1: - raise TypeError("IV is not meaningful for the ECB mode") - - return modes[mode](factory, **kwargs) diff --git a/Crypto/Cipher/__init__.pyi b/Crypto/Cipher/__init__.pyi deleted file mode 100644 index e69de29..0000000 diff --git a/Crypto/Cipher/__pycache__/AES.cpython-36.pyc b/Crypto/Cipher/__pycache__/AES.cpython-36.pyc deleted file mode 100644 index 6eae8092e0337b8960ab63552b6e1a55f3a9ca1d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8161 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 Itv71_3!+~ksQ>@~ diff --git a/Crypto/Cipher/__pycache__/__init__.cpython-36.pyc b/Crypto/Cipher/__pycache__/__init__.cpython-36.pyc deleted file mode 100644 index 2429e781241abe2dffcac1fb335dc2bffa2d2ef9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1724 zcmZ`(&2HO95aup_MAMWk%d#9dMZrtjszAg;5cgsfMcow0q3)rnQSd_0+?6bge;ATU zWUxR{_narl3l!)R6nTU`0k1vj6?$oBD7$tMio||9ocVTUXSp*^x?Ss^uaAQdw-x0t z<=$hW{3VY34+NnI7AYRhJYq5TI3rn&)L8ShM%E%dHaw$|^{5k@p4rGov=v*P)ySP_ zJGMQ$kNOMALW8rSBevIeVIL~!xqGZ6 zKO%F4%s2O#KflKuAajDuy#Jf_;J!!2v-R;mUcDrcN9rODBL? z8Ox-|ooNbAaWT&w@(T1TYCTDlP(qK^?GW?{1_&O1eg?ZJTs?Yz=HMcV9?Kw^C$ni8 z-8hrZvy-nHe`9^)j>cMBfU#L?VjdQ?vCgtqvox!XG80%8we8E-1q3%H>nw;$`3xY1 zT8(5+i8qccwvDq_BhsxZPT#>}n0u&TC`ws+slX9Dh^b6J-4TgIng{MrjyC z?#lq&X_$`O~AtVuI3{Qm4AkyaFd(NW)?G<$u&e9NAG|0+6H4}k3Xn+ntKQ9K$CT# zNpld?D}bt}-HJT}s7^Lmr{|z;v|Tg#3jnG*?_t}nZh8t(4R2T<#z0lwZp9u0 zRQl~!>@`5mpxuf+2dGQ5Te0^5wGVhm@DTwWadQps!KbLJ&11YIWhB2i#IJmUU~(IO Q)q5}J?Cv$ywQQ>Y0{gGf<^TWy diff --git a/Crypto/Cipher/__pycache__/_mode_cbc.cpython-36.pyc b/Crypto/Cipher/__pycache__/_mode_cbc.cpython-36.pyc deleted file mode 100644 index 1770fcc1f7de9bf5c176bd2ae391338b17564306..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 7595 zcmdT}&u`<#6(%WKl4aTJ>~7MgXwylX#afD23c6{!b%SjjCuohJZm`}MsDgr`$dOH( zBAMYxt^_X%)Im>0(LbZT^wfJV1#;RD> zecyY}cUMmd|NObWKX8RC##B8g4JO=?*^1{3A?KcxNRizL zQs-0zlDoZ-=aQhuaB&;14jA~@>@4{;zv5SMSN3hV{faO# z#QhL$Q#-|-%Ur+Nswv}n*Y%EA+-LHLGwlEhEqa6&Df4;4BR^$vq&p0S;E_}V-N{!8V$^2h9cxQYQFE!$5F9AF+bFDKVMp?%z=N3tVl=``08hSk5tjaZ*fdy$LJYB;GT+TYapTl+ikVf6` zEf_<|eF-?YqhOi2EaIn3oos&8n+*Qm4-SXed=^B6jX5Pufo1D`SGWTXcu%*cFPWC& zXoJCq@32I3z+4x`wpmJ0U;M^otgI-EPw#|$#KQ$$Fh4va^1w%PLV^*bD;{c7>k8qH z+XFs`#ds9()486EJ%kC<5zU#}NShia9;Tf2VRbn$k{#hG#~3`d7DVj=&r{~6ER4aG z_@23kR(e56#+prDkJrYwE zJT_^(D+Ko97Ni{oA?+a@1p3KBiNY@S8aKrfY&eJ z!x*tl153dCtmgW@;A!f_{j7H2hC{A25LNW(T-Q?OfitTJ9&$J3Sxs55iWmfWU}goQ z%-TK3D*3r)mHbGvB_~4I)37r;yg@G#q%__3?0Cte=@|k@c6HT_AnJ~;GP?{ zN3Ll1hmpdYwCyH$4u@`ZI5~=k?a&?E8Jzs!`)`~apSJhnh_`_v=TRnhuy1xgUzN zo6^n4c8kHV;SdWMz`TP5E-eGBXklL3v~*KL2e~q_+}1quGIsy|ede`t(Hm}qy*l^U zYs@-hQ;ESxE}UBed?d{~39y6QyA6 zf=SGvo18OmJQXL2k-qzc4N zVe+so*zjEBSTG=EZxRM9-kO=o8YS0MeQhs8^E(7r-iu}LCoZb^P?0N(Vi-UrGo~;=MhK{(J`?NP_@p@KP3{J z+K>B>y z%nIiFQknH8nDrfq5Xg#fYa8Ya#dZ5Nkg6e?hFd z=z>^_$9ZzR8nG55-3!EeDY*&24uYL|e(NJe&~a6f!9SbfW)AvaQe3Y53~=Wu4#-!a z+E-3-QG#49B4yVQJ#n#-7sCjTog&15fs9wy6GYM6WUze4$Dgrvi9vYJDQ=nw^T zC#yToM?*Kvf2lYQN?VR2zDAdR_-n^G@=bM*;wA2FWP+tLyKf;&yeCnsItCX~B@DUhvUq^} zk-iV4?c0=@M#w5vzKUMd7ul&mZn;GFc|K{1-=a6w*D!C+s?{?K*(KG$s_s9b?C!Lv z0r0z!6snvfuc@S}2$q{X>O$?pZm2}0_~w$Bzwc5-a||fd`#t3)%I^?+aS@Km@D^)t zAVYOJOaXAWyYQC`3Q_fR7X$XImc(doRHWu=UkJ^n$c|sGR9M>%0|cLxb#=SJXsXpV z@*|yPAu*?X0+~9B!3d2LH%)c;NkQxr7O&x+3cb{csyic8oREU)a;r`+Xi}d`HwaU< zfvk{9KoV+TMnwH;zKC;Q?Gjc=bEBez6ttnmix*&yd#ctmY5oEkyy6m$iW!1-$|`RM zquUgg-`+jAy{S^a9@aEz?M7aVLO03<*rhxI-$3E6;G#UP*44qrnT~0YLJ6Zl)i|AVhiVF4Y)asjG1}=YLawigS}d5Im@|p~hB<{Z*+? zRRncrKuJVrH6Q&zRYmo-P)>ogKoxJ)Rw%9J7CFVKtoo*Qr~9;vDQ%!_m9e&srMhLW LmF@Lk8{7W|VQ*81 diff --git a/Crypto/Cipher/__pycache__/_mode_ccm.cpython-36.pyc b/Crypto/Cipher/__pycache__/_mode_ccm.cpython-36.pyc deleted file mode 100644 index 5ec359fcfe65124c218b38c8f689205917a908eb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 18154 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 P`O3|qsXw#yzgPYbR>aFq diff --git a/Crypto/Cipher/__pycache__/_mode_cfb.cpython-36.pyc b/Crypto/Cipher/__pycache__/_mode_cfb.cpython-36.pyc deleted file mode 100644 index f44e3cb0296f29a5efc37a64b85f58ed7a53efa2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 7915 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 diff --git a/Crypto/Cipher/__pycache__/_mode_ecb.cpython-36.pyc b/Crypto/Cipher/__pycache__/_mode_ecb.cpython-36.pyc deleted file mode 100644 index cf4819736fc30460c15be7060e9dec249e7bf610..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5989 zcmds5TXP#p6`qmCk}NA1k`UNkmTIWVmgRM%g)G@%wo;pQTvXUvlUip})I2b1&9vmP z=A!LxSu2%ORN?#pUU=sb{sDi2KQOO6?K5w@z;}9PB*i!t!v+c%dD?U7bNckTeCM3G zbLmp^Zx27@6J}X|wpI=Y*B{|jzrYY!t`*or+qHvAP>m{a)vd;k>%?pBT3mB$aow%Q z4Yv`myX$e&ZQ7Qo22QYcT5&giY6Z2xehzxkI<2~wf_l(+Zn>9(^#iNjoPWQ$7YSd> zGzopSn+Ae?oTekTxwrdqo5i^AG_(4i-~SYsUqKYB-N@dEQXY8YnJ;H!od#(vJjthC z6!x=?r)d~GPQyeCnceWE;97V}%P<*w{mEc}rmcS*moyFEQ{h~AI@|EQ z3HaRe##(0AL*-3ns0HswqTn>YxoZUI?1tk*Av=bt@cVpJv8*OL=Kwo~jX@x+=%r&J zxen80^B6+2E#I)&K9}+wX68{&xi$Vws7a*TKRK7UTvjATW5sfi^gu&B7hBLz6QxG_h#AwZK6vZb%y>{4W@{ULKQMou=`zCx@Y8 z_|u1isW2W#0`5^b7+g9JUAD*lLzWKAtZ~FCEWgyOAEo|C88+Y$gc1M{%}Qz!Fw9FC zXL&#@Nw)DK5MzNMA%b*Zc<=<5kVEE-R|O;hAt?i%424W5iuHxhCkhWC?U&H4Nc~9+?TKKAd0v==+VhMO zePEV3$bsnG#i^cRII)kc6U(!-eM)@kKg<)k9->UvPm1ysE zD1T zz%XSl_xd@BA*&)+xlJAfQYhu6gRJ?KM-yR|mv!)RujOQ`kdf7;hy+)nUCkUNqJi7W zCCJs1)xZqN;t!U*4i0~P+MOubMM(0fd(35bFiDJ8sxBYj9!?NBbNF^Q;_>Zx^udqr zj*h0?{WK9>IAb@@fZbh_y1E_(2JNUbo@I^FzaC;0bpwM{Z&Vs~({9-gevP%J-E`(x z_wwZ4DW~uIihPb5(;Gy4fEp)1+jZW@Cie1tYjPQzhWgOB#z@SV5}I)hzX{nGR#2URal;QrkvQ)@J2`xm?tlOOedc!x)|6ec81ZrtF$J+l&;8v6gx^%C@l!Evl$!X!o*r0x=Vy!uKp5)SWE>x^k-VAE{$AD zKI_H;8k`-6V!BXiX$_-QN)TtvvP6Y)CN?{SspAO}BJ8!$b&&=OY%&qa^0`YMJD-Tz zG?l>%n1<46Jkf=?uN0I5*(8-IG9oMtPs*1xd9;*@YFQ08(&=(>+Q6d$>-8wQd%fHV zR%l^PDfC1p0(p%l)3NiJd9;ebhDR=RuSePUA{-f~dBz~U-jY4bGww80Vtc`7`Fel; zexaRmW84_kXbF*l+_I?J+0wf6AFom!^5a}j3JIk!35i3h3lma3+XU1b+1g(bIL&|f zkb-luW)u#g6bjbdto;<3mdhE1XqgG-x6UMuB7n$?SEjXFl3*{Z!Zl=*uGXK-#s%VE z!M(hM!QCL(FF42+J-$rCIt>jPY8cvU@*DVj zFL9&Z!C<}JurF5};CG{P73kfnwCoywmkG)7YneCmD}A4zVzg;iRgv!OLQT8qfGqYhv*CSEHLQ8fW9PsO?ZAT!~YdHmp6e;uLaHv?>QgN z<+remfpht7x;g{o1?{VVT)suLZ_@Av4d()P!Rxn}@Gk*(LEpCb>90;@e1g2_d0Eq= z`hJ4%UtZSoye}p^D&EvR4~?bg$#0Ta-=X1c8kR}LTv28*9~ti8LQ$G(TtP;8v-yEf zpC0I-bU{7RCpc9H1B!HXpeXdwK^~!;_fXi&cQhISU8Uzm3UH{+70m9a9}xlF`q(k+dcCI#-CgE<54YgCBpPaOte^VQ$;|6qSk! TF{e_iY}TAs&AIw3>#e^7ICY3j diff --git a/Crypto/Cipher/__pycache__/_mode_gcm.cpython-36.pyc b/Crypto/Cipher/__pycache__/_mode_gcm.cpython-36.pyc deleted file mode 100644 index b96de6c2f3b1b73eb6d9fbcdb6608a9655538388..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 17122 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 IH2%H#U$}te+5i9m diff --git a/Crypto/Cipher/__pycache__/_mode_ocb.cpython-36.pyc b/Crypto/Cipher/__pycache__/_mode_ocb.cpython-36.pyc deleted file mode 100644 index b63e910690c9f57ae3d6f64aa3cf4c54e281c11c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 14585 zcmd^GO^hSQb?zSy*~9tWnf;lSEU7JJ<>6?Sqg_R^u$I<4`(s<5j zXGk_(-Q3w>I1UiXfG;r;1o8>UY8O6^i-rZLkgH_CiH)2?)^hSiyE%<^@)UG2;@<~Uzz&vzCY3!Jywi=Cy$ z66a^z%bin=Q=OH@N@umP+Bw}g-8s`Z(>dEX+d0=b*I8?<>6(8^RK?uLXq^A1Cg#P$ zr&Gv%co-etj zs_>&=w~M;XBm0gFTXp-+UeIm_J^OCB>mIsCw%ZkU)bqWd6`)wqwRi4*PY=i6?3HG&Gck&-}R0*?I5PX-}mK_?YCNi7hn#X zRov}Is2q0NM@W48z*qI~z;nBH)2HV=1{4WUfQVtQN1+|>xv}l%)31io7Jg0)svO0x zjL}3Zls=04C@t);#o3M@MeeRoV{-4iLECM%{TfdWchE<_jc1)++wWkU5m$-#0x6g_ zZ8wVT`>qV!ZcGi*%Ft51R^!JQJI$wh7|Mf)$mfNfX3%xVtK{03F28xPiGs~`=pES6 zQK#d_GVs!c+O*rjfp2f$x;I|;9u~DrOO6IVyk|H2vAxrhzK^1w-vtqO9NT{oU}TuD z9fhs<(8av-NpSa3wd2#EsYo~MUhD+z08~1%dwtmp(Fppx^}wZxU#Z&oT)leLZppA? z-=J+4)^DhdgjPe)76Ux7)LrZ#)JaS2`mrPVj?+Af{V1!F{qv%~ZBG|lf9-NDFOqKH zx0xng|8N}}Ws@)7d;jJwhxjBf+iSZ4DD@z=-?p1CZpX0;5@WLn_ptk7UP`q{#WwAZ z>!GZ=Q&0DlgAqF-*!81$J#TT`$xHT4za3ydXVpMX&)-b1xOZYBw9Gx$>-DLg(IKtx ziF4Vc#qs>NIUV;I%cJqC(CXyl8jn8Z0UkX@7qpJnr)D~C&wt?gz1aT9ZTJ0KQigJ> zbqO-sFTT^g@3sR>MX}77f_^(H>=GUi*T_dztzPM4BY1scB41pw9jAx20N*)IwOX&+ zPAXTf*n4r@yRx-)cz9TsE$^Z)f;g1*Q0{I8-B!4TdnA9j&cvo4*YulpFRJ%F;oc9T zx-a@$-cv_Yhrk(8RD6v>?9g}o!SQE_vj z9d>t}I8-;11>V4PP5044If~_jP$E~k{_gg-Z(WX%U7p^`H7hya4qf5&j#xs4;0_-= zap<&zW-|9t7>GL|?OBO>GWcm%mz_fesFezee2vcsN((v3X}IGt={84v=hK&7#8|bRm05UplWkZNK~EmDQLxdiP=wy7sjv8g(}R zR5+yb1~p>;$vd8!cJLHq9@DB1wfVS}Dn3ieB!C2nL{B-_RFwR`m}|cWBKiO0Q~iPq zq_mUT&ri7*^9>cdyHCBLQ0Ld!Pf;B99uXZp>?hoq9?9+OV6r&xfImw}%lO^EFZ#KzX+wP<=F5R8S7I18BmGZc*bFsCiwyyDXK0K} zT$ynRIX#{crqD;mK}B9e=@ONW%k(6=6Ia9xT@R_eCCWpyq?y`*9`2!ay<0LgU5oCc zR)zb}P-<3KNUNOA4YmDw{1)(A#BT||<=q)PKNYVG(bMtFaAtp1%pzBgPw$@*Rg|#A z+*KGs*R+vAlvkr%(@tyWG_iCJee9d(v|}SaJ2b@dd2OVNQ`fZPO5u71*A{4SZdgXT z)-r}OKhlq9hqL<&+{-FzYGU~Z#(8aMjZE}j9aiJ>!z%8U`EC_7IZe5dfxhPAXX0mv zbLi>Ju(GCoT@z<9wzANu#PK}(_!7@%VOaVzUH%AEI~PAkcg|sSpyu-%$`2`J7d$^co^@p_k zAAX&ZpCW0LF1;RIe>h9m*C<&-GFbVrd(aIJyJSPa-V)Ijdr)I6YhMudAq-oXKmZ#s zdSDd;QL!nPk+im+RGB=CpOWer2}>GRGQ$8oF`+w?8JIA;zC1p6_huxjRW&X_%yvB8a4ts@J5fjEtnL;CeFSbYYYvB@uXWV)nuwgUmiI zN`#&z3BJUH-H=#p``o&5T~=^UlGKnSE|OIzMUhQ6@*TB95)+V8&e7vC!MNB@<}(~f zFto9H0=`R308dE^kyKqFBuoG&Y)M+A#)>Lml<7%D`fVS5)|Qe|}(?l;^0AId~P~u;b81Zdjy0I5&4dS=C0PL>G+; zX6MJ=Uc<^jVWUa_JDq$PL+`iaztQA3(C#lk+UiGg3yk5mw_wO`wfbF;%=2i=?OojM zW2FZe$X46!T5qucEJ~I%pI(!g04^`yb=%YdYDMxK``4(=-tCWxk^t^`AXXGPjL}dk!VbdDyT77%ITmw_Y8WD50QYl zfywYs$bba&)1eSgLt%mpP=HW6_?7U3`r0q!r?Dc_;|lT?RD*F)l0S}Tg_+%1(~v{$ zk#P*MT|%k2Dxh+4&-|)pK%owGD54T8k#RfbfhK=AglHGklVy}h zXu>?L9hc(j5FmzHrIIK&hjvRNLq|<0h_d^0OcfqH4_wJ&jVY;|e?(gNatKY(=Ncm{+~n$DhBo{edoEfFvBdYo13zy8-Y+=DeDEiHXz;_45@5et0KWjV zgYvTVBZ%0%&dyFM<92qa{LW4)`*wB;L%V)tZ%hqmBlQ+4Ulom)25GPR_1(HnG7vt} zJ>M0+jB2d+@*WT2$b|2Nm0Q{wJZ9vG;U`deF~oS(3F6d~Ms7h5B1||4aXQeyQ4dbL>E?(fBY#)9E8&wQs*!cENwd%CqZSo3EB4%u1Ni&wSgoWF)x~+` zP$mMAKFS&|4C~4rlHQl*fl-l1S2*KE4YYZInF;SguyBC1cB~ z3*&VeypXxW9iug~&#totcLgfc!TWp%2dL^Y|~Bi+UBBU=h-7u$alURIHIWqYtV2T&$6x zjS2S?;wDj|?;Aj&`fw&TS;Ci&%fqt#-M9n^UmliPMv6Xx&qq3h2qe8dCFw5^4^K$= zvYbah1*uMefCai-K(1C%QoRy%l}MjUGYpHW%yABB*d)#4xWG#+QuM^vCrbQPhpVx- z%)uhkfyIBJuV@8{MmiH3k#u4SUr_7Wj9Mqu^GG4mhp=N#y8pn%5JuyHB{x_GgLpCI z`935&WVs30PDIlj$Xv*55IB3v8sV>F6B;2c4~;<5pELqA2sDBYf@@@?q#8lTl4NE@ z-iu(3Ag~Od(f^Fj!Yt)`?qNJmO5r)Ey=<#msYv2yC4_0 zS^TI2r#OJp%?q(^ZIWHogP4P6TBl>2RCn$uJ7A|acE=oreS2erbi>953%Uu(O=_5r zqDXQpX-#TI?y|p~mADr|GI?<>YiUp|97VOq@>T(4I9#Vc?@_#8k3x9NNnKK*>wq+zCx z3wb3#i6Gib0Rk5wtttHu&W}h2j!84oR0@!wdvN$E`ks$zQy28Pa@UXhvRl-L)Hl== zTMO#A2>{Dw%?La}UjA`)YT_N(>|m!|9H)}DCs5FFVcBpq>4WqXb0eqb#<-2awUjLD zCo0O5lp_%kDmBxuw^K`uxvfo-0HjN_ zRnmSIv|hD<;M2B#%MAT@VCb9bq?k!MxwXdYRA7fkIC@;_@hq)O`rkTBkGJe&1=C}> zI)&HPxVkzX(llFBWA6}KFHf;GDebXwo;K(a3a5{WUk=3v zxF8)2Fg7a}$pe8aUDlB@zyg+KSVpFA3W-YO{XS+*jb{}Y>Hs|PEJ_j#1N4DuZpbDK zbKu|<^TK?FIZtiRvo9EabM|&*;Aj=Y7`!rthR1#nrJg5%@q&B>b=W{)vp^v!2Fqig zh^qIQ=vi){iJF;0XmXIjg?J(+UdGWhIbnQuIil1a(ft`zCnr-0?xWLs8PIATz-rMT zU~K7wwHz`{RnC`!mV}@a!=`T`0|M~^6k!uD0UX}|Pe$}|Jj0%oF=zr@0;sx9OEH22 z8~vWUQ4~IMzF^`IE zAa(`}2%9k!IrsZ$cLXXjr!|b>uI~!~0far`IpPxyi_>f`z?V6c2?W; zJ9tvl6|SE$O-Zx=5$z`O>}vB+&c=#SCD)}fHbm7JC-x1oG4C64#tS-};=?zrzdq7# z;-G_#%+lb~iA{i@ux?CFl#}+s2L;~*7KQ_%GHCqy*ww!zI#LH^ZEzvuK8#C|ul^Q$oujMBWHl)GWFPS#yq+hoP%@jh@E2M8T4iwR zk@j=&MAM@mFV7E=`QmIHTXc$u6S~>`Dx8=ko6Dm7r|=@@cXYlk4bA;INaPZwIIa9N zo)_vQk!&i<{YOjzXDtD6yfQ7mkX%T0%M;559L*pgEO;~!Fyn7_7;?~4al@VL?Mg+3 z$Yk=9`@DFgV~3N#DbAk-Mb@kezM~=$q8I&woASzCH=xkT@tM`6(UH!NWSj_5F1I7< zHp#v$0Fq!2Tck0f{(K1;NJ2FiZzM`#9MAx8C`0b!pzDPa!-Kg<59u?wm`0kh!SRIR zi+ynqe~gV;Gm|;R9DKUNCqFp;f@^57Ov6{})k2h}FKP?QF?WK{lMS>rmUNQ5J(5l* zCHWkbth|6+>bpypGa6@0hjTWV1wPK%poK4SdU=Y^x%0mw1|%P%wpbLDmcD|sn&pD$ zPEjT2NRkP;z$8BwabyhF5Q#}bHsB4z{rC~yczSV}njN3Ndm&V^*<<4>ftfEWE$zf6 zogB#jy?uHcc$U#Ftwe@x=L$5KT5T4(ik5$$3*ChYp?ks-Q{yaj37N6b#q!es2!Rgx zhh}V1%(w2oj7D!2TuT{G(s_kCz|Ft|pREJS5a@xUrT6(On_DJNBakRWnmtz8NX9;v zF}G*HW@4YXcHE~!1V&`>VOVr;;B;W3>_whcYV1Sc5T~C|0IZ+i#bU89f^bT@aPlMM zrx$D`ZMEQ=`dMM+p2^hZqs1mpPxB?TPgp`evV)75cy>toOn3hsecV(o1 z^3kF-9bwA1Ybz93(8XDs<0MswA`b9=0`l{Y^S!>?PM=g92f@~kBgu$U_9!255y+Kn z;4=^L1jrUpDshK$EENOF?Nf3<$=F2T+&AeSX{`=^(ep^GQpvF1vntj_Yr%S@`dsw| zYt>q_W~~>jC2NVx=75`!=qi46$`Eyt9BrytHrVlWjBc=3{&_@5QPdU=Q(#IUeh<&g zkG1aQ5)N1ns`3wY9EO-pQ-2D??}EX&o;J?9f{&%mv@hBAn7X9GmoH!eHCR>naHH2h&l=7e#+{ z>5Q9Vz@*P_*w7mxJHZ1t1>HHO8Ge>Glm&n-8LdXi`TZ}pL7l|Mt zZ1oyQUYO&}P>N#G04;a@F2$9TKRume8ZU%d!eaChewEYfUF9K9&2Q)mykdm+g(!-x zFoblnm?j>QT;?DyL?ZmboAvsoH@-`e2rOfee1ONoZ@CB)qQM|$Z9R*j%hq5!Cr}!0 z27L#w1)T(_^BfR@dcj){zHA@S8G?GjN9{7z*FC(m!$U!+)O~sxCwoJJ&#BqgM_>Wa zZe*`xwJ4qnulnqu$DJM3A2};{*yxT=A$%AIaVjx6((1M(29*Ru7-tVorMt)O1US~| z?q0ER0{A*TCYYR9c&t1HHM;jTN{H8im9NwD@&R5Z+KsqvZZ*;Uf`A~|kgQ}uXQ9_j z!><05Bpo{j*9^F&=wuIZPWp?6jHvPFWQafc2GzDmmqcC=NK(GZnUoPeM8E|Ct6n3^ z+Kt%;SD|?;#RA=ar|HW=0Nlh=z*@Yb!7*~lTw3j0ZnVe7L9&qExeHYtb`&{I7aQjw zIky)`3OwQfI&~aQN8cO?r{bGvnj9U-ha*WjZ0^HIVk+`%3*^e>X=1&lq{r1;sLetZ aA{D11M5TFS9>4XO(&@6f{Kp!7&Hn~z0aC62 diff --git a/Crypto/Cipher/__pycache__/_mode_ofb.cpython-36.pyc b/Crypto/Cipher/__pycache__/_mode_ofb.cpython-36.pyc deleted file mode 100644 index 173cc0b5b6b96aa176b6e7de119b880540ddf4d3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 7482 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 diff --git a/Crypto/Cipher/__pycache__/_mode_siv.cpython-36.pyc b/Crypto/Cipher/__pycache__/_mode_siv.cpython-36.pyc deleted file mode 100644 index ec40a483273bb4a491e9f717e468d8181e2e272f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 11836 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 J_N8|1e*nT8+b;kB diff --git a/Crypto/Cipher/_chacha20.abi3.so b/Crypto/Cipher/_chacha20.abi3.so deleted file mode 100644 index f3467957d8fa838f51763c11d8a204a247161af0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 28224 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 SDJfEl1D%%s>J)_(Qv7c?Kp!0d diff --git a/Crypto/Cipher/_mode_cbc.py b/Crypto/Cipher/_mode_cbc.py deleted file mode 100644 index 79c871a..0000000 --- a/Crypto/Cipher/_mode_cbc.py +++ /dev/null @@ -1,293 +0,0 @@ -# =================================================================== -# -# Copyright (c) 2014, Legrandin -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# =================================================================== - -""" -Ciphertext Block Chaining (CBC) mode. -""" - -__all__ = ['CbcMode'] - -from Crypto.Util.py3compat import _copy_bytes -from Crypto.Util._raw_api import (load_pycryptodome_raw_lib, VoidPointer, - create_string_buffer, get_raw_buffer, - SmartPointer, c_size_t, c_uint8_ptr, - is_writeable_buffer) - -from Crypto.Random import get_random_bytes - -raw_cbc_lib = load_pycryptodome_raw_lib("Crypto.Cipher._raw_cbc", """ - int CBC_start_operation(void *cipher, - const uint8_t iv[], - size_t iv_len, - void **pResult); - int CBC_encrypt(void *cbcState, - const uint8_t *in, - uint8_t *out, - size_t data_len); - int CBC_decrypt(void *cbcState, - const uint8_t *in, - uint8_t *out, - size_t data_len); - int CBC_stop_operation(void *state); - """ - ) - - -class CbcMode(object): - """*Cipher-Block Chaining (CBC)*. - - Each of the ciphertext blocks depends on the current - and all previous plaintext blocks. - - An Initialization Vector (*IV*) is required. - - See `NIST SP800-38A`_ , Section 6.2 . - - .. _`NIST SP800-38A` : http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf - - :undocumented: __init__ - """ - - def __init__(self, block_cipher, iv): - """Create a new block cipher, configured in CBC mode. - - :Parameters: - block_cipher : C pointer - A smart pointer to the low-level block cipher instance. - - iv : bytes/bytearray/memoryview - The initialization vector to use for encryption or decryption. - It is as long as the cipher block. - - **The IV must be unpredictable**. Ideally it is picked randomly. - - Reusing the *IV* for encryptions performed with the same key - compromises confidentiality. - """ - - self._state = VoidPointer() - result = raw_cbc_lib.CBC_start_operation(block_cipher.get(), - c_uint8_ptr(iv), - c_size_t(len(iv)), - self._state.address_of()) - if result: - raise ValueError("Error %d while instantiating the CBC mode" - % result) - - # Ensure that object disposal of this Python object will (eventually) - # free the memory allocated by the raw library for the cipher mode - self._state = SmartPointer(self._state.get(), - raw_cbc_lib.CBC_stop_operation) - - # Memory allocated for the underlying block cipher is now owed - # by the cipher mode - block_cipher.release() - - self.block_size = len(iv) - """The block size of the underlying cipher, in bytes.""" - - self.iv = _copy_bytes(None, None, iv) - """The Initialization Vector originally used to create the object. - The value does not change.""" - - self.IV = self.iv - """Alias for `iv`""" - - self._next = [ self.encrypt, self.decrypt ] - - def encrypt(self, plaintext, output=None): - """Encrypt data with the key and the parameters set at initialization. - - A cipher object is stateful: once you have encrypted a message - you cannot encrypt (or decrypt) another message using the same - object. - - The data to encrypt can be broken up in two or - more pieces and `encrypt` can be called multiple times. - - That is, the statement: - - >>> c.encrypt(a) + c.encrypt(b) - - is equivalent to: - - >>> c.encrypt(a+b) - - That also means that you cannot reuse an object for encrypting - or decrypting other data with the same key. - - This function does not add any padding to the plaintext. - - :Parameters: - plaintext : bytes/bytearray/memoryview - The piece of data to encrypt. - Its lenght must be multiple of the cipher block size. - :Keywords: - output : bytearray/memoryview - The location where the ciphertext must be written to. - If ``None``, the ciphertext is returned. - :Return: - If ``output`` is ``None``, the ciphertext is returned as ``bytes``. - Otherwise, ``None``. - """ - - if self.encrypt not in self._next: - raise TypeError("encrypt() cannot be called after decrypt()") - self._next = [ self.encrypt ] - - if output is None: - ciphertext = create_string_buffer(len(plaintext)) - else: - ciphertext = output - - if not is_writeable_buffer(output): - raise TypeError("output must be a bytearray or a writeable memoryview") - - if len(plaintext) != len(output): - raise ValueError("output must have the same length as the input" - " (%d bytes)" % len(plaintext)) - - result = raw_cbc_lib.CBC_encrypt(self._state.get(), - c_uint8_ptr(plaintext), - c_uint8_ptr(ciphertext), - c_size_t(len(plaintext))) - if result: - if result == 3: - raise ValueError("Data must be padded to %d byte boundary in CBC mode" % self.block_size) - raise ValueError("Error %d while encrypting in CBC mode" % result) - - if output is None: - return get_raw_buffer(ciphertext) - else: - return None - - def decrypt(self, ciphertext, output=None): - """Decrypt data with the key and the parameters set at initialization. - - A cipher object is stateful: once you have decrypted a message - you cannot decrypt (or encrypt) another message with the same - object. - - The data to decrypt can be broken up in two or - more pieces and `decrypt` can be called multiple times. - - That is, the statement: - - >>> c.decrypt(a) + c.decrypt(b) - - is equivalent to: - - >>> c.decrypt(a+b) - - This function does not remove any padding from the plaintext. - - :Parameters: - ciphertext : bytes/bytearray/memoryview - The piece of data to decrypt. - Its length must be multiple of the cipher block size. - :Keywords: - output : bytearray/memoryview - The location where the plaintext must be written to. - If ``None``, the plaintext is returned. - :Return: - If ``output`` is ``None``, the plaintext is returned as ``bytes``. - Otherwise, ``None``. - """ - - if self.decrypt not in self._next: - raise TypeError("decrypt() cannot be called after encrypt()") - self._next = [ self.decrypt ] - - if output is None: - plaintext = create_string_buffer(len(ciphertext)) - else: - plaintext = output - - if not is_writeable_buffer(output): - raise TypeError("output must be a bytearray or a writeable memoryview") - - if len(ciphertext) != len(output): - raise ValueError("output must have the same length as the input" - " (%d bytes)" % len(plaintext)) - - result = raw_cbc_lib.CBC_decrypt(self._state.get(), - c_uint8_ptr(ciphertext), - c_uint8_ptr(plaintext), - c_size_t(len(ciphertext))) - if result: - if result == 3: - raise ValueError("Data must be padded to %d byte boundary in CBC mode" % self.block_size) - raise ValueError("Error %d while decrypting in CBC mode" % result) - - if output is None: - return get_raw_buffer(plaintext) - else: - return None - - -def _create_cbc_cipher(factory, **kwargs): - """Instantiate a cipher object that performs CBC encryption/decryption. - - :Parameters: - factory : module - The underlying block cipher, a module from ``Crypto.Cipher``. - - :Keywords: - iv : bytes/bytearray/memoryview - The IV to use for CBC. - - IV : bytes/bytearray/memoryview - Alias for ``iv``. - - Any other keyword will be passed to the underlying block cipher. - See the relevant documentation for details (at least ``key`` will need - to be present). - """ - - cipher_state = factory._create_base_cipher(kwargs) - iv = kwargs.pop("IV", None) - IV = kwargs.pop("iv", None) - - if (None, None) == (iv, IV): - iv = get_random_bytes(factory.block_size) - if iv is not None: - if IV is not None: - raise TypeError("You must either use 'iv' or 'IV', not both") - else: - iv = IV - - if len(iv) != factory.block_size: - raise ValueError("Incorrect IV length (it must be %d bytes long)" % - factory.block_size) - - if kwargs: - raise TypeError("Unknown parameters for CBC: %s" % str(kwargs)) - - return CbcMode(cipher_state, iv) diff --git a/Crypto/Cipher/_mode_cbc.pyi b/Crypto/Cipher/_mode_cbc.pyi deleted file mode 100644 index 8b9fb16..0000000 --- a/Crypto/Cipher/_mode_cbc.pyi +++ /dev/null @@ -1,25 +0,0 @@ -from typing import Union, overload - -from Crypto.Util._raw_api import SmartPointer - -Buffer = Union[bytes, bytearray, memoryview] - -__all__ = ['CbcMode'] - -class CbcMode(object): - block_size: int - iv: Buffer - IV: Buffer - - def __init__(self, - block_cipher: SmartPointer, - iv: Buffer) -> None: ... - @overload - def encrypt(self, plaintext: Buffer) -> bytes: ... - @overload - def encrypt(self, plaintext: Buffer, output: Union[bytearray, memoryview]) -> None: ... - @overload - def decrypt(self, plaintext: Buffer) -> bytes: ... - @overload - def decrypt(self, plaintext: Buffer, output: Union[bytearray, memoryview]) -> None: ... - diff --git a/Crypto/Cipher/_mode_ccm.py b/Crypto/Cipher/_mode_ccm.py deleted file mode 100644 index 64077de..0000000 --- a/Crypto/Cipher/_mode_ccm.py +++ /dev/null @@ -1,650 +0,0 @@ -# =================================================================== -# -# Copyright (c) 2014, Legrandin -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# =================================================================== - -""" -Counter with CBC-MAC (CCM) mode. -""" - -__all__ = ['CcmMode'] - -import struct -from binascii import unhexlify - -from Crypto.Util.py3compat import (byte_string, bord, - _copy_bytes) -from Crypto.Util._raw_api import is_writeable_buffer - -from Crypto.Util.strxor import strxor -from Crypto.Util.number import long_to_bytes - -from Crypto.Hash import BLAKE2s -from Crypto.Random import get_random_bytes - - -def enum(**enums): - return type('Enum', (), enums) - -MacStatus = enum(NOT_STARTED=0, PROCESSING_AUTH_DATA=1, PROCESSING_PLAINTEXT=2) - - -class CcmMode(object): - """Counter with CBC-MAC (CCM). - - This is an Authenticated Encryption with Associated Data (`AEAD`_) mode. - It provides both confidentiality and authenticity. - - The header of the message may be left in the clear, if needed, and it will - still be subject to authentication. The decryption step tells the receiver - if the message comes from a source that really knowns the secret key. - Additionally, decryption detects if any part of the message - including the - header - has been modified or corrupted. - - This mode requires a nonce. The nonce shall never repeat for two - different messages encrypted with the same key, but it does not need - to be random. - Note that there is a trade-off between the size of the nonce and the - maximum size of a single message you can encrypt. - - It is important to use a large nonce if the key is reused across several - messages and the nonce is chosen randomly. - - It is acceptable to us a short nonce if the key is only used a few times or - if the nonce is taken from a counter. - - The following table shows the trade-off when the nonce is chosen at - random. The column on the left shows how many messages it takes - for the keystream to repeat **on average**. In practice, you will want to - stop using the key way before that. - - +--------------------+---------------+-------------------+ - | Avg. # of messages | nonce | Max. message | - | before keystream | size | size | - | repeats | (bytes) | (bytes) | - +====================+===============+===================+ - | 2^52 | 13 | 64K | - +--------------------+---------------+-------------------+ - | 2^48 | 12 | 16M | - +--------------------+---------------+-------------------+ - | 2^44 | 11 | 4G | - +--------------------+---------------+-------------------+ - | 2^40 | 10 | 1T | - +--------------------+---------------+-------------------+ - | 2^36 | 9 | 64P | - +--------------------+---------------+-------------------+ - | 2^32 | 8 | 16E | - +--------------------+---------------+-------------------+ - - This mode is only available for ciphers that operate on 128 bits blocks - (e.g. AES but not TDES). - - See `NIST SP800-38C`_ or RFC3610_. - - .. _`NIST SP800-38C`: http://csrc.nist.gov/publications/nistpubs/800-38C/SP800-38C.pdf - .. _RFC3610: https://tools.ietf.org/html/rfc3610 - .. _AEAD: http://blog.cryptographyengineering.com/2012/05/how-to-choose-authenticated-encryption.html - - :undocumented: __init__ - """ - - def __init__(self, factory, key, nonce, mac_len, msg_len, assoc_len, - cipher_params): - - self.block_size = factory.block_size - """The block size of the underlying cipher, in bytes.""" - - self.nonce = _copy_bytes(None, None, nonce) - """The nonce used for this cipher instance""" - - self._factory = factory - self._key = _copy_bytes(None, None, key) - self._mac_len = mac_len - self._msg_len = msg_len - self._assoc_len = assoc_len - self._cipher_params = cipher_params - - self._mac_tag = None # Cache for MAC tag - - if self.block_size != 16: - raise ValueError("CCM mode is only available for ciphers" - " that operate on 128 bits blocks") - - # MAC tag length (Tlen) - if mac_len not in (4, 6, 8, 10, 12, 14, 16): - raise ValueError("Parameter 'mac_len' must be even" - " and in the range 4..16 (not %d)" % mac_len) - - # Nonce value - if not (nonce and 7 <= len(nonce) <= 13): - raise ValueError("Length of parameter 'nonce' must be" - " in the range 7..13 bytes") - - # Create MAC object (the tag will be the last block - # bytes worth of ciphertext) - self._mac = self._factory.new(key, - factory.MODE_CBC, - iv=b'\x00' * 16, - **cipher_params) - self._mac_status = MacStatus.NOT_STARTED - self._t = None - - # Allowed transitions after initialization - self._next = [self.update, self.encrypt, self.decrypt, - self.digest, self.verify] - - # Cumulative lengths - self._cumul_assoc_len = 0 - self._cumul_msg_len = 0 - - # Cache for unaligned associated data/plaintext. - # This is a list with byte strings, but when the MAC starts, - # it will become a binary string no longer than the block size. - self._cache = [] - - # Start CTR cipher, by formatting the counter (A.3) - q = 15 - len(nonce) # length of Q, the encoded message length - self._cipher = self._factory.new(key, - self._factory.MODE_CTR, - nonce=struct.pack("B", q - 1) + self.nonce, - **cipher_params) - - # S_0, step 6 in 6.1 for j=0 - self._s_0 = self._cipher.encrypt(b'\x00' * 16) - - # Try to start the MAC - if None not in (assoc_len, msg_len): - self._start_mac() - - def _start_mac(self): - - assert(self._mac_status == MacStatus.NOT_STARTED) - assert(None not in (self._assoc_len, self._msg_len)) - assert(isinstance(self._cache, list)) - - # Formatting control information and nonce (A.2.1) - q = 15 - len(self.nonce) # length of Q, the encoded message length - flags = (64 * (self._assoc_len > 0) + 8 * ((self._mac_len - 2) // 2) + - (q - 1)) - b_0 = struct.pack("B", flags) + self.nonce + long_to_bytes(self._msg_len, q) - - # Formatting associated data (A.2.2) - # Encoded 'a' is concatenated with the associated data 'A' - assoc_len_encoded = b'' - if self._assoc_len > 0: - if self._assoc_len < (2 ** 16 - 2 ** 8): - enc_size = 2 - elif self._assoc_len < (2 ** 32): - assoc_len_encoded = b'\xFF\xFE' - enc_size = 4 - else: - assoc_len_encoded = b'\xFF\xFF' - enc_size = 8 - assoc_len_encoded += long_to_bytes(self._assoc_len, enc_size) - - # b_0 and assoc_len_encoded must be processed first - self._cache.insert(0, b_0) - self._cache.insert(1, assoc_len_encoded) - - # Process all the data cached so far - first_data_to_mac = b"".join(self._cache) - self._cache = b"" - self._mac_status = MacStatus.PROCESSING_AUTH_DATA - self._update(first_data_to_mac) - - def _pad_cache_and_update(self): - - assert(self._mac_status != MacStatus.NOT_STARTED) - assert(len(self._cache) < self.block_size) - - # Associated data is concatenated with the least number - # of zero bytes (possibly none) to reach alignment to - # the 16 byte boundary (A.2.3) - len_cache = len(self._cache) - if len_cache > 0: - self._update(b'\x00' * (self.block_size - len_cache)) - - def update(self, assoc_data): - """Protect associated data - - If there is any associated data, the caller has to invoke - this function one or more times, before using - ``decrypt`` or ``encrypt``. - - By *associated data* it is meant any data (e.g. packet headers) that - will not be encrypted and will be transmitted in the clear. - However, the receiver is still able to detect any modification to it. - In CCM, the *associated data* is also called - *additional authenticated data* (AAD). - - If there is no associated data, this method must not be called. - - The caller may split associated data in segments of any size, and - invoke this method multiple times, each time with the next segment. - - :Parameters: - assoc_data : bytes/bytearray/memoryview - A piece of associated data. There are no restrictions on its size. - """ - - if self.update not in self._next: - raise TypeError("update() can only be called" - " immediately after initialization") - - self._next = [self.update, self.encrypt, self.decrypt, - self.digest, self.verify] - - self._cumul_assoc_len += len(assoc_data) - if self._assoc_len is not None and \ - self._cumul_assoc_len > self._assoc_len: - raise ValueError("Associated data is too long") - - self._update(assoc_data) - return self - - def _update(self, assoc_data_pt=b""): - """Update the MAC with associated data or plaintext - (without FSM checks)""" - - # If MAC has not started yet, we just park the data into a list. - # If the data is mutable, we create a copy and store that instead. - if self._mac_status == MacStatus.NOT_STARTED: - if is_writeable_buffer(assoc_data_pt): - assoc_data_pt = _copy_bytes(None, None, assoc_data_pt) - self._cache.append(assoc_data_pt) - return - - assert(len(self._cache) < self.block_size) - - if len(self._cache) > 0: - filler = min(self.block_size - len(self._cache), - len(assoc_data_pt)) - self._cache += _copy_bytes(None, filler, assoc_data_pt) - assoc_data_pt = _copy_bytes(filler, None, assoc_data_pt) - - if len(self._cache) < self.block_size: - return - - # The cache is exactly one block - self._t = self._mac.encrypt(self._cache) - self._cache = b"" - - update_len = len(assoc_data_pt) // self.block_size * self.block_size - self._cache = _copy_bytes(update_len, None, assoc_data_pt) - if update_len > 0: - self._t = self._mac.encrypt(assoc_data_pt[:update_len])[-16:] - - def encrypt(self, plaintext, output=None): - """Encrypt data with the key set at initialization. - - A cipher object is stateful: once you have encrypted a message - you cannot encrypt (or decrypt) another message using the same - object. - - This method can be called only **once** if ``msg_len`` was - not passed at initialization. - - If ``msg_len`` was given, the data to encrypt can be broken - up in two or more pieces and `encrypt` can be called - multiple times. - - That is, the statement: - - >>> c.encrypt(a) + c.encrypt(b) - - is equivalent to: - - >>> c.encrypt(a+b) - - This function does not add any padding to the plaintext. - - :Parameters: - plaintext : bytes/bytearray/memoryview - The piece of data to encrypt. - It can be of any length. - :Keywords: - output : bytearray/memoryview - The location where the ciphertext must be written to. - If ``None``, the ciphertext is returned. - :Return: - If ``output`` is ``None``, the ciphertext as ``bytes``. - Otherwise, ``None``. - """ - - if self.encrypt not in self._next: - raise TypeError("encrypt() can only be called after" - " initialization or an update()") - self._next = [self.encrypt, self.digest] - - # No more associated data allowed from now - if self._assoc_len is None: - assert(isinstance(self._cache, list)) - self._assoc_len = sum([len(x) for x in self._cache]) - if self._msg_len is not None: - self._start_mac() - else: - if self._cumul_assoc_len < self._assoc_len: - raise ValueError("Associated data is too short") - - # Only once piece of plaintext accepted if message length was - # not declared in advance - if self._msg_len is None: - self._msg_len = len(plaintext) - self._start_mac() - self._next = [self.digest] - - self._cumul_msg_len += len(plaintext) - if self._cumul_msg_len > self._msg_len: - raise ValueError("Message is too long") - - if self._mac_status == MacStatus.PROCESSING_AUTH_DATA: - # Associated data is concatenated with the least number - # of zero bytes (possibly none) to reach alignment to - # the 16 byte boundary (A.2.3) - self._pad_cache_and_update() - self._mac_status = MacStatus.PROCESSING_PLAINTEXT - - self._update(plaintext) - return self._cipher.encrypt(plaintext, output=output) - - def decrypt(self, ciphertext, output=None): - """Decrypt data with the key set at initialization. - - A cipher object is stateful: once you have decrypted a message - you cannot decrypt (or encrypt) another message with the same - object. - - This method can be called only **once** if ``msg_len`` was - not passed at initialization. - - If ``msg_len`` was given, the data to decrypt can be - broken up in two or more pieces and `decrypt` can be - called multiple times. - - That is, the statement: - - >>> c.decrypt(a) + c.decrypt(b) - - is equivalent to: - - >>> c.decrypt(a+b) - - This function does not remove any padding from the plaintext. - - :Parameters: - ciphertext : bytes/bytearray/memoryview - The piece of data to decrypt. - It can be of any length. - :Keywords: - output : bytearray/memoryview - The location where the plaintext must be written to. - If ``None``, the plaintext is returned. - :Return: - If ``output`` is ``None``, the plaintext as ``bytes``. - Otherwise, ``None``. - """ - - if self.decrypt not in self._next: - raise TypeError("decrypt() can only be called" - " after initialization or an update()") - self._next = [self.decrypt, self.verify] - - # No more associated data allowed from now - if self._assoc_len is None: - assert(isinstance(self._cache, list)) - self._assoc_len = sum([len(x) for x in self._cache]) - if self._msg_len is not None: - self._start_mac() - else: - if self._cumul_assoc_len < self._assoc_len: - raise ValueError("Associated data is too short") - - # Only once piece of ciphertext accepted if message length was - # not declared in advance - if self._msg_len is None: - self._msg_len = len(ciphertext) - self._start_mac() - self._next = [self.verify] - - self._cumul_msg_len += len(ciphertext) - if self._cumul_msg_len > self._msg_len: - raise ValueError("Message is too long") - - if self._mac_status == MacStatus.PROCESSING_AUTH_DATA: - # Associated data is concatenated with the least number - # of zero bytes (possibly none) to reach alignment to - # the 16 byte boundary (A.2.3) - self._pad_cache_and_update() - self._mac_status = MacStatus.PROCESSING_PLAINTEXT - - # Encrypt is equivalent to decrypt with the CTR mode - plaintext = self._cipher.encrypt(ciphertext, output=output) - if output is None: - self._update(plaintext) - else: - self._update(output) - return plaintext - - def digest(self): - """Compute the *binary* MAC tag. - - The caller invokes this function at the very end. - - This method returns the MAC that shall be sent to the receiver, - together with the ciphertext. - - :Return: the MAC, as a byte string. - """ - - if self.digest not in self._next: - raise TypeError("digest() cannot be called when decrypting" - " or validating a message") - self._next = [self.digest] - return self._digest() - - def _digest(self): - if self._mac_tag: - return self._mac_tag - - if self._assoc_len is None: - assert(isinstance(self._cache, list)) - self._assoc_len = sum([len(x) for x in self._cache]) - if self._msg_len is not None: - self._start_mac() - else: - if self._cumul_assoc_len < self._assoc_len: - raise ValueError("Associated data is too short") - - if self._msg_len is None: - self._msg_len = 0 - self._start_mac() - - if self._cumul_msg_len != self._msg_len: - raise ValueError("Message is too short") - - # Both associated data and payload are concatenated with the least - # number of zero bytes (possibly none) that align it to the - # 16 byte boundary (A.2.2 and A.2.3) - self._pad_cache_and_update() - - # Step 8 in 6.1 (T xor MSB_Tlen(S_0)) - self._mac_tag = strxor(self._t, self._s_0)[:self._mac_len] - - return self._mac_tag - - def hexdigest(self): - """Compute the *printable* MAC tag. - - This method is like `digest`. - - :Return: the MAC, as a hexadecimal string. - """ - return "".join(["%02x" % bord(x) for x in self.digest()]) - - def verify(self, received_mac_tag): - """Validate the *binary* MAC tag. - - The caller invokes this function at the very end. - - This method checks if the decrypted message is indeed valid - (that is, if the key is correct) and it has not been - tampered with while in transit. - - :Parameters: - received_mac_tag : bytes/bytearray/memoryview - This is the *binary* MAC, as received from the sender. - :Raises ValueError: - if the MAC does not match. The message has been tampered with - or the key is incorrect. - """ - - if self.verify not in self._next: - raise TypeError("verify() cannot be called" - " when encrypting a message") - self._next = [self.verify] - - self._digest() - secret = get_random_bytes(16) - - mac1 = BLAKE2s.new(digest_bits=160, key=secret, data=self._mac_tag) - mac2 = BLAKE2s.new(digest_bits=160, key=secret, data=received_mac_tag) - - if mac1.digest() != mac2.digest(): - raise ValueError("MAC check failed") - - def hexverify(self, hex_mac_tag): - """Validate the *printable* MAC tag. - - This method is like `verify`. - - :Parameters: - hex_mac_tag : string - This is the *printable* MAC, as received from the sender. - :Raises ValueError: - if the MAC does not match. The message has been tampered with - or the key is incorrect. - """ - - self.verify(unhexlify(hex_mac_tag)) - - def encrypt_and_digest(self, plaintext, output=None): - """Perform encrypt() and digest() in one step. - - :Parameters: - plaintext : bytes/bytearray/memoryview - The piece of data to encrypt. - :Keywords: - output : bytearray/memoryview - The location where the ciphertext must be written to. - If ``None``, the ciphertext is returned. - :Return: - a tuple with two items: - - - the ciphertext, as ``bytes`` - - the MAC tag, as ``bytes`` - - The first item becomes ``None`` when the ``output`` parameter - specified a location for the result. - """ - - return self.encrypt(plaintext, output=output), self.digest() - - def decrypt_and_verify(self, ciphertext, received_mac_tag, output=None): - """Perform decrypt() and verify() in one step. - - :Parameters: - ciphertext : bytes/bytearray/memoryview - The piece of data to decrypt. - received_mac_tag : bytes/bytearray/memoryview - This is the *binary* MAC, as received from the sender. - :Keywords: - output : bytearray/memoryview - The location where the plaintext must be written to. - If ``None``, the plaintext is returned. - :Return: the plaintext as ``bytes`` or ``None`` when the ``output`` - parameter specified a location for the result. - :Raises ValueError: - if the MAC does not match. The message has been tampered with - or the key is incorrect. - """ - - plaintext = self.decrypt(ciphertext, output=output) - self.verify(received_mac_tag) - return plaintext - - -def _create_ccm_cipher(factory, **kwargs): - """Create a new block cipher, configured in CCM mode. - - :Parameters: - factory : module - A symmetric cipher module from `Crypto.Cipher` (like - `Crypto.Cipher.AES`). - - :Keywords: - key : bytes/bytearray/memoryview - The secret key to use in the symmetric cipher. - - nonce : bytes/bytearray/memoryview - A value that must never be reused for any other encryption. - - Its length must be in the range ``[7..13]``. - 11 or 12 bytes are reasonable values in general. Bear in - mind that with CCM there is a trade-off between nonce length and - maximum message size. - - If not specified, a 11 byte long random string is used. - - mac_len : integer - Length of the MAC, in bytes. It must be even and in - the range ``[4..16]``. The default is 16. - - msg_len : integer - Length of the message to (de)cipher. - If not specified, ``encrypt`` or ``decrypt`` may only be called once. - - assoc_len : integer - Length of the associated data. - If not specified, all data is internally buffered. - """ - - try: - key = key = kwargs.pop("key") - except KeyError as e: - raise TypeError("Missing parameter: " + str(e)) - - nonce = kwargs.pop("nonce", None) # N - if nonce is None: - nonce = get_random_bytes(11) - mac_len = kwargs.pop("mac_len", factory.block_size) - msg_len = kwargs.pop("msg_len", None) # p - assoc_len = kwargs.pop("assoc_len", None) # a - cipher_params = dict(kwargs) - - return CcmMode(factory, key, nonce, mac_len, msg_len, - assoc_len, cipher_params) diff --git a/Crypto/Cipher/_mode_ccm.pyi b/Crypto/Cipher/_mode_ccm.pyi deleted file mode 100644 index 4b9f620..0000000 --- a/Crypto/Cipher/_mode_ccm.pyi +++ /dev/null @@ -1,47 +0,0 @@ -from types import ModuleType -from typing import Union, overload, Dict, Tuple, Optional - -Buffer = Union[bytes, bytearray, memoryview] - -__all__ = ['CcmMode'] - -class CcmMode(object): - block_size: int - nonce: bytes - - def __init__(self, - factory: ModuleType, - key: Buffer, - nonce: Buffer, - mac_len: int, - msg_len: int, - assoc_len: int, - cipher_params: Dict) -> None: ... - - def update(self, assoc_data: Buffer) -> CcmMode: ... - - @overload - def encrypt(self, plaintext: Buffer) -> bytes: ... - @overload - def encrypt(self, plaintext: Buffer, output: Union[bytearray, memoryview]) -> None: ... - @overload - def decrypt(self, plaintext: Buffer) -> bytes: ... - @overload - def decrypt(self, plaintext: Buffer, output: Union[bytearray, memoryview]) -> None: ... - - def digest(self) -> bytes: ... - def hexdigest(self) -> str: ... - def verify(self, received_mac_tag: Buffer) -> None: ... - def hexverify(self, hex_mac_tag: str) -> None: ... - - @overload - def encrypt_and_digest(self, - plaintext: Buffer) -> Tuple[bytes, bytes]: ... - @overload - def encrypt_and_digest(self, - plaintext: Buffer, - output: Buffer) -> Tuple[None, bytes]: ... - def decrypt_and_verify(self, - ciphertext: Buffer, - received_mac_tag: Buffer, - output: Optional[Union[bytearray, memoryview]] = ...) -> bytes: ... diff --git a/Crypto/Cipher/_mode_cfb.py b/Crypto/Cipher/_mode_cfb.py deleted file mode 100644 index b3ee1c7..0000000 --- a/Crypto/Cipher/_mode_cfb.py +++ /dev/null @@ -1,293 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Cipher/mode_cfb.py : CFB mode -# -# =================================================================== -# The contents of this file are dedicated to the public domain. To -# the extent that dedication to the public domain is not available, -# everyone is granted a worldwide, perpetual, royalty-free, -# non-exclusive license to exercise all rights associated with the -# contents of this file for any purpose whatsoever. -# No rights are reserved. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS -# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN -# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# =================================================================== - -""" -Counter Feedback (CFB) mode. -""" - -__all__ = ['CfbMode'] - -from Crypto.Util.py3compat import _copy_bytes -from Crypto.Util._raw_api import (load_pycryptodome_raw_lib, VoidPointer, - create_string_buffer, get_raw_buffer, - SmartPointer, c_size_t, c_uint8_ptr, - is_writeable_buffer) - -from Crypto.Random import get_random_bytes - -raw_cfb_lib = load_pycryptodome_raw_lib("Crypto.Cipher._raw_cfb",""" - int CFB_start_operation(void *cipher, - const uint8_t iv[], - size_t iv_len, - size_t segment_len, /* In bytes */ - void **pResult); - int CFB_encrypt(void *cfbState, - const uint8_t *in, - uint8_t *out, - size_t data_len); - int CFB_decrypt(void *cfbState, - const uint8_t *in, - uint8_t *out, - size_t data_len); - int CFB_stop_operation(void *state);""" - ) - - -class CfbMode(object): - """*Cipher FeedBack (CFB)*. - - This mode is similar to CFB, but it transforms - the underlying block cipher into a stream cipher. - - Plaintext and ciphertext are processed in *segments* - of **s** bits. The mode is therefore sometimes - labelled **s**-bit CFB. - - An Initialization Vector (*IV*) is required. - - See `NIST SP800-38A`_ , Section 6.3. - - .. _`NIST SP800-38A` : http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf - - :undocumented: __init__ - """ - - def __init__(self, block_cipher, iv, segment_size): - """Create a new block cipher, configured in CFB mode. - - :Parameters: - block_cipher : C pointer - A smart pointer to the low-level block cipher instance. - - iv : bytes/bytearray/memoryview - The initialization vector to use for encryption or decryption. - It is as long as the cipher block. - - **The IV must be unpredictable**. Ideally it is picked randomly. - - Reusing the *IV* for encryptions performed with the same key - compromises confidentiality. - - segment_size : integer - The number of bytes the plaintext and ciphertext are segmented in. - """ - - self._state = VoidPointer() - result = raw_cfb_lib.CFB_start_operation(block_cipher.get(), - c_uint8_ptr(iv), - c_size_t(len(iv)), - c_size_t(segment_size), - self._state.address_of()) - if result: - raise ValueError("Error %d while instantiating the CFB mode" % result) - - # Ensure that object disposal of this Python object will (eventually) - # free the memory allocated by the raw library for the cipher mode - self._state = SmartPointer(self._state.get(), - raw_cfb_lib.CFB_stop_operation) - - # Memory allocated for the underlying block cipher is now owed - # by the cipher mode - block_cipher.release() - - self.block_size = len(iv) - """The block size of the underlying cipher, in bytes.""" - - self.iv = _copy_bytes(None, None, iv) - """The Initialization Vector originally used to create the object. - The value does not change.""" - - self.IV = self.iv - """Alias for `iv`""" - - self._next = [ self.encrypt, self.decrypt ] - - def encrypt(self, plaintext, output=None): - """Encrypt data with the key and the parameters set at initialization. - - A cipher object is stateful: once you have encrypted a message - you cannot encrypt (or decrypt) another message using the same - object. - - The data to encrypt can be broken up in two or - more pieces and `encrypt` can be called multiple times. - - That is, the statement: - - >>> c.encrypt(a) + c.encrypt(b) - - is equivalent to: - - >>> c.encrypt(a+b) - - This function does not add any padding to the plaintext. - - :Parameters: - plaintext : bytes/bytearray/memoryview - The piece of data to encrypt. - It can be of any length. - :Keywords: - output : bytearray/memoryview - The location where the ciphertext must be written to. - If ``None``, the ciphertext is returned. - :Return: - If ``output`` is ``None``, the ciphertext is returned as ``bytes``. - Otherwise, ``None``. - """ - - if self.encrypt not in self._next: - raise TypeError("encrypt() cannot be called after decrypt()") - self._next = [ self.encrypt ] - - if output is None: - ciphertext = create_string_buffer(len(plaintext)) - else: - ciphertext = output - - if not is_writeable_buffer(output): - raise TypeError("output must be a bytearray or a writeable memoryview") - - if len(plaintext) != len(output): - raise ValueError("output must have the same length as the input" - " (%d bytes)" % len(plaintext)) - - result = raw_cfb_lib.CFB_encrypt(self._state.get(), - c_uint8_ptr(plaintext), - c_uint8_ptr(ciphertext), - c_size_t(len(plaintext))) - if result: - raise ValueError("Error %d while encrypting in CFB mode" % result) - - if output is None: - return get_raw_buffer(ciphertext) - else: - return None - - def decrypt(self, ciphertext, output=None): - """Decrypt data with the key and the parameters set at initialization. - - A cipher object is stateful: once you have decrypted a message - you cannot decrypt (or encrypt) another message with the same - object. - - The data to decrypt can be broken up in two or - more pieces and `decrypt` can be called multiple times. - - That is, the statement: - - >>> c.decrypt(a) + c.decrypt(b) - - is equivalent to: - - >>> c.decrypt(a+b) - - This function does not remove any padding from the plaintext. - - :Parameters: - ciphertext : bytes/bytearray/memoryview - The piece of data to decrypt. - It can be of any length. - :Keywords: - output : bytearray/memoryview - The location where the plaintext must be written to. - If ``None``, the plaintext is returned. - :Return: - If ``output`` is ``None``, the plaintext is returned as ``bytes``. - Otherwise, ``None``. - """ - - if self.decrypt not in self._next: - raise TypeError("decrypt() cannot be called after encrypt()") - self._next = [ self.decrypt ] - - if output is None: - plaintext = create_string_buffer(len(ciphertext)) - else: - plaintext = output - - if not is_writeable_buffer(output): - raise TypeError("output must be a bytearray or a writeable memoryview") - - if len(ciphertext) != len(output): - raise ValueError("output must have the same length as the input" - " (%d bytes)" % len(plaintext)) - - result = raw_cfb_lib.CFB_decrypt(self._state.get(), - c_uint8_ptr(ciphertext), - c_uint8_ptr(plaintext), - c_size_t(len(ciphertext))) - if result: - raise ValueError("Error %d while decrypting in CFB mode" % result) - - if output is None: - return get_raw_buffer(plaintext) - else: - return None - - -def _create_cfb_cipher(factory, **kwargs): - """Instantiate a cipher object that performs CFB encryption/decryption. - - :Parameters: - factory : module - The underlying block cipher, a module from ``Crypto.Cipher``. - - :Keywords: - iv : bytes/bytearray/memoryview - The IV to use for CFB. - - IV : bytes/bytearray/memoryview - Alias for ``iv``. - - segment_size : integer - The number of bit the plaintext and ciphertext are segmented in. - If not present, the default is 8. - - Any other keyword will be passed to the underlying block cipher. - See the relevant documentation for details (at least ``key`` will need - to be present). - """ - - cipher_state = factory._create_base_cipher(kwargs) - - iv = kwargs.pop("IV", None) - IV = kwargs.pop("iv", None) - - if (None, None) == (iv, IV): - iv = get_random_bytes(factory.block_size) - if iv is not None: - if IV is not None: - raise TypeError("You must either use 'iv' or 'IV', not both") - else: - iv = IV - - if len(iv) != factory.block_size: - raise ValueError("Incorrect IV length (it must be %d bytes long)" % - factory.block_size) - - segment_size_bytes, rem = divmod(kwargs.pop("segment_size", 8), 8) - if segment_size_bytes == 0 or rem != 0: - raise ValueError("'segment_size' must be positive and multiple of 8 bits") - - if kwargs: - raise TypeError("Unknown parameters for CFB: %s" % str(kwargs)) - return CfbMode(cipher_state, iv, segment_size_bytes) diff --git a/Crypto/Cipher/_mode_cfb.pyi b/Crypto/Cipher/_mode_cfb.pyi deleted file mode 100644 index e13a909..0000000 --- a/Crypto/Cipher/_mode_cfb.pyi +++ /dev/null @@ -1,26 +0,0 @@ -from typing import Union, overload - -from Crypto.Util._raw_api import SmartPointer - -Buffer = Union[bytes, bytearray, memoryview] - -__all__ = ['CfbMode'] - - -class CfbMode(object): - block_size: int - iv: Buffer - IV: Buffer - - def __init__(self, - block_cipher: SmartPointer, - iv: Buffer, - segment_size: int) -> None: ... - @overload - def encrypt(self, plaintext: Buffer) -> bytes: ... - @overload - def encrypt(self, plaintext: Buffer, output: Union[bytearray, memoryview]) -> None: ... - @overload - def decrypt(self, plaintext: Buffer) -> bytes: ... - @overload - def decrypt(self, plaintext: Buffer, output: Union[bytearray, memoryview]) -> None: ... diff --git a/Crypto/Cipher/_mode_ctr.py b/Crypto/Cipher/_mode_ctr.py deleted file mode 100644 index 15c7e83..0000000 --- a/Crypto/Cipher/_mode_ctr.py +++ /dev/null @@ -1,393 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Cipher/mode_ctr.py : CTR mode -# -# =================================================================== -# The contents of this file are dedicated to the public domain. To -# the extent that dedication to the public domain is not available, -# everyone is granted a worldwide, perpetual, royalty-free, -# non-exclusive license to exercise all rights associated with the -# contents of this file for any purpose whatsoever. -# No rights are reserved. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS -# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN -# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# =================================================================== - -""" -Counter (CTR) mode. -""" - -__all__ = ['CtrMode'] - -import struct - -from Crypto.Util._raw_api import (load_pycryptodome_raw_lib, VoidPointer, - create_string_buffer, get_raw_buffer, - SmartPointer, c_size_t, c_uint8_ptr, - is_writeable_buffer) - -from Crypto.Random import get_random_bytes -from Crypto.Util.py3compat import _copy_bytes, is_native_int -from Crypto.Util.number import long_to_bytes - -raw_ctr_lib = load_pycryptodome_raw_lib("Crypto.Cipher._raw_ctr", """ - int CTR_start_operation(void *cipher, - uint8_t initialCounterBlock[], - size_t initialCounterBlock_len, - size_t prefix_len, - unsigned counter_len, - unsigned littleEndian, - void **pResult); - int CTR_encrypt(void *ctrState, - const uint8_t *in, - uint8_t *out, - size_t data_len); - int CTR_decrypt(void *ctrState, - const uint8_t *in, - uint8_t *out, - size_t data_len); - int CTR_stop_operation(void *ctrState);""" - ) - - -class CtrMode(object): - """*CounTeR (CTR)* mode. - - This mode is very similar to ECB, in that - encryption of one block is done independently of all other blocks. - - Unlike ECB, the block *position* contributes to the encryption - and no information leaks about symbol frequency. - - Each message block is associated to a *counter* which - must be unique across all messages that get encrypted - with the same key (not just within the same message). - The counter is as big as the block size. - - Counters can be generated in several ways. The most - straightword one is to choose an *initial counter block* - (which can be made public, similarly to the *IV* for the - other modes) and increment its lowest **m** bits by one - (modulo *2^m*) for each block. In most cases, **m** is - chosen to be half the block size. - - See `NIST SP800-38A`_, Section 6.5 (for the mode) and - Appendix B (for how to manage the *initial counter block*). - - .. _`NIST SP800-38A` : http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf - - :undocumented: __init__ - """ - - def __init__(self, block_cipher, initial_counter_block, - prefix_len, counter_len, little_endian): - """Create a new block cipher, configured in CTR mode. - - :Parameters: - block_cipher : C pointer - A smart pointer to the low-level block cipher instance. - - initial_counter_block : bytes/bytearray/memoryview - The initial plaintext to use to generate the key stream. - - It is as large as the cipher block, and it embeds - the initial value of the counter. - - This value must not be reused. - It shall contain a nonce or a random component. - Reusing the *initial counter block* for encryptions - performed with the same key compromises confidentiality. - - prefix_len : integer - The amount of bytes at the beginning of the counter block - that never change. - - counter_len : integer - The length in bytes of the counter embedded in the counter - block. - - little_endian : boolean - True if the counter in the counter block is an integer encoded - in little endian mode. If False, it is big endian. - """ - - if len(initial_counter_block) == prefix_len + counter_len: - self.nonce = _copy_bytes(None, prefix_len, initial_counter_block) - """Nonce; not available if there is a fixed suffix""" - - self._state = VoidPointer() - result = raw_ctr_lib.CTR_start_operation(block_cipher.get(), - c_uint8_ptr(initial_counter_block), - c_size_t(len(initial_counter_block)), - c_size_t(prefix_len), - counter_len, - little_endian, - self._state.address_of()) - if result: - raise ValueError("Error %X while instantiating the CTR mode" - % result) - - # Ensure that object disposal of this Python object will (eventually) - # free the memory allocated by the raw library for the cipher mode - self._state = SmartPointer(self._state.get(), - raw_ctr_lib.CTR_stop_operation) - - # Memory allocated for the underlying block cipher is now owed - # by the cipher mode - block_cipher.release() - - self.block_size = len(initial_counter_block) - """The block size of the underlying cipher, in bytes.""" - - self._next = [self.encrypt, self.decrypt] - - def encrypt(self, plaintext, output=None): - """Encrypt data with the key and the parameters set at initialization. - - A cipher object is stateful: once you have encrypted a message - you cannot encrypt (or decrypt) another message using the same - object. - - The data to encrypt can be broken up in two or - more pieces and `encrypt` can be called multiple times. - - That is, the statement: - - >>> c.encrypt(a) + c.encrypt(b) - - is equivalent to: - - >>> c.encrypt(a+b) - - This function does not add any padding to the plaintext. - - :Parameters: - plaintext : bytes/bytearray/memoryview - The piece of data to encrypt. - It can be of any length. - :Keywords: - output : bytearray/memoryview - The location where the ciphertext must be written to. - If ``None``, the ciphertext is returned. - :Return: - If ``output`` is ``None``, the ciphertext is returned as ``bytes``. - Otherwise, ``None``. - """ - - if self.encrypt not in self._next: - raise TypeError("encrypt() cannot be called after decrypt()") - self._next = [self.encrypt] - - if output is None: - ciphertext = create_string_buffer(len(plaintext)) - else: - ciphertext = output - - if not is_writeable_buffer(output): - raise TypeError("output must be a bytearray or a writeable memoryview") - - if len(plaintext) != len(output): - raise ValueError("output must have the same length as the input" - " (%d bytes)" % len(plaintext)) - - result = raw_ctr_lib.CTR_encrypt(self._state.get(), - c_uint8_ptr(plaintext), - c_uint8_ptr(ciphertext), - c_size_t(len(plaintext))) - if result: - if result == 0x60002: - raise OverflowError("The counter has wrapped around in" - " CTR mode") - raise ValueError("Error %X while encrypting in CTR mode" % result) - - if output is None: - return get_raw_buffer(ciphertext) - else: - return None - - def decrypt(self, ciphertext, output=None): - """Decrypt data with the key and the parameters set at initialization. - - A cipher object is stateful: once you have decrypted a message - you cannot decrypt (or encrypt) another message with the same - object. - - The data to decrypt can be broken up in two or - more pieces and `decrypt` can be called multiple times. - - That is, the statement: - - >>> c.decrypt(a) + c.decrypt(b) - - is equivalent to: - - >>> c.decrypt(a+b) - - This function does not remove any padding from the plaintext. - - :Parameters: - ciphertext : bytes/bytearray/memoryview - The piece of data to decrypt. - It can be of any length. - :Keywords: - output : bytearray/memoryview - The location where the plaintext must be written to. - If ``None``, the plaintext is returned. - :Return: - If ``output`` is ``None``, the plaintext is returned as ``bytes``. - Otherwise, ``None``. - """ - - if self.decrypt not in self._next: - raise TypeError("decrypt() cannot be called after encrypt()") - self._next = [self.decrypt] - - if output is None: - plaintext = create_string_buffer(len(ciphertext)) - else: - plaintext = output - - if not is_writeable_buffer(output): - raise TypeError("output must be a bytearray or a writeable memoryview") - - if len(ciphertext) != len(output): - raise ValueError("output must have the same length as the input" - " (%d bytes)" % len(plaintext)) - - result = raw_ctr_lib.CTR_decrypt(self._state.get(), - c_uint8_ptr(ciphertext), - c_uint8_ptr(plaintext), - c_size_t(len(ciphertext))) - if result: - if result == 0x60002: - raise OverflowError("The counter has wrapped around in" - " CTR mode") - raise ValueError("Error %X while decrypting in CTR mode" % result) - - if output is None: - return get_raw_buffer(plaintext) - else: - return None - - -def _create_ctr_cipher(factory, **kwargs): - """Instantiate a cipher object that performs CTR encryption/decryption. - - :Parameters: - factory : module - The underlying block cipher, a module from ``Crypto.Cipher``. - - :Keywords: - nonce : bytes/bytearray/memoryview - The fixed part at the beginning of the counter block - the rest is - the counter number that gets increased when processing the next block. - The nonce must be such that no two messages are encrypted under the - same key and the same nonce. - - The nonce must be shorter than the block size (it can have - zero length; the counter is then as long as the block). - - If this parameter is not present, a random nonce will be created with - length equal to half the block size. No random nonce shorter than - 64 bits will be created though - you must really think through all - security consequences of using such a short block size. - - initial_value : posive integer or bytes/bytearray/memoryview - The initial value for the counter. If not present, the cipher will - start counting from 0. The value is incremented by one for each block. - The counter number is encoded in big endian mode. - - counter : object - Instance of ``Crypto.Util.Counter``, which allows full customization - of the counter block. This parameter is incompatible to both ``nonce`` - and ``initial_value``. - - Any other keyword will be passed to the underlying block cipher. - See the relevant documentation for details (at least ``key`` will need - to be present). - """ - - cipher_state = factory._create_base_cipher(kwargs) - - counter = kwargs.pop("counter", None) - nonce = kwargs.pop("nonce", None) - initial_value = kwargs.pop("initial_value", None) - if kwargs: - raise TypeError("Invalid parameters for CTR mode: %s" % str(kwargs)) - - if counter is not None and (nonce, initial_value) != (None, None): - raise TypeError("'counter' and 'nonce'/'initial_value'" - " are mutually exclusive") - - if counter is None: - # Crypto.Util.Counter is not used - if nonce is None: - if factory.block_size < 16: - raise TypeError("Impossible to create a safe nonce for short" - " block sizes") - nonce = get_random_bytes(factory.block_size // 2) - else: - if len(nonce) >= factory.block_size: - raise ValueError("Nonce is too long") - - # What is not nonce is counter - counter_len = factory.block_size - len(nonce) - - if initial_value is None: - initial_value = 0 - - if is_native_int(initial_value): - if (1 << (counter_len * 8)) - 1 < initial_value: - raise ValueError("Initial counter value is too large") - initial_counter_block = nonce + long_to_bytes(initial_value, counter_len) - else: - if len(initial_value) != counter_len: - raise ValueError("Incorrect length for counter byte string (%d bytes, expected %d)" % - (len(initial_value), counter_len)) - initial_counter_block = nonce + initial_value - - return CtrMode(cipher_state, - initial_counter_block, - len(nonce), # prefix - counter_len, - False) # little_endian - - # Crypto.Util.Counter is used - - # 'counter' used to be a callable object, but now it is - # just a dictionary for backward compatibility. - _counter = dict(counter) - try: - counter_len = _counter.pop("counter_len") - prefix = _counter.pop("prefix") - suffix = _counter.pop("suffix") - initial_value = _counter.pop("initial_value") - little_endian = _counter.pop("little_endian") - except KeyError: - raise TypeError("Incorrect counter object" - " (use Crypto.Util.Counter.new)") - - # Compute initial counter block - words = [] - while initial_value > 0: - words.append(struct.pack('B', initial_value & 255)) - initial_value >>= 8 - words += [b'\x00'] * max(0, counter_len - len(words)) - if not little_endian: - words.reverse() - initial_counter_block = prefix + b"".join(words) + suffix - - if len(initial_counter_block) != factory.block_size: - raise ValueError("Size of the counter block (%d bytes) must match" - " block size (%d)" % (len(initial_counter_block), - factory.block_size)) - - return CtrMode(cipher_state, initial_counter_block, - len(prefix), counter_len, little_endian) diff --git a/Crypto/Cipher/_mode_ctr.pyi b/Crypto/Cipher/_mode_ctr.pyi deleted file mode 100644 index ce70855..0000000 --- a/Crypto/Cipher/_mode_ctr.pyi +++ /dev/null @@ -1,27 +0,0 @@ -from typing import Union, overload - -from Crypto.Util._raw_api import SmartPointer - -Buffer = Union[bytes, bytearray, memoryview] - -__all__ = ['CtrMode'] - -class CtrMode(object): - block_size: int - nonce: bytes - - def __init__(self, - block_cipher: SmartPointer, - initial_counter_block: Buffer, - prefix_len: int, - counter_len: int, - little_endian: bool) -> None: ... - @overload - def encrypt(self, plaintext: Buffer) -> bytes: ... - @overload - def encrypt(self, plaintext: Buffer, output: Union[bytearray, memoryview]) -> None: ... - @overload - def decrypt(self, plaintext: Buffer) -> bytes: ... - @overload - def decrypt(self, plaintext: Buffer, output: Union[bytearray, memoryview]) -> None: ... - diff --git a/Crypto/Cipher/_mode_eax.py b/Crypto/Cipher/_mode_eax.py deleted file mode 100644 index d5fb135..0000000 --- a/Crypto/Cipher/_mode_eax.py +++ /dev/null @@ -1,408 +0,0 @@ -# =================================================================== -# -# Copyright (c) 2014, Legrandin -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# =================================================================== - -""" -EAX mode. -""" - -__all__ = ['EaxMode'] - -import struct -from binascii import unhexlify - -from Crypto.Util.py3compat import byte_string, bord, _copy_bytes - -from Crypto.Util._raw_api import is_buffer - -from Crypto.Util.strxor import strxor -from Crypto.Util.number import long_to_bytes, bytes_to_long - -from Crypto.Hash import CMAC, BLAKE2s -from Crypto.Random import get_random_bytes - - -class EaxMode(object): - """*EAX* mode. - - This is an Authenticated Encryption with Associated Data - (`AEAD`_) mode. It provides both confidentiality and authenticity. - - The header of the message may be left in the clear, if needed, - and it will still be subject to authentication. - - The decryption step tells the receiver if the message comes - from a source that really knowns the secret key. - Additionally, decryption detects if any part of the message - - including the header - has been modified or corrupted. - - This mode requires a *nonce*. - - This mode is only available for ciphers that operate on 64 or - 128 bits blocks. - - There are no official standards defining EAX. - The implementation is based on `a proposal`__ that - was presented to NIST. - - .. _AEAD: http://blog.cryptographyengineering.com/2012/05/how-to-choose-authenticated-encryption.html - .. __: http://csrc.nist.gov/groups/ST/toolkit/BCM/documents/proposedmodes/eax/eax-spec.pdf - - :undocumented: __init__ - """ - - def __init__(self, factory, key, nonce, mac_len, cipher_params): - """EAX cipher mode""" - - self.block_size = factory.block_size - """The block size of the underlying cipher, in bytes.""" - - self.nonce = _copy_bytes(None, None, nonce) - """The nonce originally used to create the object.""" - - self._mac_len = mac_len - self._mac_tag = None # Cache for MAC tag - - # Allowed transitions after initialization - self._next = [self.update, self.encrypt, self.decrypt, - self.digest, self.verify] - - # MAC tag length - if not (4 <= self._mac_len <= self.block_size): - raise ValueError("Parameter 'mac_len' must not be larger than %d" - % self.block_size) - - # Nonce cannot be empty and must be a byte string - if len(self.nonce) == 0: - raise ValueError("Nonce cannot be empty in EAX mode") - if not is_buffer(nonce): - raise TypeError("nonce must be bytes, bytearray or memoryview") - - self._omac = [ - CMAC.new(key, - b'\x00' * (self.block_size - 1) + struct.pack('B', i), - ciphermod=factory, - cipher_params=cipher_params) - for i in range(0, 3) - ] - - # Compute MAC of nonce - self._omac[0].update(self.nonce) - self._signer = self._omac[1] - - # MAC of the nonce is also the initial counter for CTR encryption - counter_int = bytes_to_long(self._omac[0].digest()) - self._cipher = factory.new(key, - factory.MODE_CTR, - initial_value=counter_int, - nonce=b"", - **cipher_params) - - def update(self, assoc_data): - """Protect associated data - - If there is any associated data, the caller has to invoke - this function one or more times, before using - ``decrypt`` or ``encrypt``. - - By *associated data* it is meant any data (e.g. packet headers) that - will not be encrypted and will be transmitted in the clear. - However, the receiver is still able to detect any modification to it. - - If there is no associated data, this method must not be called. - - The caller may split associated data in segments of any size, and - invoke this method multiple times, each time with the next segment. - - :Parameters: - assoc_data : bytes/bytearray/memoryview - A piece of associated data. There are no restrictions on its size. - """ - - if self.update not in self._next: - raise TypeError("update() can only be called" - " immediately after initialization") - - self._next = [self.update, self.encrypt, self.decrypt, - self.digest, self.verify] - - self._signer.update(assoc_data) - return self - - def encrypt(self, plaintext, output=None): - """Encrypt data with the key and the parameters set at initialization. - - A cipher object is stateful: once you have encrypted a message - you cannot encrypt (or decrypt) another message using the same - object. - - The data to encrypt can be broken up in two or - more pieces and `encrypt` can be called multiple times. - - That is, the statement: - - >>> c.encrypt(a) + c.encrypt(b) - - is equivalent to: - - >>> c.encrypt(a+b) - - This function does not add any padding to the plaintext. - - :Parameters: - plaintext : bytes/bytearray/memoryview - The piece of data to encrypt. - It can be of any length. - :Keywords: - output : bytearray/memoryview - The location where the ciphertext must be written to. - If ``None``, the ciphertext is returned. - :Return: - If ``output`` is ``None``, the ciphertext as ``bytes``. - Otherwise, ``None``. - """ - - if self.encrypt not in self._next: - raise TypeError("encrypt() can only be called after" - " initialization or an update()") - self._next = [self.encrypt, self.digest] - ct = self._cipher.encrypt(plaintext, output=output) - if output is None: - self._omac[2].update(ct) - else: - self._omac[2].update(output) - return ct - - def decrypt(self, ciphertext, output=None): - """Decrypt data with the key and the parameters set at initialization. - - A cipher object is stateful: once you have decrypted a message - you cannot decrypt (or encrypt) another message with the same - object. - - The data to decrypt can be broken up in two or - more pieces and `decrypt` can be called multiple times. - - That is, the statement: - - >>> c.decrypt(a) + c.decrypt(b) - - is equivalent to: - - >>> c.decrypt(a+b) - - This function does not remove any padding from the plaintext. - - :Parameters: - ciphertext : bytes/bytearray/memoryview - The piece of data to decrypt. - It can be of any length. - :Keywords: - output : bytearray/memoryview - The location where the plaintext must be written to. - If ``None``, the plaintext is returned. - :Return: - If ``output`` is ``None``, the plaintext as ``bytes``. - Otherwise, ``None``. - """ - - if self.decrypt not in self._next: - raise TypeError("decrypt() can only be called" - " after initialization or an update()") - self._next = [self.decrypt, self.verify] - self._omac[2].update(ciphertext) - return self._cipher.decrypt(ciphertext, output=output) - - def digest(self): - """Compute the *binary* MAC tag. - - The caller invokes this function at the very end. - - This method returns the MAC that shall be sent to the receiver, - together with the ciphertext. - - :Return: the MAC, as a byte string. - """ - - if self.digest not in self._next: - raise TypeError("digest() cannot be called when decrypting" - " or validating a message") - self._next = [self.digest] - - if not self._mac_tag: - tag = b'\x00' * self.block_size - for i in range(3): - tag = strxor(tag, self._omac[i].digest()) - self._mac_tag = tag[:self._mac_len] - - return self._mac_tag - - def hexdigest(self): - """Compute the *printable* MAC tag. - - This method is like `digest`. - - :Return: the MAC, as a hexadecimal string. - """ - return "".join(["%02x" % bord(x) for x in self.digest()]) - - def verify(self, received_mac_tag): - """Validate the *binary* MAC tag. - - The caller invokes this function at the very end. - - This method checks if the decrypted message is indeed valid - (that is, if the key is correct) and it has not been - tampered with while in transit. - - :Parameters: - received_mac_tag : bytes/bytearray/memoryview - This is the *binary* MAC, as received from the sender. - :Raises MacMismatchError: - if the MAC does not match. The message has been tampered with - or the key is incorrect. - """ - - if self.verify not in self._next: - raise TypeError("verify() cannot be called" - " when encrypting a message") - self._next = [self.verify] - - if not self._mac_tag: - tag = b'\x00' * self.block_size - for i in range(3): - tag = strxor(tag, self._omac[i].digest()) - self._mac_tag = tag[:self._mac_len] - - secret = get_random_bytes(16) - - mac1 = BLAKE2s.new(digest_bits=160, key=secret, data=self._mac_tag) - mac2 = BLAKE2s.new(digest_bits=160, key=secret, data=received_mac_tag) - - if mac1.digest() != mac2.digest(): - raise ValueError("MAC check failed") - - def hexverify(self, hex_mac_tag): - """Validate the *printable* MAC tag. - - This method is like `verify`. - - :Parameters: - hex_mac_tag : string - This is the *printable* MAC, as received from the sender. - :Raises MacMismatchError: - if the MAC does not match. The message has been tampered with - or the key is incorrect. - """ - - self.verify(unhexlify(hex_mac_tag)) - - def encrypt_and_digest(self, plaintext, output=None): - """Perform encrypt() and digest() in one step. - - :Parameters: - plaintext : bytes/bytearray/memoryview - The piece of data to encrypt. - :Keywords: - output : bytearray/memoryview - The location where the ciphertext must be written to. - If ``None``, the ciphertext is returned. - :Return: - a tuple with two items: - - - the ciphertext, as ``bytes`` - - the MAC tag, as ``bytes`` - - The first item becomes ``None`` when the ``output`` parameter - specified a location for the result. - """ - - return self.encrypt(plaintext, output=output), self.digest() - - def decrypt_and_verify(self, ciphertext, received_mac_tag, output=None): - """Perform decrypt() and verify() in one step. - - :Parameters: - ciphertext : bytes/bytearray/memoryview - The piece of data to decrypt. - received_mac_tag : bytes/bytearray/memoryview - This is the *binary* MAC, as received from the sender. - :Keywords: - output : bytearray/memoryview - The location where the plaintext must be written to. - If ``None``, the plaintext is returned. - :Return: the plaintext as ``bytes`` or ``None`` when the ``output`` - parameter specified a location for the result. - :Raises MacMismatchError: - if the MAC does not match. The message has been tampered with - or the key is incorrect. - """ - - pt = self.decrypt(ciphertext, output=output) - self.verify(received_mac_tag) - return pt - - -def _create_eax_cipher(factory, **kwargs): - """Create a new block cipher, configured in EAX mode. - - :Parameters: - factory : module - A symmetric cipher module from `Crypto.Cipher` (like - `Crypto.Cipher.AES`). - - :Keywords: - key : bytes/bytearray/memoryview - The secret key to use in the symmetric cipher. - - nonce : bytes/bytearray/memoryview - A value that must never be reused for any other encryption. - There are no restrictions on its length, but it is recommended to use - at least 16 bytes. - - The nonce shall never repeat for two different messages encrypted with - the same key, but it does not need to be random. - - If not specified, a 16 byte long random string is used. - - mac_len : integer - Length of the MAC, in bytes. It must be no larger than the cipher - block bytes (which is the default). - """ - - try: - key = kwargs.pop("key") - nonce = kwargs.pop("nonce", None) - if nonce is None: - nonce = get_random_bytes(16) - mac_len = kwargs.pop("mac_len", factory.block_size) - except KeyError as e: - raise TypeError("Missing parameter: " + str(e)) - - return EaxMode(factory, key, nonce, mac_len, kwargs) diff --git a/Crypto/Cipher/_mode_eax.pyi b/Crypto/Cipher/_mode_eax.pyi deleted file mode 100644 index cbfa467..0000000 --- a/Crypto/Cipher/_mode_eax.pyi +++ /dev/null @@ -1,45 +0,0 @@ -from types import ModuleType -from typing import Any, Union, Tuple, Dict, overload, Optional - -Buffer = Union[bytes, bytearray, memoryview] - -__all__ = ['EaxMode'] - -class EaxMode(object): - block_size: int - nonce: bytes - - def __init__(self, - factory: ModuleType, - key: Buffer, - nonce: Buffer, - mac_len: int, - cipher_params: Dict) -> None: ... - - def update(self, assoc_data: Buffer) -> EaxMode: ... - - @overload - def encrypt(self, plaintext: Buffer) -> bytes: ... - @overload - def encrypt(self, plaintext: Buffer, output: Union[bytearray, memoryview]) -> None: ... - @overload - def decrypt(self, plaintext: Buffer) -> bytes: ... - @overload - def decrypt(self, plaintext: Buffer, output: Union[bytearray, memoryview]) -> None: ... - - def digest(self) -> bytes: ... - def hexdigest(self) -> str: ... - def verify(self, received_mac_tag: Buffer) -> None: ... - def hexverify(self, hex_mac_tag: str) -> None: ... - - @overload - def encrypt_and_digest(self, - plaintext: Buffer) -> Tuple[bytes, bytes]: ... - @overload - def encrypt_and_digest(self, - plaintext: Buffer, - output: Buffer) -> Tuple[None, bytes]: ... - def decrypt_and_verify(self, - ciphertext: Buffer, - received_mac_tag: Buffer, - output: Optional[Union[bytearray, memoryview]] = ...) -> bytes: ... diff --git a/Crypto/Cipher/_mode_ecb.py b/Crypto/Cipher/_mode_ecb.py deleted file mode 100644 index 3783357..0000000 --- a/Crypto/Cipher/_mode_ecb.py +++ /dev/null @@ -1,220 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Cipher/mode_ecb.py : ECB mode -# -# =================================================================== -# The contents of this file are dedicated to the public domain. To -# the extent that dedication to the public domain is not available, -# everyone is granted a worldwide, perpetual, royalty-free, -# non-exclusive license to exercise all rights associated with the -# contents of this file for any purpose whatsoever. -# No rights are reserved. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS -# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN -# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# =================================================================== - -""" -Electronic Code Book (ECB) mode. -""" - -__all__ = [ 'EcbMode' ] - -from Crypto.Util._raw_api import (load_pycryptodome_raw_lib, - VoidPointer, create_string_buffer, - get_raw_buffer, SmartPointer, - c_size_t, c_uint8_ptr, - is_writeable_buffer) - -raw_ecb_lib = load_pycryptodome_raw_lib("Crypto.Cipher._raw_ecb", """ - int ECB_start_operation(void *cipher, - void **pResult); - int ECB_encrypt(void *ecbState, - const uint8_t *in, - uint8_t *out, - size_t data_len); - int ECB_decrypt(void *ecbState, - const uint8_t *in, - uint8_t *out, - size_t data_len); - int ECB_stop_operation(void *state); - """ - ) - - -class EcbMode(object): - """*Electronic Code Book (ECB)*. - - This is the simplest encryption mode. Each of the plaintext blocks - is directly encrypted into a ciphertext block, independently of - any other block. - - This mode is dangerous because it exposes frequency of symbols - in your plaintext. Other modes (e.g. *CBC*) should be used instead. - - See `NIST SP800-38A`_ , Section 6.1. - - .. _`NIST SP800-38A` : http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf - - :undocumented: __init__ - """ - - def __init__(self, block_cipher): - """Create a new block cipher, configured in ECB mode. - - :Parameters: - block_cipher : C pointer - A smart pointer to the low-level block cipher instance. - """ - self.block_size = block_cipher.block_size - - self._state = VoidPointer() - result = raw_ecb_lib.ECB_start_operation(block_cipher.get(), - self._state.address_of()) - if result: - raise ValueError("Error %d while instantiating the ECB mode" - % result) - - # Ensure that object disposal of this Python object will (eventually) - # free the memory allocated by the raw library for the cipher - # mode - self._state = SmartPointer(self._state.get(), - raw_ecb_lib.ECB_stop_operation) - - # Memory allocated for the underlying block cipher is now owned - # by the cipher mode - block_cipher.release() - - def encrypt(self, plaintext, output=None): - """Encrypt data with the key set at initialization. - - The data to encrypt can be broken up in two or - more pieces and `encrypt` can be called multiple times. - - That is, the statement: - - >>> c.encrypt(a) + c.encrypt(b) - - is equivalent to: - - >>> c.encrypt(a+b) - - This function does not add any padding to the plaintext. - - :Parameters: - plaintext : bytes/bytearray/memoryview - The piece of data to encrypt. - The length must be multiple of the cipher block length. - :Keywords: - output : bytearray/memoryview - The location where the ciphertext must be written to. - If ``None``, the ciphertext is returned. - :Return: - If ``output`` is ``None``, the ciphertext is returned as ``bytes``. - Otherwise, ``None``. - """ - - if output is None: - ciphertext = create_string_buffer(len(plaintext)) - else: - ciphertext = output - - if not is_writeable_buffer(output): - raise TypeError("output must be a bytearray or a writeable memoryview") - - if len(plaintext) != len(output): - raise ValueError("output must have the same length as the input" - " (%d bytes)" % len(plaintext)) - - result = raw_ecb_lib.ECB_encrypt(self._state.get(), - c_uint8_ptr(plaintext), - c_uint8_ptr(ciphertext), - c_size_t(len(plaintext))) - if result: - if result == 3: - raise ValueError("Data must be aligned to block boundary in ECB mode") - raise ValueError("Error %d while encrypting in ECB mode" % result) - - if output is None: - return get_raw_buffer(ciphertext) - else: - return None - - def decrypt(self, ciphertext, output=None): - """Decrypt data with the key set at initialization. - - The data to decrypt can be broken up in two or - more pieces and `decrypt` can be called multiple times. - - That is, the statement: - - >>> c.decrypt(a) + c.decrypt(b) - - is equivalent to: - - >>> c.decrypt(a+b) - - This function does not remove any padding from the plaintext. - - :Parameters: - ciphertext : bytes/bytearray/memoryview - The piece of data to decrypt. - The length must be multiple of the cipher block length. - :Keywords: - output : bytearray/memoryview - The location where the plaintext must be written to. - If ``None``, the plaintext is returned. - :Return: - If ``output`` is ``None``, the plaintext is returned as ``bytes``. - Otherwise, ``None``. - """ - - if output is None: - plaintext = create_string_buffer(len(ciphertext)) - else: - plaintext = output - - if not is_writeable_buffer(output): - raise TypeError("output must be a bytearray or a writeable memoryview") - - if len(ciphertext) != len(output): - raise ValueError("output must have the same length as the input" - " (%d bytes)" % len(plaintext)) - - result = raw_ecb_lib.ECB_decrypt(self._state.get(), - c_uint8_ptr(ciphertext), - c_uint8_ptr(plaintext), - c_size_t(len(ciphertext))) - if result: - if result == 3: - raise ValueError("Data must be aligned to block boundary in ECB mode") - raise ValueError("Error %d while decrypting in ECB mode" % result) - - if output is None: - return get_raw_buffer(plaintext) - else: - return None - - -def _create_ecb_cipher(factory, **kwargs): - """Instantiate a cipher object that performs ECB encryption/decryption. - - :Parameters: - factory : module - The underlying block cipher, a module from ``Crypto.Cipher``. - - All keywords are passed to the underlying block cipher. - See the relevant documentation for details (at least ``key`` will need - to be present""" - - cipher_state = factory._create_base_cipher(kwargs) - cipher_state.block_size = factory.block_size - if kwargs: - raise TypeError("Unknown parameters for ECB: %s" % str(kwargs)) - return EcbMode(cipher_state) diff --git a/Crypto/Cipher/_mode_ecb.pyi b/Crypto/Cipher/_mode_ecb.pyi deleted file mode 100644 index 1772b23..0000000 --- a/Crypto/Cipher/_mode_ecb.pyi +++ /dev/null @@ -1,19 +0,0 @@ -from typing import Union, overload - -from Crypto.Util._raw_api import SmartPointer - -Buffer = Union[bytes, bytearray, memoryview] - -__all__ = [ 'EcbMode' ] - -class EcbMode(object): - def __init__(self, block_cipher: SmartPointer) -> None: ... - @overload - def encrypt(self, plaintext: Buffer) -> bytes: ... - @overload - def encrypt(self, plaintext: Buffer, output: Union[bytearray, memoryview]) -> None: ... - @overload - def decrypt(self, plaintext: Buffer) -> bytes: ... - @overload - def decrypt(self, plaintext: Buffer, output: Union[bytearray, memoryview]) -> None: ... - diff --git a/Crypto/Cipher/_mode_gcm.py b/Crypto/Cipher/_mode_gcm.py deleted file mode 100644 index da8e337..0000000 --- a/Crypto/Cipher/_mode_gcm.py +++ /dev/null @@ -1,620 +0,0 @@ -# =================================================================== -# -# Copyright (c) 2014, Legrandin -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# =================================================================== - -""" -Galois/Counter Mode (GCM). -""" - -__all__ = ['GcmMode'] - -from binascii import unhexlify - -from Crypto.Util.py3compat import bord, _copy_bytes - -from Crypto.Util._raw_api import is_buffer - -from Crypto.Util.number import long_to_bytes, bytes_to_long -from Crypto.Hash import BLAKE2s -from Crypto.Random import get_random_bytes - -from Crypto.Util._raw_api import (load_pycryptodome_raw_lib, VoidPointer, - create_string_buffer, get_raw_buffer, - SmartPointer, c_size_t, c_uint8_ptr) - -from Crypto.Util import _cpu_features - - -# C API by module implementing GHASH -_ghash_api_template = """ - int ghash_%imp%(uint8_t y_out[16], - const uint8_t block_data[], - size_t len, - const uint8_t y_in[16], - const void *exp_key); - int ghash_expand_%imp%(const uint8_t h[16], - void **ghash_tables); - int ghash_destroy_%imp%(void *ghash_tables); -""" - -def _build_impl(lib, postfix): - from collections import namedtuple - - funcs = ( "ghash", "ghash_expand", "ghash_destroy" ) - GHASH_Imp = namedtuple('_GHash_Imp', funcs) - try: - imp_funcs = [ getattr(lib, x + "_" + postfix) for x in funcs ] - except AttributeError: # Make sphinx stop complaining with its mocklib - imp_funcs = [ None ] * 3 - params = dict(zip(funcs, imp_funcs)) - return GHASH_Imp(**params) - - -def _get_ghash_portable(): - api = _ghash_api_template.replace("%imp%", "portable") - lib = load_pycryptodome_raw_lib("Crypto.Hash._ghash_portable", api) - result = _build_impl(lib, "portable") - return result -_ghash_portable = _get_ghash_portable() - - -def _get_ghash_clmul(): - """Return None if CLMUL implementation is not available""" - - if not _cpu_features.have_clmul(): - return None - try: - api = _ghash_api_template.replace("%imp%", "clmul") - lib = load_pycryptodome_raw_lib("Crypto.Hash._ghash_clmul", api) - result = _build_impl(lib, "clmul") - except OSError: - result = None - return result -_ghash_clmul = _get_ghash_clmul() - - -class _GHASH(object): - """GHASH function defined in NIST SP 800-38D, Algorithm 2. - - If X_1, X_2, .. X_m are the blocks of input data, the function - computes: - - X_1*H^{m} + X_2*H^{m-1} + ... + X_m*H - - in the Galois field GF(2^256) using the reducing polynomial - (x^128 + x^7 + x^2 + x + 1). - """ - - def __init__(self, subkey, ghash_c): - assert len(subkey) == 16 - - self.ghash_c = ghash_c - - self._exp_key = VoidPointer() - result = ghash_c.ghash_expand(c_uint8_ptr(subkey), - self._exp_key.address_of()) - if result: - raise ValueError("Error %d while expanding the GHASH key" % result) - - self._exp_key = SmartPointer(self._exp_key.get(), - ghash_c.ghash_destroy) - - # create_string_buffer always returns a string of zeroes - self._last_y = create_string_buffer(16) - - def update(self, block_data): - assert len(block_data) % 16 == 0 - - result = self.ghash_c.ghash(self._last_y, - c_uint8_ptr(block_data), - c_size_t(len(block_data)), - self._last_y, - self._exp_key.get()) - if result: - raise ValueError("Error %d while updating GHASH" % result) - - return self - - def digest(self): - return get_raw_buffer(self._last_y) - - -def enum(**enums): - return type('Enum', (), enums) - - -MacStatus = enum(PROCESSING_AUTH_DATA=1, PROCESSING_CIPHERTEXT=2) - - -class GcmMode(object): - """Galois Counter Mode (GCM). - - This is an Authenticated Encryption with Associated Data (`AEAD`_) mode. - It provides both confidentiality and authenticity. - - The header of the message may be left in the clear, if needed, and it will - still be subject to authentication. The decryption step tells the receiver - if the message comes from a source that really knowns the secret key. - Additionally, decryption detects if any part of the message - including the - header - has been modified or corrupted. - - This mode requires a *nonce*. - - This mode is only available for ciphers that operate on 128 bits blocks - (e.g. AES but not TDES). - - See `NIST SP800-38D`_. - - .. _`NIST SP800-38D`: http://csrc.nist.gov/publications/nistpubs/800-38D/SP-800-38D.pdf - .. _AEAD: http://blog.cryptographyengineering.com/2012/05/how-to-choose-authenticated-encryption.html - - :undocumented: __init__ - """ - - def __init__(self, factory, key, nonce, mac_len, cipher_params, ghash_c): - - self.block_size = factory.block_size - if self.block_size != 16: - raise ValueError("GCM mode is only available for ciphers" - " that operate on 128 bits blocks") - - if len(nonce) == 0: - raise ValueError("Nonce cannot be empty") - - if not is_buffer(nonce): - raise TypeError("Nonce must be bytes, bytearray or memoryview") - - # See NIST SP 800 38D, 5.2.1.1 - if len(nonce) > 2**64 - 1: - raise ValueError("Nonce exceeds maximum length") - - - self.nonce = _copy_bytes(None, None, nonce) - """Nonce""" - - self._factory = factory - self._key = _copy_bytes(None, None, key) - self._tag = None # Cache for MAC tag - - self._mac_len = mac_len - if not (4 <= mac_len <= 16): - raise ValueError("Parameter 'mac_len' must be in the range 4..16") - - # Allowed transitions after initialization - self._next = [self.update, self.encrypt, self.decrypt, - self.digest, self.verify] - - self._no_more_assoc_data = False - - # Length of associated data - self._auth_len = 0 - - # Length of the ciphertext or plaintext - self._msg_len = 0 - - # Step 1 in SP800-38D, Algorithm 4 (encryption) - Compute H - # See also Algorithm 5 (decryption) - hash_subkey = factory.new(key, - self._factory.MODE_ECB, - **cipher_params - ).encrypt(b'\x00' * 16) - - # Step 2 - Compute J0 - if len(self.nonce) == 12: - j0 = self.nonce + b"\x00\x00\x00\x01" - else: - fill = (16 - (len(nonce) % 16)) % 16 + 8 - ghash_in = (self.nonce + - b'\x00' * fill + - long_to_bytes(8 * len(nonce), 8)) - j0 = _GHASH(hash_subkey, ghash_c).update(ghash_in).digest() - - # Step 3 - Prepare GCTR cipher for encryption/decryption - nonce_ctr = j0[:12] - iv_ctr = (bytes_to_long(j0) + 1) & 0xFFFFFFFF - self._cipher = factory.new(key, - self._factory.MODE_CTR, - initial_value=iv_ctr, - nonce=nonce_ctr, - **cipher_params) - - # Step 5 - Bootstrat GHASH - self._signer = _GHASH(hash_subkey, ghash_c) - - # Step 6 - Prepare GCTR cipher for GMAC - self._tag_cipher = factory.new(key, - self._factory.MODE_CTR, - initial_value=j0, - nonce=b"", - **cipher_params) - - # Cache for data to authenticate - self._cache = b"" - - self._status = MacStatus.PROCESSING_AUTH_DATA - - def update(self, assoc_data): - """Protect associated data - - If there is any associated data, the caller has to invoke - this function one or more times, before using - ``decrypt`` or ``encrypt``. - - By *associated data* it is meant any data (e.g. packet headers) that - will not be encrypted and will be transmitted in the clear. - However, the receiver is still able to detect any modification to it. - In GCM, the *associated data* is also called - *additional authenticated data* (AAD). - - If there is no associated data, this method must not be called. - - The caller may split associated data in segments of any size, and - invoke this method multiple times, each time with the next segment. - - :Parameters: - assoc_data : bytes/bytearray/memoryview - A piece of associated data. There are no restrictions on its size. - """ - - if self.update not in self._next: - raise TypeError("update() can only be called" - " immediately after initialization") - - self._next = [self.update, self.encrypt, self.decrypt, - self.digest, self.verify] - - self._update(assoc_data) - self._auth_len += len(assoc_data) - - # See NIST SP 800 38D, 5.2.1.1 - if self._auth_len > 2**64 - 1: - raise ValueError("Additional Authenticated Data exceeds maximum length") - - return self - - def _update(self, data): - assert(len(self._cache) < 16) - - if len(self._cache) > 0: - filler = min(16 - len(self._cache), len(data)) - self._cache += _copy_bytes(None, filler, data) - data = data[filler:] - - if len(self._cache) < 16: - return - - # The cache is exactly one block - self._signer.update(self._cache) - self._cache = b"" - - update_len = len(data) // 16 * 16 - self._cache = _copy_bytes(update_len, None, data) - if update_len > 0: - self._signer.update(data[:update_len]) - - def _pad_cache_and_update(self): - assert(len(self._cache) < 16) - - # The authenticated data A is concatenated to the minimum - # number of zero bytes (possibly none) such that the - # - ciphertext C is aligned to the 16 byte boundary. - # See step 5 in section 7.1 - # - ciphertext C is aligned to the 16 byte boundary. - # See step 6 in section 7.2 - len_cache = len(self._cache) - if len_cache > 0: - self._update(b'\x00' * (16 - len_cache)) - - def encrypt(self, plaintext, output=None): - """Encrypt data with the key and the parameters set at initialization. - - A cipher object is stateful: once you have encrypted a message - you cannot encrypt (or decrypt) another message using the same - object. - - The data to encrypt can be broken up in two or - more pieces and `encrypt` can be called multiple times. - - That is, the statement: - - >>> c.encrypt(a) + c.encrypt(b) - - is equivalent to: - - >>> c.encrypt(a+b) - - This function does not add any padding to the plaintext. - - :Parameters: - plaintext : bytes/bytearray/memoryview - The piece of data to encrypt. - It can be of any length. - :Keywords: - output : bytearray/memoryview - The location where the ciphertext must be written to. - If ``None``, the ciphertext is returned. - :Return: - If ``output`` is ``None``, the ciphertext as ``bytes``. - Otherwise, ``None``. - """ - - if self.encrypt not in self._next: - raise TypeError("encrypt() can only be called after" - " initialization or an update()") - self._next = [self.encrypt, self.digest] - - ciphertext = self._cipher.encrypt(plaintext, output=output) - - if self._status == MacStatus.PROCESSING_AUTH_DATA: - self._pad_cache_and_update() - self._status = MacStatus.PROCESSING_CIPHERTEXT - - self._update(ciphertext if output is None else output) - self._msg_len += len(plaintext) - - # See NIST SP 800 38D, 5.2.1.1 - if self._msg_len > 2**39 - 256: - raise ValueError("Plaintext exceeds maximum length") - - return ciphertext - - def decrypt(self, ciphertext, output=None): - """Decrypt data with the key and the parameters set at initialization. - - A cipher object is stateful: once you have decrypted a message - you cannot decrypt (or encrypt) another message with the same - object. - - The data to decrypt can be broken up in two or - more pieces and `decrypt` can be called multiple times. - - That is, the statement: - - >>> c.decrypt(a) + c.decrypt(b) - - is equivalent to: - - >>> c.decrypt(a+b) - - This function does not remove any padding from the plaintext. - - :Parameters: - ciphertext : bytes/bytearray/memoryview - The piece of data to decrypt. - It can be of any length. - :Keywords: - output : bytearray/memoryview - The location where the plaintext must be written to. - If ``None``, the plaintext is returned. - :Return: - If ``output`` is ``None``, the plaintext as ``bytes``. - Otherwise, ``None``. - """ - - if self.decrypt not in self._next: - raise TypeError("decrypt() can only be called" - " after initialization or an update()") - self._next = [self.decrypt, self.verify] - - if self._status == MacStatus.PROCESSING_AUTH_DATA: - self._pad_cache_and_update() - self._status = MacStatus.PROCESSING_CIPHERTEXT - - self._update(ciphertext) - self._msg_len += len(ciphertext) - - return self._cipher.decrypt(ciphertext, output=output) - - def digest(self): - """Compute the *binary* MAC tag in an AEAD mode. - - The caller invokes this function at the very end. - - This method returns the MAC that shall be sent to the receiver, - together with the ciphertext. - - :Return: the MAC, as a byte string. - """ - - if self.digest not in self._next: - raise TypeError("digest() cannot be called when decrypting" - " or validating a message") - self._next = [self.digest] - - return self._compute_mac() - - def _compute_mac(self): - """Compute MAC without any FSM checks.""" - - if self._tag: - return self._tag - - # Step 5 in NIST SP 800-38D, Algorithm 4 - Compute S - self._pad_cache_and_update() - self._update(long_to_bytes(8 * self._auth_len, 8)) - self._update(long_to_bytes(8 * self._msg_len, 8)) - s_tag = self._signer.digest() - - # Step 6 - Compute T - self._tag = self._tag_cipher.encrypt(s_tag)[:self._mac_len] - - return self._tag - - def hexdigest(self): - """Compute the *printable* MAC tag. - - This method is like `digest`. - - :Return: the MAC, as a hexadecimal string. - """ - return "".join(["%02x" % bord(x) for x in self.digest()]) - - def verify(self, received_mac_tag): - """Validate the *binary* MAC tag. - - The caller invokes this function at the very end. - - This method checks if the decrypted message is indeed valid - (that is, if the key is correct) and it has not been - tampered with while in transit. - - :Parameters: - received_mac_tag : bytes/bytearray/memoryview - This is the *binary* MAC, as received from the sender. - :Raises ValueError: - if the MAC does not match. The message has been tampered with - or the key is incorrect. - """ - - if self.verify not in self._next: - raise TypeError("verify() cannot be called" - " when encrypting a message") - self._next = [self.verify] - - secret = get_random_bytes(16) - - mac1 = BLAKE2s.new(digest_bits=160, key=secret, - data=self._compute_mac()) - mac2 = BLAKE2s.new(digest_bits=160, key=secret, - data=received_mac_tag) - - if mac1.digest() != mac2.digest(): - raise ValueError("MAC check failed") - - def hexverify(self, hex_mac_tag): - """Validate the *printable* MAC tag. - - This method is like `verify`. - - :Parameters: - hex_mac_tag : string - This is the *printable* MAC, as received from the sender. - :Raises ValueError: - if the MAC does not match. The message has been tampered with - or the key is incorrect. - """ - - self.verify(unhexlify(hex_mac_tag)) - - def encrypt_and_digest(self, plaintext, output=None): - """Perform encrypt() and digest() in one step. - - :Parameters: - plaintext : bytes/bytearray/memoryview - The piece of data to encrypt. - :Keywords: - output : bytearray/memoryview - The location where the ciphertext must be written to. - If ``None``, the ciphertext is returned. - :Return: - a tuple with two items: - - - the ciphertext, as ``bytes`` - - the MAC tag, as ``bytes`` - - The first item becomes ``None`` when the ``output`` parameter - specified a location for the result. - """ - - return self.encrypt(plaintext, output=output), self.digest() - - def decrypt_and_verify(self, ciphertext, received_mac_tag, output=None): - """Perform decrypt() and verify() in one step. - - :Parameters: - ciphertext : bytes/bytearray/memoryview - The piece of data to decrypt. - received_mac_tag : byte string - This is the *binary* MAC, as received from the sender. - :Keywords: - output : bytearray/memoryview - The location where the plaintext must be written to. - If ``None``, the plaintext is returned. - :Return: the plaintext as ``bytes`` or ``None`` when the ``output`` - parameter specified a location for the result. - :Raises ValueError: - if the MAC does not match. The message has been tampered with - or the key is incorrect. - """ - - plaintext = self.decrypt(ciphertext, output=output) - self.verify(received_mac_tag) - return plaintext - - -def _create_gcm_cipher(factory, **kwargs): - """Create a new block cipher, configured in Galois Counter Mode (GCM). - - :Parameters: - factory : module - A block cipher module, taken from `Crypto.Cipher`. - The cipher must have block length of 16 bytes. - GCM has been only defined for `Crypto.Cipher.AES`. - - :Keywords: - key : bytes/bytearray/memoryview - The secret key to use in the symmetric cipher. - It must be 16 (e.g. *AES-128*), 24 (e.g. *AES-192*) - or 32 (e.g. *AES-256*) bytes long. - - nonce : bytes/bytearray/memoryview - A value that must never be reused for any other encryption. - - There are no restrictions on its length, - but it is recommended to use at least 16 bytes. - - The nonce shall never repeat for two - different messages encrypted with the same key, - but it does not need to be random. - - If not provided, a 16 byte nonce will be randomly created. - - mac_len : integer - Length of the MAC, in bytes. - It must be no larger than 16 bytes (which is the default). - """ - - try: - key = kwargs.pop("key") - except KeyError as e: - raise TypeError("Missing parameter:" + str(e)) - - nonce = kwargs.pop("nonce", None) - if nonce is None: - nonce = get_random_bytes(16) - mac_len = kwargs.pop("mac_len", 16) - - # Not documented - only used for testing - use_clmul = kwargs.pop("use_clmul", True) - if use_clmul and _ghash_clmul: - ghash_c = _ghash_clmul - else: - ghash_c = _ghash_portable - - return GcmMode(factory, key, nonce, mac_len, kwargs, ghash_c) diff --git a/Crypto/Cipher/_mode_gcm.pyi b/Crypto/Cipher/_mode_gcm.pyi deleted file mode 100644 index 8912955..0000000 --- a/Crypto/Cipher/_mode_gcm.pyi +++ /dev/null @@ -1,45 +0,0 @@ -from types import ModuleType -from typing import Union, Tuple, Dict, overload, Optional - -__all__ = ['GcmMode'] - -Buffer = Union[bytes, bytearray, memoryview] - -class GcmMode(object): - block_size: int - nonce: Buffer - - def __init__(self, - factory: ModuleType, - key: Buffer, - nonce: Buffer, - mac_len: int, - cipher_params: Dict) -> None: ... - - def update(self, assoc_data: Buffer) -> GcmMode: ... - - @overload - def encrypt(self, plaintext: Buffer) -> bytes: ... - @overload - def encrypt(self, plaintext: Buffer, output: Union[bytearray, memoryview]) -> None: ... - @overload - def decrypt(self, plaintext: Buffer) -> bytes: ... - @overload - def decrypt(self, plaintext: Buffer, output: Union[bytearray, memoryview]) -> None: ... - - def digest(self) -> bytes: ... - def hexdigest(self) -> str: ... - def verify(self, received_mac_tag: Buffer) -> None: ... - def hexverify(self, hex_mac_tag: str) -> None: ... - - @overload - def encrypt_and_digest(self, - plaintext: Buffer) -> Tuple[bytes, bytes]: ... - @overload - def encrypt_and_digest(self, - plaintext: Buffer, - output: Buffer) -> Tuple[None, bytes]: ... - def decrypt_and_verify(self, - ciphertext: Buffer, - received_mac_tag: Buffer, - output: Optional[Union[bytearray, memoryview]] = ...) -> bytes: ... diff --git a/Crypto/Cipher/_mode_ocb.py b/Crypto/Cipher/_mode_ocb.py deleted file mode 100644 index 27758b1..0000000 --- a/Crypto/Cipher/_mode_ocb.py +++ /dev/null @@ -1,525 +0,0 @@ -# =================================================================== -# -# Copyright (c) 2014, Legrandin -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# =================================================================== - -""" -Offset Codebook (OCB) mode. - -OCB is Authenticated Encryption with Associated Data (AEAD) cipher mode -designed by Prof. Phillip Rogaway and specified in `RFC7253`_. - -The algorithm provides both authenticity and privacy, it is very efficient, -it uses only one key and it can be used in online mode (so that encryption -or decryption can start before the end of the message is available). - -This module implements the third and last variant of OCB (OCB3) and it only -works in combination with a 128-bit block symmetric cipher, like AES. - -OCB is patented in US but `free licenses`_ exist for software implementations -meant for non-military purposes. - -Example: - >>> from Crypto.Cipher import AES - >>> from Crypto.Random import get_random_bytes - >>> - >>> key = get_random_bytes(32) - >>> cipher = AES.new(key, AES.MODE_OCB) - >>> plaintext = b"Attack at dawn" - >>> ciphertext, mac = cipher.encrypt_and_digest(plaintext) - >>> # Deliver cipher.nonce, ciphertext and mac - ... - >>> cipher = AES.new(key, AES.MODE_OCB, nonce=nonce) - >>> try: - >>> plaintext = cipher.decrypt_and_verify(ciphertext, mac) - >>> except ValueError: - >>> print "Invalid message" - >>> else: - >>> print plaintext - -:undocumented: __package__ - -.. _RFC7253: http://www.rfc-editor.org/info/rfc7253 -.. _free licenses: http://web.cs.ucdavis.edu/~rogaway/ocb/license.htm -""" - -import struct -from binascii import unhexlify - -from Crypto.Util.py3compat import bord, _copy_bytes -from Crypto.Util.number import long_to_bytes, bytes_to_long -from Crypto.Util.strxor import strxor - -from Crypto.Hash import BLAKE2s -from Crypto.Random import get_random_bytes - -from Crypto.Util._raw_api import (load_pycryptodome_raw_lib, VoidPointer, - create_string_buffer, get_raw_buffer, - SmartPointer, c_size_t, c_uint8_ptr, - is_buffer) - -_raw_ocb_lib = load_pycryptodome_raw_lib("Crypto.Cipher._raw_ocb", """ - int OCB_start_operation(void *cipher, - const uint8_t *offset_0, - size_t offset_0_len, - void **pState); - int OCB_encrypt(void *state, - const uint8_t *in, - uint8_t *out, - size_t data_len); - int OCB_decrypt(void *state, - const uint8_t *in, - uint8_t *out, - size_t data_len); - int OCB_update(void *state, - const uint8_t *in, - size_t data_len); - int OCB_digest(void *state, - uint8_t *tag, - size_t tag_len); - int OCB_stop_operation(void *state); - """) - - -class OcbMode(object): - """Offset Codebook (OCB) mode. - - :undocumented: __init__ - """ - - def __init__(self, factory, nonce, mac_len, cipher_params): - - if factory.block_size != 16: - raise ValueError("OCB mode is only available for ciphers" - " that operate on 128 bits blocks") - - self.block_size = 16 - """The block size of the underlying cipher, in bytes.""" - - self.nonce = _copy_bytes(None, None, nonce) - """Nonce used for this session.""" - if len(nonce) not in range(1, 16): - raise ValueError("Nonce must be at most 15 bytes long") - if not is_buffer(nonce): - raise TypeError("Nonce must be bytes, bytearray or memoryview") - - self._mac_len = mac_len - if not 8 <= mac_len <= 16: - raise ValueError("MAC tag must be between 8 and 16 bytes long") - - # Cache for MAC tag - self._mac_tag = None - - # Cache for unaligned associated data - self._cache_A = b"" - - # Cache for unaligned ciphertext/plaintext - self._cache_P = b"" - - # Allowed transitions after initialization - self._next = [self.update, self.encrypt, self.decrypt, - self.digest, self.verify] - - # Compute Offset_0 - params_without_key = dict(cipher_params) - key = params_without_key.pop("key") - nonce = (struct.pack('B', self._mac_len << 4 & 0xFF) + - b'\x00' * (14 - len(nonce)) + - b'\x01' + self.nonce) - - bottom_bits = bord(nonce[15]) & 0x3F # 6 bits, 0..63 - top_bits = bord(nonce[15]) & 0xC0 # 2 bits - - ktop_cipher = factory.new(key, - factory.MODE_ECB, - **params_without_key) - ktop = ktop_cipher.encrypt(struct.pack('15sB', - nonce[:15], - top_bits)) - - stretch = ktop + strxor(ktop[:8], ktop[1:9]) # 192 bits - offset_0 = long_to_bytes(bytes_to_long(stretch) >> - (64 - bottom_bits), 24)[8:] - - # Create low-level cipher instance - raw_cipher = factory._create_base_cipher(cipher_params) - if cipher_params: - raise TypeError("Unknown keywords: " + str(cipher_params)) - - self._state = VoidPointer() - result = _raw_ocb_lib.OCB_start_operation(raw_cipher.get(), - offset_0, - c_size_t(len(offset_0)), - self._state.address_of()) - if result: - raise ValueError("Error %d while instantiating the OCB mode" - % result) - - # Ensure that object disposal of this Python object will (eventually) - # free the memory allocated by the raw library for the cipher mode - self._state = SmartPointer(self._state.get(), - _raw_ocb_lib.OCB_stop_operation) - - # Memory allocated for the underlying block cipher is now owed - # by the cipher mode - raw_cipher.release() - - def _update(self, assoc_data, assoc_data_len): - result = _raw_ocb_lib.OCB_update(self._state.get(), - c_uint8_ptr(assoc_data), - c_size_t(assoc_data_len)) - if result: - raise ValueError("Error %d while computing MAC in OCB mode" % result) - - def update(self, assoc_data): - """Process the associated data. - - If there is any associated data, the caller has to invoke - this method one or more times, before using - ``decrypt`` or ``encrypt``. - - By *associated data* it is meant any data (e.g. packet headers) that - will not be encrypted and will be transmitted in the clear. - However, the receiver shall still able to detect modifications. - - If there is no associated data, this method must not be called. - - The caller may split associated data in segments of any size, and - invoke this method multiple times, each time with the next segment. - - :Parameters: - assoc_data : bytes/bytearray/memoryview - A piece of associated data. - """ - - if self.update not in self._next: - raise TypeError("update() can only be called" - " immediately after initialization") - - self._next = [self.encrypt, self.decrypt, self.digest, - self.verify, self.update] - - if len(self._cache_A) > 0: - filler = min(16 - len(self._cache_A), len(assoc_data)) - self._cache_A += _copy_bytes(None, filler, assoc_data) - assoc_data = assoc_data[filler:] - - if len(self._cache_A) < 16: - return self - - # Clear the cache, and proceeding with any other aligned data - self._cache_A, seg = b"", self._cache_A - self.update(seg) - - update_len = len(assoc_data) // 16 * 16 - self._cache_A = _copy_bytes(update_len, None, assoc_data) - self._update(assoc_data, update_len) - return self - - def _transcrypt_aligned(self, in_data, in_data_len, - trans_func, trans_desc): - - out_data = create_string_buffer(in_data_len) - result = trans_func(self._state.get(), - in_data, - out_data, - c_size_t(in_data_len)) - if result: - raise ValueError("Error %d while %sing in OCB mode" - % (result, trans_desc)) - return get_raw_buffer(out_data) - - def _transcrypt(self, in_data, trans_func, trans_desc): - # Last piece to encrypt/decrypt - if in_data is None: - out_data = self._transcrypt_aligned(self._cache_P, - len(self._cache_P), - trans_func, - trans_desc) - self._cache_P = b"" - return out_data - - # Try to fill up the cache, if it already contains something - prefix = b"" - if len(self._cache_P) > 0: - filler = min(16 - len(self._cache_P), len(in_data)) - self._cache_P += _copy_bytes(None, filler, in_data) - in_data = in_data[filler:] - - if len(self._cache_P) < 16: - # We could not manage to fill the cache, so there is certainly - # no output yet. - return b"" - - # Clear the cache, and proceeding with any other aligned data - prefix = self._transcrypt_aligned(self._cache_P, - len(self._cache_P), - trans_func, - trans_desc) - self._cache_P = b"" - - # Process data in multiples of the block size - trans_len = len(in_data) // 16 * 16 - result = self._transcrypt_aligned(c_uint8_ptr(in_data), - trans_len, - trans_func, - trans_desc) - if prefix: - result = prefix + result - - # Left-over - self._cache_P = _copy_bytes(trans_len, None, in_data) - - return result - - def encrypt(self, plaintext=None): - """Encrypt the next piece of plaintext. - - After the entire plaintext has been passed (but before `digest`), - you **must** call this method one last time with no arguments to collect - the final piece of ciphertext. - - If possible, use the method `encrypt_and_digest` instead. - - :Parameters: - plaintext : bytes/bytearray/memoryview - The next piece of data to encrypt or ``None`` to signify - that encryption has finished and that any remaining ciphertext - has to be produced. - :Return: - the ciphertext, as a byte string. - Its length may not match the length of the *plaintext*. - """ - - if self.encrypt not in self._next: - raise TypeError("encrypt() can only be called after" - " initialization or an update()") - - if plaintext is None: - self._next = [self.digest] - else: - self._next = [self.encrypt] - return self._transcrypt(plaintext, _raw_ocb_lib.OCB_encrypt, "encrypt") - - def decrypt(self, ciphertext=None): - """Decrypt the next piece of ciphertext. - - After the entire ciphertext has been passed (but before `verify`), - you **must** call this method one last time with no arguments to collect - the remaining piece of plaintext. - - If possible, use the method `decrypt_and_verify` instead. - - :Parameters: - ciphertext : bytes/bytearray/memoryview - The next piece of data to decrypt or ``None`` to signify - that decryption has finished and that any remaining plaintext - has to be produced. - :Return: - the plaintext, as a byte string. - Its length may not match the length of the *ciphertext*. - """ - - if self.decrypt not in self._next: - raise TypeError("decrypt() can only be called after" - " initialization or an update()") - - if ciphertext is None: - self._next = [self.verify] - else: - self._next = [self.decrypt] - return self._transcrypt(ciphertext, - _raw_ocb_lib.OCB_decrypt, - "decrypt") - - def _compute_mac_tag(self): - - if self._mac_tag is not None: - return - - if self._cache_A: - self._update(self._cache_A, len(self._cache_A)) - self._cache_A = b"" - - mac_tag = create_string_buffer(16) - result = _raw_ocb_lib.OCB_digest(self._state.get(), - mac_tag, - c_size_t(len(mac_tag)) - ) - if result: - raise ValueError("Error %d while computing digest in OCB mode" - % result) - self._mac_tag = get_raw_buffer(mac_tag)[:self._mac_len] - - def digest(self): - """Compute the *binary* MAC tag. - - Call this method after the final `encrypt` (the one with no arguments) - to obtain the MAC tag. - - The MAC tag is needed by the receiver to determine authenticity - of the message. - - :Return: the MAC, as a byte string. - """ - - if self.digest not in self._next: - raise TypeError("digest() cannot be called now for this cipher") - - assert(len(self._cache_P) == 0) - - self._next = [self.digest] - - if self._mac_tag is None: - self._compute_mac_tag() - - return self._mac_tag - - def hexdigest(self): - """Compute the *printable* MAC tag. - - This method is like `digest`. - - :Return: the MAC, as a hexadecimal string. - """ - return "".join(["%02x" % bord(x) for x in self.digest()]) - - def verify(self, received_mac_tag): - """Validate the *binary* MAC tag. - - Call this method after the final `decrypt` (the one with no arguments) - to check if the message is authentic and valid. - - :Parameters: - received_mac_tag : bytes/bytearray/memoryview - This is the *binary* MAC, as received from the sender. - :Raises ValueError: - if the MAC does not match. The message has been tampered with - or the key is incorrect. - """ - - if self.verify not in self._next: - raise TypeError("verify() cannot be called now for this cipher") - - assert(len(self._cache_P) == 0) - - self._next = [self.verify] - - if self._mac_tag is None: - self._compute_mac_tag() - - secret = get_random_bytes(16) - mac1 = BLAKE2s.new(digest_bits=160, key=secret, data=self._mac_tag) - mac2 = BLAKE2s.new(digest_bits=160, key=secret, data=received_mac_tag) - - if mac1.digest() != mac2.digest(): - raise ValueError("MAC check failed") - - def hexverify(self, hex_mac_tag): - """Validate the *printable* MAC tag. - - This method is like `verify`. - - :Parameters: - hex_mac_tag : string - This is the *printable* MAC, as received from the sender. - :Raises ValueError: - if the MAC does not match. The message has been tampered with - or the key is incorrect. - """ - - self.verify(unhexlify(hex_mac_tag)) - - def encrypt_and_digest(self, plaintext): - """Encrypt the message and create the MAC tag in one step. - - :Parameters: - plaintext : bytes/bytearray/memoryview - The entire message to encrypt. - :Return: - a tuple with two byte strings: - - - the encrypted data - - the MAC - """ - - return self.encrypt(plaintext) + self.encrypt(), self.digest() - - def decrypt_and_verify(self, ciphertext, received_mac_tag): - """Decrypted the message and verify its authenticity in one step. - - :Parameters: - ciphertext : bytes/bytearray/memoryview - The entire message to decrypt. - received_mac_tag : byte string - This is the *binary* MAC, as received from the sender. - - :Return: the decrypted data (byte string). - :Raises ValueError: - if the MAC does not match. The message has been tampered with - or the key is incorrect. - """ - - plaintext = self.decrypt(ciphertext) + self.decrypt() - self.verify(received_mac_tag) - return plaintext - - -def _create_ocb_cipher(factory, **kwargs): - """Create a new block cipher, configured in OCB mode. - - :Parameters: - factory : module - A symmetric cipher module from `Crypto.Cipher` - (like `Crypto.Cipher.AES`). - - :Keywords: - nonce : bytes/bytearray/memoryview - A value that must never be reused for any other encryption. - Its length can vary from 1 to 15 bytes. - If not specified, a random 15 bytes long nonce is generated. - - mac_len : integer - Length of the MAC, in bytes. - It must be in the range ``[8..16]``. - The default is 16 (128 bits). - - Any other keyword will be passed to the underlying block cipher. - See the relevant documentation for details (at least ``key`` will need - to be present). - """ - - try: - nonce = kwargs.pop("nonce", None) - if nonce is None: - nonce = get_random_bytes(15) - mac_len = kwargs.pop("mac_len", 16) - except KeyError as e: - raise TypeError("Keyword missing: " + str(e)) - - return OcbMode(factory, nonce, mac_len, kwargs) diff --git a/Crypto/Cipher/_mode_ocb.pyi b/Crypto/Cipher/_mode_ocb.pyi deleted file mode 100644 index a1909fc..0000000 --- a/Crypto/Cipher/_mode_ocb.pyi +++ /dev/null @@ -1,36 +0,0 @@ -from types import ModuleType -from typing import Union, Any, Optional, Tuple, Dict, overload - -Buffer = Union[bytes, bytearray, memoryview] - -class OcbMode(object): - block_size: int - nonce: Buffer - - def __init__(self, - factory: ModuleType, - nonce: Buffer, - mac_len: int, - cipher_params: Dict) -> None: ... - - def update(self, assoc_data: Buffer) -> OcbMode: ... - - @overload - def encrypt(self, plaintext: Buffer) -> bytes: ... - @overload - def encrypt(self, plaintext: Buffer, output: Union[bytearray, memoryview]) -> None: ... - @overload - def decrypt(self, plaintext: Buffer) -> bytes: ... - @overload - def decrypt(self, plaintext: Buffer, output: Union[bytearray, memoryview]) -> None: ... - - def digest(self) -> bytes: ... - def hexdigest(self) -> str: ... - def verify(self, received_mac_tag: Buffer) -> None: ... - def hexverify(self, hex_mac_tag: str) -> None: ... - - def encrypt_and_digest(self, - plaintext: Buffer) -> Tuple[bytes, bytes]: ... - def decrypt_and_verify(self, - ciphertext: Buffer, - received_mac_tag: Buffer) -> bytes: ... diff --git a/Crypto/Cipher/_mode_ofb.py b/Crypto/Cipher/_mode_ofb.py deleted file mode 100644 index 958f6d0..0000000 --- a/Crypto/Cipher/_mode_ofb.py +++ /dev/null @@ -1,282 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Cipher/mode_ofb.py : OFB mode -# -# =================================================================== -# The contents of this file are dedicated to the public domain. To -# the extent that dedication to the public domain is not available, -# everyone is granted a worldwide, perpetual, royalty-free, -# non-exclusive license to exercise all rights associated with the -# contents of this file for any purpose whatsoever. -# No rights are reserved. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS -# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN -# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# =================================================================== - -""" -Output Feedback (CFB) mode. -""" - -__all__ = ['OfbMode'] - -from Crypto.Util.py3compat import _copy_bytes -from Crypto.Util._raw_api import (load_pycryptodome_raw_lib, VoidPointer, - create_string_buffer, get_raw_buffer, - SmartPointer, c_size_t, c_uint8_ptr, - is_writeable_buffer) - -from Crypto.Random import get_random_bytes - -raw_ofb_lib = load_pycryptodome_raw_lib("Crypto.Cipher._raw_ofb", """ - int OFB_start_operation(void *cipher, - const uint8_t iv[], - size_t iv_len, - void **pResult); - int OFB_encrypt(void *ofbState, - const uint8_t *in, - uint8_t *out, - size_t data_len); - int OFB_decrypt(void *ofbState, - const uint8_t *in, - uint8_t *out, - size_t data_len); - int OFB_stop_operation(void *state); - """ - ) - - -class OfbMode(object): - """*Output FeedBack (OFB)*. - - This mode is very similar to CBC, but it - transforms the underlying block cipher into a stream cipher. - - The keystream is the iterated block encryption of the - previous ciphertext block. - - An Initialization Vector (*IV*) is required. - - See `NIST SP800-38A`_ , Section 6.4. - - .. _`NIST SP800-38A` : http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf - - :undocumented: __init__ - """ - - def __init__(self, block_cipher, iv): - """Create a new block cipher, configured in OFB mode. - - :Parameters: - block_cipher : C pointer - A smart pointer to the low-level block cipher instance. - - iv : bytes/bytearray/memoryview - The initialization vector to use for encryption or decryption. - It is as long as the cipher block. - - **The IV must be a nonce, to to be reused for any other - message**. It shall be a nonce or a random value. - - Reusing the *IV* for encryptions performed with the same key - compromises confidentiality. - """ - - self._state = VoidPointer() - result = raw_ofb_lib.OFB_start_operation(block_cipher.get(), - c_uint8_ptr(iv), - c_size_t(len(iv)), - self._state.address_of()) - if result: - raise ValueError("Error %d while instantiating the OFB mode" - % result) - - # Ensure that object disposal of this Python object will (eventually) - # free the memory allocated by the raw library for the cipher mode - self._state = SmartPointer(self._state.get(), - raw_ofb_lib.OFB_stop_operation) - - # Memory allocated for the underlying block cipher is now owed - # by the cipher mode - block_cipher.release() - - self.block_size = len(iv) - """The block size of the underlying cipher, in bytes.""" - - self.iv = _copy_bytes(None, None, iv) - """The Initialization Vector originally used to create the object. - The value does not change.""" - - self.IV = self.iv - """Alias for `iv`""" - - self._next = [ self.encrypt, self.decrypt ] - - def encrypt(self, plaintext, output=None): - """Encrypt data with the key and the parameters set at initialization. - - A cipher object is stateful: once you have encrypted a message - you cannot encrypt (or decrypt) another message using the same - object. - - The data to encrypt can be broken up in two or - more pieces and `encrypt` can be called multiple times. - - That is, the statement: - - >>> c.encrypt(a) + c.encrypt(b) - - is equivalent to: - - >>> c.encrypt(a+b) - - This function does not add any padding to the plaintext. - - :Parameters: - plaintext : bytes/bytearray/memoryview - The piece of data to encrypt. - It can be of any length. - :Keywords: - output : bytearray/memoryview - The location where the ciphertext must be written to. - If ``None``, the ciphertext is returned. - :Return: - If ``output`` is ``None``, the ciphertext is returned as ``bytes``. - Otherwise, ``None``. - """ - - if self.encrypt not in self._next: - raise TypeError("encrypt() cannot be called after decrypt()") - self._next = [ self.encrypt ] - - if output is None: - ciphertext = create_string_buffer(len(plaintext)) - else: - ciphertext = output - - if not is_writeable_buffer(output): - raise TypeError("output must be a bytearray or a writeable memoryview") - - if len(plaintext) != len(output): - raise ValueError("output must have the same length as the input" - " (%d bytes)" % len(plaintext)) - - result = raw_ofb_lib.OFB_encrypt(self._state.get(), - c_uint8_ptr(plaintext), - c_uint8_ptr(ciphertext), - c_size_t(len(plaintext))) - if result: - raise ValueError("Error %d while encrypting in OFB mode" % result) - - if output is None: - return get_raw_buffer(ciphertext) - else: - return None - - def decrypt(self, ciphertext, output=None): - """Decrypt data with the key and the parameters set at initialization. - - A cipher object is stateful: once you have decrypted a message - you cannot decrypt (or encrypt) another message with the same - object. - - The data to decrypt can be broken up in two or - more pieces and `decrypt` can be called multiple times. - - That is, the statement: - - >>> c.decrypt(a) + c.decrypt(b) - - is equivalent to: - - >>> c.decrypt(a+b) - - This function does not remove any padding from the plaintext. - - :Parameters: - ciphertext : bytes/bytearray/memoryview - The piece of data to decrypt. - It can be of any length. - :Keywords: - output : bytearray/memoryview - The location where the plaintext is written to. - If ``None``, the plaintext is returned. - :Return: - If ``output`` is ``None``, the plaintext is returned as ``bytes``. - Otherwise, ``None``. - """ - - if self.decrypt not in self._next: - raise TypeError("decrypt() cannot be called after encrypt()") - self._next = [ self.decrypt ] - - if output is None: - plaintext = create_string_buffer(len(ciphertext)) - else: - plaintext = output - - if not is_writeable_buffer(output): - raise TypeError("output must be a bytearray or a writeable memoryview") - - if len(ciphertext) != len(output): - raise ValueError("output must have the same length as the input" - " (%d bytes)" % len(plaintext)) - - result = raw_ofb_lib.OFB_decrypt(self._state.get(), - c_uint8_ptr(ciphertext), - c_uint8_ptr(plaintext), - c_size_t(len(ciphertext))) - if result: - raise ValueError("Error %d while decrypting in OFB mode" % result) - - if output is None: - return get_raw_buffer(plaintext) - else: - return None - - -def _create_ofb_cipher(factory, **kwargs): - """Instantiate a cipher object that performs OFB encryption/decryption. - - :Parameters: - factory : module - The underlying block cipher, a module from ``Crypto.Cipher``. - - :Keywords: - iv : bytes/bytearray/memoryview - The IV to use for OFB. - - IV : bytes/bytearray/memoryview - Alias for ``iv``. - - Any other keyword will be passed to the underlying block cipher. - See the relevant documentation for details (at least ``key`` will need - to be present). - """ - - cipher_state = factory._create_base_cipher(kwargs) - iv = kwargs.pop("IV", None) - IV = kwargs.pop("iv", None) - - if (None, None) == (iv, IV): - iv = get_random_bytes(factory.block_size) - if iv is not None: - if IV is not None: - raise TypeError("You must either use 'iv' or 'IV', not both") - else: - iv = IV - - if len(iv) != factory.block_size: - raise ValueError("Incorrect IV length (it must be %d bytes long)" % - factory.block_size) - - if kwargs: - raise TypeError("Unknown parameters for OFB: %s" % str(kwargs)) - - return OfbMode(cipher_state, iv) diff --git a/Crypto/Cipher/_mode_ofb.pyi b/Crypto/Cipher/_mode_ofb.pyi deleted file mode 100644 index 60f7f00..0000000 --- a/Crypto/Cipher/_mode_ofb.pyi +++ /dev/null @@ -1,25 +0,0 @@ -from typing import Union, overload - -from Crypto.Util._raw_api import SmartPointer - -Buffer = Union[bytes, bytearray, memoryview] - -__all__ = ['OfbMode'] - -class OfbMode(object): - block_size: int - iv: Buffer - IV: Buffer - - def __init__(self, - block_cipher: SmartPointer, - iv: Buffer) -> None: ... - @overload - def encrypt(self, plaintext: Buffer) -> bytes: ... - @overload - def encrypt(self, plaintext: Buffer, output: Union[bytearray, memoryview]) -> None: ... - @overload - def decrypt(self, plaintext: Buffer) -> bytes: ... - @overload - def decrypt(self, plaintext: Buffer, output: Union[bytearray, memoryview]) -> None: ... - diff --git a/Crypto/Cipher/_mode_openpgp.py b/Crypto/Cipher/_mode_openpgp.py deleted file mode 100644 index d079d59..0000000 --- a/Crypto/Cipher/_mode_openpgp.py +++ /dev/null @@ -1,206 +0,0 @@ -# =================================================================== -# -# Copyright (c) 2014, Legrandin -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# =================================================================== - -""" -OpenPGP mode. -""" - -__all__ = ['OpenPgpMode'] - -from Crypto.Util.py3compat import _copy_bytes -from Crypto.Random import get_random_bytes - -class OpenPgpMode(object): - """OpenPGP mode. - - This mode is a variant of CFB, and it is only used in PGP and - OpenPGP_ applications. If in doubt, use another mode. - - An Initialization Vector (*IV*) is required. - - Unlike CFB, the *encrypted* IV (not the IV itself) is - transmitted to the receiver. - - The IV is a random data block. For legacy reasons, two of its bytes are - duplicated to act as a checksum for the correctness of the key, which is now - known to be insecure and is ignored. The encrypted IV is therefore 2 bytes - longer than the clean IV. - - .. _OpenPGP: http://tools.ietf.org/html/rfc4880 - - :undocumented: __init__ - """ - - def __init__(self, factory, key, iv, cipher_params): - - #: The block size of the underlying cipher, in bytes. - self.block_size = factory.block_size - - self._done_first_block = False # True after the first encryption - - # Instantiate a temporary cipher to process the IV - IV_cipher = factory.new( - key, - factory.MODE_CFB, - IV=b'\x00' * self.block_size, - segment_size=self.block_size * 8, - **cipher_params) - - iv = _copy_bytes(None, None, iv) - - # The cipher will be used for... - if len(iv) == self.block_size: - # ... encryption - self._encrypted_IV = IV_cipher.encrypt(iv + iv[-2:]) - elif len(iv) == self.block_size + 2: - # ... decryption - self._encrypted_IV = iv - # Last two bytes are for a deprecated "quick check" feature that - # should not be used. (https://eprint.iacr.org/2005/033) - iv = IV_cipher.decrypt(iv)[:-2] - else: - raise ValueError("Length of IV must be %d or %d bytes" - " for MODE_OPENPGP" - % (self.block_size, self.block_size + 2)) - - self.iv = self.IV = iv - - # Instantiate the cipher for the real PGP data - self._cipher = factory.new( - key, - factory.MODE_CFB, - IV=self._encrypted_IV[-self.block_size:], - segment_size=self.block_size * 8, - **cipher_params) - - def encrypt(self, plaintext): - """Encrypt data with the key and the parameters set at initialization. - - A cipher object is stateful: once you have encrypted a message - you cannot encrypt (or decrypt) another message using the same - object. - - The data to encrypt can be broken up in two or - more pieces and `encrypt` can be called multiple times. - - That is, the statement: - - >>> c.encrypt(a) + c.encrypt(b) - - is equivalent to: - - >>> c.encrypt(a+b) - - This function does not add any padding to the plaintext. - - :Parameters: - plaintext : bytes/bytearray/memoryview - The piece of data to encrypt. - - :Return: - the encrypted data, as a byte string. - It is as long as *plaintext* with one exception: - when encrypting the first message chunk, - the encypted IV is prepended to the returned ciphertext. - """ - - res = self._cipher.encrypt(plaintext) - if not self._done_first_block: - res = self._encrypted_IV + res - self._done_first_block = True - return res - - def decrypt(self, ciphertext): - """Decrypt data with the key and the parameters set at initialization. - - A cipher object is stateful: once you have decrypted a message - you cannot decrypt (or encrypt) another message with the same - object. - - The data to decrypt can be broken up in two or - more pieces and `decrypt` can be called multiple times. - - That is, the statement: - - >>> c.decrypt(a) + c.decrypt(b) - - is equivalent to: - - >>> c.decrypt(a+b) - - This function does not remove any padding from the plaintext. - - :Parameters: - ciphertext : bytes/bytearray/memoryview - The piece of data to decrypt. - - :Return: the decrypted data (byte string). - """ - - return self._cipher.decrypt(ciphertext) - - -def _create_openpgp_cipher(factory, **kwargs): - """Create a new block cipher, configured in OpenPGP mode. - - :Parameters: - factory : module - The module. - - :Keywords: - key : bytes/bytearray/memoryview - The secret key to use in the symmetric cipher. - - IV : bytes/bytearray/memoryview - The initialization vector to use for encryption or decryption. - - For encryption, the IV must be as long as the cipher block size. - - For decryption, it must be 2 bytes longer (it is actually the - *encrypted* IV which was prefixed to the ciphertext). - """ - - iv = kwargs.pop("IV", None) - IV = kwargs.pop("iv", None) - - if (None, None) == (iv, IV): - iv = get_random_bytes(factory.block_size) - if iv is not None: - if IV is not None: - raise TypeError("You must either use 'iv' or 'IV', not both") - else: - iv = IV - - try: - key = kwargs.pop("key") - except KeyError as e: - raise TypeError("Missing component: " + str(e)) - - return OpenPgpMode(factory, key, iv, kwargs) diff --git a/Crypto/Cipher/_mode_openpgp.pyi b/Crypto/Cipher/_mode_openpgp.pyi deleted file mode 100644 index 14b8105..0000000 --- a/Crypto/Cipher/_mode_openpgp.pyi +++ /dev/null @@ -1,20 +0,0 @@ -from types import ModuleType -from typing import Union, Dict - -Buffer = Union[bytes, bytearray, memoryview] - -__all__ = ['OpenPgpMode'] - -class OpenPgpMode(object): - block_size: int - iv: Union[bytes, bytearray, memoryview] - IV: Union[bytes, bytearray, memoryview] - - def __init__(self, - factory: ModuleType, - key: Buffer, - iv: Buffer, - cipher_params: Dict) -> None: ... - def encrypt(self, plaintext: Buffer) -> bytes: ... - def decrypt(self, plaintext: Buffer) -> bytes: ... - diff --git a/Crypto/Cipher/_mode_siv.py b/Crypto/Cipher/_mode_siv.py deleted file mode 100644 index d1eca2a..0000000 --- a/Crypto/Cipher/_mode_siv.py +++ /dev/null @@ -1,392 +0,0 @@ -# =================================================================== -# -# Copyright (c) 2014, Legrandin -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# =================================================================== - -""" -Synthetic Initialization Vector (SIV) mode. -""" - -__all__ = ['SivMode'] - -from binascii import hexlify, unhexlify - -from Crypto.Util.py3compat import bord, _copy_bytes - -from Crypto.Util._raw_api import is_buffer - -from Crypto.Util.number import long_to_bytes, bytes_to_long -from Crypto.Protocol.KDF import _S2V -from Crypto.Hash import BLAKE2s -from Crypto.Random import get_random_bytes - - -class SivMode(object): - """Synthetic Initialization Vector (SIV). - - This is an Authenticated Encryption with Associated Data (`AEAD`_) mode. - It provides both confidentiality and authenticity. - - The header of the message may be left in the clear, if needed, and it will - still be subject to authentication. The decryption step tells the receiver - if the message comes from a source that really knowns the secret key. - Additionally, decryption detects if any part of the message - including the - header - has been modified or corrupted. - - Unlike other AEAD modes such as CCM, EAX or GCM, accidental reuse of a - nonce is not catastrophic for the confidentiality of the message. The only - effect is that an attacker can tell when the same plaintext (and same - associated data) is protected with the same key. - - The length of the MAC is fixed to the block size of the underlying cipher. - The key size is twice the length of the key of the underlying cipher. - - This mode is only available for AES ciphers. - - +--------------------+---------------+-------------------+ - | Cipher | SIV MAC size | SIV key length | - | | (bytes) | (bytes) | - +====================+===============+===================+ - | AES-128 | 16 | 32 | - +--------------------+---------------+-------------------+ - | AES-192 | 16 | 48 | - +--------------------+---------------+-------------------+ - | AES-256 | 16 | 64 | - +--------------------+---------------+-------------------+ - - See `RFC5297`_ and the `original paper`__. - - .. _RFC5297: https://tools.ietf.org/html/rfc5297 - .. _AEAD: http://blog.cryptographyengineering.com/2012/05/how-to-choose-authenticated-encryption.html - .. __: http://www.cs.ucdavis.edu/~rogaway/papers/keywrap.pdf - - :undocumented: __init__ - """ - - def __init__(self, factory, key, nonce, kwargs): - - self.block_size = factory.block_size - """The block size of the underlying cipher, in bytes.""" - - self._factory = factory - - self._cipher_params = kwargs - - if len(key) not in (32, 48, 64): - raise ValueError("Incorrect key length (%d bytes)" % len(key)) - - if nonce is not None: - if not is_buffer(nonce): - raise TypeError("When provided, the nonce must be bytes, bytearray or memoryview") - - if len(nonce) == 0: - raise ValueError("When provided, the nonce must be non-empty") - - self.nonce = _copy_bytes(None, None, nonce) - """Public attribute is only available in case of non-deterministic - encryption.""" - - subkey_size = len(key) // 2 - - self._mac_tag = None # Cache for MAC tag - self._kdf = _S2V(key[:subkey_size], - ciphermod=factory, - cipher_params=self._cipher_params) - self._subkey_cipher = key[subkey_size:] - - # Purely for the purpose of verifying that cipher_params are OK - factory.new(key[:subkey_size], factory.MODE_ECB, **kwargs) - - # Allowed transitions after initialization - self._next = [self.update, self.encrypt, self.decrypt, - self.digest, self.verify] - - def _create_ctr_cipher(self, v): - """Create a new CTR cipher from V in SIV mode""" - - v_int = bytes_to_long(v) - q = v_int & 0xFFFFFFFFFFFFFFFF7FFFFFFF7FFFFFFF - return self._factory.new( - self._subkey_cipher, - self._factory.MODE_CTR, - initial_value=q, - nonce=b"", - **self._cipher_params) - - def update(self, component): - """Protect one associated data component - - For SIV, the associated data is a sequence (*vector*) of non-empty - byte strings (*components*). - - This method consumes the next component. It must be called - once for each of the components that constitue the associated data. - - Note that the components have clear boundaries, so that: - - >>> cipher.update(b"builtin") - >>> cipher.update(b"securely") - - is not equivalent to: - - >>> cipher.update(b"built") - >>> cipher.update(b"insecurely") - - If there is no associated data, this method must not be called. - - :Parameters: - component : bytes/bytearray/memoryview - The next associated data component. - """ - - if self.update not in self._next: - raise TypeError("update() can only be called" - " immediately after initialization") - - self._next = [self.update, self.encrypt, self.decrypt, - self.digest, self.verify] - - return self._kdf.update(component) - - def encrypt(self, plaintext): - """ - For SIV, encryption and MAC authentication must take place at the same - point. This method shall not be used. - - Use `encrypt_and_digest` instead. - """ - - raise TypeError("encrypt() not allowed for SIV mode." - " Use encrypt_and_digest() instead.") - - def decrypt(self, ciphertext): - """ - For SIV, decryption and verification must take place at the same - point. This method shall not be used. - - Use `decrypt_and_verify` instead. - """ - - raise TypeError("decrypt() not allowed for SIV mode." - " Use decrypt_and_verify() instead.") - - def digest(self): - """Compute the *binary* MAC tag. - - The caller invokes this function at the very end. - - This method returns the MAC that shall be sent to the receiver, - together with the ciphertext. - - :Return: the MAC, as a byte string. - """ - - if self.digest not in self._next: - raise TypeError("digest() cannot be called when decrypting" - " or validating a message") - self._next = [self.digest] - if self._mac_tag is None: - self._mac_tag = self._kdf.derive() - return self._mac_tag - - def hexdigest(self): - """Compute the *printable* MAC tag. - - This method is like `digest`. - - :Return: the MAC, as a hexadecimal string. - """ - return "".join(["%02x" % bord(x) for x in self.digest()]) - - def verify(self, received_mac_tag): - """Validate the *binary* MAC tag. - - The caller invokes this function at the very end. - - This method checks if the decrypted message is indeed valid - (that is, if the key is correct) and it has not been - tampered with while in transit. - - :Parameters: - received_mac_tag : bytes/bytearray/memoryview - This is the *binary* MAC, as received from the sender. - :Raises ValueError: - if the MAC does not match. The message has been tampered with - or the key is incorrect. - """ - - if self.verify not in self._next: - raise TypeError("verify() cannot be called" - " when encrypting a message") - self._next = [self.verify] - - if self._mac_tag is None: - self._mac_tag = self._kdf.derive() - - secret = get_random_bytes(16) - - mac1 = BLAKE2s.new(digest_bits=160, key=secret, data=self._mac_tag) - mac2 = BLAKE2s.new(digest_bits=160, key=secret, data=received_mac_tag) - - if mac1.digest() != mac2.digest(): - raise ValueError("MAC check failed") - - def hexverify(self, hex_mac_tag): - """Validate the *printable* MAC tag. - - This method is like `verify`. - - :Parameters: - hex_mac_tag : string - This is the *printable* MAC, as received from the sender. - :Raises ValueError: - if the MAC does not match. The message has been tampered with - or the key is incorrect. - """ - - self.verify(unhexlify(hex_mac_tag)) - - def encrypt_and_digest(self, plaintext, output=None): - """Perform encrypt() and digest() in one step. - - :Parameters: - plaintext : bytes/bytearray/memoryview - The piece of data to encrypt. - :Keywords: - output : bytearray/memoryview - The location where the ciphertext must be written to. - If ``None``, the ciphertext is returned. - :Return: - a tuple with two items: - - - the ciphertext, as ``bytes`` - - the MAC tag, as ``bytes`` - - The first item becomes ``None`` when the ``output`` parameter - specified a location for the result. - """ - - if self.encrypt not in self._next: - raise TypeError("encrypt() can only be called after" - " initialization or an update()") - - self._next = [ self.digest ] - - # Compute V (MAC) - if hasattr(self, 'nonce'): - self._kdf.update(self.nonce) - self._kdf.update(plaintext) - self._mac_tag = self._kdf.derive() - - cipher = self._create_ctr_cipher(self._mac_tag) - - return cipher.encrypt(plaintext, output=output), self._mac_tag - - def decrypt_and_verify(self, ciphertext, mac_tag, output=None): - """Perform decryption and verification in one step. - - A cipher object is stateful: once you have decrypted a message - you cannot decrypt (or encrypt) another message with the same - object. - - You cannot reuse an object for encrypting - or decrypting other data with the same key. - - This function does not remove any padding from the plaintext. - - :Parameters: - ciphertext : bytes/bytearray/memoryview - The piece of data to decrypt. - It can be of any length. - mac_tag : bytes/bytearray/memoryview - This is the *binary* MAC, as received from the sender. - :Keywords: - output : bytearray/memoryview - The location where the plaintext must be written to. - If ``None``, the plaintext is returned. - :Return: the plaintext as ``bytes`` or ``None`` when the ``output`` - parameter specified a location for the result. - :Raises ValueError: - if the MAC does not match. The message has been tampered with - or the key is incorrect. - """ - - if self.decrypt not in self._next: - raise TypeError("decrypt() can only be called" - " after initialization or an update()") - self._next = [ self.verify ] - - # Take the MAC and start the cipher for decryption - self._cipher = self._create_ctr_cipher(mac_tag) - - plaintext = self._cipher.decrypt(ciphertext, output=output) - - if hasattr(self, 'nonce'): - self._kdf.update(self.nonce) - self._kdf.update(plaintext if output is None else output) - self.verify(mac_tag) - - return plaintext - - -def _create_siv_cipher(factory, **kwargs): - """Create a new block cipher, configured in - Synthetic Initializaton Vector (SIV) mode. - - :Parameters: - - factory : object - A symmetric cipher module from `Crypto.Cipher` - (like `Crypto.Cipher.AES`). - - :Keywords: - - key : bytes/bytearray/memoryview - The secret key to use in the symmetric cipher. - It must be 32, 48 or 64 bytes long. - If AES is the chosen cipher, the variants *AES-128*, - *AES-192* and or *AES-256* will be used internally. - - nonce : bytes/bytearray/memoryview - For deterministic encryption, it is not present. - - Otherwise, it is a value that must never be reused - for encrypting message under this key. - - There are no restrictions on its length, - but it is recommended to use at least 16 bytes. - """ - - try: - key = kwargs.pop("key") - except KeyError as e: - raise TypeError("Missing parameter: " + str(e)) - - nonce = kwargs.pop("nonce", None) - - return SivMode(factory, key, nonce, kwargs) diff --git a/Crypto/Cipher/_mode_siv.pyi b/Crypto/Cipher/_mode_siv.pyi deleted file mode 100644 index 2934f23..0000000 --- a/Crypto/Cipher/_mode_siv.pyi +++ /dev/null @@ -1,38 +0,0 @@ -from types import ModuleType -from typing import Union, Tuple, Dict, Optional, overload - -Buffer = Union[bytes, bytearray, memoryview] - -__all__ = ['SivMode'] - -class SivMode(object): - block_size: int - nonce: bytes - - def __init__(self, - factory: ModuleType, - key: Buffer, - nonce: Buffer, - kwargs: Dict) -> None: ... - - def update(self, component: Buffer) -> SivMode: ... - - def encrypt(self, plaintext: Buffer) -> bytes: ... - def decrypt(self, plaintext: Buffer) -> bytes: ... - - def digest(self) -> bytes: ... - def hexdigest(self) -> str: ... - def verify(self, received_mac_tag: Buffer) -> None: ... - def hexverify(self, hex_mac_tag: str) -> None: ... - - @overload - def encrypt_and_digest(self, - plaintext: Buffer) -> Tuple[bytes, bytes]: ... - @overload - def encrypt_and_digest(self, - plaintext: Buffer, - output: Buffer) -> Tuple[None, bytes]: ... - def decrypt_and_verify(self, - ciphertext: Buffer, - received_mac_tag: Buffer, - output: Optional[Union[bytearray, memoryview]] = ...) -> bytes: ... diff --git a/Crypto/Cipher/_raw_aes.abi3.so b/Crypto/Cipher/_raw_aes.abi3.so deleted file mode 100644 index 7bc3d394400307caf8acc7dcfef8629071c4a987..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 66256 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 Gs{aLvSRA4N diff --git a/Crypto/Cipher/_raw_aesni.abi3.so b/Crypto/Cipher/_raw_aesni.abi3.so deleted file mode 100644 index 88be6089a03d1be24b516ac577cea67800a0aca7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 101136 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

jf;`qY%zSN+w|64bC$S~ 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 diff --git a/Crypto/Cipher/_raw_arc2.abi3.so b/Crypto/Cipher/_raw_arc2.abi3.so deleted file mode 100644 index 49f9763fe3a53d837ef66fdceb3f1840d21b9c5c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 43776 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

H#^1q;Jd%chp$r4!Y)mxU9af&%hWExk8G z3rFbH5%fNlmL~NgiezE=){$gPv`X|vxHa)68Cw@oi{u+IR=2mSUQ&dG6X1shQxq9JxtY7UnugA+jkVe~Nx{h-#t}=GQ*=wBxkP^ZuIC zWp-xd)k6zb`ZF%QJerL!S5RoI1ZOC12Z*yHFte+5fz+=hW{A7{6T@ z`Oo9D%k%!9)9DU=XZ?>k;pFEsr%!{8ZYQuj z|Gw~t=P3UyWXVL9x2{iUV!*-m$Wm(g*C0^ru{>YLc$EA;)qeIH>*F}+g{-}PzTW9A zmo-k1iS^0yoE~z>Tl>WdDMIs;{a`sx-vW{HY(MY6W-58+V;$TME+0dN>{sjzV?Qgi zS6PV6D0c`MLf*&8nB#6S zF=vsVACOWX@IfH z_ne2j#C0{BObQQ+(oqqq3s#L1DKG3UU(6G!L@4EyNTr?ia zc*PO_y)8|}@6*zX0}PjBLgq_AK2guI9zK$>uPo1*UVNlJ2xW8BwpE4<3(ju6`zwpn z>rRW<^Vg2=hxNaZ<@a>&Z`-@=6-9{a<#1B}bGG`MOszNl?K`b2FzU#*Mx`cI?h4zc@3Tb^I!kNh#->ko!K|G2*!I#xmQRFtsU zLy$ElWJgrtv8cim-s=xUZ99wHKZ@L2yUrc5$iJ)Q`Pnk}ju@F;rHSnJBsDwoqVTPH z;b+ytyUvZ7jqEe@!ehc_sHLkkwe)_X;vvVn6mIWQxFe=;8|&`9{*zMG2f?xWqTVM8 zkEzxE(Px`htSB|QxYWb4P^c*$rKwj?c1*}t)EM} z&a^+w-b}6fv9Q^Vfxu(ox2n^gS3|~o{V8bhWY@Wx3hW|kKsW{i*hSF6D0a>CvjdTz zwJB@NhRya@+oDCT8navH3^xn&&55?e%rV0q3XdTr6gp?3>zrs8k@Sg~6K$FkZJl#} zxj56uz1m##p0)8tQBn8lH%)`1hF0Ht_2Bf=7W7B5U(!3Uf8IZd>T3OyXzpG1PeRlG zpnnn;QzPZ>`X}K%|GEB2M8-YnpG15{g`j^@WBTsz~93NX4;7_}c?1`zJ9P!(Fve{h#zt!&DV&y=B?^Cov)6%;G=L zKVhac8#87xgPJh~NYucn0a5*<`gJe-tbc6b<@ZOTI*GA`H$D(EuGmL@S`2VD{WAK# zLYF|yIlX6`71`(ejlF{D===`l(JjXAimZmN8gsu%fo{KfPl*Y1i!JPjKXd)s)%6EC z-Y0f`|3AH};DUEW%!RLqd(Rd(3}C2%JF>X>k^Wsm_Fxv;45^J`rXN?hE5kdd!WJ+A z`h5uaTkOj~YwyuW4GxL?g$snzy(`WU-Dd3kNr913n`2QE?}`gVFXUZuv4}_Sipzw5 zVjdY+c)Z8_%HDBJ_QbY17wg^alj(oBc~75(%3s;$;yv>+kePdI-rnoOBIkr&*=F{h zSsul7H|^;@{f}-BZi_9v9yebtE3WWB-2A?=afN%-`S9G(*y-C{y!VHM#7^Jl(!I^6 z1wY5lUm$cD@@dGP;t6h;nmMX)Z{dCne3)?hZ2Lt_`%ccat@V$#yuDaX8jptoMP*cy znDng`qd~}}usNb@FFYDmczD|{>V!4Yd;Jwmn-=?9o?k06BN+w^dA-+P3R@t$a&ZMR zLXO`>xpRaXLoSuMM7^xS{V2_89WU#3yco7X^x!gI*c{Ohhn)D^i1y3$K>b?F;=dp0YF&5OA54m_Z-Yhy>cypg?g#-WW-sZaZ%+Y@q70uls z+#_c0TG5FV9*vp1LIhjP++`xx=B^MSgpRG&+zp~HnY&m-M9kd9!fRvZE)f2TtNwF0 z2=@RMICq1vF0jUPHwY^NYc_X-Fb%L4b2kXJ0SlkILFfWl#M})+6TsTf-7rkUD$m^@ z>IzylbcKaO0^Q=~&sOyN*%;CM1BD-}oyf1kbTQY8B1eHsAh!dRiZ);paShx5BNiRfZ>Rs^|bVW%73?~ zjSH+Mod$ggOo{HK@Mv6{UEVW?iw;GEYnub!Gh>jzBGw}xidod)2cm{VJrFfCDtU*# zURUb=ac)@m!c(z@p@sY7=JpG_7FXCW^jhrvJh#~CXRgIIxzxSM5!1)hzqvO3x|{d3 z^s7Zhz`KNe+NJQbsOj6?`pmU8P_J>Jl^m23%i*ixNe^N7IVM_>YAjs zyeUNAa?BakDe$n{i!*~Bt?nC>pKGZX;r`OW5POrw*Mr;&vwHt@CZKVbalQv54rKIu zKg;u6_`6M3Z9Nq~Y0o=HW^}6R-tC>^N2)wo^Tve2TZEQKyy6jZXw^GkEk2p|SMa-E z)j0U`ny)uJGo|6EE(<1YTJmtSi`|wi54@W7#JX=TncS-U`Pj^3{+X$ny$6nc@n+IX zQ#w5L`{TB!DRjHWij{v^*K|ux>H{CWcHfnd zYPKpJhwQKO)a>WNHXU6v{L#O`qzylA=`1Q?#ndi*)8-6jTX8QR@Iu_RdXw@@^f6E!;-6s0?>C<97 zf?WJ(ywu~u?#!Xj)m<7ra%aG^S?8{#JnuQ;!koh^KV6nEYGiP~V~t<+e&)rngq2wy zzh-~eZlZ7eg?5`3H@z{XcKXHT51Q7r={V@)j5%JNr&XWz%e=SkIbC+VJY(|vL+7?T zR*-W#-+$XodrXbUS4M3cF#Pqyy-)U6?ZaXA$n8sq3{4Fj zReep)jgjvpW_3LORvX`(pZd0|oABqDW>2?xE~d*P``q6fy2j<;x9|VeBkap^jlDD0 z^$e;$aK+xO-nQLc+9Z2?dh*8Mjqh!p(7$}>uo^p+K%i*;{YJNNQq z*Xo6y{HjVpd%w{sf9vd8UtL)dePl<`l*T(lN36>4-)G+1MuRhVCw;v6fftLuURLqKhQ%GO`)rsV@K@G5 zfA$!B_)zl+-z7eq-sRf*E!`jcbitwx^ky)Q-i-WYy%=Xd*0eC+?LDQ;Y= zn@gu0e7o+&`+A)?`Sju^7Q8X`vDH5=JMz@%gNGhFc)G!^HNk`1Klbjzg2!%rbLH{0 z`zl?kv|-MiS{EuTST=NZpISQ}ANj<^1BX^`Td}TMz2M++RlVN7*}UM#<#o+-z4tBq z{;VzMouj|4sYXqeG zuRb&D`a9z;NB7%xpyj`Ac&_>6{IbH14;`)@@MQmwHhyn@(9&@FYX_blKC=4micvlC zdw<-#+qxdFReq?il2FsHN#e7e26`X;Zs&7b9(-xoeTwbOBk$yFa;tl;=D^WEJ#)$L zc!j0`>8b12|FQ9hAZvJ0+JKoKJ~t?JL=^U)i-Ux*Gu2r{<67M^(Jxd1(Cjk zmUV1f?Yn0e_v@7Yujs)?zk7W2(N0&FlzaZu<(FHW{q;;l^IqE?XmDYc|Eai!=W}Q5 zJU1qV3uWp79r4>ejkYv`#VCxa|4HTef%FCrzB*;JpC%FaGd-;?R}g z*Cyq63tedHcDddo-+$lsixb;hhd=nv?pII!_H5UbnAf~42faJ)+Wk{hor0H^d=l|Z zu-A|6mT#UK8nUiqwTQX>db@2L)5lUFI_CqI@>dpA+R$vmq(y;wYbOj?Q@CbJ-Eq%; z>Erg)@k(#ZT^H2pz!!D%D)kQ>J38phsT%RKKbc{#)-7pb)e~;EEzjDw%$wZvT-%=} z{&c$~*Y zS7ZD44)HlUZq*~tRj-(QaX?F#(Ys#!yj``5?cHAv9Q5;<$1h#KadAm2$Ztqto zx68M)-po1oWBH+8v(`23cz>-Q>W;ha+M)NxFVdTM*ZyJ2(ZY^X8|=>LJAO}G(5Q7j z&u{Yb+d2NnZx$xD|MTVFo0qTiYVWI;I^0*gm3PB7)rU>kUfu20`hC||^1YgUbM^U* zx;uV+y33Ytr|*8~l|!u`ezS4WJkzhILU+7;f7bgm1Cr9si&u{HetG{d?Vb)kxq9-i zO=kpW4{p3Zz%MtYT$6%sr+)JBv!}FJvCsFJ_fpQ+xfyObkZO5-!I1oS+Psh(=dpC@ zk;-4bzIV&4eZRcgZ1}L1LsmYYJ>$2x*3_As_VI=Hs&CA!zbt<9{pq3ikBnURcGLDp z&MghOx*=d|b&r0}Em@X4d&-ilPp_EVVfeFiT3;L2{M$vzPyJl+kxC=0G?~-V>uB9G zyOw|T3q_U zMLWY&er|j-zx||Nj#uvSz_;(Fovr+UPxNWuj{fVv`K8N`D_?)nuTR#=gMId1kN!P+ z*E^d>{aU+SpLA=$Cs9i$)H$}R*UVX?y7l}ne)uCDE-fE^plieVgO^R8^XH4}cWv7d z==boGw!N7ikIv{e^Q|WbC?5=V|5t4F)wVZ>S5~~H)o(gKI_byD{XIMWzPffwZm0TB zUdRiJn)1~Ai$5hFJ=v~a)}Yp3P8w$WW$&w(W=3X*j@v(DYPnaI#$T)6|Jbi*TP`}D z^7^ZpuWfhr{OHe>F86=&vB%V)i7`uOgm>9t9dYEZJxl9&9X^?V@{>9JeI}ep9ue7j z#JB0;AAWQ!qT|@5*BW>5FB)_4hk%ZLJvyv?{671)XRfZEesbjf9nM{id}Lv*hH+QI zn`AD$>hBkI^)vH>L8E`)GE#Zrv$270pN;z6KkVJl-tD|5MTrl((xy(=E`f_|eF7>+ z&YAl`?LVLHwdRR;o;iH#_uMYQ%QAj)-}1rCMekV-j#>4v%gntY>l&SZCaTR}{m*o3 zaN^nWAFpgMKECnqO>r?`Ab{9M*cE?d7~F@cIq>4_3X2* zr{}%1{^;)$C)L^i`cKKN4=;If{Ql^sqa#}`z3IPk=5NPWe%|JnxxFj3yLx?3?E%%s z^bE;(vEf^bzWvd5J-cma=fS70{tz|thX44FdtWYpW6`>s$5su9?9%Az*iCKQCib5_ zf4cv>uZ_Oh^XX>}ZW*znf6}vl%Tt@YwlD1D*GmTUX!^<@4MIBAn)3V5Ng+)Zn9pAO zD>t~2%MicKQ@?H2*c$7%?df`Bc7E5%cU$Ziv%GixvgeO--gRA~UYgJ?vTF962hJxX zhaTGc+>yt(ZMl@zvSL*D_=g${d%o$g7tdb%s%BPd-R*Bz@>&}DwfRt=j5U6b9Qye5 z)AdJx{ba|m;U0nQ>TP`g7q1uInz^LHrZe+A^S*3+^@ZkL##cJ{*TQ$79_}_d?ZV}K zKjggFz2EiN$+H{%^{*Xu=6C!pDz#gATT#%GmDxFMTmNq6*IZIz zboNP~{txYJ-E72|cAup;ayfhOi(M6(Tzs)e+4rP(n|C~Z_RhRve<py>7@z{F}I_%l;^*4j6M90kXtyDhy zC(q+ee_VN__lPxV$tz}^m~-xf_iyg_E^Xk{E&rOe_3DLd4~-wzYnWwN*Xe&9T3a{b zipv{a#_jvF)#qWOqo;2US(TN2&1e@al&2ao@r)cb|M zPF;%l)%N@L_X=n4_#-3H_Sm}J{Vx@~z47>;T~ivKpE%>I+H)s(jhgYz)5%XfHYmGm z?!dSGpXh&NUfh@FJzuZ#*m%%7ZFB7K6&07hW-C}<{o!}rzj*ERa`)yLVO>K%G}pcV z?7a6cxHnj~q=(PV?Ao8`JS_>Os5ql0HEG@5tq*{E5a#<|7~+wqR;ij>9^t6n%g>+;sulZGk7Cx6l6 z^QC7hrv4aFf8nX^iQ!eYZy)f>-pyaG-?Cu&A$}?YR z@0*bI!>%JaANKxw!2S=Kwrah5=c(|}XFsnrE%nLAu6vC*tqhB7y}wP{1DCHKZar@M z%9_nTx_{}2wL_v?zt|_T(X_+wKeuJczaFc2#4q3bgDJI|AARUUW!LDM^WN>UV0pm% zZ)U&sc6O^#!7F12PRL%k<s^<@1m1>~%2i+X`su$`t?l;Q^{0NG|KZ`Y`v$ga+$7`3wZ=id z6P_?7kMBRM;O7{xXRgj0didMV##sF}jrn~}gOuf#_b#Ma{g$5J@xs6b?SHD#Xi?L0 zZC`tCOsATc15)eU$awy8_20f|*!Xx@!R5dDzd0>@fMs+0O^;R_m(cjy@$%b8B~ zGIr`2-!vb$H(m&QYs{&?n$OJ42q@=XzU#B=PHpXycHqmbq&If^*E)6e{lSs*lWIO} z`gGssZ{Hq0Wz-9&x)cp+8&kez$0MJ-y=BGzAM-ZPNW1<xOa&eXSmo1Jp&&BeM4bZ@hVRdr((#jwH>*{#)^7IKN1r}EV@bUmR|fu8|8o5YLthDLx#B7F zC;J8rf8@fdcg`2wzo=D}?0xy4&Ute9GhZI;zVVTo3*zG{57;^OyzQ5Nnsi|A`um=L@RO|_D<&TPHnPgF z_f|$+Slz9`^ZpT=9^Bvc>PO4hj2kwrz`ys+y)%!^Kl|v~KVF|W<@G<}hHQ_mKJU>R z=I=)BF#YlM`JT~KJZN5j<%+nmUd$A zrr6W9_C!%pJmA5TMMdKQF90q8T!4*LVn1Pv?~95~1ByfJwG@YGVqe8H-p5qavz*%k zJn<5XBVx~E5@baJDqcQay{h%__88|jRq0ftUDL3@dV(zS$KZ@d8R}lc?p{7Uz1-CN zLqJag{TZy*D(PN6kC|hgQ*s)(LX9g}G{Ob06!@#o&XY6-HMe5$g zeqKJ0o1?v|J!Xma@}KV#?bUdmHO8yOEZ6Q{5!1`{@j7U-banTNi1KO?<<%H0V2zf= z?%emu{sZygm|kv{>pbgxm&YuRi{+jF9{>MnV5{6*IF*|W@z=?k)8?y;OIH%YR( zEu_QAZMe!8A`=b|4Jg$l)c01(eU;mmFZr?HsivvN3o<=KUjIX;^?FLV|7pN|^N!{2lzKQS;TZ|Lb?)5OzcF^0 zH}MY-3J+@SAKD@$v_)7*n1AEG>1qD4DK?GXJT$C{Qi3@mC@d&MFt-77NHMcYZw}sO zsDWlAP1W3pz0TLMYFhe2MLelgQ8&|CK+pM5^>IjG#_4o9Tr>-Jb2(PE4S>b1T(STr zx1Hd&n9CI*qs66Mno4xttrD%50bE?Hnb|gEur9|n5HL*4uRcoPb5OMPv6=$6y1BYN z0cbI~9so}{fx9gLcFfh={>%hwQ%nxWY*MD5$-{PvzC^Mbgv{h>u9N1 zcMl=6u9k{-Una`)*HTIDYXoOKQ`XryT2_`-L=#*_st^JLrbl2-!4);wbWYoJt7rnD&HLW zHn_JDCG^(nxz+ukxE616TMp`nN_o*R*SEbqwxHl@uAAIMvpuH?p3SNX6wgbdN?TM7 zxOpxW>|0eM`Y5h$Jw(#&Unr)6Fu7=hm+&t^6;@ZNZ<6Y(cz*(6CZDb%+x@26;)==S z6DW!stS38&>_eDzbz6*dx$nSQaTjuzd%3!(v&mGk6F|9Fm^uz2*~=C1hT9$vM# zAfyR`&}w-%??-^Uy3NL4UsEbbuK=s8{`pN{e~3SV6->VX_wYxd{^iU2h=k`2{3-9@ zR{)@RzK+V4_f!*Zo+HJT3Lbu_hL2~exZ>q0#8gwtt->W&w`BFNsG3%;H#jScKe(oG z6ycgV0L7K}wg^hOnz&ja7g#h9)j$^YZ;?{287O|&P>hGEs<`TIQRJ|tW*EZ^6_s)i z0Iw1bDIT7ts^WsXWtr?>sy0M2*2f&`wgyPGM8zED^)@i2dc0x|_xf0%K1#VlzzRZ# zf^bVcRO$&*D=IZc`k0!!7lGh829-12=Ofync#6NKX4Qlsf5n`QHkz7SM82A)K9Fn5 z@KJ3cb{B|){h#T1(|U9{wMM5;08dL{AP%0j#|!xxorR8P;hcoC_GBSAW0=Sze)Dw= zv^wpC{EwhIQ?yq{EjT&qU2UUuJIm^B3HmtTuBGZ zV4ML@BJnkl&qZPu62h*+s`XYP;aU+Qai9>0GOxD=90K)MT>c(sz(+`oMypeB25dy) z2Oy_#))(x7r$8Bk!AcC|4Sql(@FM;^kJLh(fj5w_U^4Ls68^53HLx_RvKGHbGB2^d zhpPciapfT(`65vViLZcsE)tcI=#1GxJDl|+F*r4B1&ZZ~3sVB4foueMCC&!Dk!X~J zKU={QI0(oH=ph*=4*x?)ua)gIEB=^`nE&Pe67mIH!Ih7|wL@s_JQBYG`B@~sLZUi0 zlU2o8Ut|e1VOBO2srEPnJ&^bvt=lfz?1w~_m!d@CtS27duh*3tkAB@e*ejqtsBb}I zPvQ({fkY*={}R~h3y#39pyZ+IeMR--#br=0iBj(u8S#6jCvgU*A(4hjP$ zSoD#hQBO4U8uEz)wgZp(#R_T@m*b|#j#F*oULbo!LNxI*kl%3D7wl>i+t*c;8aUM^ z?)O)eWjNI)7S>mkfjHGB-jD^Elwp{SvWadDvHh@tY~sj92vwZ*1&7+ipBgL5Zk%cp z-*2iY&*D^@xS$zSh*NE%El5#1;#8aXQ44JH!zqu(qoF}@9D(vyz*0?2{Y@cFO#Lk7 zNBSsDTS#SmCoJIVwgn8XZX&u}-9$v!G(8NuX|NW&oV@%3R}%+;w`(1N2W4g}rmo?l4+zRBumO(} zeRcCtRK(P^m*@wAMZar`Rr_63u@SB`I}ILFu#~w`m)W9NW{VOsTa=L5qJ+#)O=gR+ zD8*dURM}*)!c{{=^^j~O5}~Lc@HkPyP*Fi728kMm#VO|6CNI%{hV>O_MS-GzqBm?I zHW`?Ggv5cmM4u88eM(C7DVA8NSYjn9u|+=QnmtVwOeWEpX|?k-wGg#anmsS-x=JcS z^i`^I&8zMcmxDwPYhD#4D&PDql~ZlK560Nk1EPa4;!LimVrpF`M-&U59HUzIb;vY7 zTp>qTeY;MD(0C!f?Ft9=($27{!Bs^b=>Nvguf~pGy*!>t2byw zsKA5b#^XX~wF-R&njlaiJyUBA8Zk<5#3))(jGW=ugys_-t)YfwfQ@Y#WoSnA>RV%_@sJ43u>_B(mfp z-TF6C);Ps7NJ_0P*t$aM?}7yvx;9azg1Kuu!K{S$N5Pi1V5wR`lhU@ahz`Nrww<8C zU}CNlAv%odvVqm5(0(HOGsV7Sx@vQ zjiqd}BG%AM@$La%gIcvU=4Utqjv&z@ALcnrd8XTc0gK!2sgTzcA(?#M@B-Q{~jkCVU6SxYLD@c8Y zGjKf;i`y#7{Wt@+BH`XiQFe8dgAhxrro_Xi%>~*xTRj>xjwr|$3XY!J!U9 zrY@LQ#ULTZ*{oQs4B}J=q0f7wE;!XeD6S92L7eI!G%f-2E}Y_MD?BC?RS}0(If%K9 zxt_@yE!yb`uPE%VD6??}n2}fqed zjE066$ZQSe&a0WC&qCJqdA|ZZDkOCwbXMMpQ7zxTeq-Nm^?1{upAlGrW6?2>8 zQnp2jN3rHAChJIOL7m_X9t11nR3|tyflL<(F~L~_WHrwEB9A)3xq{SZIMoTxlY`+~ zIMoTxgkjj=j8mQ9urv>487jgF&YPLg1y0qsDvnl^i=!Z0aHzhuBui1o;#7UhC09|t z$U#EP;d1ivssNm-Z+-V5CUrPf-}0WIClQmx^`@-wMF( zdR?5VZ}kMy9jE47f5}`fN((TWt4ZI=1w%G-JPTy8$e|wXO{R+oIB|L&H+dns2y}6J zo;6iaOchNHynH<@UNyZcnkt!8kFBCuyxMxS^JwGI9Wzx+pyJ`t5gb^(ktn82R&P+z zHwqxQ$~9C3aPu`;ygWRR+uFv%1cG}7O&F5heIt;ge6e)g`swT_Ot7Q*#bpb2j9uM* z#TBmr6c7xGw=Y=4Oxq{Cgy>G5f>cqG)T(QwN&#r9ub-)rrzWSeRjsIBNlr5?TcxBl zL8z+M&8jIv)Sw#b=0?4Ux>di0fF7cTugRlChMGa9PM&OzC|_tevizcGPa&?BwS+jc z>$}kiwc4QRs+Y7nx71YQs|%W570Ksc+Z5v4*R&zp+TS(FW01!{RiOb^CB#>9)GNgS zul6wY7cm}Q%+^5QxCv89P(&jS2o_9@3#Vb71PM|7CXY@tDdzG|M1!L#E-2yxrqJZU z)Gi3Vpy^9A-e0Xx^O7yZFk4aym_LB{iogtvoO|wg#KjW^qL$g3z8@4Aw?fC7RpzRy|rZO}8sWMK2hn2rrx+>7{A{ z)q*pAhLuyZQcsM^rW;-eK^!29bbel{5}cE33(gxEoR*c=2@B91>=Jwf-|#IvkKDE6_r&cf`@0?@^7Ii z%5c1iVsvt9&KSHWBPdlA4T}0s3oV7$PGqKJr|0JfjT9I2ZE0!g8Ne}DvQ5ZM7i9D& zs7q!JP>i|Y(9sF`$?17{S$M&Q#wM<13mkk}!NXJX(~&Mwton`)t!%JEu*R-fO^Unu zAbd|8mXnIfYW2nHFo5e|7qiu5dBbFKLCSJ?ipgqntzfnGaUEp!1cNDfnyV#k8u%+) z{gG~BvwFLYLyn0(aD9N)TBEYyvW!RW##VRN?;)az%DCcUakXrkVybM(HCZZ7 zb1_>!#5-M7>PC$U_HwS4K+^&j3o2t7V*<}d$X&s*6IHQR_7(qpT}`f*SQ8LSE0fh7 zNx|Di5UlQ&2$Qv%rKe=}MLi*~A?8w+0XC~|JF8!`)w8wLx4Sj4kJY^gGVZbZxguY8 zpaqptWgn}DrRlVEU>$t!AlcK^>rNu4|L+s&7jF%0=e+GrrlIM#mwHc*J++0$d zP@jjTF-#Rg(!&~P>6cN; z5B}@0|2Bt3m)c~e)w3fyIS)&N_GRi~{+8>Ou$^$-dl6~{qCaO4XXrs}wfd>O@CpnR z7WD9oMekhIS{=-u9j(>dT0MKUL5JEwP}&7`z~JE9)>^%T)iVjyp2+HAcC~yhGcQsz z`>F#B@~B9AD9hc|;%)M^RuH{#8`o#7KIo@Sy{tZMtfp~RA4^_)3^ZOzu9l=#e{(!K zT5>%4sN{IGk>k;a`gjBjc+2sqGDf3K>S(lCAB`~n_+r3GFEQXChmYuPvdS>vplxWT z7e+xS#`1t1!)jxI%QH=by1h&YQRwm363R62+)lKRJnes0va{azj@5=ff}QB&PNR{b zs;wTPNK2kg)Azqa-Oeqk`%2k{raLOfcCWP~9P!`mEoIQShs95fSGh*x)g5*6Uq6R? z*M=4U{eCWnILz8P$klCcr2D_+^V7uuWEi)qXO^>67Qr=9`2Ah{};?uNUuT?86YG4xBGIANwYhW$X(SV;^pE#NC_8 zt(Mj2JO;%HVw6q5cqwkhknnlP>ZK06@+R*o3|ZA(D_UzFw^o1HTI+XANUB=eu7dHZ zTVljL(F|VJemO0%>zX?-!K2~|O{wy{>Ry#Me5bNxzg8P-bXglhKPZk2Ge zY1yt|0n}hbaW=iUD{XKxruLg+#chzosKQ&kebZ>zdmcU||+>aHynV>G{uScT$yh|xUhP6OjV2v~|Xtp7c+u6E;! zhB%#E-<5yf(Y{(Y&_t}$W5He>X>s?5dWhMnm{jR2_F8ZoFQBNtDJp-jx*B!5rdQsn ztM#33tt8e$aixNr&CP}@K9-Rhq1q+0FP>s1C+B2jB;!r{-TNeq z_uD7u+VYg-)R8IJftZi?=8H@DBXja>!wWK$&Y8I*)ARc1@6H#QLX$)A-g~^AKMybM zM;d&|;!&Z3cl3|&SN{}b=Vy+{#;;<;uSm3qiD~Jnc@uJNw|^^tu>_GZUWgXobnx#S z(%Sz{zoYSQJ|;guJruxJke%LPM0$35US=wiDS4?QJK#ZV^H$;h%}4k*?-SljPtM&vZ3asUJcZo`DY_XevWaWE^1|sn!PV z8J(V|KFZBj30=F#bxF?6D$puBE-%xTuG%yoPk5mN7&l+&F;V-#f@)g-TMQ(On4j`s zx@N`XXz|oJS{O80U{VvIO7fT-JhO)7#rD(^j*yw1tQ3TW+HxY2hi8sZuV|GJI)kur z>PHx~_U86Y&o9W*va1ibHB>Y~$sd=Jt0d=QbB?IFd^U|z)%NB~rAqB7dIR9NdCK^l zym%!TTMvVCGjs8@eQfjL1({iC&GS=QkI!u#95Fpe+R-lc2$}au5dv z5w@JLP`wS(&C%Foc%o(#waTim7eE%6Z}I0_KO~Wso^Q)5NVVnU$*Sugrhrw(qurwL zR^cThQI)J)Lv^|2+?2Es@B+XB0)%NGTmvnYMGH6-DWdWb zvf$wkriT)rzf8wHGWD*BHo?x6_-%qXOv(_V^KW5f z>e*sOqSUA+QIk{r7dt)FV})$S5#1#5tWvTrGv2XqlM?S(3`oV&i8;2zthBQ88X>l= z$m4ri7aFjHEm=LymaHMggRyiC2b8X1Df5;tn~qz;hf9{--(I@x#L{IamM%Mytt2ci z8^8IHEx#@yepcjfXQHayVQ5m4h_Xs5U+Eepm99}z=^9~w=dA~Q0-La;C;#UxQM&B^ zoFz(^O+EkHRW6)huT(Z0Y*t#>S%G@e_JVe+vBZuwaheVDQ`Q;1OX`~;d&v8Ack26| z40^hgN$G1;h^VCHw#E31U3551N&<^%p%;@tbd*l&SGr`m%UhEp{$ls0de9fCCIowF zkH5?KcV0$f=`!vz&YhLvqU0{~FV&rBRLA($sE#45QKg!6Ah+g8r>6EeAPGkz{+jL_ zgVss(eF@!_vC0!lE&TMrPLlY^oj7=Do~cyjP0Aq0nuFw6ZICocrT>nVWw1JM$kKM` zTe^(CrOPPg$tDYff-dTc-)Bf|-BJ}p&L(B!M2~TcEF{Xg-{H_J<|D&M7>RhCP7ARU zpQF=4?Zn^LX<>Ha7j#;O$xfVxH7k*&dP}Pt_Q+#9 zy!H>c#0a&kAmqt!XP~}rD9RvOEP+2wl z1!}!mlIRxT`dE_a72qQJ$DP`iueHrhIs=^uQrk)reF&4N0!g9^p&;>lGI7v@knsyi zq5~nL`a>^p(SMLJPPzu&2N|bG61@i*iLR8F>L~ffHpqTJl{gt{9!GsqQ`r^e93o zjGjb@>T9hn{%bPd{vT()KE=kpm%Zix*51#ct0`Mt7i(6-Zm(UFxwL+hO6xbN^k|e+ zdNfKZJsKsI)^Aej(Iu($=#o@=bV({bx+IkzU6M+VE=i?Fm!#7AO)9P5q|*Insac`b zYQ-&%`nMPpX>s5R^-HB%)v1G>Np@paOw?l=*r{iBWs;k^rh+9mlkB1-H+4=$OKv9F zRaw;m(oWs8yOKhve_iQX1({^GC56xq?7E~7+JXjuCA^M{)xZEn83w>D@OK-Y+z^~kd5pEvXOm2HnI=MM)m>O$UYz&*#~4J`+#g@ zACQgg1G15QKsK@u$VT=7*~mU18`%eBNBfj3R}SC!R{s`bA}tPFF|tpDv3)=`vJc2c z_5s<*J|G*}2V^7rfNW$Rkd5pEvXOm2HnI=MM)m>O$UYz&*#~4J`+#g@ACMjG<0kI6 zw6o-2K`VKsI91AGmqO?22 z6Q#`|izvHKWF$%#fL4jJH$_IGYxF4|e(3LTm`wOq`rV&aIjJk2-1Q?$So1cw=63NC zD{=6q02&}lSQF!x;jKNU`S!^&Kkp!*XQG6+E&pwq|9uHjK2gHkmVZX(yHK2;D52Bx zMg0Ti{RD4JP(D$@+m@dw^YbnSRwqhW^ES8L_Qzy?-txe=h!Q%jKkhB;J7s>}AEEw4 z32$5f8!|s{rci&Pgtx7~c-4bAc;|)s6D7QD{YT3DyiG&>i4xwn{)=RO-lL)ZLO9w|xDG5;`qk{!(?aaTcj&ZGJMki&7G@_NB40~m zR>JMX$LO?{cH%GSv{rWFpX;>NcH&j>wi9ufl?XfW1fAB#PP|a3wY3xfK&Q2{6ThL; z+S`dYmrtC`N(Vdf9G%wDPW&aE*2zwsrZrmKbyepSx32Bpy2e{_WtYxED>~MSV3U&kuq4sG zC}@o&(Yz>#=$BZ^XQC}cSISEu z(O(Hc(gLjbFJ8XHg-?B9R53d&kxCBGu{cWCKh{Zo>DY8(a1kYRTDJ6N^0k%DhO+6{59*|3qQwrLNR(cUvWXJjsciE7 zs29|izTQguE2PrbAJ9qt=<84Gq`vg^ojNIjzD}=3(})t@$-&9jP4}w=I^uYpluVRf zi1`FjLX=HMBt+AST~WjCwCcyr19TWjy_Y@VUH5GN`JSq5-NHZBuR7&$)UZl)9BowM z5r^?cB|45cD$!BXD$#KiQHhS@h)Q(Sw@P#z8&sm>=%5lE#|M?@I6|mI$1y@BI_h2} zI(Et`(NX{Enya?ziXA5EN~^Z|s;#^VnnE9EXDAm4X$5wOaygN9V5ca#X$dM{ax=-! zPIA*4?B%S=!(vsJN!mrOcQQ%KNZCxXGn2AuDq2T!Gs#ZPs@O!4G#5KIDTD@N=O%^F zWVDjxW|DT2+)T2!lC5Nt29&L2k|U~=?PyVTl~%6Ns>`!nuhrIS@j^UTLyKZb(a548 z8(9=&Ba4D;WKocfEDExbML{;QD9A<@1=+}=ARAc}WFw1$Y-CZ8jVubXkwrl^vM9(# z76sYJq98k3R9)BAR(7#@MqSO-R(Q45T|qOnC>9}&EDExbML{;QD9A<@1=+}=ARAc} zWFw1$Y-CZ8jVubXkwrl^vM9(#76sYJq97Yt6l5cdf^1|_kc}(~vZF=ym0-u!-&@mK zimSt=Y>c@EyJXrKb8({VmNBUzO0$EDD0^whB1$j7w3#S90J4a(!$wA;bO>Z5N@qZc zMCl0NB1$KKc%tmHA)Y9G0vUBFerUvWON>PWw5!(LY%+7I}Nf*-?M}{w0AZq0?0-vFbQO z=Hsmq8bXxtwyRznWPaX9K{rGRotBTACHwC(KX1BFK2gHkme2PX^NtJU6D7QD`Kj_Q zX^eiilt7fQCMGV1tL8#~i)B9ExWVc~37ys-o3-rwWPaYYq5eb(Z(Dy)d1qEtzeDRs zl+bDUV%4#$%$K0&?@N@hCT3BF?HBc*BJ=U)5#d6V&}sdJ{@#}PKhVohCQ9hE{=$F6 z*QCV3+fw)sQ9`HXi}u%(H=MjDh5m^W-nRU7nV&bXus=~kr~V`K_pHocd`p`^l+bDY zh5oeGJNqk_#IXykKT$u)D}Hs--_8_1+o2v{l$ZnXm+8I|LeE6sz#CV^q5Y19sr8Zy zM(wiWUw=uU7p~y0pZ;MiTqlOG_l5gWy=1=4Duy=mGg#7n3qn z{oErsU(uU9)IkoC6veX9+|o>Do$XUye7~op*y5Z98Z9lplp%|S7fUL&YaK0=)nc&* z6)k2eQBB9z6f;qhMJezv<*<0YGja}-xhb!qVlyu^q1TBBw3$>SGBCiVs8}p8i;4x< zhfCdz(^Vf&bc#+YwNJ^6pMGSPF42`GTJ;iL^b*TCl*mS5SxQRMfyF}MtR9}+RF#j1 zbS{Aya+WU}r=d10iq|~f?$E3DhOCI#mrwj>ofcvz-c0`J!mNbaiD&4vFgx)VbXvHb z_}4nErJZVPD68z_z_A-Gq_`jQk-JSGukAA{kN=s=w-p1lkqijnc912=r0(Wh!vk>)Cs zimPAG!LkzRz|`v{=_<{r!zt5H$S#Bs4R-8ZcnS3;nk#CAqXaie?0Dd;Lr3=fhR6DW=- zA!IT<2*Je|AOsiDbuui_P(}<%3=;@ocn}(d2V^oV=E}H&Ohybzj0FfFN{C{J9xE2W zAR>w3f#Qe~!XQMyE*8MJB8icM;utA}kg54w@!x7@x7+@sr~XT3fmFKT7dlCI$C|}m zH{EcEPSQJF@x3c?pgQ!XgE~p?KC9~encheC)k(S&JfV|xCpf5+5@})Y(j8&EPSQKV z89GVt?LO2=dY4v7?~#(I>I9ussz>^}`c-GLjv7{p40Y;QB|2(ZB{IgTXO-xvX_d%W zq^?yWLyg*2i3~RCTO~5asBulER6ljD5*b(2x=Lg?QST~|AwtcoM7lk7uM!=#uM#!S zD*lTvzj$IZpmutyhvJDOPVrY9>Q(wV=Y3WsS3E9bk``(HHzpv+&TO3h$wyyI(xkrs zoeXjYEhmG}9hJj5ptJ~+^!!$T!y@{W5aOAi!D3a$3xhMsaFG^ck^v(t!zAZ(R^=ff zgb~C!ofN_tV%SI_OmYGzx!HGd5+}JCNemvVGEo%CB*RAvVUhtPg)qs9mux(fj4b&` zmPyXVq>$nu)3Dn3c31_T71Tqi01{5|R~+h9qfo zQK*4z6lx$Fg&N3?p@t=DFE5^6>Y;dngj4(#hkDg0)bRZFpM)B+8-*Ik{|&V}g&LG( z6lx&flTd>kqfi6cDAYhU3N?_8LJef2Py^X0)Ic^0H6hy|)Ic^0HIR)$4P>KG1KB9l zKsE|Bkc~nOWXDjei|=3JxvX}2t4DFF7!wz?l)jqID8nriQAQ5#4v8{qa5F@dK7#u_ zqVx~QB1%(37EzkH#H~L~T;g7f=7lVxoWJ1qoG7ggSwuOVfh?jlKDda|@DNXwGaFqH5i)*o-;v41G@ACwS=BueO1f1>@KvNz)W zFFc4SVNFcwoz}mb%+Fh8)SoEfZR`{wB!$TmgXoh!Q%jzp(!XnV*XVXg^Uxr}Y=@ zca@>dbp^DaD4|pT75eWg^A|4wB@!icTE2*1$Nt1>=2G2!DH%^o4WEIQ<}`RV?V?Z& zpU^sc_*$CNqKtJZRX?r1TV>rYNr-I?M0>kyEZY7DrUpo=)BO*nB_` z=4+O^sj90!o@gDNWVrvqUB1JyM2Tg3=))4(D0F|tZPqZ0g~G{<5X|>+WJB7JGox&r zhT6Q-4_EQVdD-p`5{mr~#3$*r5IgbBIxW;r{7;=0W+&c4zDrU3a+P?lPHSl={;p1I zWhZ_~r?s{d4^f}fX}?@0o~zT^*om*vX>IMqFX*&(cH)6Dpv+2pJMlD~*1=BvEuGfU zPW+-y>txq)>0U;^TrF3=yx8$9juP)CR4KQ-p%4^}4^;7XLfVF~tWiLI+7Ux4(Js4x7?Nydar{Phis~svW@474J@!|h@;Yui$debBiM<3)=Cfrjnnm`OMQM1jZNokNL7y3@?~(pCmE5Fv-Dw8TDXrAtTY&@>1#7zsY$& z=1pSHOSI%;ETSNy<8={EOogel*!w`fDU!b{rh5O>35487q&#*BnAPu=B=!hsutf$o zI|MYKy(FqtP!Q29U4#>T zVk#=yO}_Dxzqk4fia&PN&39YRby9*V{~;-tU746IOA>oB)SBp3c?l#AU4$TM{#X3h zP5l)!e#4AjTI~(BUpW{5`Wbs1Q-!Jw5y z8K7m{1*Uc|`l$J+j9)kvQAT$ecY&$$?rs;DVP9AF?(HsifvF{;Tm0L*z+MvFvOcfa zqiZdm=%Mk(mW;eP9FY&$e=Cp$UL%RP59`+BiI(BDex5|IqIq$xz z|2On=w+8vYp&f@lu?(G0Bdzz*`mj=WR~WuI=_9<|Bt=a6$j6x;h9shdb)4NC$Vngh zX3H5FMoG@ocIu?ToTp)%rFx(s&eIZgQatBrQ*=@y=V|ZhqJqBowi#}&dB$OE+U@usBJnaiRdRfsW0bKgog8}QtJjDcX<7=>sYFN3t3*fLtHckb@6+K`qND!tuoSQ2kf(T2 z2U7BN$=a(r4PXX0}25tFn?8TaMM$()_pI3Jh0rI@5i%eXJ^|I`%GPUUb`E-k_& zJ->|m@@}1^VQK*4z6lx$Fg&N34p$4*JsNo0r;#Wr6DPC;@ z4FC97O^d5Wp@zLj|0L9q-6+&R{%@$=Db%1Oqfi6+o`f3Y7=;?hMxh3>QK*4z6lx$F zg&N34p$4*1s0rByp$4*1sDW%0Y9Jeh8puYW2C`A8fov3NAUlRyCGB~c_BJ8$mU+Hc z=vJ&aRVwI8tnV^%aBE4FQBz{omOg?TZ=&=M$RbKpLl#k*xx|wjni%4V(!7vGbZ7A$ zHBnj{vWTLKQ4h!>O5=lzC=CzsL^-oTMxyis)Sf7NUt}aow}5z}bO~f6N_T*GqI3nw zB1$)aETVJ)Joq8XISw)s?W8}{zvuh%Lgh*`9|@oZLeTtl-o{37yto>f;cfTjRhPH$f%-C5JW)cY^%wR}lKIl~ z{7FO!oz`Ep{}q{!D{N>#Q9`HwEA)Rx=I0Uw+E0|wY5B(c^7!bpx$JbXi^p(pjulTg zwcePV279Jl6kg=cA!nO{N^=_S%j+aZ$IcSQI>7ES&D~GKWZDsCN_tr#H?b3PyE-8^ zrW105Iw5zb6LLQ~A$Oh=a*sJ7H<%N0D>)%IjT3UmI3c%-6LPOOA$Nrnz9{zq^6f^e zWm>9D2h=m6qn?>AtDeb6Jrh#Tgw!)3^-M@T6H?EF)H5OVOh`QwQqP3cGa>a%NIeto zllyo1sw3*1ka{QNHdbBH68Wz_HAVbgeR8+4qdw_xgt?O8WeMqj-^n!nufE)ePyb7k zY5Ly+ndYk|>@rP%JSNlhM?$_BqORQUPXD}Lrs-O+s$jb%b2!Amrqkkdt9TPHqV~StaD;laP~1LQW0|IoTuR zKa0WZOYnJ0~@m@0RXiw^y&{5A!Q_qCdGa>a% zNIer$&xF)7A@xj1Jrh#Tgw!)3^-M@T6H?EF)H5OVOvoK`c@Fc%vg)7HFGqd!aaX>Ee3LVj$HkROjDA(zV@1sudycNYpDtOnrTA5Hky#HfhOc@oeBAxWHMhm5Sbn-A@xkSK+^dwYwDeFx4g~|Thk7Nzsc)=NQjr*sRuuC zO*;`r$m{&x^#GY3A|dTam?7y|66Q}(e5GB{D?OFjBt{?&M#`y?+91Q>-@Yn{gCjq zyv}cJ6JC;Z`YBj2+PTzgY&CJvF{8;c%`X|zu7s=Pb$-@}b|yR_uk!=6XJqjEYtj6lB3_gDzEe7N%UV$Yk%vn1#hR=Etl6zX0+f%6Bi8W7Nvz; zF29xEMVTs>!EdEol_6XXE^)zvH~Wt_q?c0`8`9mBB)N=JLX2X;&qtRT(#tDr4e1`r z1w*>0GNVRG$r^6KTPl|s($TlxXTSV2lnc%MOJ%Sq6_sm-bl5n^h~HOnGo)8m zjs+X>)5`&?*`AtHA~NdBItk!-Io@1ZWi=oSJ9L z49ZbbQ?jy>M~unIPR_TbgPIh`ezEGH! zlRP3TXLw3ha+)nCFF!e@V7!u=GbT4H-Iksf)H)<0)R-wbBQrZQIVCSIWkPa#wk>ah zl987(COtW=V9b~a$WkJe3{KlEti!W%#${yYk3_YiC7PU;o|-oy*H%nO&(;X>YJMeA z1Ifu<`$qNZlH8?tOmecQT7FLQ$dv4~taK$gW>D{_Ufnx`+O2p0z6WIl$D;AVoNEmY`!fgH#sLaJuk(UnUk%k+9`Pz#wc-Fm?>6PD8DS z=jTgPs)6UNw5h6CF2G&qu2c8)DQXhe2F(C~uHthDBt zX^NT}nUX(J2}+xgjhq^^~ty9@#A{p26(z8-T28rcn*_0q*b0x@@J|2IC ztKeFWse1mE>Q#osMSdslbMPtrgy`QQiSAoG!Qr%x z^F6{q2WgJeuOM8%QdE?~{G1mOM#}u0{y9FKiNJNS^1%F@KN7~He-ei%SD?(#8Al{& zLN@bro=M1eT7pGAq&Ozk55^Uhs6XeUgq(S>{w#-3ye92tiTs?m68g)M9P7^tqyZ7v zD39}7!mW~#C7U$u}KSq=rT9Za7GBFc9xhxr}f zuqf4`<`FV}m-z)=@+fptf95Bz1q4T$xVBN||6ML~kl&G4ybjorCU{rN4k@3Ckpdif zYdgvR|EAyu(QpG+0OQaPI@%g!CVKe&NP=kaLJM%1{V>`Dsvl}RoN`KsF!$HOg}@A$ zKA0$^9|7YbXvU{dHUam8%!8FZ2;IOm#R##<16nXE042?U7?z%3^&hBwLknV{2m?a^ bJ4C-Wn&If~2SqP7{neZhmA+^i(6|f$lbE`H diff --git a/Crypto/Cipher/_raw_cast.abi3.so b/Crypto/Cipher/_raw_cast.abi3.so deleted file mode 100644 index 0aabbe84c3c36d82b925aa60cec1b4e4a401314c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 42976 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≥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 LKR9txwyl2w6Isba diff --git a/Crypto/Cipher/_raw_cbc.abi3.so b/Crypto/Cipher/_raw_cbc.abi3.so deleted file mode 100644 index d39e17247792e9d18e787fd8e167aaa572260807..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 20712 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 C>5=dN diff --git a/Crypto/Cipher/_raw_cfb.abi3.so b/Crypto/Cipher/_raw_cfb.abi3.so deleted file mode 100644 index 96dd44d23ff4aa03437bdb4fe48f4602fe055343..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 25440 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 P>ffO{-ljB#G*tWt_zA>4 diff --git a/Crypto/Cipher/_raw_ctr.abi3.so b/Crypto/Cipher/_raw_ctr.abi3.so deleted file mode 100644 index e5a71de781782dd903075d420e146ff8527c1616..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 28600 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 IkcNu?1{mFVIRF3v diff --git a/Crypto/Cipher/_raw_des.abi3.so b/Crypto/Cipher/_raw_des.abi3.so deleted file mode 100644 index a250e3ae97d8188d0aa05b82a93464dde8b87c8b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 75672 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 XFi+Nh8z{2q|4v`|J(M6wWX=Bq0Xeqj diff --git a/Crypto/Cipher/_raw_des3.abi3.so b/Crypto/Cipher/_raw_des3.abi3.so deleted file mode 100644 index ba68b325e508f9e9a8ebfe52557b574c53d9af84..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 76480 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 C28_V~ diff --git a/Crypto/Cipher/_raw_eksblowfish.abi3.so b/Crypto/Cipher/_raw_eksblowfish.abi3.so deleted file mode 100644 index a20c0b0e019064a9ff23a1f0d011f358d8ce5ffb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 167560 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 S=bG}LyQV65YEmFcHvTWn;f56e diff --git a/Crypto/Cipher/_raw_ocb.abi3.so b/Crypto/Cipher/_raw_ocb.abi3.so deleted file mode 100644 index 3af24e6b8b650d6dd38fd4aa9cffc8bb37bc5e68..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 37344 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 diff --git a/Crypto/Cipher/_raw_ofb.abi3.so b/Crypto/Cipher/_raw_ofb.abi3.so deleted file mode 100644 index 732caf67a06e43c121836176240a069b866383d8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 15368 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 BnZ*DA diff --git a/Crypto/Hash/BLAKE2b.py b/Crypto/Hash/BLAKE2b.py deleted file mode 100644 index a00e0b4..0000000 --- a/Crypto/Hash/BLAKE2b.py +++ /dev/null @@ -1,247 +0,0 @@ -# =================================================================== -# -# Copyright (c) 2014, Legrandin -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# =================================================================== - -from binascii import unhexlify - -from Crypto.Util.py3compat import bord, tobytes - -from Crypto.Random import get_random_bytes -from Crypto.Util._raw_api import (load_pycryptodome_raw_lib, - VoidPointer, SmartPointer, - create_string_buffer, - get_raw_buffer, c_size_t, - c_uint8_ptr) - -_raw_blake2b_lib = load_pycryptodome_raw_lib("Crypto.Hash._BLAKE2b", - """ - int blake2b_init(void **state, - const uint8_t *key, - size_t key_size, - size_t digest_size); - int blake2b_destroy(void *state); - int blake2b_update(void *state, - const uint8_t *buf, - size_t len); - int blake2b_digest(const void *state, - uint8_t digest[64]); - int blake2b_copy(const void *src, void *dst); - """) - - -class BLAKE2b_Hash(object): - """A BLAKE2b hash object. - Do not instantiate directly. Use the :func:`new` function. - - :ivar oid: ASN.1 Object ID - :vartype oid: string - - :ivar block_size: the size in bytes of the internal message block, - input to the compression function - :vartype block_size: integer - - :ivar digest_size: the size in bytes of the resulting hash - :vartype digest_size: integer - """ - - # The internal block size of the hash algorithm in bytes. - block_size = 64 - - def __init__(self, data, key, digest_bytes, update_after_digest): - - # The size of the resulting hash in bytes. - self.digest_size = digest_bytes - - self._update_after_digest = update_after_digest - self._digest_done = False - - # See https://tools.ietf.org/html/rfc7693 - if digest_bytes in (20, 32, 48, 64) and not key: - self.oid = "1.3.6.1.4.1.1722.12.2.1." + str(digest_bytes) - - state = VoidPointer() - result = _raw_blake2b_lib.blake2b_init(state.address_of(), - c_uint8_ptr(key), - c_size_t(len(key)), - c_size_t(digest_bytes) - ) - if result: - raise ValueError("Error %d while instantiating BLAKE2b" % result) - self._state = SmartPointer(state.get(), - _raw_blake2b_lib.blake2b_destroy) - if data: - self.update(data) - - - def update(self, data): - """Continue hashing of a message by consuming the next chunk of data. - - Args: - data (bytes/bytearray/memoryview): The next chunk of the message being hashed. - """ - - if self._digest_done and not self._update_after_digest: - raise TypeError("You can only call 'digest' or 'hexdigest' on this object") - - result = _raw_blake2b_lib.blake2b_update(self._state.get(), - c_uint8_ptr(data), - c_size_t(len(data))) - if result: - raise ValueError("Error %d while hashing BLAKE2b data" % result) - return self - - - def digest(self): - """Return the **binary** (non-printable) digest of the message that has been hashed so far. - - :return: The hash digest, computed over the data processed so far. - Binary form. - :rtype: byte string - """ - - bfr = create_string_buffer(64) - result = _raw_blake2b_lib.blake2b_digest(self._state.get(), - bfr) - if result: - raise ValueError("Error %d while creating BLAKE2b digest" % result) - - self._digest_done = True - - return get_raw_buffer(bfr)[:self.digest_size] - - - def hexdigest(self): - """Return the **printable** digest of the message that has been hashed so far. - - :return: The hash digest, computed over the data processed so far. - Hexadecimal encoded. - :rtype: string - """ - - return "".join(["%02x" % bord(x) for x in tuple(self.digest())]) - - - def verify(self, mac_tag): - """Verify that a given **binary** MAC (computed by another party) - is valid. - - Args: - mac_tag (bytes/bytearray/memoryview): the expected MAC of the message. - - Raises: - ValueError: if the MAC does not match. It means that the message - has been tampered with or that the MAC key is incorrect. - """ - - secret = get_random_bytes(16) - - mac1 = new(digest_bits=160, key=secret, data=mac_tag) - mac2 = new(digest_bits=160, key=secret, data=self.digest()) - - if mac1.digest() != mac2.digest(): - raise ValueError("MAC check failed") - - - def hexverify(self, hex_mac_tag): - """Verify that a given **printable** MAC (computed by another party) - is valid. - - Args: - hex_mac_tag (string): the expected MAC of the message, as a hexadecimal string. - - Raises: - ValueError: if the MAC does not match. It means that the message - has been tampered with or that the MAC key is incorrect. - """ - - self.verify(unhexlify(tobytes(hex_mac_tag))) - - - def new(self, **kwargs): - """Return a new instance of a BLAKE2b hash object. - See :func:`new`. - """ - - if "digest_bytes" not in kwargs and "digest_bits" not in kwargs: - kwargs["digest_bytes"] = self.digest_size - - return new(**kwargs) - - -def new(**kwargs): - """Create a new hash object. - - Args: - data (bytes/bytearray/memoryview): - Optional. The very first chunk of the message to hash. - It is equivalent to an early call to :meth:`BLAKE2b_Hash.update`. - digest_bytes (integer): - Optional. The size of the digest, in bytes (1 to 64). Default is 64. - digest_bits (integer): - Optional and alternative to ``digest_bytes``. - The size of the digest, in bits (8 to 512, in steps of 8). - Default is 512. - key (bytes/bytearray/memoryview): - Optional. The key to use to compute the MAC (1 to 64 bytes). - If not specified, no key will be used. - update_after_digest (boolean): - Optional. By default, a hash object cannot be updated anymore after - the digest is computed. When this flag is ``True``, such check - is no longer enforced. - - Returns: - A :class:`BLAKE2b_Hash` hash object - """ - - data = kwargs.pop("data", None) - update_after_digest = kwargs.pop("update_after_digest", False) - - digest_bytes = kwargs.pop("digest_bytes", None) - digest_bits = kwargs.pop("digest_bits", None) - if None not in (digest_bytes, digest_bits): - raise TypeError("Only one digest parameter must be provided") - if (None, None) == (digest_bytes, digest_bits): - digest_bytes = 64 - if digest_bytes is not None: - if not (1 <= digest_bytes <= 64): - raise ValueError("'digest_bytes' not in range 1..64") - else: - if not (8 <= digest_bits <= 512) or (digest_bits % 8): - raise ValueError("'digest_bytes' not in range 8..512, " - "with steps of 8") - digest_bytes = digest_bits // 8 - - key = kwargs.pop("key", b"") - if len(key) > 64: - raise ValueError("BLAKE2s key cannot exceed 64 bytes") - - if kwargs: - raise TypeError("Unknown parameters: " + str(kwargs)) - - return BLAKE2b_Hash(data, key, digest_bytes, update_after_digest) diff --git a/Crypto/Hash/BLAKE2b.pyi b/Crypto/Hash/BLAKE2b.pyi deleted file mode 100644 index ac3bf57..0000000 --- a/Crypto/Hash/BLAKE2b.pyi +++ /dev/null @@ -1,31 +0,0 @@ -from typing import Any, Union - -Buffer = Union[bytes, bytearray, memoryview] - -class BLAKE2b_Hash(object): - block_size: int - digest_size: int - oid: str - - def __init__(self, - data: Buffer, - key: Buffer, - digest_bytes: bytes, - update_after_digest: bool) -> None: ... - def update(self, data: Buffer) -> BLAKE2b_Hash: ... - def digest(self) -> bytes: ... - def hexdigest(self) -> str: ... - def verify(self, mac_tag: Buffer) -> None: ... - def hexverify(self, hex_mac_tag: str) -> None: ... - def new(self, - data: Buffer = ..., - digest_bytes: int = ..., - digest_bits: int = ..., - key: Buffer = ..., - update_after_digest: bool = ...) -> BLAKE2b_Hash: ... - -def new(data: Buffer = ..., - digest_bytes: int = ..., - digest_bits: int = ..., - key: Buffer = ..., - update_after_digest: bool = ...) -> BLAKE2b_Hash: ... diff --git a/Crypto/Hash/BLAKE2s.py b/Crypto/Hash/BLAKE2s.py deleted file mode 100644 index 9b25c4a..0000000 --- a/Crypto/Hash/BLAKE2s.py +++ /dev/null @@ -1,247 +0,0 @@ -# =================================================================== -# -# Copyright (c) 2014, Legrandin -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# =================================================================== - -from binascii import unhexlify - -from Crypto.Util.py3compat import bord, tobytes - -from Crypto.Random import get_random_bytes -from Crypto.Util._raw_api import (load_pycryptodome_raw_lib, - VoidPointer, SmartPointer, - create_string_buffer, - get_raw_buffer, c_size_t, - c_uint8_ptr) - -_raw_blake2s_lib = load_pycryptodome_raw_lib("Crypto.Hash._BLAKE2s", - """ - int blake2s_init(void **state, - const uint8_t *key, - size_t key_size, - size_t digest_size); - int blake2s_destroy(void *state); - int blake2s_update(void *state, - const uint8_t *buf, - size_t len); - int blake2s_digest(const void *state, - uint8_t digest[32]); - int blake2s_copy(const void *src, void *dst); - """) - - -class BLAKE2s_Hash(object): - """A BLAKE2s hash object. - Do not instantiate directly. Use the :func:`new` function. - - :ivar oid: ASN.1 Object ID - :vartype oid: string - - :ivar block_size: the size in bytes of the internal message block, - input to the compression function - :vartype block_size: integer - - :ivar digest_size: the size in bytes of the resulting hash - :vartype digest_size: integer - """ - - # The internal block size of the hash algorithm in bytes. - block_size = 32 - - def __init__(self, data, key, digest_bytes, update_after_digest): - - # The size of the resulting hash in bytes. - self.digest_size = digest_bytes - - self._update_after_digest = update_after_digest - self._digest_done = False - - # See https://tools.ietf.org/html/rfc7693 - if digest_bytes in (16, 20, 28, 32) and not key: - self.oid = "1.3.6.1.4.1.1722.12.2.2." + str(digest_bytes) - - state = VoidPointer() - result = _raw_blake2s_lib.blake2s_init(state.address_of(), - c_uint8_ptr(key), - c_size_t(len(key)), - c_size_t(digest_bytes) - ) - if result: - raise ValueError("Error %d while instantiating BLAKE2s" % result) - self._state = SmartPointer(state.get(), - _raw_blake2s_lib.blake2s_destroy) - if data: - self.update(data) - - - def update(self, data): - """Continue hashing of a message by consuming the next chunk of data. - - Args: - data (byte string/byte array/memoryview): The next chunk of the message being hashed. - """ - - if self._digest_done and not self._update_after_digest: - raise TypeError("You can only call 'digest' or 'hexdigest' on this object") - - result = _raw_blake2s_lib.blake2s_update(self._state.get(), - c_uint8_ptr(data), - c_size_t(len(data))) - if result: - raise ValueError("Error %d while hashing BLAKE2s data" % result) - return self - - - def digest(self): - """Return the **binary** (non-printable) digest of the message that has been hashed so far. - - :return: The hash digest, computed over the data processed so far. - Binary form. - :rtype: byte string - """ - - bfr = create_string_buffer(32) - result = _raw_blake2s_lib.blake2s_digest(self._state.get(), - bfr) - if result: - raise ValueError("Error %d while creating BLAKE2s digest" % result) - - self._digest_done = True - - return get_raw_buffer(bfr)[:self.digest_size] - - - def hexdigest(self): - """Return the **printable** digest of the message that has been hashed so far. - - :return: The hash digest, computed over the data processed so far. - Hexadecimal encoded. - :rtype: string - """ - - return "".join(["%02x" % bord(x) for x in tuple(self.digest())]) - - - def verify(self, mac_tag): - """Verify that a given **binary** MAC (computed by another party) - is valid. - - Args: - mac_tag (byte string/byte array/memoryview): the expected MAC of the message. - - Raises: - ValueError: if the MAC does not match. It means that the message - has been tampered with or that the MAC key is incorrect. - """ - - secret = get_random_bytes(16) - - mac1 = new(digest_bits=160, key=secret, data=mac_tag) - mac2 = new(digest_bits=160, key=secret, data=self.digest()) - - if mac1.digest() != mac2.digest(): - raise ValueError("MAC check failed") - - - def hexverify(self, hex_mac_tag): - """Verify that a given **printable** MAC (computed by another party) - is valid. - - Args: - hex_mac_tag (string): the expected MAC of the message, as a hexadecimal string. - - Raises: - ValueError: if the MAC does not match. It means that the message - has been tampered with or that the MAC key is incorrect. - """ - - self.verify(unhexlify(tobytes(hex_mac_tag))) - - - def new(self, **kwargs): - """Return a new instance of a BLAKE2s hash object. - See :func:`new`. - """ - - if "digest_bytes" not in kwargs and "digest_bits" not in kwargs: - kwargs["digest_bytes"] = self.digest_size - - return new(**kwargs) - - -def new(**kwargs): - """Create a new hash object. - - Args: - data (byte string/byte array/memoryview): - Optional. The very first chunk of the message to hash. - It is equivalent to an early call to :meth:`BLAKE2s_Hash.update`. - digest_bytes (integer): - Optional. The size of the digest, in bytes (1 to 32). Default is 32. - digest_bits (integer): - Optional and alternative to ``digest_bytes``. - The size of the digest, in bits (8 to 256, in steps of 8). - Default is 256. - key (byte string): - Optional. The key to use to compute the MAC (1 to 64 bytes). - If not specified, no key will be used. - update_after_digest (boolean): - Optional. By default, a hash object cannot be updated anymore after - the digest is computed. When this flag is ``True``, such check - is no longer enforced. - - Returns: - A :class:`BLAKE2s_Hash` hash object - """ - - data = kwargs.pop("data", None) - update_after_digest = kwargs.pop("update_after_digest", False) - - digest_bytes = kwargs.pop("digest_bytes", None) - digest_bits = kwargs.pop("digest_bits", None) - if None not in (digest_bytes, digest_bits): - raise TypeError("Only one digest parameter must be provided") - if (None, None) == (digest_bytes, digest_bits): - digest_bytes = 32 - if digest_bytes is not None: - if not (1 <= digest_bytes <= 32): - raise ValueError("'digest_bytes' not in range 1..32") - else: - if not (8 <= digest_bits <= 256) or (digest_bits % 8): - raise ValueError("'digest_bytes' not in range 8..256, " - "with steps of 8") - digest_bytes = digest_bits // 8 - - key = kwargs.pop("key", b"") - if len(key) > 32: - raise ValueError("BLAKE2s key cannot exceed 32 bytes") - - if kwargs: - raise TypeError("Unknown parameters: " + str(kwargs)) - - return BLAKE2s_Hash(data, key, digest_bytes, update_after_digest) diff --git a/Crypto/Hash/BLAKE2s.pyi b/Crypto/Hash/BLAKE2s.pyi deleted file mode 100644 index 374b3a4..0000000 --- a/Crypto/Hash/BLAKE2s.pyi +++ /dev/null @@ -1,26 +0,0 @@ -from typing import Any, Union - -Buffer = Union[bytes, bytearray, memoryview] - -class BLAKE2s_Hash(object): - block_size: int - digest_size: int - oid: str - - def __init__(self, - data: Buffer, - key: Buffer, - digest_bytes: bytes, - update_after_digest: bool) -> None: ... - def update(self, data: Buffer) -> BLAKE2s_Hash: ... - def digest(self) -> bytes: ... - def hexdigest(self) -> str: ... - def verify(self, mac_tag: Buffer) -> None: ... - def hexverify(self, hex_mac_tag: str) -> None: ... - def new(self, **kwargs: Any) -> BLAKE2s_Hash: ... - -def new(data: Buffer = ..., - digest_bytes: int = ..., - digest_bits: int = ..., - key: Buffer = ..., - update_after_digest: bool = ...) -> BLAKE2s_Hash: ... diff --git a/Crypto/Hash/CMAC.py b/Crypto/Hash/CMAC.py deleted file mode 100644 index 7585617..0000000 --- a/Crypto/Hash/CMAC.py +++ /dev/null @@ -1,302 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Hash/CMAC.py - Implements the CMAC algorithm -# -# =================================================================== -# The contents of this file are dedicated to the public domain. To -# the extent that dedication to the public domain is not available, -# everyone is granted a worldwide, perpetual, royalty-free, -# non-exclusive license to exercise all rights associated with the -# contents of this file for any purpose whatsoever. -# No rights are reserved. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS -# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN -# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# =================================================================== - -from binascii import unhexlify - -from Crypto.Hash import BLAKE2s -from Crypto.Util.strxor import strxor -from Crypto.Util.number import long_to_bytes, bytes_to_long -from Crypto.Util.py3compat import bord, tobytes, _copy_bytes -from Crypto.Random import get_random_bytes - - -# The size of the authentication tag produced by the MAC. -digest_size = None - - -def _shift_bytes(bs, xor_lsb=0): - num = (bytes_to_long(bs) << 1) ^ xor_lsb - return long_to_bytes(num, len(bs))[-len(bs):] - - -class CMAC(object): - """A CMAC hash object. - Do not instantiate directly. Use the :func:`new` function. - - :ivar digest_size: the size in bytes of the resulting MAC tag - :vartype digest_size: integer - """ - - digest_size = None - - def __init__(self, key, msg, ciphermod, cipher_params, mac_len, - update_after_digest): - - self.digest_size = mac_len - - self._key = _copy_bytes(None, None, key) - self._factory = ciphermod - self._cipher_params = cipher_params - self._block_size = bs = ciphermod.block_size - self._mac_tag = None - self._update_after_digest = update_after_digest - - # Section 5.3 of NIST SP 800 38B and Appendix B - if bs == 8: - const_Rb = 0x1B - self._max_size = 8 * (2 ** 21) - elif bs == 16: - const_Rb = 0x87 - self._max_size = 16 * (2 ** 48) - else: - raise TypeError("CMAC requires a cipher with a block size" - " of 8 or 16 bytes, not %d" % bs) - - # Compute sub-keys - zero_block = b'\x00' * bs - self._ecb = ciphermod.new(key, - ciphermod.MODE_ECB, - **self._cipher_params) - L = self._ecb.encrypt(zero_block) - if bord(L[0]) & 0x80: - self._k1 = _shift_bytes(L, const_Rb) - else: - self._k1 = _shift_bytes(L) - if bord(self._k1[0]) & 0x80: - self._k2 = _shift_bytes(self._k1, const_Rb) - else: - self._k2 = _shift_bytes(self._k1) - - # Initialize CBC cipher with zero IV - self._cbc = ciphermod.new(key, - ciphermod.MODE_CBC, - zero_block, - **self._cipher_params) - - # Cache for outstanding data to authenticate - self._cache = bytearray(bs) - self._cache_n = 0 - - # Last piece of ciphertext produced - self._last_ct = zero_block - - # Last block that was encrypted with AES - self._last_pt = None - - # Counter for total message size - self._data_size = 0 - - if msg: - self.update(msg) - - def update(self, msg): - """Authenticate the next chunk of message. - - Args: - data (byte string/byte array/memoryview): The next chunk of data - """ - - if self._mac_tag is not None and not self._update_after_digest: - raise TypeError("update() cannot be called after digest() or verify()") - - self._data_size += len(msg) - bs = self._block_size - - if self._cache_n > 0: - filler = min(bs - self._cache_n, len(msg)) - self._cache[self._cache_n:self._cache_n+filler] = msg[:filler] - self._cache_n += filler - - if self._cache_n < bs: - return self - - msg = memoryview(msg)[filler:] - self._update(self._cache) - self._cache_n = 0 - - remain = len(msg) % bs - if remain > 0: - self._update(msg[:-remain]) - self._cache[:remain] = msg[-remain:] - else: - self._update(msg) - self._cache_n = remain - return self - - def _update(self, data_block): - """Update a block aligned to the block boundary""" - - bs = self._block_size - assert len(data_block) % bs == 0 - - if len(data_block) == 0: - return - - ct = self._cbc.encrypt(data_block) - if len(data_block) == bs: - second_last = self._last_ct - else: - second_last = ct[-bs*2:-bs] - self._last_ct = ct[-bs:] - self._last_pt = strxor(second_last, data_block[-bs:]) - - def copy(self): - """Return a copy ("clone") of the CMAC object. - - The copy will have the same internal state as the original CMAC - object. - This can be used to efficiently compute the MAC tag of byte - strings that share a common initial substring. - - :return: An :class:`CMAC` - """ - - obj = self.__new__(CMAC) - obj.__dict__ = self.__dict__.copy() - obj._cbc = self._factory.new(self._key, - self._factory.MODE_CBC, - self._last_ct, - **self._cipher_params) - obj._cache = self._cache[:] - obj._last_ct = self._last_ct[:] - return obj - - def digest(self): - """Return the **binary** (non-printable) MAC tag of the message - that has been authenticated so far. - - :return: The MAC tag, computed over the data processed so far. - Binary form. - :rtype: byte string - """ - - bs = self._block_size - - if self._mac_tag is not None and not self._update_after_digest: - return self._mac_tag - - if self._data_size > self._max_size: - raise ValueError("MAC is unsafe for this message") - - if self._cache_n == 0 and self._data_size > 0: - # Last block was full - pt = strxor(self._last_pt, self._k1) - else: - # Last block is partial (or message length is zero) - partial = self._cache[:] - partial[self._cache_n:] = b'\x80' + b'\x00' * (bs - self._cache_n - 1) - pt = strxor(strxor(self._last_ct, partial), self._k2) - - self._mac_tag = self._ecb.encrypt(pt)[:self.digest_size] - - return self._mac_tag - - def hexdigest(self): - """Return the **printable** MAC tag of the message authenticated so far. - - :return: The MAC tag, computed over the data processed so far. - Hexadecimal encoded. - :rtype: string - """ - - return "".join(["%02x" % bord(x) - for x in tuple(self.digest())]) - - def verify(self, mac_tag): - """Verify that a given **binary** MAC (computed by another party) - is valid. - - Args: - mac_tag (byte string/byte array/memoryview): the expected MAC of the message. - - Raises: - ValueError: if the MAC does not match. It means that the message - has been tampered with or that the MAC key is incorrect. - """ - - secret = get_random_bytes(16) - - mac1 = BLAKE2s.new(digest_bits=160, key=secret, data=mac_tag) - mac2 = BLAKE2s.new(digest_bits=160, key=secret, data=self.digest()) - - if mac1.digest() != mac2.digest(): - raise ValueError("MAC check failed") - - def hexverify(self, hex_mac_tag): - """Return the **printable** MAC tag of the message authenticated so far. - - :return: The MAC tag, computed over the data processed so far. - Hexadecimal encoded. - :rtype: string - """ - - self.verify(unhexlify(tobytes(hex_mac_tag))) - - -def new(key, msg=None, ciphermod=None, cipher_params=None, mac_len=None, - update_after_digest=False): - """Create a new MAC object. - - Args: - key (byte string/byte array/memoryview): - key for the CMAC object. - The key must be valid for the underlying cipher algorithm. - For instance, it must be 16 bytes long for AES-128. - ciphermod (module): - A cipher module from :mod:`Crypto.Cipher`. - The cipher's block size has to be 128 bits, - like :mod:`Crypto.Cipher.AES`, to reduce the probability - of collisions. - msg (byte string/byte array/memoryview): - Optional. The very first chunk of the message to authenticate. - It is equivalent to an early call to `CMAC.update`. Optional. - cipher_params (dict): - Optional. A set of parameters to use when instantiating a cipher - object. - mac_len (integer): - Length of the MAC, in bytes. - It must be at least 4 bytes long. - The default (and recommended) length matches the size of a cipher block. - update_after_digest (boolean): - Optional. By default, a hash object cannot be updated anymore after - the digest is computed. When this flag is ``True``, such check - is no longer enforced. - Returns: - A :class:`CMAC` object - """ - - if ciphermod is None: - raise TypeError("ciphermod must be specified (try AES)") - - cipher_params = {} if cipher_params is None else dict(cipher_params) - - if mac_len is None: - mac_len = ciphermod.block_size - - if mac_len < 4: - raise ValueError("MAC tag length must be at least 4 bytes long") - - if mac_len > ciphermod.block_size: - raise ValueError("MAC tag length cannot be larger than a cipher block (%d) bytes" % ciphermod.block_size) - - return CMAC(key, msg, ciphermod, cipher_params, mac_len, - update_after_digest) diff --git a/Crypto/Hash/CMAC.pyi b/Crypto/Hash/CMAC.pyi deleted file mode 100644 index 33773aa..0000000 --- a/Crypto/Hash/CMAC.pyi +++ /dev/null @@ -1,30 +0,0 @@ -from types import ModuleType -from typing import Union, Dict - -Buffer = Union[bytes, bytearray, memoryview] - -digest_size: int - -class CMAC(object): - digest_size: int - - def __init__(self, - key: Buffer, - msg: Buffer, - ciphermod: ModuleType, - cipher_params: dict, - mac_len: int, update_after_digest: bool) -> None: ... - def update(self, data: Buffer) -> CMAC: ... - def copy(self) -> CMAC: ... - def digest(self) -> bytes: ... - def hexdigest(self) -> str: ... - def verify(self, mac_tag: Buffer) -> None: ... - def hexverify(self, hex_mac_tag: str) -> None: ... - - -def new(key: Buffer, - msg: Buffer = ..., - ciphermod: ModuleType = ..., - cipher_params: Dict = ..., - mac_len: int = ..., - update_after_digest: bool = ...) -> CMAC: ... diff --git a/Crypto/Hash/HMAC.py b/Crypto/Hash/HMAC.py deleted file mode 100644 index e82bb9d..0000000 --- a/Crypto/Hash/HMAC.py +++ /dev/null @@ -1,213 +0,0 @@ -# -# HMAC.py - Implements the HMAC algorithm as described by RFC 2104. -# -# =================================================================== -# -# Copyright (c) 2014, Legrandin -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# =================================================================== - -from Crypto.Util.py3compat import bord, tobytes - -from binascii import unhexlify - -from Crypto.Hash import MD5 -from Crypto.Hash import BLAKE2s -from Crypto.Util.strxor import strxor -from Crypto.Random import get_random_bytes - -__all__ = ['new', 'HMAC'] - - -class HMAC(object): - """An HMAC hash object. - Do not instantiate directly. Use the :func:`new` function. - - :ivar digest_size: the size in bytes of the resulting MAC tag - :vartype digest_size: integer - """ - - def __init__(self, key, msg=b"", digestmod=None): - - if digestmod is None: - digestmod = MD5 - - if msg is None: - msg = b"" - - # Size of the MAC tag - self.digest_size = digestmod.digest_size - - self._digestmod = digestmod - - if isinstance(key, memoryview): - key = key.tobytes() - - try: - if len(key) <= digestmod.block_size: - # Step 1 or 2 - key_0 = key + b"\x00" * (digestmod.block_size - len(key)) - else: - # Step 3 - hash_k = digestmod.new(key).digest() - key_0 = hash_k + b"\x00" * (digestmod.block_size - len(hash_k)) - except AttributeError: - # Not all hash types have "block_size" - raise ValueError("Hash type incompatible to HMAC") - - # Step 4 - key_0_ipad = strxor(key_0, b"\x36" * len(key_0)) - - # Start step 5 and 6 - self._inner = digestmod.new(key_0_ipad) - self._inner.update(msg) - - # Step 7 - key_0_opad = strxor(key_0, b"\x5c" * len(key_0)) - - # Start step 8 and 9 - self._outer = digestmod.new(key_0_opad) - - def update(self, msg): - """Authenticate the next chunk of message. - - Args: - data (byte string/byte array/memoryview): The next chunk of data - """ - - self._inner.update(msg) - return self - - def _pbkdf2_hmac_assist(self, first_digest, iterations): - """Carry out the expensive inner loop for PBKDF2-HMAC""" - - result = self._digestmod._pbkdf2_hmac_assist( - self._inner, - self._outer, - first_digest, - iterations) - return result - - def copy(self): - """Return a copy ("clone") of the HMAC object. - - The copy will have the same internal state as the original HMAC - object. - This can be used to efficiently compute the MAC tag of byte - strings that share a common initial substring. - - :return: An :class:`HMAC` - """ - - new_hmac = HMAC(b"fake key", digestmod=self._digestmod) - - # Syncronize the state - new_hmac._inner = self._inner.copy() - new_hmac._outer = self._outer.copy() - - return new_hmac - - def digest(self): - """Return the **binary** (non-printable) MAC tag of the message - authenticated so far. - - :return: The MAC tag digest, computed over the data processed so far. - Binary form. - :rtype: byte string - """ - - frozen_outer_hash = self._outer.copy() - frozen_outer_hash.update(self._inner.digest()) - return frozen_outer_hash.digest() - - def verify(self, mac_tag): - """Verify that a given **binary** MAC (computed by another party) - is valid. - - Args: - mac_tag (byte string/byte string/memoryview): the expected MAC of the message. - - Raises: - ValueError: if the MAC does not match. It means that the message - has been tampered with or that the MAC key is incorrect. - """ - - secret = get_random_bytes(16) - - mac1 = BLAKE2s.new(digest_bits=160, key=secret, data=mac_tag) - mac2 = BLAKE2s.new(digest_bits=160, key=secret, data=self.digest()) - - if mac1.digest() != mac2.digest(): - raise ValueError("MAC check failed") - - def hexdigest(self): - """Return the **printable** MAC tag of the message authenticated so far. - - :return: The MAC tag, computed over the data processed so far. - Hexadecimal encoded. - :rtype: string - """ - - return "".join(["%02x" % bord(x) - for x in tuple(self.digest())]) - - def hexverify(self, hex_mac_tag): - """Verify that a given **printable** MAC (computed by another party) - is valid. - - Args: - hex_mac_tag (string): the expected MAC of the message, - as a hexadecimal string. - - Raises: - ValueError: if the MAC does not match. It means that the message - has been tampered with or that the MAC key is incorrect. - """ - - self.verify(unhexlify(tobytes(hex_mac_tag))) - - -def new(key, msg=b"", digestmod=None): - """Create a new MAC object. - - Args: - key (bytes/bytearray/memoryview): - key for the MAC object. - It must be long enough to match the expected security level of the - MAC. - msg (bytes/bytearray/memoryview): - Optional. The very first chunk of the message to authenticate. - It is equivalent to an early call to :meth:`HMAC.update`. - digestmod (module): - The hash to use to implement the HMAC. - Default is :mod:`Crypto.Hash.MD5`. - - Returns: - An :class:`HMAC` object - """ - - return HMAC(key, msg, digestmod) diff --git a/Crypto/Hash/HMAC.pyi b/Crypto/Hash/HMAC.pyi deleted file mode 100644 index b577230..0000000 --- a/Crypto/Hash/HMAC.pyi +++ /dev/null @@ -1,25 +0,0 @@ -from types import ModuleType -from typing import Union, Dict - -Buffer = Union[bytes, bytearray, memoryview] - -digest_size: int - -class HMAC(object): - digest_size: int - - def __init__(self, - key: Buffer, - msg: Buffer, - digestmod: ModuleType) -> None: ... - def update(self, msg: Buffer) -> HMAC: ... - def copy(self) -> HMAC: ... - def digest(self) -> bytes: ... - def hexdigest(self) -> str: ... - def verify(self, mac_tag: Buffer) -> None: ... - def hexverify(self, hex_mac_tag: str) -> None: ... - - -def new(key: Buffer, - msg: Buffer = ..., - digestmod: ModuleType = ...) -> HMAC: ... diff --git a/Crypto/Hash/MD2.py b/Crypto/Hash/MD2.py deleted file mode 100644 index 41decbb..0000000 --- a/Crypto/Hash/MD2.py +++ /dev/null @@ -1,166 +0,0 @@ -# =================================================================== -# -# Copyright (c) 2014, Legrandin -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# =================================================================== - -from Crypto.Util.py3compat import bord - -from Crypto.Util._raw_api import (load_pycryptodome_raw_lib, - VoidPointer, SmartPointer, - create_string_buffer, - get_raw_buffer, c_size_t, - c_uint8_ptr) - -_raw_md2_lib = load_pycryptodome_raw_lib( - "Crypto.Hash._MD2", - """ - int md2_init(void **shaState); - int md2_destroy(void *shaState); - int md2_update(void *hs, - const uint8_t *buf, - size_t len); - int md2_digest(const void *shaState, - uint8_t digest[20]); - int md2_copy(const void *src, void *dst); - """) - - -class MD2Hash(object): - """An MD2 hash object. - Do not instantiate directly. Use the :func:`new` function. - - :ivar oid: ASN.1 Object ID - :vartype oid: string - - :ivar block_size: the size in bytes of the internal message block, - input to the compression function - :vartype block_size: integer - - :ivar digest_size: the size in bytes of the resulting hash - :vartype digest_size: integer - """ - - # The size of the resulting hash in bytes. - digest_size = 16 - # The internal block size of the hash algorithm in bytes. - block_size = 16 - # ASN.1 Object ID - oid = "1.2.840.113549.2.2" - - def __init__(self, data=None): - state = VoidPointer() - result = _raw_md2_lib.md2_init(state.address_of()) - if result: - raise ValueError("Error %d while instantiating MD2" - % result) - self._state = SmartPointer(state.get(), - _raw_md2_lib.md2_destroy) - if data: - self.update(data) - - def update(self, data): - """Continue hashing of a message by consuming the next chunk of data. - - Args: - data (byte string/byte array/memoryview): The next chunk of the message being hashed. - """ - - result = _raw_md2_lib.md2_update(self._state.get(), - c_uint8_ptr(data), - c_size_t(len(data))) - if result: - raise ValueError("Error %d while instantiating MD2" - % result) - - def digest(self): - """Return the **binary** (non-printable) digest of the message that has been hashed so far. - - :return: The hash digest, computed over the data processed so far. - Binary form. - :rtype: byte string - """ - - bfr = create_string_buffer(self.digest_size) - result = _raw_md2_lib.md2_digest(self._state.get(), - bfr) - if result: - raise ValueError("Error %d while instantiating MD2" - % result) - - return get_raw_buffer(bfr) - - def hexdigest(self): - """Return the **printable** digest of the message that has been hashed so far. - - :return: The hash digest, computed over the data processed so far. - Hexadecimal encoded. - :rtype: string - """ - - return "".join(["%02x" % bord(x) for x in self.digest()]) - - def copy(self): - """Return a copy ("clone") of the hash object. - - The copy will have the same internal state as the original hash - object. - This can be used to efficiently compute the digests of strings that - share a common initial substring. - - :return: A hash object of the same type - """ - - clone = MD2Hash() - result = _raw_md2_lib.md2_copy(self._state.get(), - clone._state.get()) - if result: - raise ValueError("Error %d while copying MD2" % result) - return clone - - def new(self, data=None): - return MD2Hash(data) - - -def new(data=None): - """Create a new hash object. - - :parameter data: - Optional. The very first chunk of the message to hash. - It is equivalent to an early call to :meth:`MD2Hash.update`. - :type data: bytes/bytearray/memoryview - - :Return: A :class:`MD2Hash` hash object - """ - - return MD2Hash().new(data) - -# The size of the resulting hash in bytes. -digest_size = MD2Hash.digest_size - -# The internal block size of the hash algorithm in bytes. -block_size = MD2Hash.block_size diff --git a/Crypto/Hash/MD2.pyi b/Crypto/Hash/MD2.pyi deleted file mode 100644 index 95a97a9..0000000 --- a/Crypto/Hash/MD2.pyi +++ /dev/null @@ -1,19 +0,0 @@ -from typing import Union - -Buffer = Union[bytes, bytearray, memoryview] - -class MD4Hash(object): - digest_size: int - block_size: int - oid: str - - def __init__(self, data: Buffer = ...) -> None: ... - def update(self, data: Buffer) -> None: ... - def digest(self) -> bytes: ... - def hexdigest(self) -> str: ... - def copy(self) -> MD4Hash: ... - def new(self, data: Buffer = ...) -> MD4Hash: ... - -def new(data: Buffer = ...) -> MD4Hash: ... -digest_size: int -block_size: int diff --git a/Crypto/Hash/MD4.py b/Crypto/Hash/MD4.py deleted file mode 100644 index be12b19..0000000 --- a/Crypto/Hash/MD4.py +++ /dev/null @@ -1,185 +0,0 @@ -# =================================================================== -# -# Copyright (c) 2014, Legrandin -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# =================================================================== - -""" -MD4 is specified in RFC1320_ and produces the 128 bit digest of a message. - - >>> from Crypto.Hash import MD4 - >>> - >>> h = MD4.new() - >>> h.update(b'Hello') - >>> print h.hexdigest() - -MD4 stand for Message Digest version 4, and it was invented by Rivest in 1990. -This algorithm is insecure. Do not use it for new designs. - -.. _RFC1320: http://tools.ietf.org/html/rfc1320 -""" - -from Crypto.Util.py3compat import bord - -from Crypto.Util._raw_api import (load_pycryptodome_raw_lib, - VoidPointer, SmartPointer, - create_string_buffer, - get_raw_buffer, c_size_t, - c_uint8_ptr) - -_raw_md4_lib = load_pycryptodome_raw_lib( - "Crypto.Hash._MD4", - """ - int md4_init(void **shaState); - int md4_destroy(void *shaState); - int md4_update(void *hs, - const uint8_t *buf, - size_t len); - int md4_digest(const void *shaState, - uint8_t digest[20]); - int md4_copy(const void *src, void *dst); - """) - - -class MD4Hash(object): - """Class that implements an MD4 hash - """ - - #: The size of the resulting hash in bytes. - digest_size = 16 - #: The internal block size of the hash algorithm in bytes. - block_size = 64 - #: ASN.1 Object ID - oid = "1.2.840.113549.2.4" - - def __init__(self, data=None): - state = VoidPointer() - result = _raw_md4_lib.md4_init(state.address_of()) - if result: - raise ValueError("Error %d while instantiating MD4" - % result) - self._state = SmartPointer(state.get(), - _raw_md4_lib.md4_destroy) - if data: - self.update(data) - - def update(self, data): - """Continue hashing of a message by consuming the next chunk of data. - - Repeated calls are equivalent to a single call with the concatenation - of all the arguments. In other words: - - >>> m.update(a); m.update(b) - - is equivalent to: - - >>> m.update(a+b) - - :Parameters: - data : byte string/byte array/memoryview - The next chunk of the message being hashed. - """ - - result = _raw_md4_lib.md4_update(self._state.get(), - c_uint8_ptr(data), - c_size_t(len(data))) - if result: - raise ValueError("Error %d while instantiating MD4" - % result) - - def digest(self): - """Return the **binary** (non-printable) digest of the message that - has been hashed so far. - - This method does not change the state of the hash object. - You can continue updating the object after calling this function. - - :Return: A byte string of `digest_size` bytes. It may contain non-ASCII - characters, including null bytes. - """ - - bfr = create_string_buffer(self.digest_size) - result = _raw_md4_lib.md4_digest(self._state.get(), - bfr) - if result: - raise ValueError("Error %d while instantiating MD4" - % result) - - return get_raw_buffer(bfr) - - def hexdigest(self): - """Return the **printable** digest of the message that has been - hashed so far. - - This method does not change the state of the hash object. - - :Return: A string of 2* `digest_size` characters. It contains only - hexadecimal ASCII digits. - """ - - return "".join(["%02x" % bord(x) for x in self.digest()]) - - def copy(self): - """Return a copy ("clone") of the hash object. - - The copy will have the same internal state as the original hash - object. - This can be used to efficiently compute the digests of strings that - share a common initial substring. - - :Return: A hash object of the same type - """ - - clone = MD4Hash() - result = _raw_md4_lib.md4_copy(self._state.get(), - clone._state.get()) - if result: - raise ValueError("Error %d while copying MD4" % result) - return clone - - def new(self, data=None): - return MD4Hash(data) - - -def new(data=None): - """Return a fresh instance of the hash object. - - :Parameters: - data : byte string/byte array/memoryview - The very first chunk of the message to hash. - It is equivalent to an early call to `MD4Hash.update()`. - Optional. - - :Return: A `MD4Hash` object - """ - return MD4Hash().new(data) - -#: The size of the resulting hash in bytes. -digest_size = MD4Hash.digest_size - -#: The internal block size of the hash algorithm in bytes. -block_size = MD4Hash.block_size diff --git a/Crypto/Hash/MD4.pyi b/Crypto/Hash/MD4.pyi deleted file mode 100644 index a9a7295..0000000 --- a/Crypto/Hash/MD4.pyi +++ /dev/null @@ -1,19 +0,0 @@ -from typing import Union, Optional - -Buffer = Union[bytes, bytearray, memoryview] - -class MD4Hash(object): - digest_size: int - block_size: int - oid: str - - def __init__(self, data: Optional[Buffer] = ...) -> None: ... - def update(self, data: Buffer) -> None: ... - def digest(self) -> bytes: ... - def hexdigest(self) -> str: ... - def copy(self) -> MD4Hash: ... - def new(self, data: Optional[Buffer] = ...) -> MD4Hash: ... - -def new(data: Optional[Buffer] = ...) -> MD4Hash: ... -digest_size: int -block_size: int diff --git a/Crypto/Hash/MD5.py b/Crypto/Hash/MD5.py deleted file mode 100644 index 554b777..0000000 --- a/Crypto/Hash/MD5.py +++ /dev/null @@ -1,184 +0,0 @@ -# -*- coding: utf-8 -*- -# -# =================================================================== -# The contents of this file are dedicated to the public domain. To -# the extent that dedication to the public domain is not available, -# everyone is granted a worldwide, perpetual, royalty-free, -# non-exclusive license to exercise all rights associated with the -# contents of this file for any purpose whatsoever. -# No rights are reserved. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS -# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN -# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# =================================================================== - -from Crypto.Util.py3compat import * - -from Crypto.Util._raw_api import (load_pycryptodome_raw_lib, - VoidPointer, SmartPointer, - create_string_buffer, - get_raw_buffer, c_size_t, - c_uint8_ptr) - -_raw_md5_lib = load_pycryptodome_raw_lib("Crypto.Hash._MD5", - """ - #define MD5_DIGEST_SIZE 16 - - int MD5_init(void **shaState); - int MD5_destroy(void *shaState); - int MD5_update(void *hs, - const uint8_t *buf, - size_t len); - int MD5_digest(const void *shaState, - uint8_t digest[MD5_DIGEST_SIZE]); - int MD5_copy(const void *src, void *dst); - - int MD5_pbkdf2_hmac_assist(const void *inner, - const void *outer, - const uint8_t first_digest[MD5_DIGEST_SIZE], - uint8_t final_digest[MD5_DIGEST_SIZE], - size_t iterations); - """) - -class MD5Hash(object): - """A MD5 hash object. - Do not instantiate directly. - Use the :func:`new` function. - - :ivar oid: ASN.1 Object ID - :vartype oid: string - - :ivar block_size: the size in bytes of the internal message block, - input to the compression function - :vartype block_size: integer - - :ivar digest_size: the size in bytes of the resulting hash - :vartype digest_size: integer - """ - - # The size of the resulting hash in bytes. - digest_size = 16 - # The internal block size of the hash algorithm in bytes. - block_size = 64 - # ASN.1 Object ID - oid = "1.2.840.113549.2.5" - - def __init__(self, data=None): - state = VoidPointer() - result = _raw_md5_lib.MD5_init(state.address_of()) - if result: - raise ValueError("Error %d while instantiating MD5" - % result) - self._state = SmartPointer(state.get(), - _raw_md5_lib.MD5_destroy) - if data: - self.update(data) - - def update(self, data): - """Continue hashing of a message by consuming the next chunk of data. - - Args: - data (byte string/byte array/memoryview): The next chunk of the message being hashed. - """ - - result = _raw_md5_lib.MD5_update(self._state.get(), - c_uint8_ptr(data), - c_size_t(len(data))) - if result: - raise ValueError("Error %d while instantiating MD5" - % result) - - def digest(self): - """Return the **binary** (non-printable) digest of the message that has been hashed so far. - - :return: The hash digest, computed over the data processed so far. - Binary form. - :rtype: byte string - """ - - bfr = create_string_buffer(self.digest_size) - result = _raw_md5_lib.MD5_digest(self._state.get(), - bfr) - if result: - raise ValueError("Error %d while instantiating MD5" - % result) - - return get_raw_buffer(bfr) - - def hexdigest(self): - """Return the **printable** digest of the message that has been hashed so far. - - :return: The hash digest, computed over the data processed so far. - Hexadecimal encoded. - :rtype: string - """ - - return "".join(["%02x" % bord(x) for x in self.digest()]) - - def copy(self): - """Return a copy ("clone") of the hash object. - - The copy will have the same internal state as the original hash - object. - This can be used to efficiently compute the digests of strings that - share a common initial substring. - - :return: A hash object of the same type - """ - - clone = MD5Hash() - result = _raw_md5_lib.MD5_copy(self._state.get(), - clone._state.get()) - if result: - raise ValueError("Error %d while copying MD5" % result) - return clone - - def new(self, data=None): - """Create a fresh SHA-1 hash object.""" - - return MD5Hash(data) - - -def new(data=None): - """Create a new hash object. - - :parameter data: - Optional. The very first chunk of the message to hash. - It is equivalent to an early call to :meth:`MD5Hash.update`. - :type data: byte string/byte array/memoryview - - :Return: A :class:`MD5Hash` hash object - """ - return MD5Hash().new(data) - -# The size of the resulting hash in bytes. -digest_size = 16 - -# The internal block size of the hash algorithm in bytes. -block_size = 64 - - -def _pbkdf2_hmac_assist(inner, outer, first_digest, iterations): - """Compute the expensive inner loop in PBKDF-HMAC.""" - - assert len(first_digest) == digest_size - assert iterations > 0 - - bfr = create_string_buffer(digest_size); - result = _raw_md5_lib.MD5_pbkdf2_hmac_assist( - inner._state.get(), - outer._state.get(), - first_digest, - bfr, - c_size_t(iterations)) - - if result: - raise ValueError("Error %d with PBKDF2-HMAC assis for MD5" % result) - - return get_raw_buffer(bfr) diff --git a/Crypto/Hash/MD5.pyi b/Crypto/Hash/MD5.pyi deleted file mode 100644 index d819556..0000000 --- a/Crypto/Hash/MD5.pyi +++ /dev/null @@ -1,19 +0,0 @@ -from typing import Union - -Buffer = Union[bytes, bytearray, memoryview] - -class MD5Hash(object): - digest_size: int - block_size: int - oid: str - - def __init__(self, data: Buffer = ...) -> None: ... - def update(self, data: Buffer) -> None: ... - def digest(self) -> bytes: ... - def hexdigest(self) -> str: ... - def copy(self) -> MD5Hash: ... - def new(self, data: Buffer = ...) -> MD5Hash: ... - -def new(data: Buffer = ...) -> MD5Hash: ... -digest_size: int -block_size: int diff --git a/Crypto/Hash/Poly1305.py b/Crypto/Hash/Poly1305.py deleted file mode 100644 index eb5e0da..0000000 --- a/Crypto/Hash/Poly1305.py +++ /dev/null @@ -1,217 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Hash/Poly1305.py - Implements the Poly1305 MAC -# -# =================================================================== -# The contents of this file are dedicated to the public domain. To -# the extent that dedication to the public domain is not available, -# everyone is granted a worldwide, perpetual, royalty-free, -# non-exclusive license to exercise all rights associated with the -# contents of this file for any purpose whatsoever. -# No rights are reserved. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS -# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN -# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# =================================================================== - -from binascii import unhexlify - -from Crypto.Util.py3compat import bord, tobytes, _copy_bytes - -from Crypto.Hash import BLAKE2s -from Crypto.Random import get_random_bytes -from Crypto.Util._raw_api import (load_pycryptodome_raw_lib, - VoidPointer, SmartPointer, - create_string_buffer, - get_raw_buffer, c_size_t, - c_uint8_ptr) - - -_raw_poly1305 = load_pycryptodome_raw_lib("Crypto.Hash._poly1305", - """ - int poly1305_init(void **state, - const uint8_t *r, - size_t r_len, - const uint8_t *s, - size_t s_len); - int poly1305_destroy(void *state); - int poly1305_update(void *state, - const uint8_t *in, - size_t len); - int poly1305_digest(const void *state, - uint8_t *digest, - size_t len); - """) - - -class Poly1305_MAC(object): - """An Poly1305 MAC object. - Do not instantiate directly. Use the :func:`new` function. - - :ivar digest_size: the size in bytes of the resulting MAC tag - :vartype digest_size: integer - """ - - digest_size = 16 - - def __init__(self, r, s, data): - - if len(r) != 16: - raise ValueError("Parameter r is not 16 bytes long") - if len(s) != 16: - raise ValueError("Parameter s is not 16 bytes long") - - self._mac_tag = None - - state = VoidPointer() - result = _raw_poly1305.poly1305_init(state.address_of(), - c_uint8_ptr(r), - c_size_t(len(r)), - c_uint8_ptr(s), - c_size_t(len(s)) - ) - if result: - raise ValueError("Error %d while instantiating Poly1305" % result) - self._state = SmartPointer(state.get(), - _raw_poly1305.poly1305_destroy) - if data: - self.update(data) - - def update(self, data): - """Authenticate the next chunk of message. - - Args: - data (byte string/byte array/memoryview): The next chunk of data - """ - - if self._mac_tag: - raise TypeError("You can only call 'digest' or 'hexdigest' on this object") - - result = _raw_poly1305.poly1305_update(self._state.get(), - c_uint8_ptr(data), - c_size_t(len(data))) - if result: - raise ValueError("Error %d while hashing Poly1305 data" % result) - return self - - def copy(self): - raise NotImplementedError() - - def digest(self): - """Return the **binary** (non-printable) MAC tag of the message - authenticated so far. - - :return: The MAC tag digest, computed over the data processed so far. - Binary form. - :rtype: byte string - """ - - if self._mac_tag: - return self._mac_tag - - bfr = create_string_buffer(16) - result = _raw_poly1305.poly1305_digest(self._state.get(), - bfr, - c_size_t(len(bfr))) - if result: - raise ValueError("Error %d while creating Poly1305 digest" % result) - - self._mac_tag = get_raw_buffer(bfr) - return self._mac_tag - - def hexdigest(self): - """Return the **printable** MAC tag of the message authenticated so far. - - :return: The MAC tag, computed over the data processed so far. - Hexadecimal encoded. - :rtype: string - """ - - return "".join(["%02x" % bord(x) - for x in tuple(self.digest())]) - - def verify(self, mac_tag): - """Verify that a given **binary** MAC (computed by another party) - is valid. - - Args: - mac_tag (byte string/byte string/memoryview): the expected MAC of the message. - - Raises: - ValueError: if the MAC does not match. It means that the message - has been tampered with or that the MAC key is incorrect. - """ - - secret = get_random_bytes(16) - - mac1 = BLAKE2s.new(digest_bits=160, key=secret, data=mac_tag) - mac2 = BLAKE2s.new(digest_bits=160, key=secret, data=self.digest()) - - if mac1.digest() != mac2.digest(): - raise ValueError("MAC check failed") - - def hexverify(self, hex_mac_tag): - """Verify that a given **printable** MAC (computed by another party) - is valid. - - Args: - hex_mac_tag (string): the expected MAC of the message, - as a hexadecimal string. - - Raises: - ValueError: if the MAC does not match. It means that the message - has been tampered with or that the MAC key is incorrect. - """ - - self.verify(unhexlify(tobytes(hex_mac_tag))) - - - -def new(**kwargs): - """Create a new Poly1305 MAC object. - - Args: - key (bytes/bytearray/memoryview): - The 32-byte key for the Poly1305 object. - cipher (module from ``Crypto.Cipher``): - The cipher algorithm to use for deriving the Poly1305 - key pair *(r, s)*. - It can only be ``Crypto.Cipher.AES`` or ``Crypto.Cipher.ChaCha20``. - nonce (bytes/bytearray/memoryview): - Optional. The non-repeatable value to use for the MAC of this message. - It must be 16 bytes long for ``AES`` and 8 or 12 bytes for ``ChaCha20``. - If not passed, a random nonce is created; you will find it in the - ``nonce`` attribute of the new object. - data (bytes/bytearray/memoryview): - Optional. The very first chunk of the message to authenticate. - It is equivalent to an early call to ``update()``. - - Returns: - A :class:`Poly1305_MAC` object - """ - - cipher = kwargs.pop("cipher", None) - if not hasattr(cipher, '_derive_Poly1305_key_pair'): - raise ValueError("Parameter 'cipher' must be AES or ChaCha20") - - cipher_key = kwargs.pop("key", None) - if cipher_key is None: - raise TypeError("You must pass a parameter 'key'") - - nonce = kwargs.pop("nonce", None) - data = kwargs.pop("data", None) - - if kwargs: - raise TypeError("Unknown parameters: " + str(kwargs)) - - r, s, nonce = cipher._derive_Poly1305_key_pair(cipher_key, nonce) - - new_mac = Poly1305_MAC(r, s, data) - new_mac.nonce = _copy_bytes(None, None, nonce) # nonce may still be just a memoryview - return new_mac diff --git a/Crypto/Hash/Poly1305.pyi b/Crypto/Hash/Poly1305.pyi deleted file mode 100644 index f97a14a..0000000 --- a/Crypto/Hash/Poly1305.pyi +++ /dev/null @@ -1,24 +0,0 @@ -from types import ModuleType -from typing import Union - -Buffer = Union[bytes, bytearray, memoryview] - -class Poly1305_MAC(object): - block_size: int - digest_size: int - oid: str - - def __init__(self, - r : int, - s : int, - data : Buffer) -> None: ... - def update(self, data: Buffer) -> Poly1305_MAC: ... - def digest(self) -> bytes: ... - def hexdigest(self) -> str: ... - def verify(self, mac_tag: Buffer) -> None: ... - def hexverify(self, hex_mac_tag: str) -> None: ... - -def new(key: Buffer, - cipher: ModuleType, - nonce: Buffer = ..., - data: Buffer = ...) -> Poly1305_MAC: ... diff --git a/Crypto/Hash/RIPEMD.py b/Crypto/Hash/RIPEMD.py deleted file mode 100644 index 4e80235..0000000 --- a/Crypto/Hash/RIPEMD.py +++ /dev/null @@ -1,26 +0,0 @@ -# -*- coding: utf-8 -*- -# -# =================================================================== -# The contents of this file are dedicated to the public domain. To -# the extent that dedication to the public domain is not available, -# everyone is granted a worldwide, perpetual, royalty-free, -# non-exclusive license to exercise all rights associated with the -# contents of this file for any purpose whatsoever. -# No rights are reserved. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS -# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN -# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# =================================================================== - -# This file exists for backward compatibility with old code that refers to -# Crypto.Hash.RIPEMD - -"""Deprecated alias for `Crypto.Hash.RIPEMD160`""" - -from Crypto.Hash.RIPEMD160 import new, block_size, digest_size diff --git a/Crypto/Hash/RIPEMD.pyi b/Crypto/Hash/RIPEMD.pyi deleted file mode 100644 index e33eb2d..0000000 --- a/Crypto/Hash/RIPEMD.pyi +++ /dev/null @@ -1,3 +0,0 @@ -# This file exists for backward compatibility with old code that refers to -# Crypto.Hash.SHA - diff --git a/Crypto/Hash/RIPEMD160.py b/Crypto/Hash/RIPEMD160.py deleted file mode 100644 index 820b57d..0000000 --- a/Crypto/Hash/RIPEMD160.py +++ /dev/null @@ -1,169 +0,0 @@ -# =================================================================== -# -# Copyright (c) 2014, Legrandin -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# =================================================================== - -from Crypto.Util.py3compat import bord - -from Crypto.Util._raw_api import (load_pycryptodome_raw_lib, - VoidPointer, SmartPointer, - create_string_buffer, - get_raw_buffer, c_size_t, - c_uint8_ptr) - -_raw_ripemd160_lib = load_pycryptodome_raw_lib( - "Crypto.Hash._RIPEMD160", - """ - int ripemd160_init(void **shaState); - int ripemd160_destroy(void *shaState); - int ripemd160_update(void *hs, - const uint8_t *buf, - size_t len); - int ripemd160_digest(const void *shaState, - uint8_t digest[20]); - int ripemd160_copy(const void *src, void *dst); - """) - - -class RIPEMD160Hash(object): - """A RIPEMD-160 hash object. - Do not instantiate directly. - Use the :func:`new` function. - - :ivar oid: ASN.1 Object ID - :vartype oid: string - - :ivar block_size: the size in bytes of the internal message block, - input to the compression function - :vartype block_size: integer - - :ivar digest_size: the size in bytes of the resulting hash - :vartype digest_size: integer - """ - - # The size of the resulting hash in bytes. - digest_size = 20 - # The internal block size of the hash algorithm in bytes. - block_size = 64 - # ASN.1 Object ID - oid = "1.3.36.3.2.1" - - def __init__(self, data=None): - state = VoidPointer() - result = _raw_ripemd160_lib.ripemd160_init(state.address_of()) - if result: - raise ValueError("Error %d while instantiating RIPEMD160" - % result) - self._state = SmartPointer(state.get(), - _raw_ripemd160_lib.ripemd160_destroy) - if data: - self.update(data) - - def update(self, data): - """Continue hashing of a message by consuming the next chunk of data. - - Args: - data (byte string/byte array/memoryview): The next chunk of the message being hashed. - """ - - result = _raw_ripemd160_lib.ripemd160_update(self._state.get(), - c_uint8_ptr(data), - c_size_t(len(data))) - if result: - raise ValueError("Error %d while instantiating ripemd160" - % result) - - def digest(self): - """Return the **binary** (non-printable) digest of the message that has been hashed so far. - - :return: The hash digest, computed over the data processed so far. - Binary form. - :rtype: byte string - """ - - bfr = create_string_buffer(self.digest_size) - result = _raw_ripemd160_lib.ripemd160_digest(self._state.get(), - bfr) - if result: - raise ValueError("Error %d while instantiating ripemd160" - % result) - - return get_raw_buffer(bfr) - - def hexdigest(self): - """Return the **printable** digest of the message that has been hashed so far. - - :return: The hash digest, computed over the data processed so far. - Hexadecimal encoded. - :rtype: string - """ - - return "".join(["%02x" % bord(x) for x in self.digest()]) - - def copy(self): - """Return a copy ("clone") of the hash object. - - The copy will have the same internal state as the original hash - object. - This can be used to efficiently compute the digests of strings that - share a common initial substring. - - :return: A hash object of the same type - """ - - clone = RIPEMD160Hash() - result = _raw_ripemd160_lib.ripemd160_copy(self._state.get(), - clone._state.get()) - if result: - raise ValueError("Error %d while copying ripemd160" % result) - return clone - - def new(self, data=None): - """Create a fresh RIPEMD-160 hash object.""" - - return RIPEMD160Hash(data) - - -def new(data=None): - """Create a new hash object. - - :parameter data: - Optional. The very first chunk of the message to hash. - It is equivalent to an early call to :meth:`RIPEMD160Hash.update`. - :type data: byte string/byte array/memoryview - - :Return: A :class:`RIPEMD160Hash` hash object - """ - - return RIPEMD160Hash().new(data) - -# The size of the resulting hash in bytes. -digest_size = RIPEMD160Hash.digest_size - -# The internal block size of the hash algorithm in bytes. -block_size = RIPEMD160Hash.block_size diff --git a/Crypto/Hash/RIPEMD160.pyi b/Crypto/Hash/RIPEMD160.pyi deleted file mode 100644 index b619473..0000000 --- a/Crypto/Hash/RIPEMD160.pyi +++ /dev/null @@ -1,19 +0,0 @@ -from typing import Union - -Buffer = Union[bytes, bytearray, memoryview] - -class RIPEMD160Hash(object): - digest_size: int - block_size: int - oid: str - - def __init__(self, data: Buffer = ...) -> None: ... - def update(self, data: Buffer) -> None: ... - def digest(self) -> bytes: ... - def hexdigest(self) -> str: ... - def copy(self) -> RIPEMD160Hash: ... - def new(self, data: Buffer = ...) -> RIPEMD160Hash: ... - -def new(data: Buffer = ...) -> RIPEMD160Hash: ... -digest_size: int -block_size: int diff --git a/Crypto/Hash/SHA.py b/Crypto/Hash/SHA.py deleted file mode 100644 index 0cc141c..0000000 --- a/Crypto/Hash/SHA.py +++ /dev/null @@ -1,24 +0,0 @@ -# -*- coding: utf-8 -*- -# -# =================================================================== -# The contents of this file are dedicated to the public domain. To -# the extent that dedication to the public domain is not available, -# everyone is granted a worldwide, perpetual, royalty-free, -# non-exclusive license to exercise all rights associated with the -# contents of this file for any purpose whatsoever. -# No rights are reserved. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS -# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN -# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# =================================================================== - -# This file exists for backward compatibility with old code that refers to -# Crypto.Hash.SHA - -from Crypto.Hash.SHA1 import __doc__, new, block_size, digest_size diff --git a/Crypto/Hash/SHA.pyi b/Crypto/Hash/SHA.pyi deleted file mode 100644 index 4d7d57e..0000000 --- a/Crypto/Hash/SHA.pyi +++ /dev/null @@ -1,4 +0,0 @@ -# This file exists for backward compatibility with old code that refers to -# Crypto.Hash.SHA - -from Crypto.Hash.SHA1 import __doc__, new, block_size, digest_size diff --git a/Crypto/Hash/SHA1.py b/Crypto/Hash/SHA1.py deleted file mode 100644 index f79d825..0000000 --- a/Crypto/Hash/SHA1.py +++ /dev/null @@ -1,185 +0,0 @@ -# -*- coding: utf-8 -*- -# -# =================================================================== -# The contents of this file are dedicated to the public domain. To -# the extent that dedication to the public domain is not available, -# everyone is granted a worldwide, perpetual, royalty-free, -# non-exclusive license to exercise all rights associated with the -# contents of this file for any purpose whatsoever. -# No rights are reserved. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS -# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN -# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# =================================================================== - -from Crypto.Util.py3compat import * - -from Crypto.Util._raw_api import (load_pycryptodome_raw_lib, - VoidPointer, SmartPointer, - create_string_buffer, - get_raw_buffer, c_size_t, - c_uint8_ptr) - -_raw_sha1_lib = load_pycryptodome_raw_lib("Crypto.Hash._SHA1", - """ - #define SHA1_DIGEST_SIZE 20 - - int SHA1_init(void **shaState); - int SHA1_destroy(void *shaState); - int SHA1_update(void *hs, - const uint8_t *buf, - size_t len); - int SHA1_digest(const void *shaState, - uint8_t digest[SHA1_DIGEST_SIZE]); - int SHA1_copy(const void *src, void *dst); - - int SHA1_pbkdf2_hmac_assist(const void *inner, - const void *outer, - const uint8_t first_digest[SHA1_DIGEST_SIZE], - uint8_t final_digest[SHA1_DIGEST_SIZE], - size_t iterations); - """) - -class SHA1Hash(object): - """A SHA-1 hash object. - Do not instantiate directly. - Use the :func:`new` function. - - :ivar oid: ASN.1 Object ID - :vartype oid: string - - :ivar block_size: the size in bytes of the internal message block, - input to the compression function - :vartype block_size: integer - - :ivar digest_size: the size in bytes of the resulting hash - :vartype digest_size: integer - """ - - # The size of the resulting hash in bytes. - digest_size = 20 - # The internal block size of the hash algorithm in bytes. - block_size = 64 - # ASN.1 Object ID - oid = "1.3.14.3.2.26" - - def __init__(self, data=None): - state = VoidPointer() - result = _raw_sha1_lib.SHA1_init(state.address_of()) - if result: - raise ValueError("Error %d while instantiating SHA1" - % result) - self._state = SmartPointer(state.get(), - _raw_sha1_lib.SHA1_destroy) - if data: - self.update(data) - - def update(self, data): - """Continue hashing of a message by consuming the next chunk of data. - - Args: - data (byte string/byte array/memoryview): The next chunk of the message being hashed. - """ - - result = _raw_sha1_lib.SHA1_update(self._state.get(), - c_uint8_ptr(data), - c_size_t(len(data))) - if result: - raise ValueError("Error %d while instantiating SHA1" - % result) - - def digest(self): - """Return the **binary** (non-printable) digest of the message that has been hashed so far. - - :return: The hash digest, computed over the data processed so far. - Binary form. - :rtype: byte string - """ - - bfr = create_string_buffer(self.digest_size) - result = _raw_sha1_lib.SHA1_digest(self._state.get(), - bfr) - if result: - raise ValueError("Error %d while instantiating SHA1" - % result) - - return get_raw_buffer(bfr) - - def hexdigest(self): - """Return the **printable** digest of the message that has been hashed so far. - - :return: The hash digest, computed over the data processed so far. - Hexadecimal encoded. - :rtype: string - """ - - return "".join(["%02x" % bord(x) for x in self.digest()]) - - def copy(self): - """Return a copy ("clone") of the hash object. - - The copy will have the same internal state as the original hash - object. - This can be used to efficiently compute the digests of strings that - share a common initial substring. - - :return: A hash object of the same type - """ - - clone = SHA1Hash() - result = _raw_sha1_lib.SHA1_copy(self._state.get(), - clone._state.get()) - if result: - raise ValueError("Error %d while copying SHA1" % result) - return clone - - def new(self, data=None): - """Create a fresh SHA-1 hash object.""" - - return SHA1Hash(data) - - -def new(data=None): - """Create a new hash object. - - :parameter data: - Optional. The very first chunk of the message to hash. - It is equivalent to an early call to :meth:`SHA1Hash.update`. - :type data: byte string/byte array/memoryview - - :Return: A :class:`SHA1Hash` hash object - """ - return SHA1Hash().new(data) - - -# The size of the resulting hash in bytes. -digest_size = SHA1Hash.digest_size - -# The internal block size of the hash algorithm in bytes. -block_size = SHA1Hash.block_size - - -def _pbkdf2_hmac_assist(inner, outer, first_digest, iterations): - """Compute the expensive inner loop in PBKDF-HMAC.""" - - assert len(first_digest) == digest_size - assert iterations > 0 - - bfr = create_string_buffer(digest_size); - result = _raw_sha1_lib.SHA1_pbkdf2_hmac_assist( - inner._state.get(), - outer._state.get(), - first_digest, - bfr, - c_size_t(iterations)) - - if result: - raise ValueError("Error %d with PBKDF2-HMAC assis for SHA1" % result) - - return get_raw_buffer(bfr) diff --git a/Crypto/Hash/SHA1.pyi b/Crypto/Hash/SHA1.pyi deleted file mode 100644 index d6c8e25..0000000 --- a/Crypto/Hash/SHA1.pyi +++ /dev/null @@ -1,19 +0,0 @@ -from typing import Union, Optional - -Buffer = Union[bytes, bytearray, memoryview] - -class SHA1Hash(object): - digest_size: int - block_size: int - oid: str - - def __init__(self, data: Optional[Buffer] = ...) -> None: ... - def update(self, data: Buffer) -> None: ... - def digest(self) -> bytes: ... - def hexdigest(self) -> str: ... - def copy(self) -> SHA1Hash: ... - def new(self, data: Optional[Buffer] = ...) -> SHA1Hash: ... - -def new(data: Optional[Buffer] = ...) -> SHA1Hash: ... -digest_size: int -block_size: int diff --git a/Crypto/Hash/SHA224.py b/Crypto/Hash/SHA224.py deleted file mode 100644 index f788b06..0000000 --- a/Crypto/Hash/SHA224.py +++ /dev/null @@ -1,186 +0,0 @@ -# -*- coding: utf-8 -*- -# -# =================================================================== -# The contents of this file are dedicated to the public domain. To -# the extent that dedication to the public domain is not available, -# everyone is granted a worldwide, perpetual, royalty-free, -# non-exclusive license to exercise all rights associated with the -# contents of this file for any purpose whatsoever. -# No rights are reserved. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS -# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN -# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# =================================================================== - -from Crypto.Util.py3compat import bord - -from Crypto.Util._raw_api import (load_pycryptodome_raw_lib, - VoidPointer, SmartPointer, - create_string_buffer, - get_raw_buffer, c_size_t, - c_uint8_ptr) - -_raw_sha224_lib = load_pycryptodome_raw_lib("Crypto.Hash._SHA224", - """ - int SHA224_init(void **shaState); - int SHA224_destroy(void *shaState); - int SHA224_update(void *hs, - const uint8_t *buf, - size_t len); - int SHA224_digest(const void *shaState, - uint8_t *digest, - size_t digest_size); - int SHA224_copy(const void *src, void *dst); - - int SHA224_pbkdf2_hmac_assist(const void *inner, - const void *outer, - const uint8_t *first_digest, - uint8_t *final_digest, - size_t iterations, - size_t digest_size); - """) - -class SHA224Hash(object): - """A SHA-224 hash object. - Do not instantiate directly. - Use the :func:`new` function. - - :ivar oid: ASN.1 Object ID - :vartype oid: string - - :ivar block_size: the size in bytes of the internal message block, - input to the compression function - :vartype block_size: integer - - :ivar digest_size: the size in bytes of the resulting hash - :vartype digest_size: integer - """ - - # The size of the resulting hash in bytes. - digest_size = 28 - # The internal block size of the hash algorithm in bytes. - block_size = 64 - # ASN.1 Object ID - oid = '2.16.840.1.101.3.4.2.4' - - def __init__(self, data=None): - state = VoidPointer() - result = _raw_sha224_lib.SHA224_init(state.address_of()) - if result: - raise ValueError("Error %d while instantiating SHA224" - % result) - self._state = SmartPointer(state.get(), - _raw_sha224_lib.SHA224_destroy) - if data: - self.update(data) - - def update(self, data): - """Continue hashing of a message by consuming the next chunk of data. - - Args: - data (byte string/byte array/memoryview): The next chunk of the message being hashed. - """ - - result = _raw_sha224_lib.SHA224_update(self._state.get(), - c_uint8_ptr(data), - c_size_t(len(data))) - if result: - raise ValueError("Error %d while hashing data with SHA224" - % result) - - def digest(self): - """Return the **binary** (non-printable) digest of the message that has been hashed so far. - - :return: The hash digest, computed over the data processed so far. - Binary form. - :rtype: byte string - """ - - bfr = create_string_buffer(self.digest_size) - result = _raw_sha224_lib.SHA224_digest(self._state.get(), - bfr, - c_size_t(self.digest_size)) - if result: - raise ValueError("Error %d while making SHA224 digest" - % result) - - return get_raw_buffer(bfr) - - def hexdigest(self): - """Return the **printable** digest of the message that has been hashed so far. - - :return: The hash digest, computed over the data processed so far. - Hexadecimal encoded. - :rtype: string - """ - - return "".join(["%02x" % bord(x) for x in self.digest()]) - - def copy(self): - """Return a copy ("clone") of the hash object. - - The copy will have the same internal state as the original hash - object. - This can be used to efficiently compute the digests of strings that - share a common initial substring. - - :return: A hash object of the same type - """ - - clone = SHA224Hash() - result = _raw_sha224_lib.SHA224_copy(self._state.get(), - clone._state.get()) - if result: - raise ValueError("Error %d while copying SHA224" % result) - return clone - - def new(self, data=None): - """Create a fresh SHA-224 hash object.""" - - return SHA224Hash(data) - - -def new(data=None): - """Create a new hash object. - - :parameter data: - Optional. The very first chunk of the message to hash. - It is equivalent to an early call to :meth:`SHA224Hash.update`. - :type data: byte string/byte array/memoryview - - :Return: A :class:`SHA224Hash` hash object - """ - return SHA224Hash().new(data) - - -# The size of the resulting hash in bytes. -digest_size = SHA224Hash.digest_size - -# The internal block size of the hash algorithm in bytes. -block_size = SHA224Hash.block_size - - -def _pbkdf2_hmac_assist(inner, outer, first_digest, iterations): - """Compute the expensive inner loop in PBKDF-HMAC.""" - - assert iterations > 0 - - bfr = create_string_buffer(len(first_digest)); - result = _raw_sha224_lib.SHA224_pbkdf2_hmac_assist( - inner._state.get(), - outer._state.get(), - first_digest, - bfr, - c_size_t(iterations), - c_size_t(len(first_digest))) - - if result: - raise ValueError("Error %d with PBKDF2-HMAC assist for SHA224" % result) - - return get_raw_buffer(bfr) diff --git a/Crypto/Hash/SHA224.pyi b/Crypto/Hash/SHA224.pyi deleted file mode 100644 index 613a7f9..0000000 --- a/Crypto/Hash/SHA224.pyi +++ /dev/null @@ -1,19 +0,0 @@ -from typing import Union, Optional - -Buffer = Union[bytes, bytearray, memoryview] - -class SHA224Hash(object): - digest_size: int - block_size: int - oid: str - - def __init__(self, data: Optional[Buffer] = ...) -> None: ... - def update(self, data: Buffer) -> None: ... - def digest(self) -> bytes: ... - def hexdigest(self) -> str: ... - def copy(self) -> SHA224Hash: ... - def new(self, data: Optional[Buffer] = ...) -> SHA224Hash: ... - -def new(data: Optional[Buffer] = ...) -> SHA224Hash: ... -digest_size: int -block_size: int diff --git a/Crypto/Hash/SHA256.py b/Crypto/Hash/SHA256.py deleted file mode 100644 index 957aa37..0000000 --- a/Crypto/Hash/SHA256.py +++ /dev/null @@ -1,185 +0,0 @@ -# -*- coding: utf-8 -*- -# -# =================================================================== -# The contents of this file are dedicated to the public domain. To -# the extent that dedication to the public domain is not available, -# everyone is granted a worldwide, perpetual, royalty-free, -# non-exclusive license to exercise all rights associated with the -# contents of this file for any purpose whatsoever. -# No rights are reserved. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS -# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN -# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# =================================================================== - -from Crypto.Util.py3compat import bord - -from Crypto.Util._raw_api import (load_pycryptodome_raw_lib, - VoidPointer, SmartPointer, - create_string_buffer, - get_raw_buffer, c_size_t, - c_uint8_ptr) - -_raw_sha256_lib = load_pycryptodome_raw_lib("Crypto.Hash._SHA256", - """ - int SHA256_init(void **shaState); - int SHA256_destroy(void *shaState); - int SHA256_update(void *hs, - const uint8_t *buf, - size_t len); - int SHA256_digest(const void *shaState, - uint8_t *digest, - size_t digest_size); - int SHA256_copy(const void *src, void *dst); - - int SHA256_pbkdf2_hmac_assist(const void *inner, - const void *outer, - const uint8_t *first_digest, - uint8_t *final_digest, - size_t iterations, - size_t digest_size); - """) - -class SHA256Hash(object): - """A SHA-256 hash object. - Do not instantiate directly. Use the :func:`new` function. - - :ivar oid: ASN.1 Object ID - :vartype oid: string - - :ivar block_size: the size in bytes of the internal message block, - input to the compression function - :vartype block_size: integer - - :ivar digest_size: the size in bytes of the resulting hash - :vartype digest_size: integer - """ - - # The size of the resulting hash in bytes. - digest_size = 32 - # The internal block size of the hash algorithm in bytes. - block_size = 64 - # ASN.1 Object ID - oid = "2.16.840.1.101.3.4.2.1" - - def __init__(self, data=None): - state = VoidPointer() - result = _raw_sha256_lib.SHA256_init(state.address_of()) - if result: - raise ValueError("Error %d while instantiating SHA256" - % result) - self._state = SmartPointer(state.get(), - _raw_sha256_lib.SHA256_destroy) - if data: - self.update(data) - - def update(self, data): - """Continue hashing of a message by consuming the next chunk of data. - - Args: - data (byte string/byte array/memoryview): The next chunk of the message being hashed. - """ - - result = _raw_sha256_lib.SHA256_update(self._state.get(), - c_uint8_ptr(data), - c_size_t(len(data))) - if result: - raise ValueError("Error %d while hashing data with SHA256" - % result) - - def digest(self): - """Return the **binary** (non-printable) digest of the message that has been hashed so far. - - :return: The hash digest, computed over the data processed so far. - Binary form. - :rtype: byte string - """ - - bfr = create_string_buffer(self.digest_size) - result = _raw_sha256_lib.SHA256_digest(self._state.get(), - bfr, - c_size_t(self.digest_size)) - if result: - raise ValueError("Error %d while making SHA256 digest" - % result) - - return get_raw_buffer(bfr) - - def hexdigest(self): - """Return the **printable** digest of the message that has been hashed so far. - - :return: The hash digest, computed over the data processed so far. - Hexadecimal encoded. - :rtype: string - """ - - return "".join(["%02x" % bord(x) for x in self.digest()]) - - def copy(self): - """Return a copy ("clone") of the hash object. - - The copy will have the same internal state as the original hash - object. - This can be used to efficiently compute the digests of strings that - share a common initial substring. - - :return: A hash object of the same type - """ - - clone = SHA256Hash() - result = _raw_sha256_lib.SHA256_copy(self._state.get(), - clone._state.get()) - if result: - raise ValueError("Error %d while copying SHA256" % result) - return clone - - def new(self, data=None): - """Create a fresh SHA-256 hash object.""" - - return SHA256Hash(data) - -def new(data=None): - """Create a new hash object. - - :parameter data: - Optional. The very first chunk of the message to hash. - It is equivalent to an early call to :meth:`SHA256Hash.update`. - :type data: byte string/byte array/memoryview - - :Return: A :class:`SHA256Hash` hash object - """ - - return SHA256Hash().new(data) - - -# The size of the resulting hash in bytes. -digest_size = SHA256Hash.digest_size - -# The internal block size of the hash algorithm in bytes. -block_size = SHA256Hash.block_size - - -def _pbkdf2_hmac_assist(inner, outer, first_digest, iterations): - """Compute the expensive inner loop in PBKDF-HMAC.""" - - assert iterations > 0 - - bfr = create_string_buffer(len(first_digest)); - result = _raw_sha256_lib.SHA256_pbkdf2_hmac_assist( - inner._state.get(), - outer._state.get(), - first_digest, - bfr, - c_size_t(iterations), - c_size_t(len(first_digest))) - - if result: - raise ValueError("Error %d with PBKDF2-HMAC assist for SHA256" % result) - - return get_raw_buffer(bfr) diff --git a/Crypto/Hash/SHA256.pyi b/Crypto/Hash/SHA256.pyi deleted file mode 100644 index cbf21bf..0000000 --- a/Crypto/Hash/SHA256.pyi +++ /dev/null @@ -1,18 +0,0 @@ -from typing import Union, Optional - - -class SHA256Hash(object): - digest_size: int - block_size: int - oid: str - def __init__(self, data: Optional[Union[bytes, bytearray, memoryview]]=None) -> None: ... - def update(self, data: Union[bytes, bytearray, memoryview]) -> None: ... - def digest(self) -> bytes: ... - def hexdigest(self) -> str: ... - def copy(self) -> SHA256Hash: ... - def new(self, data: Optional[Union[bytes, bytearray, memoryview]]=None) -> SHA256Hash: ... - -def new(data: Optional[Union[bytes, bytearray, memoryview]]=None) -> SHA256Hash: ... - -digest_size: int -block_size: int diff --git a/Crypto/Hash/SHA384.py b/Crypto/Hash/SHA384.py deleted file mode 100644 index a98fa9a..0000000 --- a/Crypto/Hash/SHA384.py +++ /dev/null @@ -1,186 +0,0 @@ -# -*- coding: utf-8 -*- -# -# =================================================================== -# The contents of this file are dedicated to the public domain. To -# the extent that dedication to the public domain is not available, -# everyone is granted a worldwide, perpetual, royalty-free, -# non-exclusive license to exercise all rights associated with the -# contents of this file for any purpose whatsoever. -# No rights are reserved. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS -# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN -# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# =================================================================== - -from Crypto.Util.py3compat import bord - -from Crypto.Util._raw_api import (load_pycryptodome_raw_lib, - VoidPointer, SmartPointer, - create_string_buffer, - get_raw_buffer, c_size_t, - c_uint8_ptr) - -_raw_sha384_lib = load_pycryptodome_raw_lib("Crypto.Hash._SHA384", - """ - int SHA384_init(void **shaState); - int SHA384_destroy(void *shaState); - int SHA384_update(void *hs, - const uint8_t *buf, - size_t len); - int SHA384_digest(const void *shaState, - uint8_t *digest, - size_t digest_size); - int SHA384_copy(const void *src, void *dst); - - int SHA384_pbkdf2_hmac_assist(const void *inner, - const void *outer, - const uint8_t *first_digest, - uint8_t *final_digest, - size_t iterations, - size_t digest_size); - """) - -class SHA384Hash(object): - """A SHA-384 hash object. - Do not instantiate directly. Use the :func:`new` function. - - :ivar oid: ASN.1 Object ID - :vartype oid: string - - :ivar block_size: the size in bytes of the internal message block, - input to the compression function - :vartype block_size: integer - - :ivar digest_size: the size in bytes of the resulting hash - :vartype digest_size: integer - """ - - # The size of the resulting hash in bytes. - digest_size = 48 - # The internal block size of the hash algorithm in bytes. - block_size = 128 - # ASN.1 Object ID - oid = '2.16.840.1.101.3.4.2.2' - - def __init__(self, data=None): - state = VoidPointer() - result = _raw_sha384_lib.SHA384_init(state.address_of()) - if result: - raise ValueError("Error %d while instantiating SHA384" - % result) - self._state = SmartPointer(state.get(), - _raw_sha384_lib.SHA384_destroy) - if data: - self.update(data) - - def update(self, data): - """Continue hashing of a message by consuming the next chunk of data. - - Args: - data (byte string/byte array/memoryview): The next chunk of the message being hashed. - """ - - result = _raw_sha384_lib.SHA384_update(self._state.get(), - c_uint8_ptr(data), - c_size_t(len(data))) - if result: - raise ValueError("Error %d while hashing data with SHA384" - % result) - - def digest(self): - """Return the **binary** (non-printable) digest of the message that has been hashed so far. - - :return: The hash digest, computed over the data processed so far. - Binary form. - :rtype: byte string - """ - - bfr = create_string_buffer(self.digest_size) - result = _raw_sha384_lib.SHA384_digest(self._state.get(), - bfr, - c_size_t(self.digest_size)) - if result: - raise ValueError("Error %d while making SHA384 digest" - % result) - - return get_raw_buffer(bfr) - - def hexdigest(self): - """Return the **printable** digest of the message that has been hashed so far. - - :return: The hash digest, computed over the data processed so far. - Hexadecimal encoded. - :rtype: string - """ - - return "".join(["%02x" % bord(x) for x in self.digest()]) - - def copy(self): - """Return a copy ("clone") of the hash object. - - The copy will have the same internal state as the original hash - object. - This can be used to efficiently compute the digests of strings that - share a common initial substring. - - :return: A hash object of the same type - """ - - clone = SHA384Hash() - result = _raw_sha384_lib.SHA384_copy(self._state.get(), - clone._state.get()) - if result: - raise ValueError("Error %d while copying SHA384" % result) - return clone - - def new(self, data=None): - """Create a fresh SHA-384 hash object.""" - - return SHA384Hash(data) - - -def new(data=None): - """Create a new hash object. - - :parameter data: - Optional. The very first chunk of the message to hash. - It is equivalent to an early call to :meth:`SHA384Hash.update`. - :type data: byte string/byte array/memoryview - - :Return: A :class:`SHA384Hash` hash object - """ - - return SHA384Hash().new(data) - - -# The size of the resulting hash in bytes. -digest_size = SHA384Hash.digest_size - -# The internal block size of the hash algorithm in bytes. -block_size = SHA384Hash.block_size - - -def _pbkdf2_hmac_assist(inner, outer, first_digest, iterations): - """Compute the expensive inner loop in PBKDF-HMAC.""" - - assert iterations > 0 - - bfr = create_string_buffer(len(first_digest)); - result = _raw_sha384_lib.SHA384_pbkdf2_hmac_assist( - inner._state.get(), - outer._state.get(), - first_digest, - bfr, - c_size_t(iterations), - c_size_t(len(first_digest))) - - if result: - raise ValueError("Error %d with PBKDF2-HMAC assist for SHA384" % result) - - return get_raw_buffer(bfr) diff --git a/Crypto/Hash/SHA384.pyi b/Crypto/Hash/SHA384.pyi deleted file mode 100644 index c2aab9e..0000000 --- a/Crypto/Hash/SHA384.pyi +++ /dev/null @@ -1,19 +0,0 @@ -from typing import Union, Optional - -Buffer = Union[bytes, bytearray, memoryview] - -class SHA384Hash(object): - digest_size: int - block_size: int - oid: str - - def __init__(self, data: Optional[Buffer] = ...) -> None: ... - def update(self, data: Buffer) -> None: ... - def digest(self) -> bytes: ... - def hexdigest(self) -> str: ... - def copy(self) -> SHA384Hash: ... - def new(self, data: Optional[Buffer] = ...) -> SHA384Hash: ... - -def new(data: Optional[Buffer] = ...) -> SHA384Hash: ... -digest_size: int -block_size: int diff --git a/Crypto/Hash/SHA3_224.py b/Crypto/Hash/SHA3_224.py deleted file mode 100644 index bfc9bc2..0000000 --- a/Crypto/Hash/SHA3_224.py +++ /dev/null @@ -1,147 +0,0 @@ -# -*- coding: utf-8 -*- -# -# =================================================================== -# The contents of this file are dedicated to the public domain. To -# the extent that dedication to the public domain is not available, -# everyone is granted a worldwide, perpetual, royalty-free, -# non-exclusive license to exercise all rights associated with the -# contents of this file for any purpose whatsoever. -# No rights are reserved. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS -# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN -# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# =================================================================== - -from Crypto.Util.py3compat import bord - -from Crypto.Util._raw_api import (load_pycryptodome_raw_lib, - VoidPointer, SmartPointer, - create_string_buffer, - get_raw_buffer, c_size_t, - c_uint8_ptr) - -from Crypto.Hash.keccak import _raw_keccak_lib - -class SHA3_224_Hash(object): - """A SHA3-224 hash object. - Do not instantiate directly. - Use the :func:`new` function. - - :ivar oid: ASN.1 Object ID - :vartype oid: string - - :ivar digest_size: the size in bytes of the resulting hash - :vartype digest_size: integer - """ - - # The size of the resulting hash in bytes. - digest_size = 28 - - # ASN.1 Object ID - oid = "2.16.840.1.101.3.4.2.7" - - def __init__(self, data, update_after_digest): - self._update_after_digest = update_after_digest - self._digest_done = False - - state = VoidPointer() - result = _raw_keccak_lib.keccak_init(state.address_of(), - c_size_t(self.digest_size * 2), - 0x06) - if result: - raise ValueError("Error %d while instantiating SHA-3/224" - % result) - self._state = SmartPointer(state.get(), - _raw_keccak_lib.keccak_destroy) - if data: - self.update(data) - - def update(self, data): - """Continue hashing of a message by consuming the next chunk of data. - - Args: - data (byte string/byte array/memoryview): The next chunk of the message being hashed. - """ - - if self._digest_done and not self._update_after_digest: - raise TypeError("You can only call 'digest' or 'hexdigest' on this object") - - result = _raw_keccak_lib.keccak_absorb(self._state.get(), - c_uint8_ptr(data), - c_size_t(len(data))) - if result: - raise ValueError("Error %d while updating SHA-3/224" - % result) - return self - - def digest(self): - """Return the **binary** (non-printable) digest of the message that has been hashed so far. - - :return: The hash digest, computed over the data processed so far. - Binary form. - :rtype: byte string - """ - - self._digest_done = True - - bfr = create_string_buffer(self.digest_size) - result = _raw_keccak_lib.keccak_digest(self._state.get(), - bfr, - c_size_t(self.digest_size)) - if result: - raise ValueError("Error %d while instantiating SHA-3/224" - % result) - - self._digest_value = get_raw_buffer(bfr) - return self._digest_value - - def hexdigest(self): - """Return the **printable** digest of the message that has been hashed so far. - - :return: The hash digest, computed over the data processed so far. - Hexadecimal encoded. - :rtype: string - """ - - return "".join(["%02x" % bord(x) for x in self.digest()]) - - def new(self): - """Create a fresh SHA3-224 hash object.""" - - return type(self)(None, self._update_after_digest) - - -def new(*args, **kwargs): - """Create a new hash object. - - Args: - data (byte string/byte array/memoryview): - The very first chunk of the message to hash. - It is equivalent to an early call to :meth:`update`. - update_after_digest (boolean): - Whether :meth:`digest` can be followed by another :meth:`update` - (default: ``False``). - - :Return: A :class:`SHA3_224_Hash` hash object - """ - - data = kwargs.pop("data", None) - update_after_digest = kwargs.pop("update_after_digest", False) - if len(args) == 1: - if data: - raise ValueError("Initial data for hash specified twice") - data = args[0] - - if kwargs: - raise TypeError("Unknown parameters: " + str(kwargs)) - - return SHA3_224_Hash(data, update_after_digest) - -# The size of the resulting hash in bytes. -digest_size = SHA3_224_Hash.digest_size diff --git a/Crypto/Hash/SHA3_224.pyi b/Crypto/Hash/SHA3_224.pyi deleted file mode 100644 index 3437042..0000000 --- a/Crypto/Hash/SHA3_224.pyi +++ /dev/null @@ -1,16 +0,0 @@ -from typing import Union, Optional - -Buffer = Union[bytes, bytearray, memoryview] - -class SHA3_224_Hash(object): - digest_size: int - oid: str - def __init__(self, data: Optional[Buffer], update_after_digest: bool) -> None: ... - def update(self, data: Buffer) -> SHA3_224_Hash: ... - def digest(self) -> bytes: ... - def hexdigest(self) -> str: ... - def new(self) -> SHA3_224_Hash: ... - -def new(__data: Buffer = ..., update_after_digest: bool = ...) -> SHA3_224_Hash: ... - -digest_size: int diff --git a/Crypto/Hash/SHA3_256.py b/Crypto/Hash/SHA3_256.py deleted file mode 100644 index 327dabf..0000000 --- a/Crypto/Hash/SHA3_256.py +++ /dev/null @@ -1,147 +0,0 @@ -# -*- coding: utf-8 -*- -# -# =================================================================== -# The contents of this file are dedicated to the public domain. To -# the extent that dedication to the public domain is not available, -# everyone is granted a worldwide, perpetual, royalty-free, -# non-exclusive license to exercise all rights associated with the -# contents of this file for any purpose whatsoever. -# No rights are reserved. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS -# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN -# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# =================================================================== - -from Crypto.Util.py3compat import bord - -from Crypto.Util._raw_api import (load_pycryptodome_raw_lib, - VoidPointer, SmartPointer, - create_string_buffer, - get_raw_buffer, c_size_t, - c_uint8_ptr) - -from Crypto.Hash.keccak import _raw_keccak_lib - -class SHA3_256_Hash(object): - """A SHA3-256 hash object. - Do not instantiate directly. - Use the :func:`new` function. - - :ivar oid: ASN.1 Object ID - :vartype oid: string - - :ivar digest_size: the size in bytes of the resulting hash - :vartype digest_size: integer - """ - - # The size of the resulting hash in bytes. - digest_size = 32 - - # ASN.1 Object ID - oid = "2.16.840.1.101.3.4.2.8" - - def __init__(self, data, update_after_digest): - self._update_after_digest = update_after_digest - self._digest_done = False - - state = VoidPointer() - result = _raw_keccak_lib.keccak_init(state.address_of(), - c_size_t(self.digest_size * 2), - 0x06) - if result: - raise ValueError("Error %d while instantiating SHA-3/256" - % result) - self._state = SmartPointer(state.get(), - _raw_keccak_lib.keccak_destroy) - if data: - self.update(data) - - def update(self, data): - """Continue hashing of a message by consuming the next chunk of data. - - Args: - data (byte string/byte array/memoryview): The next chunk of the message being hashed. - """ - - if self._digest_done and not self._update_after_digest: - raise TypeError("You can only call 'digest' or 'hexdigest' on this object") - - result = _raw_keccak_lib.keccak_absorb(self._state.get(), - c_uint8_ptr(data), - c_size_t(len(data))) - if result: - raise ValueError("Error %d while updating SHA-3/256" - % result) - return self - - def digest(self): - """Return the **binary** (non-printable) digest of the message that has been hashed so far. - - :return: The hash digest, computed over the data processed so far. - Binary form. - :rtype: byte string - """ - - self._digest_done = True - - bfr = create_string_buffer(self.digest_size) - result = _raw_keccak_lib.keccak_digest(self._state.get(), - bfr, - c_size_t(self.digest_size)) - if result: - raise ValueError("Error %d while instantiating SHA-3/256" - % result) - - self._digest_value = get_raw_buffer(bfr) - return self._digest_value - - def hexdigest(self): - """Return the **printable** digest of the message that has been hashed so far. - - :return: The hash digest, computed over the data processed so far. - Hexadecimal encoded. - :rtype: string - """ - - return "".join(["%02x" % bord(x) for x in self.digest()]) - - def new(self): - """Create a fresh SHA3-256 hash object.""" - - return type(self)(None, self._update_after_digest) - - -def new(*args, **kwargs): - """Create a new hash object. - - Args: - data (byte string/byte array/memoryview): - The very first chunk of the message to hash. - It is equivalent to an early call to :meth:`update`. - update_after_digest (boolean): - Whether :meth:`digest` can be followed by another :meth:`update` - (default: ``False``). - - :Return: A :class:`SHA3_256_Hash` hash object - """ - - data = kwargs.pop("data", None) - update_after_digest = kwargs.pop("update_after_digest", False) - if len(args) == 1: - if data: - raise ValueError("Initial data for hash specified twice") - data = args[0] - - if kwargs: - raise TypeError("Unknown parameters: " + str(kwargs)) - - return SHA3_256_Hash(data, update_after_digest) - -# The size of the resulting hash in bytes. -digest_size = SHA3_256_Hash.digest_size diff --git a/Crypto/Hash/SHA3_256.pyi b/Crypto/Hash/SHA3_256.pyi deleted file mode 100644 index c1a07fa..0000000 --- a/Crypto/Hash/SHA3_256.pyi +++ /dev/null @@ -1,16 +0,0 @@ -from typing import Union, Optional - -Buffer = Union[bytes, bytearray, memoryview] - -class SHA3_256_Hash(object): - digest_size: int - oid: str - def __init__(self, data: Optional[Buffer], update_after_digest: bool) -> None: ... - def update(self, data: Buffer) -> SHA3_256_Hash: ... - def digest(self) -> bytes: ... - def hexdigest(self) -> str: ... - def new(self) -> SHA3_256_Hash: ... - -def new(__data: Buffer = ..., update_after_digest: bool = ...) -> SHA3_256_Hash: ... - -digest_size: int diff --git a/Crypto/Hash/SHA3_384.py b/Crypto/Hash/SHA3_384.py deleted file mode 100644 index cdbb7dd..0000000 --- a/Crypto/Hash/SHA3_384.py +++ /dev/null @@ -1,147 +0,0 @@ -# -*- coding: utf-8 -*- -# -# =================================================================== -# The contents of this file are dedicated to the public domain. To -# the extent that dedication to the public domain is not available, -# everyone is granted a worldwide, perpetual, royalty-free, -# non-exclusive license to exercise all rights associated with the -# contents of this file for any purpose whatsoever. -# No rights are reserved. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS -# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN -# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# =================================================================== - -from Crypto.Util.py3compat import bord - -from Crypto.Util._raw_api import (load_pycryptodome_raw_lib, - VoidPointer, SmartPointer, - create_string_buffer, - get_raw_buffer, c_size_t, - c_uint8_ptr) - -from Crypto.Hash.keccak import _raw_keccak_lib - -class SHA3_384_Hash(object): - """A SHA3-384 hash object. - Do not instantiate directly. - Use the :func:`new` function. - - :ivar oid: ASN.1 Object ID - :vartype oid: string - - :ivar digest_size: the size in bytes of the resulting hash - :vartype digest_size: integer - """ - - # The size of the resulting hash in bytes. - digest_size = 48 - - # ASN.1 Object ID - oid = "2.16.840.1.101.3.4.2.9" - - def __init__(self, data, update_after_digest): - self._update_after_digest = update_after_digest - self._digest_done = False - - state = VoidPointer() - result = _raw_keccak_lib.keccak_init(state.address_of(), - c_size_t(self.digest_size * 2), - 0x06) - if result: - raise ValueError("Error %d while instantiating SHA-3/384" - % result) - self._state = SmartPointer(state.get(), - _raw_keccak_lib.keccak_destroy) - if data: - self.update(data) - - def update(self, data): - """Continue hashing of a message by consuming the next chunk of data. - - Args: - data (byte string/byte array/memoryview): The next chunk of the message being hashed. - """ - - if self._digest_done and not self._update_after_digest: - raise TypeError("You can only call 'digest' or 'hexdigest' on this object") - - result = _raw_keccak_lib.keccak_absorb(self._state.get(), - c_uint8_ptr(data), - c_size_t(len(data))) - if result: - raise ValueError("Error %d while updating SHA-3/384" - % result) - return self - - def digest(self): - """Return the **binary** (non-printable) digest of the message that has been hashed so far. - - :return: The hash digest, computed over the data processed so far. - Binary form. - :rtype: byte string - """ - - self._digest_done = True - - bfr = create_string_buffer(self.digest_size) - result = _raw_keccak_lib.keccak_digest(self._state.get(), - bfr, - c_size_t(self.digest_size)) - if result: - raise ValueError("Error %d while instantiating SHA-3/384" - % result) - - self._digest_value = get_raw_buffer(bfr) - return self._digest_value - - def hexdigest(self): - """Return the **printable** digest of the message that has been hashed so far. - - :return: The hash digest, computed over the data processed so far. - Hexadecimal encoded. - :rtype: string - """ - - return "".join(["%02x" % bord(x) for x in self.digest()]) - - def new(self): - """Create a fresh SHA3-384 hash object.""" - - return type(self)(None, self._update_after_digest) - - -def new(*args, **kwargs): - """Create a new hash object. - - Args: - data (byte string/byte array/memoryview): - The very first chunk of the message to hash. - It is equivalent to an early call to :meth:`update`. - update_after_digest (boolean): - Whether :meth:`digest` can be followed by another :meth:`update` - (default: ``False``). - - :Return: A :class:`SHA3_384_Hash` hash object - """ - - data = kwargs.pop("data", None) - update_after_digest = kwargs.pop("update_after_digest", False) - if len(args) == 1: - if data: - raise ValueError("Initial data for hash specified twice") - data = args[0] - - if kwargs: - raise TypeError("Unknown parameters: " + str(kwargs)) - - return SHA3_384_Hash(data, update_after_digest) - -# The size of the resulting hash in bytes. -digest_size = SHA3_384_Hash.digest_size diff --git a/Crypto/Hash/SHA3_384.pyi b/Crypto/Hash/SHA3_384.pyi deleted file mode 100644 index d029ab6..0000000 --- a/Crypto/Hash/SHA3_384.pyi +++ /dev/null @@ -1,16 +0,0 @@ -from typing import Union, Optional - -Buffer = Union[bytes, bytearray, memoryview] - -class SHA3_384_Hash(object): - digest_size: int - oid: str - def __init__(self, data: Optional[Buffer], update_after_digest: bool) -> None: ... - def update(self, data: Buffer) -> SHA3_384_Hash: ... - def digest(self) -> bytes: ... - def hexdigest(self) -> str: ... - def new(self) -> SHA3_384_Hash: ... - -def new(__data: Buffer = ..., update_after_digest: bool = ...) -> SHA3_384_Hash: ... - -digest_size: int diff --git a/Crypto/Hash/SHA3_512.py b/Crypto/Hash/SHA3_512.py deleted file mode 100644 index 355b049..0000000 --- a/Crypto/Hash/SHA3_512.py +++ /dev/null @@ -1,148 +0,0 @@ -# -*- coding: utf-8 -*- -# -# =================================================================== -# The contents of this file are dedicated to the public domain. To -# the extent that dedication to the public domain is not available, -# everyone is granted a worldwide, perpetual, royalty-free, -# non-exclusive license to exercise all rights associated with the -# contents of this file for any purpose whatsoever. -# No rights are reserved. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS -# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN -# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# =================================================================== - -from Crypto.Util.py3compat import bord - -from Crypto.Util._raw_api import (load_pycryptodome_raw_lib, - VoidPointer, SmartPointer, - create_string_buffer, - get_raw_buffer, c_size_t, - c_uint8_ptr) - -from Crypto.Hash.keccak import _raw_keccak_lib - -class SHA3_512_Hash(object): - """A SHA3-512 hash object. - Do not instantiate directly. - Use the :func:`new` function. - - :ivar oid: ASN.1 Object ID - :vartype oid: string - - :ivar digest_size: the size in bytes of the resulting hash - :vartype digest_size: integer - """ - - # The size of the resulting hash in bytes. - digest_size = 64 - - # ASN.1 Object ID - oid = "2.16.840.1.101.3.4.2.10" - - def __init__(self, data, update_after_digest): - self._update_after_digest = update_after_digest - self._digest_done = False - - state = VoidPointer() - result = _raw_keccak_lib.keccak_init(state.address_of(), - c_size_t(self.digest_size * 2), - 0x06) - if result: - raise ValueError("Error %d while instantiating SHA-3/512" - % result) - self._state = SmartPointer(state.get(), - _raw_keccak_lib.keccak_destroy) - if data: - self.update(data) - - def update(self, data): - """Continue hashing of a message by consuming the next chunk of data. - - Args: - data (byte string/byte array/memoryview): The next chunk of the message being hashed. - """ - - if self._digest_done and not self._update_after_digest: - raise TypeError("You can only call 'digest' or 'hexdigest' on this object") - - result = _raw_keccak_lib.keccak_absorb(self._state.get(), - c_uint8_ptr(data), - c_size_t(len(data))) - if result: - raise ValueError("Error %d while updating SHA-3/512" - % result) - return self - - def digest(self): - - """Return the **binary** (non-printable) digest of the message that has been hashed so far. - - :return: The hash digest, computed over the data processed so far. - Binary form. - :rtype: byte string - """ - - self._digest_done = True - - bfr = create_string_buffer(self.digest_size) - result = _raw_keccak_lib.keccak_digest(self._state.get(), - bfr, - c_size_t(self.digest_size)) - if result: - raise ValueError("Error %d while instantiating SHA-3/512" - % result) - - self._digest_value = get_raw_buffer(bfr) - return self._digest_value - - def hexdigest(self): - """Return the **printable** digest of the message that has been hashed so far. - - :return: The hash digest, computed over the data processed so far. - Hexadecimal encoded. - :rtype: string - """ - - return "".join(["%02x" % bord(x) for x in self.digest()]) - - def new(self): - """Create a fresh SHA3-512 hash object.""" - - return type(self)(None, self._update_after_digest) - - -def new(*args, **kwargs): - """Create a new hash object. - - Args: - data (byte string/byte array/memoryview): - The very first chunk of the message to hash. - It is equivalent to an early call to :meth:`update`. - update_after_digest (boolean): - Whether :meth:`digest` can be followed by another :meth:`update` - (default: ``False``). - - :Return: A :class:`SHA3_512_Hash` hash object - """ - - data = kwargs.pop("data", None) - update_after_digest = kwargs.pop("update_after_digest", False) - if len(args) == 1: - if data: - raise ValueError("Initial data for hash specified twice") - data = args[0] - - if kwargs: - raise TypeError("Unknown parameters: " + str(kwargs)) - - return SHA3_512_Hash(data, update_after_digest) - -# The size of the resulting hash in bytes. -digest_size = SHA3_512_Hash.digest_size diff --git a/Crypto/Hash/SHA3_512.pyi b/Crypto/Hash/SHA3_512.pyi deleted file mode 100644 index 2c5403b..0000000 --- a/Crypto/Hash/SHA3_512.pyi +++ /dev/null @@ -1,16 +0,0 @@ -from typing import Union, Optional - -Buffer = Union[bytes, bytearray, memoryview] - -class SHA3_512_Hash(object): - digest_size: int - oid: str - def __init__(self, data: Optional[Buffer], update_after_digest: bool) -> None: ... - def update(self, data: Buffer) -> SHA3_512_Hash: ... - def digest(self) -> bytes: ... - def hexdigest(self) -> str: ... - def new(self) -> SHA3_512_Hash: ... - -def new(__data: Buffer = ..., update_after_digest: bool = ...) -> SHA3_512_Hash: ... - -digest_size: int diff --git a/Crypto/Hash/SHA512.py b/Crypto/Hash/SHA512.py deleted file mode 100644 index 403fe45..0000000 --- a/Crypto/Hash/SHA512.py +++ /dev/null @@ -1,204 +0,0 @@ -# -*- coding: utf-8 -*- -# -# =================================================================== -# The contents of this file are dedicated to the public domain. To -# the extent that dedication to the public domain is not available, -# everyone is granted a worldwide, perpetual, royalty-free, -# non-exclusive license to exercise all rights associated with the -# contents of this file for any purpose whatsoever. -# No rights are reserved. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS -# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN -# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# =================================================================== - -from Crypto.Util.py3compat import bord - -from Crypto.Util._raw_api import (load_pycryptodome_raw_lib, - VoidPointer, SmartPointer, - create_string_buffer, - get_raw_buffer, c_size_t, - c_uint8_ptr) - -_raw_sha512_lib = load_pycryptodome_raw_lib("Crypto.Hash._SHA512", - """ - int SHA512_init(void **shaState, - size_t digest_size); - int SHA512_destroy(void *shaState); - int SHA512_update(void *hs, - const uint8_t *buf, - size_t len); - int SHA512_digest(const void *shaState, - uint8_t *digest, - size_t digest_size); - int SHA512_copy(const void *src, void *dst); - - int SHA512_pbkdf2_hmac_assist(const void *inner, - const void *outer, - const uint8_t *first_digest, - uint8_t *final_digest, - size_t iterations, - size_t digest_size); - """) - -class SHA512Hash(object): - """A SHA-512 hash object (possibly in its truncated version SHA-512/224 or - SHA-512/256. - Do not instantiate directly. Use the :func:`new` function. - - :ivar oid: ASN.1 Object ID - :vartype oid: string - - :ivar block_size: the size in bytes of the internal message block, - input to the compression function - :vartype block_size: integer - - :ivar digest_size: the size in bytes of the resulting hash - :vartype digest_size: integer - """ - - # The internal block size of the hash algorithm in bytes. - block_size = 128 - - def __init__(self, data, truncate): - self._truncate = truncate - - if truncate is None: - self.oid = "2.16.840.1.101.3.4.2.3" - self.digest_size = 64 - elif truncate == "224": - self.oid = "2.16.840.1.101.3.4.2.5" - self.digest_size = 28 - elif truncate == "256": - self.oid = "2.16.840.1.101.3.4.2.6" - self.digest_size = 32 - else: - raise ValueError("Incorrect truncation length. It must be '224' or '256'.") - - state = VoidPointer() - result = _raw_sha512_lib.SHA512_init(state.address_of(), - c_size_t(self.digest_size)) - if result: - raise ValueError("Error %d while instantiating SHA-512" - % result) - self._state = SmartPointer(state.get(), - _raw_sha512_lib.SHA512_destroy) - if data: - self.update(data) - - def update(self, data): - """Continue hashing of a message by consuming the next chunk of data. - - Args: - data (byte string/byte array/memoryview): The next chunk of the message being hashed. - """ - - result = _raw_sha512_lib.SHA512_update(self._state.get(), - c_uint8_ptr(data), - c_size_t(len(data))) - if result: - raise ValueError("Error %d while hashing data with SHA512" - % result) - - def digest(self): - """Return the **binary** (non-printable) digest of the message that has been hashed so far. - - :return: The hash digest, computed over the data processed so far. - Binary form. - :rtype: byte string - """ - - bfr = create_string_buffer(self.digest_size) - result = _raw_sha512_lib.SHA512_digest(self._state.get(), - bfr, - c_size_t(self.digest_size)) - if result: - raise ValueError("Error %d while making SHA512 digest" - % result) - - return get_raw_buffer(bfr) - - def hexdigest(self): - """Return the **printable** digest of the message that has been hashed so far. - - :return: The hash digest, computed over the data processed so far. - Hexadecimal encoded. - :rtype: string - """ - - return "".join(["%02x" % bord(x) for x in self.digest()]) - - def copy(self): - """Return a copy ("clone") of the hash object. - - The copy will have the same internal state as the original hash - object. - This can be used to efficiently compute the digests of strings that - share a common initial substring. - - :return: A hash object of the same type - """ - - clone = SHA512Hash(None, self._truncate) - result = _raw_sha512_lib.SHA512_copy(self._state.get(), - clone._state.get()) - if result: - raise ValueError("Error %d while copying SHA512" % result) - return clone - - def new(self, data=None): - """Create a fresh SHA-512 hash object.""" - - return SHA512Hash(data, self._truncate) - - -def new(data=None, truncate=None): - """Create a new hash object. - - Args: - data (bytes/bytearray/memoryview): - Optional. The very first chunk of the message to hash. - It is equivalent to an early call to :meth:`SHA512Hash.update`. - truncate (string): - Optional. The desired length of the digest. It can be either "224" or - "256". If not present, the digest is 512 bits long. - Passing this parameter is **not** equivalent to simply truncating - the output digest. - - :Return: A :class:`SHA512Hash` hash object - """ - - return SHA512Hash(data, truncate) - - -# The size of the full SHA-512 hash in bytes. -digest_size = 64 - -# The internal block size of the hash algorithm in bytes. -block_size = 128 - - -def _pbkdf2_hmac_assist(inner, outer, first_digest, iterations): - """Compute the expensive inner loop in PBKDF-HMAC.""" - - assert iterations > 0 - - bfr = create_string_buffer(len(first_digest)); - result = _raw_sha512_lib.SHA512_pbkdf2_hmac_assist( - inner._state.get(), - outer._state.get(), - first_digest, - bfr, - c_size_t(iterations), - c_size_t(len(first_digest))) - - if result: - raise ValueError("Error %d with PBKDF2-HMAC assist for SHA512" % result) - - return get_raw_buffer(bfr) diff --git a/Crypto/Hash/SHA512.pyi b/Crypto/Hash/SHA512.pyi deleted file mode 100644 index f219ee9..0000000 --- a/Crypto/Hash/SHA512.pyi +++ /dev/null @@ -1,22 +0,0 @@ -from typing import Union, Optional - -Buffer = Union[bytes, bytearray, memoryview] - -class SHA512Hash(object): - digest_size: int - block_size: int - oid: str - - def __init__(self, - data: Optional[Buffer], - truncate: Optional[str]) -> None: ... - def update(self, data: Buffer) -> None: ... - def digest(self) -> bytes: ... - def hexdigest(self) -> str: ... - def copy(self) -> SHA512Hash: ... - def new(self, data: Optional[Buffer] = ...) -> SHA512Hash: ... - -def new(data: Optional[Buffer] = ..., - truncate: Optional[str] = ...) -> SHA512Hash: ... -digest_size: int -block_size: int diff --git a/Crypto/Hash/SHAKE128.py b/Crypto/Hash/SHAKE128.py deleted file mode 100644 index 011268b..0000000 --- a/Crypto/Hash/SHAKE128.py +++ /dev/null @@ -1,127 +0,0 @@ -# =================================================================== -# -# Copyright (c) 2015, Legrandin -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# =================================================================== - -from Crypto.Util.py3compat import bord - -from Crypto.Util._raw_api import (load_pycryptodome_raw_lib, - VoidPointer, SmartPointer, - create_string_buffer, - get_raw_buffer, c_size_t, - c_uint8_ptr) - -from Crypto.Hash.keccak import _raw_keccak_lib - -class SHAKE128_XOF(object): - """A SHAKE128 hash object. - Do not instantiate directly. - Use the :func:`new` function. - - :ivar oid: ASN.1 Object ID - :vartype oid: string - """ - - # ASN.1 Object ID - oid = "2.16.840.1.101.3.4.2.11" - - def __init__(self, data=None): - state = VoidPointer() - result = _raw_keccak_lib.keccak_init(state.address_of(), - c_size_t(32), - 0x1F) - if result: - raise ValueError("Error %d while instantiating SHAKE128" - % result) - self._state = SmartPointer(state.get(), - _raw_keccak_lib.keccak_destroy) - self._is_squeezing = False - if data: - self.update(data) - - def update(self, data): - """Continue hashing of a message by consuming the next chunk of data. - - Args: - data (byte string/byte array/memoryview): The next chunk of the message being hashed. - """ - - if self._is_squeezing: - raise TypeError("You cannot call 'update' after the first 'read'") - - result = _raw_keccak_lib.keccak_absorb(self._state.get(), - c_uint8_ptr(data), - c_size_t(len(data))) - if result: - raise ValueError("Error %d while updating SHAKE128 state" - % result) - return self - - def read(self, length): - """ - Compute the next piece of XOF output. - - .. note:: - You cannot use :meth:`update` anymore after the first call to - :meth:`read`. - - Args: - length (integer): the amount of bytes this method must return - - :return: the next piece of XOF output (of the given length) - :rtype: byte string - """ - - self._is_squeezing = True - bfr = create_string_buffer(length) - result = _raw_keccak_lib.keccak_squeeze(self._state.get(), - bfr, - c_size_t(length)) - if result: - raise ValueError("Error %d while extracting from SHAKE128" - % result) - - return get_raw_buffer(bfr) - - def new(self, data=None): - return type(self)(data=data) - - -def new(data=None): - """Return a fresh instance of a SHAKE128 object. - - Args: - data (bytes/bytearray/memoryview): - The very first chunk of the message to hash. - It is equivalent to an early call to :meth:`update`. - Optional. - - :Return: A :class:`SHAKE128_XOF` object - """ - - return SHAKE128_XOF(data=data) diff --git a/Crypto/Hash/SHAKE128.pyi b/Crypto/Hash/SHAKE128.pyi deleted file mode 100644 index f618881..0000000 --- a/Crypto/Hash/SHAKE128.pyi +++ /dev/null @@ -1,13 +0,0 @@ -from typing import Union, Optional - -Buffer = Union[bytes, bytearray, memoryview] - -class SHAKE128_XOF(object): - oid: str - def __init__(self, - data: Optional[Buffer] = ...) -> None: ... - def update(self, data: Buffer) -> SHAKE128_XOF: ... - def read(self, length: int) -> bytes: ... - def new(self, data: Optional[Buffer] = ...) -> SHAKE128_XOF: ... - -def new(data: Optional[Buffer] = ...) -> SHAKE128_XOF: ... diff --git a/Crypto/Hash/SHAKE256.py b/Crypto/Hash/SHAKE256.py deleted file mode 100644 index 4b1b141..0000000 --- a/Crypto/Hash/SHAKE256.py +++ /dev/null @@ -1,127 +0,0 @@ -# =================================================================== -# -# Copyright (c) 2015, Legrandin -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# =================================================================== - -from Crypto.Util.py3compat import bord - -from Crypto.Util._raw_api import (load_pycryptodome_raw_lib, - VoidPointer, SmartPointer, - create_string_buffer, - get_raw_buffer, c_size_t, - c_uint8_ptr) - -from Crypto.Hash.keccak import _raw_keccak_lib - -class SHAKE256_XOF(object): - """A SHAKE256 hash object. - Do not instantiate directly. - Use the :func:`new` function. - - :ivar oid: ASN.1 Object ID - :vartype oid: string - """ - - # ASN.1 Object ID - oid = "2.16.840.1.101.3.4.2.12" - - def __init__(self, data=None): - state = VoidPointer() - result = _raw_keccak_lib.keccak_init(state.address_of(), - c_size_t(64), - 0x1F) - if result: - raise ValueError("Error %d while instantiating SHAKE256" - % result) - self._state = SmartPointer(state.get(), - _raw_keccak_lib.keccak_destroy) - self._is_squeezing = False - if data: - self.update(data) - - def update(self, data): - """Continue hashing of a message by consuming the next chunk of data. - - Args: - data (byte string/byte array/memoryview): The next chunk of the message being hashed. - """ - - if self._is_squeezing: - raise TypeError("You cannot call 'update' after the first 'read'") - - result = _raw_keccak_lib.keccak_absorb(self._state.get(), - c_uint8_ptr(data), - c_size_t(len(data))) - if result: - raise ValueError("Error %d while updating SHAKE256 state" - % result) - return self - - def read(self, length): - """ - Compute the next piece of XOF output. - - .. note:: - You cannot use :meth:`update` anymore after the first call to - :meth:`read`. - - Args: - length (integer): the amount of bytes this method must return - - :return: the next piece of XOF output (of the given length) - :rtype: byte string - """ - - self._is_squeezing = True - bfr = create_string_buffer(length) - result = _raw_keccak_lib.keccak_squeeze(self._state.get(), - bfr, - c_size_t(length)) - if result: - raise ValueError("Error %d while extracting from SHAKE256" - % result) - - return get_raw_buffer(bfr) - - def new(self, data=None): - return type(self)(data=data) - - -def new(data=None): - """Return a fresh instance of a SHAKE256 object. - - Args: - data (bytes/bytearray/memoryview): - The very first chunk of the message to hash. - It is equivalent to an early call to :meth:`update`. - Optional. - - :Return: A :class:`SHAKE256_XOF` object - """ - - return SHAKE256_XOF(data=data) diff --git a/Crypto/Hash/SHAKE256.pyi b/Crypto/Hash/SHAKE256.pyi deleted file mode 100644 index 029347a..0000000 --- a/Crypto/Hash/SHAKE256.pyi +++ /dev/null @@ -1,13 +0,0 @@ -from typing import Union, Optional - -Buffer = Union[bytes, bytearray, memoryview] - -class SHAKE256_XOF(object): - oid: str - def __init__(self, - data: Optional[Buffer] = ...) -> None: ... - def update(self, data: Buffer) -> SHAKE256_XOF: ... - def read(self, length: int) -> bytes: ... - def new(self, data: Optional[Buffer] = ...) -> SHAKE256_XOF: ... - -def new(data: Optional[Buffer] = ...) -> SHAKE256_XOF: ... diff --git a/Crypto/Hash/_BLAKE2b.abi3.so b/Crypto/Hash/_BLAKE2b.abi3.so deleted file mode 100644 index e2c472f98c032286d3aa35c0c570c96cd8ea7d3a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 21888 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 diff --git a/Crypto/Hash/_MD4.abi3.so b/Crypto/Hash/_MD4.abi3.so deleted file mode 100644 index c783791e6bcda3816ab7d55463fdc21809295575..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 25576 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 O(Qe3JV-c{R+W!F{0paxk diff --git a/Crypto/Hash/_RIPEMD160.abi3.so b/Crypto/Hash/_RIPEMD160.abi3.so deleted file mode 100644 index fbca9c82a8fcb92a0d267047a5d3c670216ff8f3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 55608 zcmeIb4SZDPnKph-CX>wM8v=-em|#Ri2^l`acLru4AZotQd}zi<0;Gln^MPQkx}dgG zq!sJix@}*NZQu59w{F+=@4p|G-AxFKpG8DPv{u=^w#C+6qqt)27T)VV=Un$pCNq(D z_qW}B-@lXJ0@8`MaIWxD1*R4u3O@l9wvCNRvLm3WJ;hy-(VHe;~ zVU!!0_&?Psw)1*pr$(ThsSd@XVHDYf)FD-TIMYtzSY!hpE7Bak(mk@AB&A$IsdK)d zw8#cL9(J3;qtD4^q~j>>C*AXj#}YRmkCInjRln|S6-Mx{B5!u+@*=|JE)Ljv2ZR>8^)ZWwE)?IhS%8stiwz`%ZI@+9b$Dy)Tidp@2IiMVAhOrk(9+S-wIPmeZR_dn?%H8&>~4$C+_$y0rMJ!4 z(za#8)*W%#H*^h4wzh9Vd84EKhONDuyW3h?OMALX%Ot%)(0n7(201Ng-wi!IPV+!@ zwi>I~ty!@$GP`tk={)p-+&*dce>s{-{+y1IGh*_1z532;_e+WQoYQKrXkWHwx+h$F zM83@BeF;3%$7dDU1!Wkxx3--=5y!{d*P%E*e&~D{$5Ry%G|?Tu!pS|uS5X`tQyCqq95}JO(mYuC z{OR6t5bzT2KdH}m<~XVf#me8Y)I>R>Z`S(CT}yu?cWGtx*S$Fq`}njXw^OW zSts+mt||%z4uy7usSEAiR0ignvh};WiU1-NwfMiOYImf<{9R~wSCx4<|B`hjKiPdv zfv2uy-#~x1XLUiy6DsM?zof3@$-u$rz(9Xi{w3Fz95avZz9v2YlGc(F0|)awH|GrO z&k8)hYR}}Ufp=H!8E1xehe{4a-yJxZ6&%=~9~cOmPlwGXLxJam_#b^fIMAOHcsFPs z4h056<}2ao;J|>_96;VI)b?yB+EMaYIPe0pWks(oc{CV!CS)E9MxQ~82Ks&Bz@Rzg z=`A@N3=D?M*MlhCpEYnW)6RA@1l3;*22O^}7lP6EYz+qe!NC5oIT$pL?Y_3;#c<%& zu(>}RJ%;+SgMp!-`Lt(U$!p=jVQ3c|7|e1s%nb!z5siXoKa@HSRYi9wiOTx(&=y;X zH$fk=`(@x@zTKSH!{+ZpyE{sT0`H=2!RSfoFffo|EBm}?_cjz=y=O^bF#2?G;0dVx zUf6sh9Qa6jdI(Kiy=QV-IQn5|cU{S|$bc@C20R%w2a)0ZaNt;Y&s+l+G_*T2IB?Ln zde5B&zuEoGs#Axv<;tgr%>EFrU^t2rAE3K}rw+?y%wC-y4D_$wbN>v+o6#YFeW5_?aYR^5nwhUY$ zG;m-bJ7~%!%?cy?sh5yXn*UnJj|;dzD-?KUg#=6VxN^1mQMY!HpLGXpo)V7&5P zSJK-~3q;va;DyzD?zzON5zTzX7B-OS=EPWd9xZ_O(uk2QV7~X`S`gfGr+0V@e6F-d zN47xvXdl`Tm0_NJ>IJ(6ygaskgOcSqE3(YMHbOET2$|1>F$f3qf~TH0 zUkLl3r^0gfv0&hpkook${v2saIQqP~pM5Q-UqqRp|CQjL$L9Uzj-8D{y^Wh7C^zds z2;(q-8wEE-@er<4Mkw%M*c>nqhN4JfU?0rHdGkdbK9lsO=s#0-xGi=P8Yz4M_oS{SeQYmU;6_VKFY1{c-Cu1-m`&Karovm>?6 zx3yk@F-xWThii>yC1^dQT0>d8!_h&~wF!OxW=gH&JN(fks^hvOb~vt!bhzB9CC^`R zt&FEPgXXDF^ibd^%vnzH>p}Cmz)=jvpg9B<b{>`UEK1y6!Yjvoih`3e$3U`?qXMMvG(y@{900- zGaa3$*_9O(T?+o*b_9+ar{geoRpM z&5=rbk;}E^RQg#eeJUJ%U5rHV)X|{%M7+|Eh5e_4n8}($;ppjseq0n-lff+Wn3x30 zdEcHd`45HzuVb)}Ke=q{78y^^hG2ii(xB5$9UU0-hW!W4XM%yFVe@D>x?k=`TxVRC zBd+sc!F^%>d*Q&-A<2fhBq}}P+yTsRASfC32hAg)=zGEF2QV|ZCSu&+tmQsnMqHMo zc7^YTqfi`krcYPg2M z0Enl<(RZO6&OVR%Ka6~lbN2aQ;9ayN96gNdf=i5p_yc+7@R3X4|%q%!D<{bM~Y_tdZJDxHL@D@1H8UVA6v21dN*c z%>Ay3q>uwimGwKfEHh!P_OU9zpG;-1qw@I_G?Y~33`gY|%=K)d-dIxZhw5T#mMlXI>1nmPGGGR^Nn7p{_FlIyM^SH04+WCqP@s>U$ zRu65oZHj$MQ;fh0=C@z+inO+Qz=yuHQ(ZR#I{rGV0 zyI)9|xF@u)KAK-;l2JPmzi zh>53!o3#DMX~%0JDB^!zZUpDN%x#XkRu1butO5^uVI0lZ{cuEIztkS57>JmL51E6Q zj=|nQMX_f*^;q=qsly?^y;2MubLJWY{mv}m7-kPLCzHHl60t;suzuUth;ftI2o%OV zM7*AzOJWjlNUr0sIkGeqTaF3Gdzd}Q4I-IjPJr82at-MW4!#PqUJv?lE4nqpMPWII zT>ES@`7$O2$Yc&;YQ!FpvoK*Y1;ni-^CX0=><#f*uV8T`kt!cf$_;7$4zUkeGGX9( z0}^|a_ydZ;OG)4-ilq#~KDO16Ra4l+iKjHc=eHAB^b8j51kgoYJDObef^F#}IQg?>>%f_Sj2PYoPIbk7dunXh}UEqNQOhF7p^gDiV7 zh~`V>LlSp24VD7)QyT?3l1E> zV1vI${n3BGY;oWpvOHbsn8zSa=R?o}{VF%>0HU-7Ve?m*j-Z#{3`MU=M}`~;lbTP# zGJDREwWT>|9>v_%+>f4o+rGPy5!dWPnA&W)(9uYa`6TW#^I*_?Clp;Cy}6+2y5P0J z>w?X}2m;9!Ml68*6N#i(-gTyTe(m3F78w2G-wSo(OD7OKk9s7Cec{IZE^jSD?7PQb zhyVFwjA&IspuY*CG%o%ViNH4v-fPG6SEFp8-ww1xbpD;s;au>V;MHp|JzgKITVHEO z|T9+a9@Q@{4w~q0)m$u2uFXrZsA8gWtGw2RqnafQ?xGn z!3iJ4n>SuR@M}+{dE-Q>2Fk=Y5b<_qUKjo73iI@dmwtQZOvv1DeQ@ASMC;#JXKt8y zVgO>+UGk^izuUd?`f&7Zr?NE*-?{lqzaNNwJ^<-<9}TOZ!mzo)jrU5|U0!+D2feEh zNYBh4lYzrk1^HvHEC9HsD1Xe=cAUK|e@wGP-Zxd`kJ(rO&{dT`rn9ONZLW;2x<1g) z_`WMw1N?UX{a89hy6gJ@=)LGkbl`R=3`v=IU**(>j}nlGI2Bb!LnYVmsWR=#q6pxp zmq={CKqC1?62dQ&=zT^0B^@PI2Se#ackKG8{O0mX#O)_mM&Ee?h2;{6l=>52M)%=F z0S3a{lITiY{QNO<(DB=wt{Zed--s)6Vl#68{zne4{Uo2mI3MvqYV2iR7~T~9-p}7T z{o3OXY^$4HF!YZ{2F*#H#TCdRpA-G-ug{#h7RSpVQ$Dfj_|us)PvW=_$G35O7RPi9 z*hfyEIn#k-4n7{a14sERTVCcZHHNvpz?_tm>AM$v3Ao94KLEK^k|D2PRo=w4`Pn!7 z?l6|0w|K^!lBq&h;EiEqJoKA0XJ*TX&XsuuUrbwm zO;HP@%vCrVm**AiO1mk~7aD}L zU1_V3NA!FI?Dqg9o4e`Jv~e&dbm*<>*I#7F`Ce0^FV8?9Y8`^9t@x3+7GS zrB%&o`)_4WryAuTOg5lOFh_2R`Y6PkP{!9{8jOKIwr^ zdf<~D_`k0QxL+}Gea#HPJol-bQ!-qFcX+=9d)BEuCAsplEhkV0PJ@z?`D#HEpd$ zl`XvvKXdk+ON_Y8<)w2<1Cn_mG6!OrZGI;5UItB^i{y0m9qtwQ4tqF3(_3)`oX+!^ zcjH{n0hE3aZx)@Wag99bnHy~~<35}8K8{0r zy0^Wv7X`eZ!8s71_M9s_*3*`u>hv#6672P5`1a!HF*E)Wc`^n2wg4UT=9|710RA-8 z;4LsSH{g`vm-czboBrLB(LW@q2~MiOUkSP1bDY#f{|l0u=%kALcZ-yBoz!&y4cQWgGRNNS3cs`Ni5GB0paRsO3bRpg}V{ht+?Q_Tst<9NM) zyvQsu$K8e0X8#FEO>^3?)i1r_o#CW<{Y#{V%go%HkY~HUOj2d$*wskg;XfcX1kC*P zNbU5?R&4KV)3+Ptclke(ob%26uOan0zl1Kl%guc0?0fy)Qm)eUN0EBKze7@MoYX`9 zJ0!K%Nj>cUtfVe?Qjhw-AgOg`mONkb6Tdtz;l0w)v)}*U*zJEvUo{LJnGBj*RA(muNfd^y`Bd%t}V3ycikS|l@k5(v$eOD=85lkp|2 zTy>lM0og($e>;Sk1>?bZ8_o0OjA<6UD9I*GE=O_iwM=IC9zZ(tP2?HVjnWz4K36V= zX^zRmA>%ttJqVpM{vW0uM$XJhIU7*aG;@E4oU?I$tdV&!4r4xzbmrtKLYXFp_I6~$ zEg`YGv`0Yt0uw8MGi!m<{(#KBx#wIdM5_=DLX=OEc4qd0DBNt$^X~^3x7je~=Ls@$ z#^b-aAWzOu9Ct(CM#Ef`djyH1oa?0v7Uzk)>y2EID7@Wm=|-+p`75TE8);(e%_W|@ zL1hY`8^J$645(AU{-1ATo&-C-W}RVPIYCa2uR-MS8VA;b-RMHFT{g_!iUMm@jFGtr zc*5n#ddE3J+pa-&>dD>|`D9sQ^Aj#d`KWVVc8ba_DcNEmA0VPN#yMu8v~8AIU~Z7s zxsPAa2$^3uyWklnZtjsha|Fv%H}X37e5c^@K9DlnZ^!$*-Yr`VGhh}-yFGh{ZkyC@ zn6pj0=l+EAf5dz8{V2E_h0ODR2%B=)tr7+BGFO=16*xELX`H$c8H@3r(vQUD0Bi6z zF8G~W;(x%lHzIG5xjwBAIVTp01j7*Ca*c9jR7%D66(}$=KMj12DI?9i z$n5}qPR6YR9qYEX1xb%9ijTOQo?>fd zK-7cK%g8Wi#r>&&sL}5S{47j%d@+BATq-zW3}W8)NekL zYtkqE@O*8;5%{-@D(&-^*{xqc?PkOLzI}zG7=^1*{$jcF&F_y9C5>ryhWR&na?ku0 z4@}J*115+u`>0KQwZt$!xDeC|p~gzC?_UZdHv`m4p(Y4*8O-m#xu8NqohQ_oMTW5j zxAU~HP*a5ZLxo|~;yo>hA^!tg{BhXwa=fRl5Xu&RJ6z5;pxCsPLfPUUt2c~gcuxxn z<%n-Kj2o{56&A`CpVej<8(R%yx{PD{yl^$GhqhZX!yZBu9g0$c=V*Gkens7dsm>bYGbFU+fk5lElSt0Ea zNV_y39lrN6!M8%xR=lT44PP1~H57Ef>*GD$FW2oWlf+v1JrzYz6R+Z5x>pzOQR+1V zMP^-^Z?lXBDSg>wD3I1R&h)$l@iVsqU)l$L=FLFMghR%^K%UYx$#~U7Q?7<54bmj@ zRf}X)k4NTe`|oJTJc58ghNI# zinC1fBwF?s-dRSOY05~JxBrBhi{!VFMc)2b%sj&!V_uY3nC;1%lsCp4YZjoovs;NU{RqQBvAq%1Ws*I|&2HB%*>g>EO`)90D@Fygz~mP~;u0)m3g*U%UY;Y=7?-k( zJJi@>w7js;w3Tve8HZYYY@yUL9_5sP7l}_!hJ`<;)LfopcM95Zan71T>8pyYudK)s z)v#EwOWSQs%lPpMbmF<-q!Z)0^IWkG2eFfe5l+F$;PTcK&P8j^Ki>=#)|fw8;a#6m zpWWcS#_pmiUL#QG)^b5~CuR}IC2ACXey3@qW$j%7$;CVYTRluWoV!qJNKmb$6xYq^ zk&APNHSQv}A$FIhq4+dcX@_u>zStFMbCc1b)8h##b&2*M@{H)g8Lp1;GA|ugu~W}w z@oE;?-7z!1C~ms=9BT@lJhMs-84RDT$a5Nr=i!DkxFQ%O-wmFl&4H{K)*d zGrQYbH@Ec8>}c=o+div&R(t1$j=t75!_Mj^X5G-<+cS(YjG8r7;VVLT2(uLa)iCe? zWP3|zTTf3Z=4H5vds|!EHUh)E_3qf(CNyqjRNdYM2s4Hp3U~BG+Pb?t@JOhWP0n=+ zcJiT=gO}XU*WS@Pv%PZ}T8=y0#7c*r&hvdp16Sc`PWMxb$}4w~W_j}u>%M6b}k$GzD;WLV;z^0GJgFGPYj!?SItNF873^%oX; z$C_C7cxReeMtJ>WP?PD+UgGssiMwq>nJ(uap}gUsNX5O-8*HyXqug>nQOP-a3!SNGg8WU=R%Ki z3ExDa%ae_cDSvG@%vU;6sy%!j@n%05cgh(*aTnP;#a9Tek1#qJ;_D=cP$LWa-quhzH zhK#04>T_bgp~YS=<~1?f96wmy8vb3Kd3W8XcGgwY!Dh@DS&L&b?E7x`9iE^CY&SY0 z-UK9MKvR%mXUa<=)_?S_?6WV%y(4wx*zz@u+EIT76`k=iii%E#QM&14mBiim@9W3m zmT$z^7qb!BiGPkQUFjH1&yLd3%|`Z%bP~KM5)a-&GE``(SUVK=z2y`=g&Dl{__=0 zHRBW4Gb{CEIqFV4)?f|-YqHX_W9{e`#PuQ#NuE0BFhjHB!I#rCvxt<-c{*R12ImVf<+VkWoALIKSzdOpBp!R z9o?1EQo1vF+pf5NC!v*gL(pUY!Ad%dY{wA)=UKO8(~r1yqD(&=fASU2j*a&0Bipk* z$r{I5t&Fk~!~zQ!R2HMQo#E|Gnjy(r zEPiaCrG#Xy#3Ip&SV#bdO-ZUl>eaAqb-kXkI}uvyM3}_33`k2XO46GUnHsYeYf2=N zSF#g1#$pXBImUVlrQnucZ+3i8D5*}VJkNulDu>0uasa&_zhoJ9jS^y9?lk0bo%<#0 z4a_l~N|4;=@_)giHD@V6;^w5uRzzYl?y0i zu+2Ml1qRYBYvq{jxh08-7&CkfcqhQdXLxQgz2}F#Q!AzLk|o}$RS1q=?wyK&=lN*9 z*qW&x|HjLfE}c0O$-X5Uk%l9bOeo!JBAN3DlF%W;(<8~;dT-_o6sr(+Jff>+Mq!3$ z@9jPe{K5(2yagGBUf(qc&%(6L@MISu+fMI{471)lzTOt(L*?F#CU}t?AahpHT5rK^ zUh~?bi~uA++!(L-@{9&Y?k|j9kmIm_23hxbeZKMD?7#J1(CD2YU2v~=0(gJMecmxR z<_P74}KBvsf@=*^b)i;Obw1vqEdznS%#p7HN_3p{NSt)2v7p0+n_l(AfzARj+wn#@`?V+vl5%(-ElX*@0G7OWu<4w(|ak-bqbf|E1nZzP|_0NiNTh4y#z-%|*YT=|e2-#eYj3v^*|50c23#f z_!v7U6n2gktqd$E`ndgIMKibb^t8>!p|`KIZRw`A&bIFM4M?_hZ`iyPpOws@#gN9t=n*{TC-BV*%F`lcg5O?&q54ndNa;+v~21zzB2{ed>anYZk~g+> z+n=eREIMk{nswpG){Z{s^v&Jvy=_kSN2+SVb#)DqRqL-@S-0k@EAh>oJ^1(qjm5R; zk$$%?K+&*nja@DGJ2a(=o|bKG&c(ntVan$+?VS<#yEP;DKF%B6*3UK~Te|Rh5-wv` zpEDTTtBU-_4Lf?y9j`%7xNs zBO-kwO>#d`LiKj%^cdPC48d+=7B;-h+S=ek`WqX(a+ z&5Hk|OB8X{M{6QRcUK=2iuI5EU817joY_#SqYIU#fj!U6Cwxgru@@p&Y`^O&n+V#>Cv5M_)LXAYWwzLLN6bJOX9OgKOxz1sp z5$Wsf>uJMT=eFXPr;5tuZa3c0vf;+Qt?s4W)+^u5%Apv$4z@1#r*QVaQ ztnRwRTGNbAxq>Mz%_y@*=As(Rm2T|)-0dUsnFjNtRM6)u%wY{Ry<$rjVB(lo9njMZK(Jw5Vu+-*I3*)*+&qg|wqnXF&6sZy zmnyfwB9`rUPQG%BST+MY+(L`^cI6gX#Q#mX#TKz_7k0`nv4~|Wqr)w=h~H6enMGWT ztrYZm1=U{J$!_Bvd=PI|r zB5qc$+#??NUEwYFYDYw`nepk6A7V!jZI&sP_wTR1=TV@e&S8lmQEc+;( zvSk+Wca#fQ#7`(U+aexPZjMEK4tDD~^5$B^OO%^u5nrd=e2e&Yi}xP;P-m{9EP9E#fTMM~PROvCtweRc?_* zT&LV(i?~O*B^L3Qm0M~N|5UkU7V$~tmRpKtYo)DAnI+pe<#nlY0gKq)f{Al!#%znY zOY_aKh#ydHu0_00xp@}xKPorhBF@BKI(elT3oPOp%9UHhwaP8Dh;LGEkwyGvC|70?4=NY1h<~lzY>PMx+jgCPnPU-8S8lFFe1&rJEaD#J=3B(~ zDYw8P{;_i97V$5XTWAp*`P5~RMLbQp#TM~e<(62)UCJ%Bh`*%VGK=`Ia?35^-zZmR z5s#5?UcoEP2w23km78r5Hz+s9BED6*xfbz*%FVNgpH^`27-jM9wCj`q|H(bzaVP(&)X2!lfy+!wv!9WZOy6{KnnoSr z!%EeB&xQR;H4+|Ds-EyYrD_O2RH}*V$}D%?hWHR+fl^IeY0A^L@`7H3mnzkmxb`%S zCN4c&W4XBUyjiJw!p|sG!?ox=N>vfwr&JABrw=PtNBDiEniAKmrcuM?>aR6dgis!= zbJ|#+xPV2264$Q?A|)K72zs)P^l)urnh5VwDw4RC#<)*hN}EO`aV0Gy$CbgwGe!;}*Ur$MkV|Kb973*~F>(mGaE5q7 zuA3pAkjrL>C*-Ob;t9EEhIm4*nIWE#OJ;~Ct%>1C}2`_M0 zwYY}}<#9*H3`GdJrcOsdxoE@+8yB1l><%s4M0l@K&4gc8DniJWw^IXCk7>p#!pD`0 z5ORg?lx6CeW~?QAU8x8mSMp9-rv9WEYY5ZbB{#+zAy@oPS*Ez=$K6kOxt47vtX3*Q z$iRRjj;VIdSVh>SRD_TL1g9)hdo*J$;g^((5Hir^>pm5g3hx3`gL$CuB4NIAxhC(~Q-G^Ob5QWCX-1%hYnlsILXVypyR zK=>^!+d%kNN;MNQpyG&Q>S@hbPk30VW1aVG~?j z!t<1BBxE2b-M9spjVXq5Fjfc|$w99WGLQqqNXR%23?m`KI52L6jN)Ke6EcV+X5Edk zFouI+O~?=qhBYB0I1o?xMOOgC6Ec1S@q`TDKs+I%HxN(A;0?qRGIj&;gbdw4JRu`D z5KqX!4a5^NZiBm-FwYI8;JPt_GhL|~!dXf+Gp2KuQjLUHE7hDB<-tWu4D#TjF~&2X z1?vc(P^y_xpMO-UhVX<^&5Q&2+;|K|4k5nm+cgW#iIE}b#lXI}YYG&}rQmTgVJ4!VthLfNwqe*XTt_DH|kkDU*j342m5i)#)VM5605rzrjy>5UA zcN!sMM;IoA3>{%G5i)WF@q`Q&1Jjjcw}ZAS6!#>JmDrtW?0_WRSP=KL`2k*g=qA2+TKJ3%s#Hy4hzZvwF~S7#i2){zKgN=H#P}oRai+1u z*lt|hYh2uI?0rN!c{X%$Db5${Fb6Tl7hG-^g z_(J0`0j260k6EWw4dXF4Dpkec%Pytr7-@MxDGjUqNU27KRgNg7F_e=^RWXKAtBdwJ z#su~%Rl@+l_mzq;0PvhrO} znJaYp-Wz%0uHkb0Bc*D%9G|31=qfJ9S1Q%SwRgKx&0J{Tt5h8q+ArwxvW5%CEL|d1 zadkLHsV1%muU4v=>%p6qs^T*5A*E`$dOM(04Hso^Db>WaR=%!Cnz`1RtyC44P>o8} za%HqbsTwYL9#pD{>zD&dHFF*FTcxVFj>*wgMJ?Acx9W_whV#kqD%HgKupZ$zw`2aUQZ*XBgF-hcqcw#d*jbO4V{6@-?L* zoQFK2R1@bR|D;qk=OJTt?$FG6$U>!RIS;u`sVdGxb}7}wdB}H_s^&c8mr6Br9^#96 zYR*G0RVp%a9@4~l$UEwTtIx)prR7TK7dy)k=*N+7uQ!IB^RfTKk&{YYS~jgAk5u8* z0pz6P|0m;EN=goYrP^Yb$lH~oR-Z44PlOY@N2>VM53VG}aM>j6fq7A*UNo%#kV1IMA_#+~EbMMaT%WtXtjb1S8O>fspeOrv|1N zfyQ+rWCR*z2|0mrBcg64j6kDhgp5F=EFot)PFbcHfkw*+8G%MwLQaXCvP^MSgf1Xt z1R7mH$OtsV5pwS2h+~QoXmkM~BhV;I$Vrw{mMKP{(FKHzK%*=nXJbxTrWk=n7Z5T6 zjk1KCwmD^);>-<_3icIdg*^gq*oSJRxUpa6W{bxj{T3XKoNr z$eA0&6LMD<#1nGn2JwWPxj{T3XKoNr$eA0&6LRJT@r0bYK|CR6ZV*q%nH$6ta^{9! zCFINv;t4r(gLp#jM8b$9(&K|CR6ZV*q%nH$6ta^?o{gq*oSJmJ4N zn8azC++yy0jz@G3At!PFwqVlP%=g zT)+QPDP4xs4P!n*c;Cp?^kpL##lO`>aWmmtO4Sk$xl}s7^tDJgEKk<8Y=m&SQdJ`z zSPdQ6F3qI|J*Z1kHE?OVByFOB8?RJ^aH2~&AHdM;eI>R8rP=$jQnfUDuPRkTvv)?R zCYrtTbtPF%vlmpVie_)4Qne$^UJcFOBbuv;X78|4)iitWD^*3acdjljYiahvO4ZQp zwJOy_v-dfrs%iFqs#F!t-sG{)_=GK?*;}qugk~?IRMSYaS533`J$P9P0+<<6V2WdrK)N6+Ldai*}Ge*TAIB_l&a!FHCtDu)m*63iosqI@)&3K7=DG> zI~#+QF3&l6@N)hO8ts)TS1LYHR;ql-cznAuOaPX^G-y1+dgTz)q9L40_&v2=)r9>@ zRS_Ohs*aG6R#-wpMp|JB3AytPKAn(85?6+hkyh9^LPlEQI|&(SMU8~qz=j$LX>cK) zkh|3&o{%;edJ%E~hp|A&NGp^eq@~6nB4nf$;t3gPg?K_nTA>#qBdrimND~k7gp9O8 zJRu{k5KqWRE5s8r(hBi}jI=^LAtS92Psm6s#1k^o3h{(o6+t{97dsG7NMC`1g!C1# zNQ7L&phiM2R3M&^D-MV!8&81klqU73F)mMo{-)O6Bt5zD~Kngw}N;=dMk)0q_={2 zLV7ERC#1K6ctUzBh$p1Cf_OrDD~Kngw}N;=dMk)0q_={2LV7FoDj~gr&qZB#CBBcC-VMHwklqcKjqs2< zx++3?HyB7ldN+6?LV7oNB0_pMjC?|RH(W_VdN+tCq<6!pAf$IgjfC`WsF9G~4dMyu z-5{Qj-VJ&Y(!1dLV7odC!}|SctUzNh$p0XgLp!EH;5;scY}CBex!(kg!FE(0fh8! zsF9G~4dMyu-5{Qj-VNdj>D?fnklqdA3F+M+o{-)R;tA>9AfAxk4dMyu-5{Qj-VNdj z>D@5C29AfAxk4dMyu-Ebol@*_ovC!}|SctUzNh$p0XgLp!EH;5;s zcY}CBdN+tCq<4dOLV7odC!}|SctUzNh$p0XgLuMwb)gj@q<4dOLV7odC!}|i!Q`%{ z=-nWmklqbS5YoFrJR!Xs#1qCGT{9sa9>f#U;bBY=@*_ovC#1uJctZT-jQxUMgkG0Q zmyJ)>**H08^Nj4AvA@OSzv4ccVKJ*2X-=cz(hOogOarcfm`~G)>m&Y*TNbYG^Dg|p zQq_cf!sdL0yY5dEd|Ih$J{9tyQVo16WI(BUJ{59dHZNKuH{D;WR2?_ne@3ZlZo2=D zQVra6|EyB=+*yB0scLSKpPa)Q>$vkhs8l02v~NG4QmTR5 znp>2r=eFiMm8#>m=I<(1!#&JLlxpOL<&#P^aCh=~x(m3TyOWnHRmZK!8@!N$atG|MlxpM-*pHNI;11aFx{0QqJ76zUs*XEgE0wC{4%moNjobmdO{oU%fc=6} z_1ppbZKXzRcf|~bTUh@^bJd=WqlK+@HqIn&j2XV2CRIvG$=yg94j%cRxssi6%EmSm zNm@kmotSd#lnD$`{W%|7x{6amuw=sd`SiHY?T0Dc3zpHE_!H1Es1t<@$wERh)9U zS3$NQamqDE0}qXyay2Pc%PH62X_TRwQ?56aYT%SBTf+eLoN|>a)yOH=TBYhZ<+@p^ zYEHSnq*Mc^T#qYN&nee0m1^Xa>$FmJoN^Uwu%Mb#uGLC4aLU!LR6VC$_bAmka>`Z5 zDc3JGS2d?xvvoq$KsZmSX2QiT<;+4jzuFtiNcc6SG-$zj7HkLMG0mk<&i|#(Xc`$D zXw*nRGlK)2N;MMRUAsk_2=RopiMZDZX%iuykTwy`CZtV-ctYAlh$o~? zgm^;QM2IJ(O@w$t+C+#aq)mi)LfS-#C**^Ck&y9O)JVwqENUdAS3~Cz(uIj-ax3Q%;t7wq zrzXMMr~FjyY+N6nU;MB98un}@ogG#X1;q4r;BtuR?$BR^pN~!E3F+?OP6&Uex#|h& z?r^mU>Fyw&knRq4f{^YG;tA>QFeV7;?jW9!?hfJ!>Fyw&knRrR3F+G)o{+u`;tA>7 zFun-s+aR8hz70wc(zii8A$=Rf6VkU~kQ36kK|CRS8^jaRw?RB1eH+9R(zii8A$=Rf z6VkUqJmHUY%3n`N-v;r7^lc)3gqy1#>E;^f=J+urv?ru*gID!<^ zA$=Rf6VkUqJRyA>#1qoDK|CRS8^jaRw?RB1eH+9R(zii8A$=P>A0d4kY9yp@Lyd&= zZK#ouz766D>Dyo)3F+G)o{+u`;tA>7AfAxE4dMyu+aR8hz766D>DwTlkiHG#3E$Sm zQ5_+D8^jaRw?RB1eH+9R#@t*zA>AFcC#1W>jZ8>)2l0e-cMwlVcL(hW>Fyw&kiHG# z3F+G)o{+u`;tA>7AfAxE4dMyu$j~{2JjQuGM#&)lY@C?{tnPI;3_YNGiPjVHmzA7f zYLd*UUKMWP`j`;HTa~IM{ESOEa+&%I&A6WM3rf`zesNgYRQd>iotyL1Dx`{#ilpID zFJh|UkzWR*0()X*38{#bC8kn#*+iZAV_NIoAJe+tJ@Uu367zpt+JoTMlkPKg@p(O1 z@(v~CJw}D=sE6lIH-_8@+Hl@${Ik0#9L{GL6WzV4!}(03JSp!pjwj{)Muodz94;rz zs7lIb8xJMrbByUl@e&;DF>;NHq+)r8NCHXwbv^!@My#KCJ9XLo z$m{-P@S^9|1UcWd^N$=q1K^Xj_vfyhJ6t(@DB-v*CpMnlD4>z5AKtO^=NrDM012;T z_5KNYOk?D@%|gRXW8}DX_V|yykEYrA$B!7Fvt2%MJj+u6ZrpR2mW|+xhA~cJ8~6fa zq^MZ(D2W zfZo7FxaTsujU?k*ij%stwmg>VhlqTetR4|5jA2Ubkk&%E;`}*`=sz zP2CldSWiKK^i!Suo~aROYi;Rmk)Q7EY)||Z)eS8j_)*#6vYa2b9nMAKE{?Qi_z$w$ zzXXe4#_j2GFJG*0^hb1|AFtyu?P6K^>&S78`@_MJ4cl8p{gw{=aPn})jMAPRTkyNB zIQDis$IV2YUA=9kn>zbSou9mIZ#C?c{MN2f+Pb3?C7mOFtJyxYt*yJKy{mIrB7$?> zZ5=IAz(rd-dW}-K)<$Ws{CsVx-Ls|LU3Nd0wrzF?(dJf^Wy&exj3%c9v6PZ3Ai!3q zWlQ@8sL%z$_*ZJzhORYAG0wJN$RbnQ4SkzXyrpv!?gcm5-nmiAJEv~Ap}TDxQyuM{ zZN%ssLR@%4SCV^M|C^hF+MXe{S%M3C6s^2RfNaSB}`3Oj$-dj zD9`ynkA7x!kBRz!-Yw7muPAad^2qs>TU_;L`aS?@Kg-t@IcInbIZ6GWSpP#f6JMU| z4jy~uWZa9_pVVIg$Ti~l;QHjlnNE(x{7m!sBV@~uE3fMqxv}wLJ|`7Rli!aMq9W_( zddK%MW0IA>2P8#!O2R10<0Jl5rGQzx%H#sMV z^M9{fK2dIBUJr;wP9zMt1@B0>ffDoPrzjs>RU$N9F@ogGB<+xeatX1spI3*#iUt&}r2Mg1?j9sfXwTQH$K+2tw9cN}zbB^HbHn|{aC>!Eq|ljn0Q^0P#_^`{4e4Z BHgy01 diff --git a/Crypto/Hash/_SHA1.abi3.so b/Crypto/Hash/_SHA1.abi3.so deleted file mode 100644 index 9f4a0151ea685012234904c220e54ce890eaa6b0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 74416 zcmeIb3w%`7wLgB&OlFus$b*E3Ad+ZQP)Ha+o(X1P20}m$A%TR~5b`255KIOHAD{%4 zDMq2vD{Zal)mGYKFYWc$QfgZw%1eYq5%GvyKe>;Pc#f<*ln`N@Jp;|jFOS@D{QL-+U zX${QjZBPYjTCyULHaG55{ZtSzSs?;*9R|ISp~Ryg#fwif`0;7U3K7`IW(xEeVp=mS zbU1O3y}m$8*fl)%+8>U;y1gUtx7r_uOPqi02p??|*b+zGfx z1z!H}wU@^Hb@RJFy6y2j4gHSY_Jf~vzWn}%12+|3{HOZku^+tj&)A_GPQ=xR|H`F@ zNS13c!ksKM3UcatwTJX|LWyp)R5r4!lNO`h#`P9Kb^RawlKsbe8R0ND-rq3&5vE^nur)0hte9Ip zFIXEYt_cN$TCluwUZoZsmw#Qbw5+DAqOvwrR+E3-=&I^@W%zrW8qGD1| zTvd5XnKmig=M6$zNGmC>s;VwA2&HAUp_=N&T6s+wi!7L5S{y3V=9bMZnZFqJ6xY_4 z!Itvk$|{ahS%F9fUQ!JirFs7B8%xUv1n0~xE}|J(kVY|-&#tXC@(R+tQf=&naic~D2c!*1yM`P>h2&6wMo33Hvi}i}sBZ#F{aDbw z5>3pZoh2qN>F1<>(gflDOoCguANE-25??K$!<8~%nl#RZa92xw!SU9=}agI3IeRa zbM_#T@;Ar7BlAwMv<2w}*>#y$5SktSM<@nrueu^xJDdrV56{8RHdhgt`V2`|;E`Lw zEKd{jSNW!7hfn(^`wD#d1(T53+)v`FZ%D$=($w;}>drq$ceS!6Dz49j)D^@T1mg76 z6>)uTOI=GseuPh~yq5Uuf%;R|`ohP;$AKb(e`TJ>ce2qJK2sj|`ZMKmH@)Pch@1Q? zb7DZ*1*y{1P57+>Ev2bEu40FwBai~*^}i#=%O0P1NB9e1jh==E7eo#y5hO+$E1p$4 zD0EE8;Afu)^nZZ<0jNhnXd=SLAe;bUAMQ^?Y6ln~!Y*(r{Wr?}an*auh~TGgtz$`b~=!Mf9iU@$=9&W<<}MU3_`-V( ziIaq#+^?Swgoy|Zfs}25lwD)$@AVk!A+g`@eI-!8W)KmKXs`Hnq9dj+eA*xWT;VVJ zQug>$w)wpXo*}u0T@GK$u7G~rzcQ41v0vW)MQ`E=|KH*wqPgfwol&?J`SgyY)WbJdz<`vLm<2Z%_k6kh7j0|D87_q^-qr= zr2%iFe`S7ZDy;5A;V`UdY~n?KCN-?4cVu z`64_J2onw`1X3D&DKCz#U+yyO-Q{07A$3ro{@!Sn#PNW>i?SU)?n8Ar?o0W?%=}K$ z0bW4g0Ze(K(U)?Z`jV7W0k3jk2D}%q6zdH>@(;XArQ!W&!22$oOf>J?{(-lpW>CDQ z?f!w&Q~T0SmLJ{-?|^swsDt|gDUB&7d`(;Z-e;&_vV8SV4^?^%rG9<8Q4Y#;ToV42 zS9~eZe`@7zss8$>ho}tg_vxp?ulQ5;G;Bv<0wtfllCsx(a&-MuT@9674Es?as9x|_ zn5tsRe(!TeG3-YPs3s8pBH;bhukVK!l*0$2%IJH-U--R;eclgFHiiG?ADEx&_oqCE zw$k*B-+RD&B>b5a3%uX(9Ek(nw8cL#l$z@OY)t)f?a`yJ&hv%;>GSTTwxe(Ng&WD+z{p=2{xCEj z^MyZ0TvSS*caN`Wi_g2C3Inb*V(;_mXW*+WpZ+mAg=FuW-hYN)@V@N#?rnm;kNn}! z0^WbsKQ)A;mF1uLs2S-WK{|C{6>6sUE3`1b_hTgI-PW`X-a%3J_aQs=_r_8*zxOkr zzS|!@;`e^!Yk0w-n$&JoxqaSO{oaP~^ZxKVOmk|S7v3B2zT)$qq`HOT3Zvq^ zKc@aEuTnlC^$n_u)Q7yKI*J$Ix|7sP3?kQN1iX6)uJAQ&^M}!iz320OJf?m_ACA1% z=Y6Z;c|`d*5dN2sJga}~hcDLq;fyRFs*Cq!U(<8QExhORzB#7;@f41_9-buU1@wOe z!k_vYo<-b$P)D2LA6S~|4|ty?_=d0PSvbTOegmFuPInXh>eD~;hd)xK@FDpZ$?l_6 zz5l}R+NS5=VbnhFXY~(V#7XXEm+No(!|yh1b?I-SpZEK{uLr!(dp|)rt#8^IeihD! ztKrLG9IX+~R*u%cr22(s%g^S(qaoJt-2 z=G%eryFRpPG!$fayU%;n=iPc{Z2g9GvI0K#o(kx124EWsbuInu^C1gpZ|ej4 z(LnfRU-$#R_Y|D%^S&1Fo)}yI_~jInJQL9O1;Vcx9pK*s;oZLQt8i-oLzVYcU;T!@ zhTQWGzy1REXw)Q8YR6D?-UB}GF+bATvsGh!|%HwT6Lf+%#7W78w*nu6O zzKU|))BxAQXCc%}Vxn7pKHLz1%TpTsUJO>J(S-J*A<f4$hKdu$Xao#B z;4_e{U+y5b54}CKq#RE<4fp!JyJ#dsLNq_XIQ9XOJBWc8Lk+CQXx>CaGfefR>`Xa9 z9lCcHxTaL+Fm-b1AW;sO>|zkuqV(**nD0y3LNQSSYklYlNSR;X<_n)v z7Uvc8@ZSwZE1 zGBFASMMSwj3%~lqrKyJk^^Zr9lCWWQBQ;b^QN+^${aJG9TA%(b`R_11 z=slIP!ykT*{F#Cd0BMJ-QV)|9jB2P~-kH>)vpwiT!G;f#LcIY#Mr+iixS&Fe~t-d$h zK;qtafi=NAbXMUeOq0<0_)<=UclpDJiLv@LIwSM~P0yq>cwZQWX(*}CU%<4x!3EF| zJ`nx{(J@bg&l=&U=g}*NKS6s+c^-WvX8jt)@P!Zib@Z5MMyOiozP74nN=;u4%!jDM zK<^G0??4Yhvu$)VYtcJ`KvPCF_Jk1&KK~LmbFk8?^r5HmQAfHzK;7^`%vq2_RC(3g zA65f9)k12k+ff%i`x|EO3WN{n$H|=V$M8N?H%v7HC@kdSfcGt9uHZ$3J&t%ZykO*_ zE@(aGmhq&3>Je(r@$eo_Xe|nlo{3-}o{})ypr7;7tQTEVnu-yA0S^n91dw@+J{@)I z3yk_G?tQ9L^<%!MANGge^kUZea#KSXQ?~khFQTZZD=RRT=zCErRF^QW!~Nd3Xe7}0 zf_o@@9QjA}IMjrZ0QKT+Jl`P-On8Or3JOjs3V79==rB!f(Q!aYz>6w|ii#1VD8KAG^L|2eVN&2jp1el` z`tzz^R--l~5a}}?CWh3+Vedhj4XZgWO}r>W|G?;q={HJ7#{&R{Jafjo8&w(|8clhr zbT*+tFzLm3LepI%#pf|~J>w6b4TNbFHRitSY0B&OzKLfoHRm-ZyoUT<$RpdIV=jid z6%`y!!#<-?7-jF>)3gnfTqUYzxNs9qKQP@z-Nh^lQ8BervtDl#a&!pgp+;srDtX@p zwyCMXdjccB@;Qyc==t8IZUghx0fq@%F`m3h&*vCQwyM@k^}1>6SUhi%1g2)qlQd(p z+hT%?*%wXSc4JCL(gxVRN_DNML7Gfbo*3{&cNd|}M7Fs43>wu>$d4{oUB0ev?LAEkmG&`1c?Ox53i zpaS^y=cs`onNxl*$`egdb%vO~Z$Y(h+K#41{_yVd*Wau1i`u>w3iTZ*Ksb>q&xbq{ zSb?56P`@F8tjb=A6%SNv==Z*bexiQ)U?PX#!c5rvF*!qxLzsF}+dhDh_Y|tI^S0Da zQD*vKCssn2*+ z%)aYvXw0O)<AY<==>OIPoYJE5lA&q#TG<8rLV$nzlVFA1p0&pQtPcxd~o)xcZ*u+L{f3f{|TON%DC{!h=oE=_FbRHE&mHR zE63)K3x8F2>e{$_b|aXLDf3^lfGGXhcYPGPF%bUP*9XrzpJWd^T7xJ4kHbeNgwKqt zzbz^$JN()>{q4hLND;Nd=k%xMXZLy2hn_9J?o`%-Efd1;A1*}J#-a2IecM5XW-Z%A zi{IlQRhXT57WrS;3-;di(Sje7(a2r1!(`nR^iAy%wFN6nEh{UZTIh#w;1I96IG0UUnd$l0@Ty{IVSmY;-Ptezr&bsx^bvS>A}qPC;;(s=w#NybmG zKYl8*;`&sj=3)UQKdw(yDy^Ev(^6h?Tpv8k#`P&p&8j;MH||Ap^-(XYoWdi8*_6?^ zWwhd4pQCTe0^H_LO1c9}zkPO~W6jU54|PlmKa(APrS4R_xVztmK=^dPyQS`|r*>}L z`%!UsK`s+Q}+tm(4_ICfsQ%DXze&265dv~#WNusQ%I%e&w$<+!~5%=@nnZHyu+TU`Q+#mtUugjWOlnh_A6-Dj;w=PA$2iG zi(oZsk{4dte3em?T)-=0Ut5p4*g6$5~T(4Kii*d^X3fURAJOjvecWsGV z{(Ka*akGKn`60OiY6rw6cvp^!5Bn(j;lOC=I3Cp|d0gEoJ?`$8NK-wk#stvdpXbp{ zpgZ^r@`Ds@7AD7F8D`VFb8$U6%`R^?asca+==q=}O2ph_<8u0;rDuUwwG0+JKL zC%JmwcDN7@Lgnj^%7=7-4N_PVu%Qa;1}sBi7X!;uSaSBtL8+T*i+lpAKdF_Wp_LRYrs%}Bm~w< zpc?`YN#J4x9+3c52q$(R;GOKc=XCfW**h9l#+f~=3axl~I*j}TyA(00^qZd=&we>c z!Re{V1WHr;6TmtTbxZxpd(<^$5iyjSO90zE(+v#$8p2c1Z0JqGI|%8F_S zl@-CbWnIwR%(C()`Hh02xG1Q>5e0P=B(tEF-Tp6Xl1oruk2UvJ()!;=Z*@vZF+->aIFbi)`6_$=2c>5J7pd_~ebfL^d8~DnuY%0|3e~7ns8J0tn>x8g zs99*HceMwk3hjrJ#-UH!oCSgH%T?6`rX8tPIy57G?F5Q@1IMLz0nn}vdsN(oW?b?X zT}R%4Go|0W^I7TuS`4Ml`Qm<^99T!*I%D>g>+GI7y7D|C#x1)7y`(+zkvNcz{$Y6* zPz-A2cKH7NaC#JProcs5&q2!|2*@? z=Cup+2gK_=oFnL+7jj1QL#@Z^_g2MNl8p&a(=yxkJ0Q z`-rOsrd~?qY}|g_E8voii9klh#^3J<#CE&SIVv`}K5A5K?|WUo*#39BeX&F9+WBKw z=*~5Xu|q-f#rB5CsMv0ZGAb4sN=9_b$A_PuJsSkn#>d9jIhMqF#%|3fYz&0R-luT) zMqcAd#vdC$9`t*G(rh&uboI^+;-1rvEXPmV#||BBGb6i$AM`OcdZ2^9Rr1ztyI_hP$^j*a)l zdi-0r<$_S>yxT$fA>Z#td0h{jt~+o)4w~l_>NLH@P)+%Q(^~iM*w~E@=cUeAk6~6W zf{}JP_O_a5UkAqqi896#1xa4GE_mRA2QGNvf(QN=d4MJWxUBCNVyIBp3k)UvCWm7f z%KN4rIV|s)Uc_N}zmZ>iHD7P+&U}sEXQVj-U2Kl_*_pG|6qfmgyepU-MO5S6Z-QAE zBk7_g9J)HNp&g8%){P+^w2X`2C*){qo%I&)v8du_0pTdZuGl zOg6is*hy5nYD?qM}@t^FoN=3WEm%Nc9)}fbdcz9d%z1 z!d)J>XEmTxcmEkO?FjeG26n&|r+Y>LiB3Wau6SLgt3^}BT%Gmkl_VJ5j(A;+P<-?} z=yi29LfxXjpinm>lpH;iBrh^Ty`!mNxVjsm{?QXjXAdJZG`a^#UTlQ2qG?spb%_zm zj((SP_A)}b(YH}3*$5Rz-$Obt)w?VOoE6=fbf)S_cOf(x?j_4Dl)2qi7Ahay{GSV_Y_pAi9F8X7V9IVIv451a# zLnw5u9(OxrRz=@OmSyYF()BlJl0Llnv}LhGX+qtJLGv@!bE6q=y7r!N*Z zMSn#)uQ%-668%@=0af`zd7FQ?VVcg-|!wW)EdMW+ut}S-C)q2~+f^l?OaA z3rT#7D#Uor?a4vV?V+mIk&2x15KHxos8s5T`a7W}YH_(xrpG6O;+m@WB#y4fCs1b+$g(RfB7NvEh6yK5XwVJ~RT%Yf}6QCW@lk`7Q{DpeFUIKOUWrMVH{UJS!rq%fq zindT6P674g2ieYh4B{jrJ`cj5iFh>;Z`L#J2XPrx(;{W(ju?RSMf%_$gV+2XF7TF-6n5{y@`L>K#iU7>DFtxG%Z_Bis|0f`UuevViHU_2}QBd+r_p z>jB8r;qE>Rff5WdlW=z%UB`2TAMYdd%gb^;bZC zLIKix6T19L+}%h_X?+Qy7jX9=ts{|xLAZO6_NRdSo&uE0>p)(`ebIdwWq+HjvViV0 z>oTMk&|R;>((b50R!l2`xVw81co3%l7`N8TlS+{_ zjdayQmi6_Ns@DA?MT>U+jK`Qu^!#Y&Dl;(A+5Rg15Doq$g?i9WZ1F+Ji(Ax#N;guRiXjOw!PC z9fNQ(mIO(tFZEG+L2@ZRWI`~LczQlm8-3s)2L)M`d{y>fvnuL0IuE7v^7S-Q<;3T9 zC*hjT!;F|&)U&Mx@jl#L29o4tvlCmILh)z!G%VA!tYolf=q^=5J7L|fJ#JMi76Z8n zcQ+DIwc_sx9l+gM4gD2sbZC!|M%2)^sR>gXoPw$OMBJ)|{sPEjG*?%xD9JdkcA~RMl#X=4Jlf=3aLd6p67?AfU zR!@l`b@66OwAU%tL)7=7f$G{qNK4Uvt3F4&bOP!lIZh3k`dZ}qvN^Rxxt!`%YS>^8 zpgM86CknDx>T0mQ0%O;edeZeU?TV^uP4BJ8(s+G&5k=^&ccQ?RRXR2)pi+K~4Np>s^oGOjp5JwtY zxHIi@#q1E8O1$2Q%rnf6*VQZqjgQi&2rB&!T02TBN&huW)iK{vevpqk<>O1Vz$K6} znvJesMJC3~Ez35>ao>|nLkX*mtQBsRL>hTEBCCMR~DAcGl zQn~m_65R(4yK(m|#zaIF*vohj_u}q58kjXYp(@iz1R zP4VsoeW~Kz0p6F)drEnB2Ys31#bY$4ah-HNqQZ(`?=!12>Nct>yLi?G3Gt2c*(b* z_rk4tS0TN>F>jsX1wbFIcw11muQTsa#rpy1a}@6p=sd~1e^xks9Yefy<~^=>AA|m(;;llw@yz>$;w9cnk3(cm!Mr~y-ix3& z5^um@%!uf^gW+D5+pOeHLgq6iC;UAucar7)tmH1n<4kwl+5q8qqgfKJUXUjrJgww> zkhzxRyp6DF1oQr)c;%p%D&8#kbPDtSs(33w4=Y|gc(u&?o8oN*{kMwu2zd81Z;Rr+ z4EjromkfJ(b}HTw(63RvM)00s-t&q#9rUS+*S`z;f9CC0ygNZ(s(4vl(f*nD zg5v!W^v4x%BjSC@ygiEdJm@Vf{Bc`qwoBj~#o?-B4`XWo9r^DM)R2RFvWi_!lx?-j-C2l~~Dw+g&O_=fU+K=JZG z&sDtmp6LIW_p0LE4Eh4a%K~pa^IlWDhd}?S;ynUh1@m54yav$!rg+*V=*5`#hT^>k z`XR;3>ZNJxnD?gQb*#gR25$6~i1(l1^@p8rDV{cPB+5-DaTvmJ>37Bt$^{jLh6ksq zzy_8@2t{khKzB@Y4Z0oF?zQ*{K>KJ)0hd}rqXhsp*NxMz`IQ4IYk0CxsST#NVND9n z4Tn6bm}%Ej%xiQf^iJuf(?rclNe-Tm@DQ4RV?N|4Qj{I z7&TeP9Fl)sho+&8G@DW6VAWi3n(Q~xSyRU=a>B2;o9&frgfOl&h zR?BdAe*uAum*Wu?clXy2xDiMhZf_&peg{0(<10}A49XvI_lU+oauUdK+-lut8)}Nu zuEi%Kjf?e!Nr#I;2bVmm|X6iciZFILktW$6wih=I-uj;WQb^U!E&jh$(o}Qpz9-G*~8QUW^LGPr; zyHTcHG-vGa4kJ1Y>o5*It}|8Z&|xGbu>HX(O4$_$DoU6DNwvE|Bj8EYov|G{Ahv5* z2OWgyj)pP>$0ZI$jP}jiVSp))#7I1b#Z}rQ-ci@bB@!n#1qq~s5|;>#87TSqK@qC2 zjUiG3lT>tr)F}mSNQ7FCWQo)!rRmqks9eIZD`UnbQs%STKR7Ce((3Gr(Cl#kaTL7L zB{DS!W|mz+Ae|~_EYz)oUI5vPdg|W9JblwBSAn~*Ly>EW%3F7r=1pY59)p_kiwQ@S z3opYeKO&+M{t#=^j`piZA(>u6Cc~0pSaX`-rr1)#nMY|T1H&-NS+Yv}vdEZN1&GWc zp06S^hsXcOtl@#2xZ@HB#Zb0;TRms!??bz^SD8E%fX%B{bDFAf*bjXqLQU12nh>)>g1^qcJf5MO_CPja^WpI@dByGekWUi}+qo|XsbB-%L$JM^j)k6?} zp{sq4tH&y$`*W7LTyAHA?n-w%t93l{pJraN<15iJi1mAf*RQEW(MDp{2k2vk@Ne}f?0rMq$R(Xyh#5$SU#_j6V(^ssJlIBiOZ%u?Ch*N zZ!CAOvM^6%r0pzor&*{OTolAik_sq3)9kez!xH(#FjnT zFK0*6@QP_;Y#i?}&$YugXH+zop2Rs(UcSLBHARH}@lzgN<=(+w5=qaYWl6&`$C=qM z=_ekx(-KE47?%@D98nQU$gp!)jUSP2H{X-yNp=@nQgvM3$z#{xxT4d;HUk~0oi^Bs zmv=%9)%6^zvZl%VH@Kzh32otUPpFmXttC`9uHw#$%#8RA8J(}5^U!r;Z5f<1+|wz? zW{RiWPFr{9!-*rWUX_%cnK}MyTd~!R*q_*MVgE4?Ck?lyQ8Z#h;)ue;9SIfv3(N{4 znHgC#Cp%|C`uO~o(NMInjL7Vl@nk=naVPe>H(OnQMW_9VQx-J0MA7cJtW$>jgjITY zCsLXb>1T(x(+OKjj()8XhjdE%HR_j5digfblgkpyGwgaiIW`+Arff*+dnj{6#hv4u z+o4$P38B&2GvnDgW!*T+dkf2VW@2FRWF+=$CC2``5$T!PA@_cZ2Rsk&NGuzFXJ)Of z96diOj9)mM$e~F0WMpI%x>1$Uou;Qz(~PL1@Uh`}_kxU{w`65($k^bSFnMG~ysdPL z3KKFO_HDcDJKf+rWDj2^kU zdy;60mWRA$G%bYxZ#K??hyy7LT#{PoiUHKqlS8g}XYDeV?(A5Y?DirNB$wcFjdvGO zy6&5aLW;3P7d50a(Sjx zLi1KZj?rA$?fjub zpJq(klbj!^NJR#pCgQN`euti*G#bnbgGtlu|57GZEShtxl1WAp+){{wK|V`1Y`}cM zvn<22nJieSJ9;OgPC!1|Q{&mZ10wCwvUj+m!9$=1vy)X+C`0#4jdi*Iojj1>iW%=} z-_I4}=$}Z)b28gHm8e)11FeNB@^I-N@~BO-J*Nao)ca*+zZ-tkr6J2wtjdv)bMTcT;Us z)fU}Fm&j`C_U!m(K3mpS&0TF&&eq-X-^D~msV8%~ozLUZ9EkPD)m5=|*Chm(I46QNVxf^`l*&V}^^YNw0%XTc=v46j6v7R)L&}JRIu)q=wR+pCtLpTrn zh9Dg|9h@Jk(Sjv&iYw=7wK)HpShaJiYeMvnOXa+IWi`Q2+1&XWzVMtBq64of;((wR z$5G>??HU}tjWA?`vx{rXG@Q3xk*t0e%&V=en1^@l>78`-IjA}VTb-ZXEJe(SZ%gr_ ze)4GVkmRp>{XV(hT%5K&03ftrURh>E8O*FKL9n={WKJd)g!&C0l-#c(x!(-~llzt5 zTvI%MAz<#f(R5Ha-q)#a&ORNd9W1XZuBbJ0qDc6}HCR$zwP5Z%Em&PuN?ybIlafIy zH!8ZeAcizbH7S;QG<|<8HVfCzaP?r3lu- z=e6YFP<2QxN-38o+npxojw=tga&|Z+Ut7Ge%y2&r3a2Hd%6UOKmK+C|-^lqJpathv zV@0g0xHhEDAEz8tFEH}NC5o7u@o}%VVBmmI_0Zt#$_k_SN{!>pDM2HLqrkI=NFfH4S@2Y&_DwWGQc$|k&^1U^J}m&sRb9zTTok8I)I9fDv|P+R$?4f zPeu;q0+?M~a^r&eMy*h-SXES`;Ea}9Rvyxzb3s)|tv*Kn9Hb2}T(xSSkJe)g1RaTe zP`Y$&x}alBQh}fe=3drxLHjZ(O2Zpz>m>AYv!I}FnWO?i<)a!TYNX!wuif-~yXir@ z>G^ikgRPmK--_u$yXpCM(}Qgrt!Z|%CtA%W$4y*kw|t^lE>;+V5)wmnZK9y!PDAiq zW)aVBTAtN3U7KXLD^KhaH$qBKDSombuN99@vRj{LwI1ruWxCz$LaW)7dSNRbEfmYe z3PVsrVu-F43L5Fr!gW@&XiKB{8o`Z9tZ``Gb%N6ik#yRjL{2SDlxdRdx7*z2>nc4A>hF@^#uPvzJo=;j( zJ-l7sg`uH$2#0c7Pz}2xe!nI^x;E3A8IY_w0m+&TkgRzC$(jL>tk#2MH65e~i*4vj z?Cp;j>RPTCc+BkcbH%`M>^n#aI@u&mwA-9(w&h}w4S_H~l)mbK05YNJ+Iy=_qK`DvLCNe=~KO$;P!N+4O2 zX|)8gVQCKCD>$FgnkQ@Zz9nm-E;h3j&1D$Dk`&+Lf{S2Tv!YAMIM#C#QVb5Q|2n~? z5U7(AT#CS<4X_o5LmOx-42L$z-d$)9bE;1;bZV>LSYk7>HL(LWF-JSmCeW>&kbgnc zLZ@941-*NT%|2{u^Pkl_C^4&ZpknzFn|nZAvBc&eQ14x0a}lVkzKIc#M_<^A9p6d2 zY2h&nU{jy!WNVkS=r6e#;T}O{xX`s3PgweWNXfV-Jrbk@m2m)4(mBZ>0Ft26BO#)o ze>MB7nSwTtp);g$$RGh-f=aW5ElQ(8dPh>45~dN%@nJBaD~-4kgS%0WHk#Ut4$zT z4Fah-Z98@qPe|y~7P>HWt>#YgspbJrtXXE(j$A<>Fi8{b2Ii*n3_%JT>Wy@oe8sdgw{1v(Z5J&Lo*fQvV{KBOvSh?A(?eT zFUDo@ijgPg`lCQwO=vndDEzTK}VR$PZCrtqvZ2ju`^%n zl;qE`f{@24N^-h({waTpWQLl#nIdR&Zt&saI?*Xk#q+zM&AFMm+b#Gtsk70#`Q^W7bJvP%|;!EFSSGYSu9Jl6b4N%BF?{F;Nu4OH$g+ z>L%OOO}4s7<`SatQ+AYx9{uvw2*Wl{W7y1D&6J{-Bms59WtEby+)LM}$v`RVJiIhN$I|K24w(YV@ zV!WGhj$y~@8kDxxGZ+MxFSYpw)D=r@-U0RAr8fV7y6RkGpWTT6l2&2!76|e9MvN}` z9uT8~pvlZKh7Uum^AWu^Vv(S)n4~;GPne`aK`+Bc1xCb)g65f| z0zvOFN%?~Q(j-k4^i`9TC#W3mr)x!mPIZ|n3VNGKDirj$CaFNsLnbL-&?J04WLTdk zXr@V;C}@pI3JUs&Nt!9>YbI%ipl_O_yn~E-_)!4+f`Se(Ns|SgXObof`WurJ6!d+Q zG*i&a@U57Up&5csF-g+}U2T#k3%bW7O%k*hzV$bB%@j1pBux{v#w1M@^tUFdNYM98 zQm&vWJUC%bO3?8psX)*rCMjRg^(HA#&|@YkS5P`-$FP2)pz}>qfuM98lp&Qbs0Sam z8KgWxXPcy4K^sicL_yy(NddAZQ97jet41ptDTUBtd^_lBNmzzDddxGzFi*8+H{5ns1T{1%1pU z6$rY^B;^bGxk<_slulbP)K3$%!XyO+{kch+Dd^u!(hNcAqyt0ObU{1d<9LHKEtb*2 zCTX&u`6g+Spi4~BOhI>>q+CHiFiFz|?Qf2@lLf6YNdG%m?Dmp1B==2?K4>yxFpzAJ?=q;2EbxhgF#lds7u7s&rift|BxVgIEI&7zg^n`{W!kiAzWKBxvlsdw!n_V4 z=chhCd??#g}S+@KhHc69Y%kMRl6tr*o&6F*_>&(r(8M5WK+$2qxEx!hn zG+DO%)c=c7E}JAF&cWXta%lQdPf{0^F=BH8lOo44s?%Ws%TDwHk1 zQj=65TYe9jqJC|iDN14Fs6K(_n}%+0)f`<7pxZ29dlrKZc4-)WOnBwK#t&CR?*`-bU7qX$7Mi4KvJ1GvBn4#`@M)7YQ+5FxP0|ee z{@!HS-}`~Nb2mx$_kL@VX3GBFTP7)2_V;jLs=BblFZ+ANCTX(l>j{MK1zm1R3B*wAki9(FmD9DUg34|i_BaKVeJ;H3A*k#P zVUQ72_7qT;1(nqdy!j%i4DWEUpfZ*tML}hVMv8*U5DoQ$%E${N1eIYHDGDm1CsGtt zMo*+Ds0@nmgrG74B1J)EV1r$P%D{#c1(ksfb_puu6^sy6#w!>hsEk)gQBWDLpkB~} z=Fk-sRE98o{v)UiVR#>1P#MC|2n3ZO4DTEWDnl4vG!;~aFkK4@Dnl4j6jX*Vq$sEi zVMtL>8N!gFpfZFZML}fw(F9TgwsaMCev?G%RQyj0`Nwc-IoAsq+~6&!CI!Gw3{-L06h9N`>|r^hEm% zy1+hz&bQB?r`l)GdG;A}k$na|(LRGNw9lXm>@(B6XL1o&EL0nLoHe*sPs7#wNhzlyyW(?wj%Cs4C1VLrm z4E2J_v>9_3L1WD|oT>I1bdh}qook;#7usjg1@;+qzRaNKnkzkdg37cRa~DBn+KjPJ zP?KHW^SXRNWfr*m!i!?(^})wEpXC34`?0`<7sbpEfxb^2!uM+F zr>)-W!i!=pzCmd5`B|GjJ7+iby{Z-$K6+{X2=V*W_q6$%7i!EM)C9Nz-K^E5=;Nnk)-hqfF8yS;$&!l7h03^+%I5Qx>w$nxq-BkTuMF zKWVxwWEGpF$+D1jpGle|3t8Ju(o9*%`obhlv#(ke$*R?T=5klAtXjQck_u(jD$!h` zDv(vHStco8R;_+#lJaEL>PwT9E2~y{=6cjbS+#n~B$=lad}WgIWIbxMx%iZ8Uyqt7 z>rro*QU$Ue)!AHD%9r)1ktQim)}vOKr0Mqcs3KX9`qGptl=Y|?%}Z3W9<{pZ;!270Ke$rRIWBp)5Y-o1_9+d|Gaj@@4Vq zKTJ}dEIxf=lFai5`j{(CL0M_4F-bFIrRmouX}YX5y>5~w%SuyEbHQkmtTZ(*E6o&i zttn+YeX4nxNfu`0gLo{Y2r3`MV?9ey`5M0ExA7nIqRw~vZM-ObiM!m~?|M1Mb~aYC zQ)CTFKE}s7si5*PKAa+`e2E{WMShpxhgV4c7k-y7rip8R`~6y+YPH~GjZh94z#_k( zlFbWe4SX-3Lt8CwYOAswEC&x@6Gu=vcmOZ#2rA3N7tSD{6FNY&l)naysWG1@|?o zp5yW8Lf^wJ=A8XRi=E4JO1607Jf~!fzUQ2h=XK6nn;Oh5r&ec1^7fb%@yd*5UvJq!X*fq&MZNzC4b|KlhmCtms&tVsmz1)ZsDeOYByBl#vgeaO!!9J-))6Od*o9;xJL2pOyO3;c%SX%TcI-m3*&T5{ zhh0dvzaviUunWnCc*GeVb|Kj!k2uxCE+m`g5$Al^h2%?*h?76;Lh|iL#91JAA=!PG zkEk(J*o9<2KH|I(yO8YAN1PyH7m_{uh%-g(Lb8khD|0ixm9o<`+1Z!lMo@tTl@GLA z&5dmT4>0%VZQu54n!FGYaXN|JPwQlyC!*OA>ysR68|T%){aaxQ45NowP56}y4?qRwl^%@?#;T`TiCO5Cn)qNuydR5wvjQAhcm*y>~4BF<=| z>4TZ#mM@w~>}(6Tkp&hu3koV~@tv8VKV&JlcDpuTyVz!p@ixvMSgP5c>0*zR4L(5= zRI=XszdWOgWYrg?wbvZ$L}hb)qFS{g{@<39d?+dZ z@1~f`VIISU3>PuHi=n)oXDunQOX^iydX})Bx;FI6H<;_0FaJJg6NlwRIBWXWd|35J zymwj85r*=XmQ|nC&bH#ot9I5yQmp!{`B=|O4I3D4WcZ&9w=>+uP?iw7xed)d8Oo}G zHNCd%x{Md_u3*@gVLC&3MJ>SLY=+k{lpRxRdf%1ad7REo3}r3SnqFISvi@k57rHE9 z%E2;CoX$Rmvf^lsf4=c#A<`OO=$G(vUkXE6Xtc_=B{z=a-M~;58?Eu%l9Sa-ITPbf z*0Y?UEH_&9oo~EHSkGe&WmVFuuPr%Q=G@QmWfjsIU*u%>{SB5s#PEHFA27_}b|jxY zOyqDrLs?_InZvg*lx0P0`jW2LDd~L5>B;(Pd)CvI-g}rIX82QvKWF$DL+K}E_0npO z_^B;Fh+VQI>|niCJ5!l{6+>CcwWep)W3~Hjj{gorStpf#%&M=gbkDcktop2e6+cS9 zD}MaCez&cBSkr5(UzU$v=5T*~Bg1NjvY>0#XN@N-y1(OiPci&6!@n_<&u3oX@JkG3 z`BzqWt?9L8m!xZz|E}yf!}jUCnCxWeW+;oz*7VOeo~%P#B zvbejSD7;-}*F43ijkV|Xz`Ss%9AbH3>w=X6ES<*c_iLs?q3 z>X&$8x7ALGC#%lZ_||+{^JTR|^xVdFEoUg-MLob_Spt8A!;dlCz)%*rt@gB~ceO>& zFD-ihz~MhJl#jA@a=4Mv}KNv!%suau+6$%ldO zaJq*Xe#B6=RIK{WH=gXaSmVpKi0qx@@V9~TC1C-FWoN`1|LfvC!13k8EZIDf{Sm7^ zN#_R~?`DQ=>9NMQ#*=hDWIe|j$~TZ_I2_NPHYPH>h+zuD%Nh1&C|fty^sVW9TfNgb zommWJ7s#5PH6LxoyOZ_Y&2SaNH4J47%Buf-<85R;e_$w|ioV6+Lky2Fl)WfxdZOn) zzo8xnZ&$e(wqqE}P`0(K=}9_bcUyYeTlB~t+C-)oFr2|~7Q+gLvR`IRU-XKd-&SuO zrz2n5-p}D5F_g2Ft?7SVye5wSGDF$ibMXFMJBA4iFJUN0GF#IVJKEA~l|SEf@;Kco z45u=b4~S(W(5nA@6!`B(U#qbbA z*`BnfFX@P#I&V5gGmK#v$FK*(OBl+I=3oxXN7S+nI*#cR80ImQO-`#l-&H=pE+3uP z4r@NF_J~{;mjAZ-l>8R5o*4{_8J07wWH_H;EyJY@?_s!-;e8BOGklbx>Bl(bW zwAyvPb}Zv`tahwv!;W7v{Z|bC$nY-=8yIe9C|lQ7`>lQxJH#*I2eISZrYq_1VSC-4_Ng}Jh4mU%i>AuSGCEa%|dgZ+c(JQYsSoMn@$%p7U-+V|qk`GBo z-j0~aFFwfo7S{CJl9LxFtnxyCko7*qP~O7$9f$wOa5KZdGTg~f-np>q|E7AkwxL&E z*RbjrJ0zaSonk%zV(8=}Hrx#5-H-$h_h8tI;pGhbF_bq!tm%K#bmTw~NvDYQPiI)c zu#(|ihH^fwylP^F@`j51kA~Yh-aQQEJrt|`l5ep~^4*)`Nxp}2*w1h*!yJa+HXl}d z3ixG+Sq#elMLl$2#If%&*PUJ1co@gh~X-RXDx6Lzo(PS@Sd(# z%|`eq98cgcIJ}XeHP)+^bR=DCdYd@iEKawejr1kH6-IGblkGH^!I4tl|4hy`R z!ve)#tN!wC2IXN3Ty&8^7ud+*eGK1Xc!XhA4?{keVYiEoa9@T87{0}@vZukf{w}iE zA$GmS^ar~eF(kbMZKPMm>HLD>UoGi>!eI~F(S_jy=%FiwPjCgTlKjO{dcrs&s|Lakp-^fu)qx* z7WgL)3l#gU`8{{oi5Jdx@EcH(l1|N`9cz{D)Ux;um6q~RS~Bl2x1_tY)^=*0nj4?| zL`oXCQ){O!YL)KMl6gliGL}<|);6|EZ?A1>mEJ+?&pUW6^~7kmT^>mhdpc^XTBXNo z$6BSwX<1jarYBxI)i2q`aB7(5rnN@zq8iBtYTiPDarwKB*Ohh{JLtJ;vi zhUIfD^<)Us@37Ewn7+kAp9Q+EHTzkbQ?;Vo%l+S2kH$Nr2&(Jf@vCe0`qKb^=#xB;>$`;M{Nt&TVCkbK4$txrt?Cx)|P+TAtSmLru=&un`0k@WXxKlFrsbX9_Wse!im zy;8}y(x0aAlHT#l$WQK zXr*N}WfhgRp|YA_Xl}5is(M~otriTHRtGDps%IBh1xrKKHMPOw1&g$j>bdi)%0gwO zX+yk22ed8}EU%nb87!`;DP9~bn-{8Ctd-Xk&n*jwVXa8x88%>kEQ`Y!=P-=Yf=e-Drt4cESy#d=r8f>zW)DIE`7ghCHlXQgE9>rwV|5o#j2pHOIixdEt^|1e{oA%FrqXmlV$TtHKl0&>>EqV2L$KL zEiR!XQLspRc5N*eypkcm8`7nf6-d~~hE#(VnNad2)$Zl&P64MP}%GS6^LFu5B`*3<-Br=Z?I<1 zt|?n6p{mMxWrD*uf>u={8AF~mwP^O=IzZhP4Y}wx)Fty+fvHRvV4a?(f${m-v(*w` z=DPxOIU>J+YaN!gq2SYr!xBG>5rGG}zoT>sm0?|GQdyvpZiz4RXMr6!K19@I32ND( z;`|xYewk+rl;K(ImvjUcApV(%_%a_Cn5%EGX$)^FNQ{ zk77BQ-wRw75g)TyoBtMpMm~{gzB~sAjOF+O$kxcK7J z3V{W4fZo$6;uSmh-w@DC7+i->PNM^VGZC2~fnIV|*N zz@YM%^yPWW^EL5B-(Db8_aweNm&J4ZMsBd;H%V8@;Q-=BrZ3NL2h)udk_}+~N_>HD zf)g3vod5PWqGX#f4MgGzd=F&8#eSI|W^;Uz6E%_#2_FSQ>9e?yG0!y6B9meu><$%& zD4*gMnjvBQKFaZ}dabff5Ue!P(8Lk*Esv&F*|;|1UrrBnxSkQm7(rWFG@rHVB+>V; zGa}UD5ijzx%J$*-)_hLoiFlI5;SyiqAdVlI2I2Ec49beTTXH0xP_Jzx{^v&wiAOB! z8`k&~wlr}SaVXVFr)W2C=42q@|b}{11mtBg8A8Y#L-qzy3+0Br= K&Jw{A)c!x#>C~zK diff --git a/Crypto/Hash/_SHA224.abi3.so b/Crypto/Hash/_SHA224.abi3.so deleted file mode 100644 index dc4dbfb6229ab0b3c25fd7dfd05b8f206d0a9bbc..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 43792 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 diff --git a/Crypto/Hash/_SHA256.abi3.so b/Crypto/Hash/_SHA256.abi3.so deleted file mode 100644 index 6daaa16c0268dcb8dea975cdd22991b6b9b26c2a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 43872 zcmeHw3w%`7wf8wQnaNCElaK%rqRikRL?mGdZwO>y0t500Nq|s7hCmXCh9o8v9`%I; ztkW2U*6-F~nH+{;X*RRaN*fDw7n-t&i0(d9vWx{SrWur;Jr%@jFm) z2wGF9s0Wnh(omc#id`T`h8gE)xgv|yE&xtT3>to^Ot~Iqsb2CVtvq>>T>zXOkWJy# zqLC>vNa<{s<&mjV(s4?(bQFBxuORq|ERpSz7HepQQ?54;^+?ZedL&E2LMiV;cCko% za4MT4+Li_$Mx4{<%vYv7aLqgY3eLYhJf>*Gk>4f#^0B8sA59{tJPs$@|L*PE=530Z zl1aEEoTSH;{DU9;?B@-co%8Qo`}@EA;D*E3m1I2AdOGRD*FH|#Xu15)OCPUxO^nUA z9!dVmT98LQT7c~prKAsV_9*zRz(u29d;xsZ1@Ox*fT#A_aYh~^fUrj*k)MTgU=;ip zz$Giam4ZBbx6&Js>!rji$`B3B{;Zbx&4V?3ot7wxP$*gHqm)GOp{_{yNd8o>mts{q zBZ7+L^imR(kup9ddu6x4$14R_YMA%P@i;c)Bt4U*p2HxIjz@74J}*;bmH*TdS`;C%a_$u zYGu(&e9PCC6NB=a>hD%6t14GDR{AMfUcXK$^14Ti8tnsjzp}i%rlxK=qbe#J{S9^N zl&XfxO2#$SSCso9%U9mmSP8|d%ByR*tfG1aYH)6OU5I)8vTG}7ak9J94lZzj(eO>F146MX+klNAftszkzo4>K)BTi;`^?`P?Yu7Q`fb~STQ>LI_C+J5tP?Gtz zH~6*D8|d@~J0^S8-QHKe_NRftxiKh&JWJOxi1LK$ug@KadP-CFd~b8^Ay6sazz6;W zuzhosUFpb$${j25v)hycI&}%l<@Ch$D6Gn2^*6g0x}Txgb}w+xcNfnu^4{{%He{=8 zb&2W~igMOgx6qEC>BI4}!al3jzyzyo*S&73vaL8EsDU{G z%t2tTJ3#1TgwE3lSL~$flL##PASGKdA!!VHBPgg}aFOG!cKAt}$@iPIdx$ zat~!8_2hoRFCFsE*fM819|q74c~GJn%9KOphEFZvdh#`mE9!oMGN^*8)B;=eN4Crx zoOf5*Zu(5CScjH3bSC46^sI)IhI0@=I#5GwCwJh4QBR)7xfADpTc*d^?rAA?9%w0c zzD{~P?Fk(91dimlB)fwrdxSYaqgD9uUx0|10^F}d)>x@jKJkbr*bvJ)L$+qdch{%@Powp5r?C(!$S(x79OHhNL zJb%Ekqh)%U$I8($iw|K@}7dWiKtb5KMxO{q=`@9`*V2uRsgO zk$gvo+tnU8?N&Pi=Yo3-!F`F-Tb%~iKIj^ZL-L9%=s4|heeMptprYyr&?rA}jD$GO zlN^uhdE}`%5YbZOe7N=Ap^JAc7$-<~o<9hUJdShuj$~pJ!gZm6qS~CoRy}`YS zt`7tIg3rexdERx-vCrfBFL&U)dNA-N6m$m;2ltAmcw9S>(L_-EKbqhAWS`S1rxyj@ z%vX1xe--jQjt||A!*17se6@30>qrG=Xg9bWFC(}BCAtm-K13uSIpf;v_|W6}!X0>7 zMRaw#9Uptt9WVvFq&0`Urpellka!}$^-Yxz#%pLexg_BNsRPgP91aojdT=<4?-6@2a2N44~Pfl-rFy>%c z#xIFV{ltA95&S8dpCrD4F!BW6 zbCclXh&Ti{jR@~iw>gbae7g1CoVy>1J&aQI#q)1vmO@Un=3V{pDlg#>aZLT-P2KFLFFcWk~E z3++=7bN(fNY@ona&mk5_AIIT*$8k`Q*Hx(34ijEA8ot?&SP)nd3xL|Y$3kb|6nX`W zgE%00@Tf5e1w4kZfYU-@fdHdH zC^9lU0d)5Bhz{}@4G|(Vbe~aZybhnG`A^@2Y2ici8Dit8<3r&ygvRk{aMw2r4LAUy z0T)X#!d39F2ttaE!|+wG`kwba!dJpo!c!tR;3)WMDgu#%g9eSLk>RE&Brk=9h4hgO zi?^q=-fO&d`X4_Qq-RA~9H;Tyaf-tN#-^~yhztvgIf{`Uk#Q8kAc6xPmMtU)h9ct_ zd^T$LeL-8`DEaJ=@Y!+UGYSoI+J17{#X>_&I-iom^w^LNgOf2VAUxiO&k|nxX@V29 zMbfU6>dBWh$| z%0gU_zx23}{=%4m5#tj$Yvh}^eZE={enNq96miHy291go7tW}0K_iepk21U?k=N!W;?dy4|&tJZr{ zSM7E^Ok`&%E)eAB#j*kpLu?#Hx4K|#bPEi4i{`1&kRhE#Q4!;$^+fw%;}gP7!b@0A zi2fud6B;k3|2N|W1s%=t+GK)o(k7GeQA7Gk#zqV+EMB;I(VwueK(7*kfnHDZ7Y7Cm zO@ZP3hJkTh1P1&of)P^**-DIu6c`qa7iZ&-VHtd!T!p#h6haWLqHeCuCNyNgT~R|L zEG}sAfWati#Lyi^F_F-EZ~XKvKR@`7tT8CwT%XHjhBlXw$Mm^G_ZUS+GA%RaE#GVY z*Df<~9q?exip75PP%8R@jl*cA7>!T+>n22UnogNE)hij52` zGsZglXZ>rJ8FpG`e6{MT+0mC7G~xAFX+)n&F1pM>Z+HF0dw|9F|9O(rw~c3Wxa z%ZwrLRdHin<-dNJaTP5yejj(u>WeHh5MWVO8c`<`EGRCr%ot9~jI2F7ZuuuJGiYHU zmWH%W)CMRTH%8JjW7Aa)xT5>lEi=Yq$oOf;pYFfNG6O@;MJ`S*zRZ{icU@i8@8N&$ zG6Pqr+NFsc3gv8)N6U=*maFN4{C{Ja;h|;51M_NL_-4xtgxLizPQJl1!;69Al8zs| z@=si5(Bwjwtug>HT*81p>O{0=N`8(Db z7=xl-n$RtYuyuxzCoWn=qhw?hW1V5I-*!#%zjmELeVVTSX*wyvn9(Qr;3Ykl8voRF zMk&@AmYOk_{T=HJj66LqS_5xhY@M-`))}+bcnAN>))`_Uf#9g1rN&dwJu$M!QseJm zXI$i7#!6ab{3an|+&{d?pnGNEx3+LQgJ+Wqtutz{&Y1bg;W_`>bw)khOiPWqd+%Kw zeW~${*BN{-Lw04{aR?hP{L@+=9C)@aYvn(($UxAA-|51#kScN>-t|skr;xNe_@aR%;ldSn?RN%u z;(prEz>BWe96LR(FL9d_7i#Xnr|QYTIT`_j`{E%7H?gIdC!Oo@U;^{isI;~18=;X$ z{hJ%4j!)gVEA99o--Xs3bpr_*xE#q09KmHIT~QvvYLL=bXgUcxj%atkwW~+B<6Vz> z!X2Pmxc=FPyLYEV?s?q3L*t%w(&I&pg(EG77jB1o`RWJmz(;i1fByA+$F6+WC+@)h zeDx!eii`1qbRQg24~ct|lB6bT;n&-vg0Q@VpMne$!8MQ#`59rv_6=)4W` z;8nWJ`=aZQo5k>ZTwLZsYG=OVqkPvc+DZ8kK=D{*GGYK!fu~>)c5e*LR(QL$}mHWoC+Mo^AE>4Jh&i< zcM0bEJ>>G2y4ejmX*WFIf;N-Rti28oYj7zdg3xiEA_9*`9QzTRZpZT?IB^F?#E!I} z2pt+1sO5-f7+Ku<`#N8xdzx`bKVfv7k zg-ctfsF}gQ^rgE!eeLT5d%dkU#M+xbk6pdi^=ZdMJk z^FgDxrKsK;IPML6Y-3}Ab^CHsmTIJZkd`UfV7sW=>kY^ znVKPhjE)$R)4XelYy09QJ0W-1yT}LL?f3}z7p5+S&UmJOz5Urd04FN&gi=1gf0}k0 zcsF(V7Zm+*ErEeA|3s*c2LuBnJ+z;S=e4HSu!X?;Lf%r8DKF%S4GXpudaiETqm|U# zQDRHUONI($ENwplKc|11b}%g7xmoOohy`!gcCqmQqHPQ)0fT&eAWEfWZU=NM%EiR=>9_<0O1esroY)X{s1|e8!~Zw<*awyJ8R5XS$YE} zX9d2V(RxFS-5YpwhWc*Dv7=pG^lZ!MaW3^{zT<|umo|Tv*Yx{YfxmX_gidZ+1h`)S z8VnT^w#6t!RFT^SldN&Nn?25zYEuR&{xof13yThJFPa67Hr2wyL`Lq=BZ&5Uh`MCp z2)yvaPH$`C)!4f6Y&j^rt)py!u@l09q~kB|kk80fwvBD5|1|9~@s3+q?~j3v73_1M z0RS5j)-1(OEY7*f_*sa?7dz{1nSSR|w2sPrV(&v9pt=HEW{fj<%m|BA(9`o|TV}D- zZp$on4!31iIP+|oHO>OEKx1E2UfH}|MP_AF9C`;y+gY{Q3)6LcCEUq4;TNqvC`V`& z!Il0wkQZx9F(a9qY)hG=DQ8PrU>7RcQpz;7Y$;VzwUpWd6s=imOIf|t+cF)!Wm>&! zyX=SI{D%_%E4-Ut^*g+q_V_cNwm`Sp2;3B5q*>$U);F1Fjhj>NPuVH!=^I95*v$xh z?G3!_o<9SFP4Vo&OY;$BvjTh3$xp$uv>nIWTI$T3h32Ps-2HY}*Q~&wsSG{r`^b5l zZ*Zoowp)i`U(O8dDe3wHx!4P8`>en*?1hOTcnHDG$2tifj&q_Hq)RE6>}}oXJSMAH zW(7KC2mWhz;QWlh?z3)NosE7LCJT{A3HI6Pcg1k}t;?g|HSpvtco*Q!OJ~4Xs$}6gq|&a=O^1TA9T{DJi;xp({JT)TjrzAZ4$Q%PJhz*gv>P+*fO7UZkM?mq3lNI z0pw=1VNebi|e>66akB7M%8hm?2}P>QJ`xnt;CFy@2@ z1=l85%SIuLLUN;X7np*UlE%2^jm~xesy|WG^9GJ~)PDiXg9!`mQlt9zL>9Yk^8dx6(KVWST@81oFe~ zNTWa=?2e2P$nD*cCV~8AccfV$|D!uHRv>TbjHZ0FxS>CwPNBcB={>oMLHQ0cewOm=*IBe4LriPlzTKh!% z=#glvIOKLtxla@O?;`$I9JgMx=|5NezTs@`#PR3mK6G&xH>^rtt z?Qfhwd#!1-EjZlORgd(EBVAp0BTfFStLuHF$BBvX>oQDsUJ#>ye6z8R4K!`BuY>r1WOv^rSq)opDL& zQ;p#KI}Q04(%A#qTjP?(PV1rajQF|0Pwj!vkM~3)&)>QGrG5Kfo|cr?9DA$z zc2jH29mYH12eR{Ru=%6VN9;fLC2dv>wQ)(7sqyomFX{d;$|u5~Wq|3Jh4VS!ZUav2 zaW)9Ui$-|K@cCqT4;g+s8GdHcHluNgF{--Luzma6<68@SYk_Yq@T~>DwZOL)_|^j7 zTHsp?d~1PkE%5)F1^7L}$oB?uDJ70$GUa@y%qPf{-$PB5d4B)&5}D`s7W>OQE^Ecn zPo~NwyMXALj}9(B_qBEz+bIR(R;xJ1#%L+MI7dgGyl$u4zI0qB>G={aT|m*MLrJ?=Y;ylzLCUm(kI z*(%C$qw?Q!@O$%-!u!aEUm?@cGMy&V1v0IY>1vrypE`BCeF)w_&$N%s8ksf5K4Q3Q z#PA$fj(tdBWrf{a?$_|cM&x8FVZ>vza^b<(7!&(L zfi!#l)DZYyGHTdIV)cxtP{Vt|9pQRD4H&f=w2)Ws6pqqA`|W%Tu5}Y_h4A zDFCeVA;FZa#x6&ZVx@+edaKqJBD9XBvOZca*?Jc^nEGnDbn7^D3RAk4vs)h{%1gA| z5bI_zHuckT!>!j6&;D9&td(x6nliLpo;8gqFVk{fYhU6yK+6?a?!G=XUEEDl1SeKLvJ|688ud zKA9AM2Lz{^p0!Z36E+gf?}Z7Jgu|rLbHW0aggr#QT{tmWFw7rD(e$Y+~+8RL{6=)X#J$sKYgBjMUKT1x; ze9?O)43a{S(tBA`m7@MQ@p5GB2{)0`f09IQSekH@!swoq9F$ZfY^9QW6DZj0l|(W* z)sWsvBp(u;w7w{x%6U~WEJe9`pK&+b9!vN>Doxkwel=NL4uHQc!6T`9uNsH>ux}3N zLFA?k&(D1g8uB}YycLyiz}a^u33yq}O$PF7An0y%-`PZYKpoQu$OUN3Oq_lHNDX;K z9Yrm97l^kADO&fch8zHbzBtoqSW#bBlSyIYmhCsD|Anf)u4YKYO_x+F>Ooc5WFv~m zcK5@R@5JJeoe+EYML@96(J8r7TTBOIy@6)@(MYP}Y- zVFrB-WD44nhcn|W>Z|}zNtwSQb31_V1r%25 zKavnR>in23oi~^-SBnjecrXIx4CF=4AWNB@!q7d8IjdT4fGLGRDj}g9r!YtxfO{xI z1~~%YAkIr8>qj%lHIjF%Vy6&-K^Bk%QoT1;ZmBrCXQ+jFz>dc$46;#jFenV&!TL&r z{1~J^!r9Fr+$h~39Z?K2h<%y^8{H4Zx|{BDbsiaRAUBk#1clB^QYeGkuOtIwvqK8D ziD--rH-fm>uo}M_n?qqVU<2QDE5~#*7iKkEe6W<+LVaFz{HqY^qT>%hzaES@QJ<0h zn!oijM>0mgz7E7!;8`CL=5RD>Mv|nW>&c46bYI>>T_eXs9#;Nu3ht-9{P-7JkD{!XIrs|JyAMdQ?5zSj{H>SBgnzu{wo@>nrhOmuTk@|LotR;(vl%wHoWQfWR?)*fKxj zr9vA#H4Q3Mu~t9?(!zx*hzLwnVo6pX^*G6&FXii>QW_%oVIEUs5;%6|tHVj9(Ktuo z9B7q98_`kF31BfSDEp}NnJjgXWXRuO>Kd#wT(2`6q-Ig(dN8ZQc?sEdsG34TY;d{} zCrunzsn+GF{R?D&gmd6ylGhJ4xvGo$o@FidG^*cJRSD>QX4g4MPXUq5dw}kqxZy#%1FGjq-#MS(O4185Wxy zrNCws(vL$?`r)KQEI??sk_(d2H07#oGTcw0U<}!-%|Z4WdqxzxNMmK3k1}_psYcRi z>_CwlOhserfgejfA{7nTEE=GU&WBqJ3)59vi5f{mkQo+^p}trfr#N|q8vxdZo_yGZkD{p4&T zuNaeN!4w{xVzhb+z%Ox5pe4bufr>I1=LA|BYzA->&WW@{Fl@;aBi(|_6{Q&GfK?Fq z2?v_;1f;7!R!uIFu?a=%L30z%jO&qk7{JePDg(&Ay`@Uph5_}bs`a~6%L2lqAlgs0 zz5?BYPDQy3=a6HlIiVMd?-~T*I2C0Oi@qNbx&_tICDh@{pjgTKR&=vp2sF)A%Ait- zr#bEgiKp4E7{i}3s796&v!gn*f&MUNH0d=#@OT;!`NL+pnWPI^ey>W5Gp3_#1j5pZ zGouKZR{`v$%u-~=f!c*Lmsr%RsD@E+Jk_Jp2T*bkPEpT#C3dYK;~}Bb7>$91xHVj4c%$C&G})Bg0rvP9Ri@M2YGes+R-JP6gf)YEoKwHp7VC z2(fxOiS3i6PEHV3fZ~G_W~7pF^5T9pC4qG5YYLNWF#m1}td<_GjUf(`m=q#fE{XcZ ztMkpoq5q|-E45I4dWwk{m&7kJEfnp~Fe$E7NqlKMoI{_dyKE$o2yMO2d~>LVUB^mJ z@e83pcFt0jfq@OUM*&d?yYFwng=XBADNxNxuq#!-gP4TWx&jR&J7_wCac|8#>hO5j!zCrd z%YzfTIc9_uFZ@sRIZ}j%&^$G=8xBOHx;Ii7aCEo~ZXK@NLScg0Pqt1l$IupDMbmwJ z7Hr>5!wKX|>EMY1h61^y02`S6FezRj(95$F3ghqPC23s}LsWMRJcVs*-Eq(dF~1TW z)}UMpd#UP|N$BY~fTlcMUu4(S`?DKXW>-|M_Se=b9Xr}LdgQQ%%8Hfc{$VxMwM}cY$7Wa8F0W~-s8j^0%w#XC_BVFJK!s@g6`=sW z;#gf?TiMu{g{2TSrur)?DyslvEc36cuOu`&C3L99of`$C7$|gbU8AqEp`ixfj?~Dg ztd?NVX`3FgDN^GK4jO*qvZm@9|FG)XNw9#TeX>$3QB100HSpTX__(T?OsT1j($Y+6#%lrejZsai+4zB?nvzDDRO7lT5cM|RbMyPAIKyLVFH`@SrtA{> z?OkHZo@t7kY4ViNZ~x7d^~~I0GMSAjswvxStW!<>H%MyK$((7*tupm5F-<8EbvB!F zQ4{zQQ(+ZhfREcszlC5|1x1pKA1N~-KihcM%|a$5WNsh|)Wk3GBAJqO14um}-AwxA zf>f{vGvdlbmWd@Mt73>Tn2(r}MT$Wq#$c&3B~faa)Jqo6!&gAA*H?o082o zQ|xa{$;NelQ|ubFHy5ZRQ|vVWuZC$;Q`3Mj`ax_=$jU{jv0);?TLJkAO0<*!Y@8_w z7@3eo&}PDIuvD2XC6AgdD~4qcGhJrRg3HW%$D0jqgxEY)ln)XQwy;0Lz}f}4iC9LSQHX3N?E>?v|Y$ar09Pa;34g)dXE4P zS>$3);>KS*z@s{etHVhlm86qIfOq#&6?#2}8X^@#k|7h?&qTNHhI9f+QU6$Y@8+)1 z9NrVN$V`XKmTt%^fh=jK5%hOATQHp%_b4=4{_bWPIrk_VWS1j?-_qP=+^ZO_RxQ2E zhT*-cFhr(?S~3)@+EqM*1XUkQYuC`6(#PObC+6nnPR|=Rg9h(ZQ<6Dtycoul%%C)1 zO^6AT#z_$TBo(H{+|8y0v+NA2s!zXo{O`>O0ib z9~zq%r{b}#AAm8gB((`sRGRUpH$qHb%oAoc23j39s4)iPLpQ3xQ2s3gO?q+0`){nG zSqn9f8q~#@uK^A>rJ0QO{;<#ybouc>nFjlI~?Q|DP#CLpK}L z?_m9r>bH~DEA8ei^P*-nSu9F^atWP|v^*&>IgRml7-oaXX;$F?v>x-Z zMK}_s?`1ZosfeCyH<$)BlPP=oflD*>egv6j*pwEHIDmvV=a|%NJI&G+8^AoH#BO#$ zAQVb5nXWc3BF)U0@X4dl=uVTx0-xMv#@fOBr$Z4*n#IkZAR zT4GAfHCZQ^7p00eC8B8)P`W4$fux!ewYD06eUplH*?zPp(Yyt5^*Hh-EYLt=GPeoY z3FhlerhXE&LQ}{1vYLf@-<@ev%d%!>Wg!^rH=E+G+>EBc1_?9JxU8%y>Pss?W4uH_ z?`sg=h>TH<*Vrj}mVW%=ht`7a=yE13X*8SOr5k@0w3$u>P1FP8Da0*JP}f7+rl$1; zc(0~;oZ0w81Dazs&c!+_&gk-sK&8%&&PIF_%tJ%%c}%wFPD7S|B9?0jDbU;xwO9K| zTq3C>wYlFEC#+(~PZcIizTKoQfs<*8L(4GYJ&9Vf6{7BE)lKG728U8%6>QMI3IfXP zfWCVMw8oUJB&&|boRmYrY7mtRsF(jf^P!pWMCtdE=0mK#QS>;4LS?mst8uSEJ&U@x z{!`eIC5-zph$NaVSDX5pRm)6MB9KOm^?gN3D`lglmnrQaXs$M04&(OCGNs*VvQ8AC ziaMstyXF45Ws68FU7nU>d4EsY<>=3S(Gl;2)}r24(`Cl%5Vq7U(jGM>G$PN+Px<@m{SAt5`O5O@TK+cxQ9k|Oh<`#rl^R#pHTda~ zM|Ev&WrKLPO=(;BKa_pgD*T6o5lH+^wUxOmDxqTa za%9UJmaojk_3^OLBkjXh*oV!{u@9?S(@9ICOv6 zk7_`@YbzVXg)>Njm^NcpzOTNfNn^OCq1s=mdC6B$m|tAH$Tw~NoT`mYl{{GW+y zWm88ezEyR&tx!|m=okMZg4C~T@+U!KQxo#N6WyP?@@-b`c$KZyOW-E$2-)cYomk#z^Seqchr&Lup zaO0amj!^I`Fb3U7!G8e3f83y`(*J`8G9!Fz>KZDjIklB*@k@+HkCe?5eNpQv>g=27JT4I$0PN)?us zFTb{_UJC*l9^yZOh`uh|p*c!uSyNf%SI}RYYW#GgMjo9G4agm+rK&QY!2>#~jKRmn zvk|({s4g|b7#eYisXkp-+rZ=lYHv92~Mp>flLj`@V4(um{WLx!Jo<^Bc7qPJti~1m8q)C zWAMcgow4l=nK>4sWAI#v&eWz#`^D*YoX6k*iGtkNwxKdJJVeK!J49z~n=LbiA!J+| zXO@SM@ojZ7f&t}0LAAu1i6GF6o*Zth7`q}2-j_T+@f?CcSl z2IWr?0;7^?k;SBYWEG3DW!p`6#pF2K7;`|^x`4rtdk}||)F4$kB5D5e4QNqE`aKlP zr9Fc=iq)dkEb3V^iYa^6gq1pOh^#A+TAM<@1|?4F%iSd^nPy=oO_No~!Z!;GGp4^R zLBC>fd=KJ~bPZA!r=-ccD6LlGm|aU79n4`qgBv7Do0vFvM~G0X5&6p;*XV@B3^EUG zy5U@iV{s%eE#H&lyl5Qfwe{pUFOs7QL|>^HGeJjYkU2!3tD;xFK=YzWCLBv&CACnM zg$&k8R1A9XO>LaJB}B+zNKGP)loTrw|9VMgy*0FfhmKffOM!@EE!+Kf+W;;9uuQR5 zV(qvqEjr{A_m*K)$OiD_uOnrxk+bI zz#uDPP#P76Sq&pC`B;JbLUkErMW`;rtdywRT?AH!=!tR21B39oH;%GALu(7-o|gl(B7*t@=Cj27{>ZfR-p_ zF?hPJmN0l$zV(Ndj8(qimn&1O#~Eyw z?*hU&4DPvjzT3TccFd5_+yjJlmDDOvUzrh1V9;Bz!y;egLymtah&b1}GC?_7lprt3Xv zNsa_7byOLH?_wLB#=eBXM!j<_2}tmFI;xDpe7$qcWAF|6Pbr~lrvx)Xor}TyHsCzx&;Xg~)%CWIM_2H~8Nq{X)k5H>q<$ zkN%tV`ESC=LScju9k^we2%{~5cLK3(9LTfv7%yRPm%hB1$KZT@xGSoa;E#1w8H1PU z!(B0hkI)7>9I8^ZLxP<;s*J%VeYh)N(5jDZMGgrT=%_LV-`1BGg$yp!hr6O1CHSO{ zDr0cCKHQZsxIBL6-!F zhvJXH$MqSwgu%&ruq~J`!P|6H8G~th{LN!GwFT4sFbm=}Woh8AWbW|CGU+E)J34?d&ZZCaMf(La}8H44z z+vhR(u|5)&TBN(jhuqHKbNWbB%wWFm_R=L1Y|&9=3?}MVH3bYlq%XWmw@dJEArymr zDT8Yt28YVvFe}$7bm5^HHuNif8bVwI;`lfb8lln{9;gRMA%mOs04ZiLL63$d10`6X zqskb3OCKucF<7q$$dZ5rpVCof3{KDkq?p0&`cSdtumlrA0m5Lb9v}q_(pxNaU>QD1 zg4gP(G6v74FgAq7a8dlJ52*2A!ek$Y6MmPFBF+c75cS$KX^w6pFqh z!P|6HA%n4cbQCkVS&xnd4@>Znjw)ktkscid44%_Rjs=M_Dn^H*gTbBp$Wh4P)p~R+ zsFL7MbW|CGee~!kVen`A)Ux0?34W}j${4&}kB)f^#_OT5z$wAGI;xDp*YuI2m_eT& z9Sc@V@cs~r!3lbF6hw8tiu=I07p#?~%T!esG58&cGAiqCYWtqdaB5U6lcFIf>qzls zYcL08UXKY&x{_qeI|pXvOtbWprcuQ2QrVi@^j6Jh&?xT|<5Gt~lSF9`3OJV;B8=c3 zmSsV$x}ahPWAyq97-ZJk!z#|j>V(A%hGZ`Y6DB}a*x(i^kA-2_W$=fx$O=<79#ig$ z$!KFq@w%iQb3xBrGC!Amo|Y-y=4Uvl<6LbF@6~Z5+8BOK$K|v!{I-r8*~ah(I&M@O z!>4rI=r)GW>$ov(40Ge6-R4&nb`V?CtbBo&LY1~2W;Nd>d2<@0G+eq4Yn)OaV3<>S)WtBT^r(wr_P9aGX=7V)O8gk+l=v~sDe+^N!-e>< zojE0b40B5S80M7tG0c%h{MbjF5ppC~Yp}++m$?K7;S*s8Zzu zM^F8VSwCj1&4iqLMdw+}U`UMb0#cNoV&+8?Gp~)s?A680W01v=KG8Q6(ggW|G&Hlv zMK^;(b)E}`ORz44S}VaHhEPh>Bf1pbZ2k56J_ZNqsA9VW*XSr83%)0WQlcD*vbaen zE906RD|p@-r6N#W(kOAEx(qT~thE?qb{368b+n9LERE|TV7%$TznO4cPUZ!hhdNF>H z^&{zd-|n_ST1mT1dDCtrJ@3%uls94W#>z-~-fze$Zz<$$f|2y!Aa6t;Xjgj@8gZ+M zzuO#MYQ*(op1juVj*n6JyUyM5CWXI`+#PRL)|hAbB+Q!!7Fyc~VeN=pc!r#3PuVhpb>3bMG4x^H!JP{RdQ!Lp%$YHf)g}F)5)lR6}uZ6?Yg8p zLgtK$yx|d1YE=ZdNDoJ^lV4z>}T@5q$0!^gZJz2z<2m?v;G_lOuem z=M9PHZ+VM#RlUV^@7JP#1~p7A^c zczlhiNB^22=zI5w+vyS?8RtuYm$w7MG{iRnfwyG)XU^^YfNXyt2(=MQrJr^F{?oZf|jqU^i?#iT7_2+ePKBty|dVjRDad2+k2ehuis_WL;Wn0 z-QyL?tejD<(I}W!=$@VL%b(-HTa{3;u@0~D)mGHtJw(rpEY-idzNqRv}r~8#lB+q6uibM-e=9rn?7sCl&QWEStGJW;YGUQ*}jnZ zz<`WbOs^U$zRHSne>uH^T3gMp{Y7~l*XPqdjO42-udeCNU3J5IjLC;!2u%<;RS zoUL9_iI3N6uLX9m4wiWTvpdcg78Wp=WTL%IDqer}Eo*F)Q6n16(bBECvYL3y(C1se zHuSz^cWFviitn)Ko-@_nbw^ z>dJ;jyg}M6<3m|PWlcE|N~j($HfD(iW%=oK%`D-QtcE(_p{&Z4GA376pf2aM8d`8_ zH5jH^BmxYCI_0aXmqUd*Fvd@okOq?}S?DdR&;vkJxvXggs+ZToGn}oit)lu`(XwR? zm8&_2FMd@r4BIe>H)t7@oWe$ge+;CR2Tk1=PQ=0MUQV47&q?G{ds^;&ivRJ!^?7~F zDL=-MPu`S>XzK&Z(U$;fT~rC1Irf zxc#-V{uD{a|JQ}n@cQ&LFVcQ%fg_vnvsb=u;FQ-rlD%jL!<07S46m2Eg!&;+yoyxuFw>rSubLhazZcAbGQY%)To zTz^pnUYbMbOhupIWL!AuFY>fpB;QC{BM^}|s(D1#|06ER!jDK=+Xd?Xs8Fl*CL2aF ziL5U^lo>8S!q>?s&NUGOP-Oi~DL=BE?^I}viaBs1Cto)9=>mAC?2N9a*{t=eXnXpT@Tc5y0T(>#ZVD?vG#|sXw_l RTKymVRI5KbqC!Mg`M-0;l2rfz diff --git a/Crypto/Hash/_SHA384.abi3.so b/Crypto/Hash/_SHA384.abi3.so deleted file mode 100644 index 7c9a175f87001fa0d4f904bd0f9d2dea0cb70677..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 50520 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 diff --git a/Crypto/Hash/_SHA512.abi3.so b/Crypto/Hash/_SHA512.abi3.so deleted file mode 100644 index d848ff8ed64c1ee620b5e528c8fbc82130fbe3e7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 50624 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 diff --git a/Crypto/Hash/__init__.py b/Crypto/Hash/__init__.py deleted file mode 100644 index 719cd8d..0000000 --- a/Crypto/Hash/__init__.py +++ /dev/null @@ -1,22 +0,0 @@ -# -*- coding: utf-8 -*- -# -# =================================================================== -# The contents of this file are dedicated to the public domain. To -# the extent that dedication to the public domain is not available, -# everyone is granted a worldwide, perpetual, royalty-free, -# non-exclusive license to exercise all rights associated with the -# contents of this file for any purpose whatsoever. -# No rights are reserved. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS -# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN -# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# =================================================================== - -__all__ = ['HMAC', 'MD2', 'MD4', 'MD5', 'RIPEMD160', 'SHA1', - 'SHA224', 'SHA256', 'SHA384', 'SHA512', 'CMAC', 'Poly1305'] diff --git a/Crypto/Hash/__init__.pyi b/Crypto/Hash/__init__.pyi deleted file mode 100644 index e69de29..0000000 diff --git a/Crypto/Hash/__pycache__/BLAKE2s.cpython-36.pyc b/Crypto/Hash/__pycache__/BLAKE2s.cpython-36.pyc deleted file mode 100644 index e74582db701bce769b837dffc2561f042a979cc8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 7236 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 diff --git a/Crypto/Hash/__pycache__/HMAC.cpython-36.pyc b/Crypto/Hash/__pycache__/HMAC.cpython-36.pyc deleted file mode 100644 index 8ef9b0455e2ea77e02964a348d37e701885b601b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5361 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

txQB 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 T*1Lw%5&Q8OzS^;Rjx^wpZ$ z<>HWOWRdE$M4hCJ8B;wZ*FK7A5uK&Qi^B1ZS2T3NUv!M$7XAtl4xkI zYg?1#2+bqa~*ZHoif@@M03kK zIxr*1_%Qw6s!BpPMpJtLMJrO*+9n?+Ywc(}BPZ3aZE9TEqTDsj#i=FTSWeruFBhgD+B+IsTM~(! zK$1mMKCEgznTf z%bZfVvQ-SrpUSW_Y2%<$rtW5$jzy?pdDlu&uWeZ=T^-5BmK8?dW-VXd-msdfrbcNb zu1NmO&D_57-|2(keVb|&XuurOsn09?Ny0O>sn7d5#ABHuGUkWV0-KP($IJhZ zWB&904{-@3=|9a8=S%)aF@4@AB33|O`ww1%w-v&&AQ3``{Eh4LJ{EC<3V1n`iDxT)-tQtl zvlt3WkKFT=KJSYW^=&&7tN8B{Nf;Lyf8IYMu4M+4=r?U#uJm~wN*u20ugl+{^m#vy zcqVT^pg^`ilEEE9m^Nbn;C;Klon_`1YF`glftoafD8l%Gu z{5kR~me>+!3Qaw-i-e(hChtAyH(W|di&}PoNB@*^D|s~M6PVHZ`+M}SF&XkZb0HJ~ zT7Lxeb^P{PZ6%8_kJ1YDiQ}NpeBx)#O5&l;QZA`I0@%U%vH}*Xt-EURiau1j5*7#5RFL!n`^{=|g>d#UNDjEC_ D;!>$} diff --git a/Crypto/Protocol/KDF.py b/Crypto/Protocol/KDF.py deleted file mode 100644 index 1348265..0000000 --- a/Crypto/Protocol/KDF.py +++ /dev/null @@ -1,574 +0,0 @@ -# coding=utf-8 -# -# KDF.py : a collection of Key Derivation Functions -# -# Part of the Python Cryptography Toolkit -# -# =================================================================== -# The contents of this file are dedicated to the public domain. To -# the extent that dedication to the public domain is not available, -# everyone is granted a worldwide, perpetual, royalty-free, -# non-exclusive license to exercise all rights associated with the -# contents of this file for any purpose whatsoever. -# No rights are reserved. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS -# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN -# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# =================================================================== - -import re -import struct -from functools import reduce - -from Crypto.Util.py3compat import (tobytes, bord, _copy_bytes, iter_range, - tostr, bchr, bstr) - -from Crypto.Hash import SHA1, SHA256, HMAC, CMAC, BLAKE2s -from Crypto.Util.strxor import strxor -from Crypto.Random import get_random_bytes -from Crypto.Util.number import size as bit_size, long_to_bytes, bytes_to_long - -from Crypto.Util._raw_api import (load_pycryptodome_raw_lib, - create_string_buffer, - get_raw_buffer, c_size_t) - -_raw_salsa20_lib = load_pycryptodome_raw_lib("Crypto.Cipher._Salsa20", - """ - int Salsa20_8_core(const uint8_t *x, const uint8_t *y, - uint8_t *out); - """) - -_raw_scrypt_lib = load_pycryptodome_raw_lib("Crypto.Protocol._scrypt", - """ - typedef int (core_t)(const uint8_t [64], const uint8_t [64], uint8_t [64]); - int scryptROMix(const uint8_t *data_in, uint8_t *data_out, - size_t data_len, unsigned N, core_t *core); - """) - - -def PBKDF1(password, salt, dkLen, count=1000, hashAlgo=None): - """Derive one key from a password (or passphrase). - - This function performs key derivation according to an old version of - the PKCS#5 standard (v1.5) or `RFC2898 - `_. - - Args: - password (string): - The secret password to generate the key from. - salt (byte string): - An 8 byte string to use for better protection from dictionary attacks. - This value does not need to be kept secret, but it should be randomly - chosen for each derivation. - dkLen (integer): - The length of the desired key. The default is 16 bytes, suitable for - instance for :mod:`Crypto.Cipher.AES`. - count (integer): - The number of iterations to carry out. The recommendation is 1000 or - more. - hashAlgo (module): - The hash algorithm to use, as a module or an object from the :mod:`Crypto.Hash` package. - The digest length must be no shorter than ``dkLen``. - The default algorithm is :mod:`Crypto.Hash.SHA1`. - - Return: - A byte string of length ``dkLen`` that can be used as key. - """ - - if not hashAlgo: - hashAlgo = SHA1 - password = tobytes(password) - pHash = hashAlgo.new(password+salt) - digest = pHash.digest_size - if dkLen > digest: - raise TypeError("Selected hash algorithm has a too short digest (%d bytes)." % digest) - if len(salt) != 8: - raise ValueError("Salt is not 8 bytes long (%d bytes instead)." % len(salt)) - for i in iter_range(count-1): - pHash = pHash.new(pHash.digest()) - return pHash.digest()[:dkLen] - - -def PBKDF2(password, salt, dkLen=16, count=1000, prf=None, hmac_hash_module=None): - """Derive one or more keys from a password (or passphrase). - - This function performs key derivation according to the PKCS#5 standard (v2.0). - - Args: - password (string or byte string): - The secret password to generate the key from. - salt (string or byte string): - A (byte) string to use for better protection from dictionary attacks. - This value does not need to be kept secret, but it should be randomly - chosen for each derivation. It is recommended to use at least 16 bytes. - dkLen (integer): - The cumulative length of the keys to produce. - - Due to a flaw in the PBKDF2 design, you should not request more bytes - than the ``prf`` can output. For instance, ``dkLen`` should not exceed - 20 bytes in combination with ``HMAC-SHA1``. - count (integer): - The number of iterations to carry out. The higher the value, the slower - and the more secure the function becomes. - - You should find the maximum number of iterations that keeps the - key derivation still acceptable on the slowest hardware you must support. - - Although the default value is 1000, **it is recommended to use at least - 1000000 (1 million) iterations**. - prf (callable): - A pseudorandom function. It must be a function that returns a - pseudorandom byte string from two parameters: a secret and a salt. - The slower the algorithm, the more secure the derivation function. - If not specified, **HMAC-SHA1** is used. - hmac_hash_module (module): - A module from ``Crypto.Hash`` implementing a Merkle-Damgard cryptographic - hash, which PBKDF2 must use in combination with HMAC. - This parameter is mutually exclusive with ``prf``. - - Return: - A byte string of length ``dkLen`` that can be used as key material. - If you want multiple keys, just break up this string into segments of the desired length. - """ - - password = tobytes(password) - salt = tobytes(salt) - - if prf and hmac_hash_module: - raise ValueError("'prf' and 'hmac_hash_module' are mutually exlusive") - - if prf is None and hmac_hash_module is None: - hmac_hash_module = SHA1 - - if prf or not hasattr(hmac_hash_module, "_pbkdf2_hmac_assist"): - # Generic (and slow) implementation - - if prf is None: - prf = lambda p,s: HMAC.new(p, s, hmac_hash_module).digest() - - def link(s): - s[0], s[1] = s[1], prf(password, s[1]) - return s[0] - - key = b'' - i = 1 - while len(key) < dkLen: - s = [ prf(password, salt + struct.pack(">I", i)) ] * 2 - key += reduce(strxor, (link(s) for j in range(count)) ) - i += 1 - - else: - # Optimized implementation - key = b'' - i = 1 - while len(key)I", i)).digest() - key += base._pbkdf2_hmac_assist(first_digest, count) - i += 1 - - return key[:dkLen] - - -class _S2V(object): - """String-to-vector PRF as defined in `RFC5297`_. - - This class implements a pseudorandom function family - based on CMAC that takes as input a vector of strings. - - .. _RFC5297: http://tools.ietf.org/html/rfc5297 - """ - - def __init__(self, key, ciphermod, cipher_params=None): - """Initialize the S2V PRF. - - :Parameters: - key : byte string - A secret that can be used as key for CMACs - based on ciphers from ``ciphermod``. - ciphermod : module - A block cipher module from `Crypto.Cipher`. - cipher_params : dictionary - A set of extra parameters to use to create a cipher instance. - """ - - self._key = _copy_bytes(None, None, key) - self._ciphermod = ciphermod - self._last_string = self._cache = b'\x00' * ciphermod.block_size - - # Max number of update() call we can process - self._n_updates = ciphermod.block_size * 8 - 1 - - if cipher_params is None: - self._cipher_params = {} - else: - self._cipher_params = dict(cipher_params) - - @staticmethod - def new(key, ciphermod): - """Create a new S2V PRF. - - :Parameters: - key : byte string - A secret that can be used as key for CMACs - based on ciphers from ``ciphermod``. - ciphermod : module - A block cipher module from `Crypto.Cipher`. - """ - return _S2V(key, ciphermod) - - def _double(self, bs): - doubled = bytes_to_long(bs)<<1 - if bord(bs[0]) & 0x80: - doubled ^= 0x87 - return long_to_bytes(doubled, len(bs))[-len(bs):] - - def update(self, item): - """Pass the next component of the vector. - - The maximum number of components you can pass is equal to the block - length of the cipher (in bits) minus 1. - - :Parameters: - item : byte string - The next component of the vector. - :Raise TypeError: when the limit on the number of components has been reached. - """ - - if self._n_updates == 0: - raise TypeError("Too many components passed to S2V") - self._n_updates -= 1 - - mac = CMAC.new(self._key, - msg=self._last_string, - ciphermod=self._ciphermod, - cipher_params=self._cipher_params) - self._cache = strxor(self._double(self._cache), mac.digest()) - self._last_string = _copy_bytes(None, None, item) - - def derive(self): - """"Derive a secret from the vector of components. - - :Return: a byte string, as long as the block length of the cipher. - """ - - if len(self._last_string) >= 16: - # xorend - final = self._last_string[:-16] + strxor(self._last_string[-16:], self._cache) - else: - # zero-pad & xor - padded = (self._last_string + b'\x80' + b'\x00' * 15)[:16] - final = strxor(padded, self._double(self._cache)) - mac = CMAC.new(self._key, - msg=final, - ciphermod=self._ciphermod, - cipher_params=self._cipher_params) - return mac.digest() - - -def HKDF(master, key_len, salt, hashmod, num_keys=1, context=None): - """Derive one or more keys from a master secret using - the HMAC-based KDF defined in RFC5869_. - - Args: - master (byte string): - The unguessable value used by the KDF to generate the other keys. - It must be a high-entropy secret, though not necessarily uniform. - It must not be a password. - salt (byte string): - A non-secret, reusable value that strengthens the randomness - extraction step. - Ideally, it is as long as the digest size of the chosen hash. - If empty, a string of zeroes in used. - key_len (integer): - The length in bytes of every derived key. - hashmod (module): - A cryptographic hash algorithm from :mod:`Crypto.Hash`. - :mod:`Crypto.Hash.SHA512` is a good choice. - num_keys (integer): - The number of keys to derive. Every key is :data:`key_len` bytes long. - The maximum cumulative length of all keys is - 255 times the digest size. - context (byte string): - Optional identifier describing what the keys are used for. - - Return: - A byte string or a tuple of byte strings. - - .. _RFC5869: http://tools.ietf.org/html/rfc5869 - """ - - output_len = key_len * num_keys - if output_len > (255 * hashmod.digest_size): - raise ValueError("Too much secret data to derive") - if not salt: - salt = b'\x00' * hashmod.digest_size - if context is None: - context = b"" - - # Step 1: extract - hmac = HMAC.new(salt, master, digestmod=hashmod) - prk = hmac.digest() - - # Step 2: expand - t = [ b"" ] - n = 1 - tlen = 0 - while tlen < output_len: - hmac = HMAC.new(prk, t[-1] + context + struct.pack('B', n), digestmod=hashmod) - t.append(hmac.digest()) - tlen += hashmod.digest_size - n += 1 - derived_output = b"".join(t) - if num_keys == 1: - return derived_output[:key_len] - kol = [derived_output[idx:idx + key_len] - for idx in iter_range(0, output_len, key_len)] - return list(kol[:num_keys]) - - - -def scrypt(password, salt, key_len, N, r, p, num_keys=1): - """Derive one or more keys from a passphrase. - - Args: - password (string): - The secret pass phrase to generate the keys from. - salt (string): - A string to use for better protection from dictionary attacks. - This value does not need to be kept secret, - but it should be randomly chosen for each derivation. - It is recommended to be at least 16 bytes long. - key_len (integer): - The length in bytes of every derived key. - N (integer): - CPU/Memory cost parameter. It must be a power of 2 and less - than :math:`2^{32}`. - r (integer): - Block size parameter. - p (integer): - Parallelization parameter. - It must be no greater than :math:`(2^{32}-1)/(4r)`. - num_keys (integer): - The number of keys to derive. Every key is :data:`key_len` bytes long. - By default, only 1 key is generated. - The maximum cumulative length of all keys is :math:`(2^{32}-1)*32` - (that is, 128TB). - - A good choice of parameters *(N, r , p)* was suggested - by Colin Percival in his `presentation in 2009`__: - - - *( 2¹⁴, 8, 1 )* for interactive logins (≤100ms) - - *( 2²⁰, 8, 1 )* for file encryption (≤5s) - - Return: - A byte string or a tuple of byte strings. - - .. __: http://www.tarsnap.com/scrypt/scrypt-slides.pdf - """ - - if 2 ** (bit_size(N) - 1) != N: - raise ValueError("N must be a power of 2") - if N >= 2 ** 32: - raise ValueError("N is too big") - if p > ((2 ** 32 - 1) * 32) // (128 * r): - raise ValueError("p or r are too big") - - prf_hmac_sha256 = lambda p, s: HMAC.new(p, s, SHA256).digest() - - stage_1 = PBKDF2(password, salt, p * 128 * r, 1, prf=prf_hmac_sha256) - - scryptROMix = _raw_scrypt_lib.scryptROMix - core = _raw_salsa20_lib.Salsa20_8_core - - # Parallelize into p flows - data_out = [] - for flow in iter_range(p): - idx = flow * 128 * r - buffer_out = create_string_buffer(128 * r) - result = scryptROMix(stage_1[idx : idx + 128 * r], - buffer_out, - c_size_t(128 * r), - N, - core) - if result: - raise ValueError("Error %X while running scrypt" % result) - data_out += [ get_raw_buffer(buffer_out) ] - - dk = PBKDF2(password, - b"".join(data_out), - key_len * num_keys, 1, - prf=prf_hmac_sha256) - - if num_keys == 1: - return dk - - kol = [dk[idx:idx + key_len] - for idx in iter_range(0, key_len * num_keys, key_len)] - return kol - - -def _bcrypt_encode(data): - s = "./ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789" - - bits = [] - for c in data: - bits_c = bin(bord(c))[2:].zfill(8) - bits.append(bstr(bits_c)) - bits = b"".join(bits) - - bits6 = [ bits[idx:idx+6] for idx in range(0, len(bits), 6) ] - - result = [] - for g in bits6[:-1]: - idx = int(g, 2) - result.append(s[idx]) - - g = bits6[-1] - idx = int(g, 2) << (6 - len(g)) - result.append(s[idx]) - result = "".join(result) - - return tobytes(result) - - -def _bcrypt_decode(data): - s = "./ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789" - - bits = [] - for c in tostr(data): - idx = s.find(c) - bits6 = bin(idx)[2:].zfill(6) - bits.append(bits6) - bits = "".join(bits) - - modulo4 = len(data) % 4 - if modulo4 == 1: - raise ValueError("Incorrect length") - elif modulo4 == 2: - bits = bits[:-4] - elif modulo4 == 3: - bits = bits[:-2] - - bits8 = [ bits[idx:idx+8] for idx in range(0, len(bits), 8) ] - - result = [] - for g in bits8: - result.append(bchr(int(g, 2))) - result = b"".join(result) - - return result - - -def _bcrypt_hash(password, cost, salt, constant, invert): - from Crypto.Cipher import _EKSBlowfish - - if len(password) > 72: - raise ValueError("The password is too long. It must be 72 bytes at most.") - - if not (4 <= cost <= 31): - raise ValueError("bcrypt cost factor must be in the range 4..31") - - cipher = _EKSBlowfish.new(password, _EKSBlowfish.MODE_ECB, salt, cost, invert) - ctext = constant - for _ in range(64): - ctext = cipher.encrypt(ctext) - return ctext - - -def bcrypt(password, cost, salt=None): - """Hash a password into a key, using the OpenBSD bcrypt protocol. - - Args: - password (byte string or string): - The secret password or pass phrase. - It must be at most 72 bytes long. - It must not contain the zero byte. - Unicode strings will be encoded as UTF-8. - cost (integer): - The exponential factor that makes it slower to compute the hash. - It must be in the range 4 to 31. - A value of at least 12 is recommended. - salt (byte string): - Optional. Random byte string to thwarts dictionary and rainbow table - attacks. It must be 16 bytes long. - If not passed, a random value is generated. - - Return (byte string): - The bcrypt hash - - Raises: - ValueError: if password is longer than 72 bytes or if it contains the zero byte - - """ - - password = tobytes(password, "utf-8") - - if password.find(bchr(0)[0]) != -1: - raise ValueError("The password contains the zero byte") - - if len(password) < 72: - password += b"\x00" - - if salt is None: - salt = get_random_bytes(16) - if len(salt) != 16: - raise ValueError("bcrypt salt must be 16 bytes long") - - ctext = _bcrypt_hash(password, cost, salt, b"OrpheanBeholderScryDoubt", True) - - cost_enc = b"$" + bstr(str(cost).zfill(2)) - salt_enc = b"$" + _bcrypt_encode(salt) - hash_enc = _bcrypt_encode(ctext[:-1]) # only use 23 bytes, not 24 - return b"$2a" + cost_enc + salt_enc + hash_enc - - -def bcrypt_check(password, bcrypt_hash): - """Verify if the provided password matches the given bcrypt hash. - - Args: - password (byte string or string): - The secret password or pass phrase to test. - It must be at most 72 bytes long. - It must not contain the zero byte. - Unicode strings will be encoded as UTF-8. - bcrypt_hash (byte string, bytearray): - The reference bcrypt hash the password needs to be checked against. - - Raises: - ValueError: if the password does not match - """ - - bcrypt_hash = tobytes(bcrypt_hash) - - if len(bcrypt_hash) != 60: - raise ValueError("Incorrect length of the bcrypt hash: %d bytes instead of 60" % len(bcrypt_hash)) - - if bcrypt_hash[:4] != b'$2a$': - raise ValueError("Unsupported prefix") - - p = re.compile(br'\$2a\$([0-9][0-9])\$([A-Za-z0-9./]{22,22})([A-Za-z0-9./]{31,31})') - r = p.match(bcrypt_hash) - if not r: - raise ValueError("Incorrect bcrypt hash format") - - cost = int(r.group(1)) - if not (4 <= cost <= 31): - raise ValueError("Incorrect cost") - - salt = _bcrypt_decode(r.group(2)) - - bcrypt_hash2 = bcrypt(password, cost, salt) - - secret = get_random_bytes(16) - - mac1 = BLAKE2s.new(digest_bits=160, key=secret, data=bcrypt_hash).digest() - mac2 = BLAKE2s.new(digest_bits=160, key=secret, data=bcrypt_hash2).digest() - if mac1 != mac2: - raise ValueError("Incorrect bcrypt hash") diff --git a/Crypto/Protocol/KDF.pyi b/Crypto/Protocol/KDF.pyi deleted file mode 100644 index fb004bf..0000000 --- a/Crypto/Protocol/KDF.pyi +++ /dev/null @@ -1,24 +0,0 @@ -from types import ModuleType -from typing import Optional, Callable, Tuple, Union, Dict, Any - -RNG = Callable[[int], bytes] - -def PBKDF1(password: str, salt: bytes, dkLen: int, count: Optional[int]=1000, hashAlgo: Optional[ModuleType]=None) -> bytes: ... -def PBKDF2(password: str, salt: bytes, dkLen: Optional[int]=16, count: Optional[int]=1000, prf: Optional[RNG]=None, hmac_hash_module: Optional[ModuleType]=None) -> bytes: ... - -class _S2V(object): - def __init__(self, key: bytes, ciphermod: ModuleType, cipher_params: Optional[Dict[Any, Any]]=None) -> None: ... - - @staticmethod - def new(key: bytes, ciphermod: ModuleType) -> None: ... - def update(self, item: bytes) -> None: ... - def derive(self) -> bytes: ... - -def HKDF(master: bytes, key_len: int, salt: bytes, hashmod: ModuleType, num_keys: Optional[int]=1, context: Optional[bytes]=None) -> Union[bytes, Tuple[bytes, ...]]: ... - -def scrypt(password: str, salt: str, key_len: int, N: int, r: int, p: int, num_keys: Optional[int]=1) -> Union[bytes, Tuple[bytes, ...]]: ... - -def _bcrypt_decode(data: bytes) -> bytes: ... -def _bcrypt_hash(password:bytes , cost: int, salt: bytes, constant:bytes, invert:bool) -> bytes: ... -def bcrypt(password: Union[bytes, str], cost: int, salt: Optional[bytes]=None) -> bytes: ... -def bcrypt_check(password: Union[bytes, str], bcrypt_hash: Union[bytes, bytearray, str]) -> None: ... diff --git a/Crypto/Protocol/SecretSharing.py b/Crypto/Protocol/SecretSharing.py deleted file mode 100644 index a757e7c..0000000 --- a/Crypto/Protocol/SecretSharing.py +++ /dev/null @@ -1,278 +0,0 @@ -# -# SecretSharing.py : distribute a secret amongst a group of participants -# -# =================================================================== -# -# Copyright (c) 2014, Legrandin -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# =================================================================== - -from Crypto.Util.py3compat import is_native_int -from Crypto.Util import number -from Crypto.Util.number import long_to_bytes, bytes_to_long -from Crypto.Random import get_random_bytes as rng - - -def _mult_gf2(f1, f2): - """Multiply two polynomials in GF(2)""" - - # Ensure f2 is the smallest - if f2 > f1: - f1, f2 = f2, f1 - z = 0 - while f2: - if f2 & 1: - z ^= f1 - f1 <<= 1 - f2 >>= 1 - return z - - -def _div_gf2(a, b): - """ - Compute division of polynomials over GF(2). - Given a and b, it finds two polynomials q and r such that: - - a = b*q + r with deg(r)= d: - s = 1 << (deg(r) - d) - q ^= s - r ^= _mult_gf2(b, s) - return (q, r) - - -class _Element(object): - """Element of GF(2^128) field""" - - # The irreducible polynomial defining this field is 1+x+x^2+x^7+x^128 - irr_poly = 1 + 2 + 4 + 128 + 2 ** 128 - - def __init__(self, encoded_value): - """Initialize the element to a certain value. - - The value passed as parameter is internally encoded as - a 128-bit integer, where each bit represents a polynomial - coefficient. The LSB is the constant coefficient. - """ - - if is_native_int(encoded_value): - self._value = encoded_value - elif len(encoded_value) == 16: - self._value = bytes_to_long(encoded_value) - else: - raise ValueError("The encoded value must be an integer or a 16 byte string") - - def __eq__(self, other): - return self._value == other._value - - def __int__(self): - """Return the field element, encoded as a 128-bit integer.""" - return self._value - - def encode(self): - """Return the field element, encoded as a 16 byte string.""" - return long_to_bytes(self._value, 16) - - def __mul__(self, factor): - - f1 = self._value - f2 = factor._value - - # Make sure that f2 is the smallest, to speed up the loop - if f2 > f1: - f1, f2 = f2, f1 - - if self.irr_poly in (f1, f2): - return _Element(0) - - mask1 = 2 ** 128 - v, z = f1, 0 - while f2: - # if f2 ^ 1: z ^= v - mask2 = int(bin(f2 & 1)[2:] * 128, base=2) - z = (mask2 & (z ^ v)) | ((mask1 - mask2 - 1) & z) - v <<= 1 - # if v & mask1: v ^= self.irr_poly - mask3 = int(bin((v >> 128) & 1)[2:] * 128, base=2) - v = (mask3 & (v ^ self.irr_poly)) | ((mask1 - mask3 - 1) & v) - f2 >>= 1 - return _Element(z) - - def __add__(self, term): - return _Element(self._value ^ term._value) - - def inverse(self): - """Return the inverse of this element in GF(2^128).""" - - # We use the Extended GCD algorithm - # http://en.wikipedia.org/wiki/Polynomial_greatest_common_divisor - - if self._value == 0: - raise ValueError("Inversion of zero") - - r0, r1 = self._value, self.irr_poly - s0, s1 = 1, 0 - while r1 > 0: - q = _div_gf2(r0, r1)[0] - r0, r1 = r1, r0 ^ _mult_gf2(q, r1) - s0, s1 = s1, s0 ^ _mult_gf2(q, s1) - return _Element(s0) - - def __pow__(self, exponent): - result = _Element(self._value) - for _ in range(exponent - 1): - result = result * self - return result - - -class Shamir(object): - """Shamir's secret sharing scheme. - - A secret is split into ``n`` shares, and it is sufficient to collect - ``k`` of them to reconstruct the secret. - """ - - @staticmethod - def split(k, n, secret, ssss=False): - """Split a secret into ``n`` shares. - - The secret can be reconstructed later using just ``k`` shares - out of the original ``n``. - Each share must be kept confidential to the person it was - assigned to. - - Each share is associated to an index (starting from 1). - - Args: - k (integer): - The sufficient number of shares to reconstruct the secret (``k < n``). - n (integer): - The number of shares that this method will create. - secret (byte string): - A byte string of 16 bytes (e.g. the AES 128 key). - ssss (bool): - If ``True``, the shares can be used with the ``ssss`` utility. - Default: ``False``. - - Return (tuples): - ``n`` tuples. A tuple is meant for each participant and it contains two items: - - 1. the unique index (an integer) - 2. the share (a byte string, 16 bytes) - """ - - # - # We create a polynomial with random coefficients in GF(2^128): - # - # p(x) = \sum_{i=0}^{k-1} c_i * x^i - # - # c_0 is the encoded secret - # - - coeffs = [_Element(rng(16)) for i in range(k - 1)] - coeffs.append(_Element(secret)) - - # Each share is y_i = p(x_i) where x_i is the public index - # associated to each of the n users. - - def make_share(user, coeffs, ssss): - idx = _Element(user) - share = _Element(0) - for coeff in coeffs: - share = idx * share + coeff - if ssss: - share += _Element(user) ** len(coeffs) - return share.encode() - - return [(i, make_share(i, coeffs, ssss)) for i in range(1, n + 1)] - - @staticmethod - def combine(shares, ssss=False): - """Recombine a secret, if enough shares are presented. - - Args: - shares (tuples): - The *k* tuples, each containin the index (an integer) and - the share (a byte string, 16 bytes long) that were assigned to - a participant. - ssss (bool): - If ``True``, the shares were produced by the ``ssss`` utility. - Default: ``False``. - - Return: - The original secret, as a byte string (16 bytes long). - """ - - # - # Given k points (x,y), the interpolation polynomial of degree k-1 is: - # - # L(x) = \sum_{j=0}^{k-1} y_i * l_j(x) - # - # where: - # - # l_j(x) = \prod_{ \overset{0 \le m \le k-1}{m \ne j} } - # \frac{x - x_m}{x_j - x_m} - # - # However, in this case we are purely interested in the constant - # coefficient of L(x). - # - - k = len(shares) - - gf_shares = [] - for x in shares: - idx = _Element(x[0]) - value = _Element(x[1]) - if any(y[0] == idx for y in gf_shares): - raise ValueError("Duplicate share") - if ssss: - value += idx ** k - gf_shares.append((idx, value)) - - result = _Element(0) - for j in range(k): - x_j, y_j = gf_shares[j] - - numerator = _Element(1) - denominator = _Element(1) - - for m in range(k): - x_m = gf_shares[m][0] - if m != j: - numerator *= x_m - denominator *= x_j + x_m - result += y_j * numerator * denominator.inverse() - return result.encode() diff --git a/Crypto/Protocol/SecretSharing.pyi b/Crypto/Protocol/SecretSharing.pyi deleted file mode 100644 index 5952c99..0000000 --- a/Crypto/Protocol/SecretSharing.pyi +++ /dev/null @@ -1,22 +0,0 @@ -from typing import Union, List, Tuple, Optional - -def _mult_gf2(f1: int, f2: int) -> int : ... -def _div_gf2(a: int, b: int) -> int : ... - -class _Element(object): - irr_poly: int - def __init__(self, encoded_value: Union[int, bytes]) -> None: ... - def __eq__(self, other) -> bool: ... - def __int__(self) -> int: ... - def encode(self) -> bytes: ... - def __mul__(self, factor: int) -> _Element: ... - def __add__(self, term: _Element) -> _Element: ... - def inverse(self) -> _Element: ... - def __pow__(self, exponent) -> _Element: ... - -class Shamir(object): - @staticmethod - def split(k: int, n: int, secret: bytes, ssss: Optional[bool]) -> List[Tuple[int, bytes]]: ... - @staticmethod - def combine(shares: List[Tuple[int, bytes]], ssss: Optional[bool]) -> bytes: ... - diff --git a/Crypto/Protocol/__init__.py b/Crypto/Protocol/__init__.py deleted file mode 100644 index efdf034..0000000 --- a/Crypto/Protocol/__init__.py +++ /dev/null @@ -1,31 +0,0 @@ -# =================================================================== -# -# Copyright (c) 2014, Legrandin -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# =================================================================== - -__all__ = ['KDF', 'SecretSharing'] diff --git a/Crypto/Protocol/__init__.pyi b/Crypto/Protocol/__init__.pyi deleted file mode 100644 index 377ed90..0000000 --- a/Crypto/Protocol/__init__.pyi +++ /dev/null @@ -1 +0,0 @@ -__all__ = ['KDF.pyi', 'SecretSharing.pyi'] diff --git a/Crypto/Protocol/__pycache__/KDF.cpython-36.pyc b/Crypto/Protocol/__pycache__/KDF.cpython-36.pyc deleted file mode 100644 index b48e0b0eb3bb373bb3acc0505e362a4b387b1f8f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 18158 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 bI+INmzFYXg*Dfbzn diff --git a/Crypto/Protocol/__pycache__/__init__.cpython-36.pyc b/Crypto/Protocol/__pycache__/__init__.cpython-36.pyc deleted file mode 100644 index 8b4c04bfc7421512dc429df93178c74e0e98ee70..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 204 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 K%Tvf>#s2_dQUApN diff --git a/Crypto/PublicKey/DSA.py b/Crypto/PublicKey/DSA.py deleted file mode 100644 index 8d603a9..0000000 --- a/Crypto/PublicKey/DSA.py +++ /dev/null @@ -1,682 +0,0 @@ -# -*- coding: utf-8 -*- -# -# PublicKey/DSA.py : DSA signature primitive -# -# Written in 2008 by Dwayne C. Litzenberger -# -# =================================================================== -# The contents of this file are dedicated to the public domain. To -# the extent that dedication to the public domain is not available, -# everyone is granted a worldwide, perpetual, royalty-free, -# non-exclusive license to exercise all rights associated with the -# contents of this file for any purpose whatsoever. -# No rights are reserved. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS -# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN -# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# =================================================================== - -__all__ = ['generate', 'construct', 'DsaKey', 'import_key' ] - -import binascii -import struct -import itertools - -from Crypto.Util.py3compat import bchr, bord, tobytes, tostr, iter_range - -from Crypto import Random -from Crypto.IO import PKCS8, PEM -from Crypto.Hash import SHA256 -from Crypto.Util.asn1 import ( - DerObject, DerSequence, - DerInteger, DerObjectId, - DerBitString, - ) - -from Crypto.Math.Numbers import Integer -from Crypto.Math.Primality import (test_probable_prime, COMPOSITE, - PROBABLY_PRIME) - -from Crypto.PublicKey import (_expand_subject_public_key_info, - _create_subject_public_key_info, - _extract_subject_public_key_info) - -# ; The following ASN.1 types are relevant for DSA -# -# SubjectPublicKeyInfo ::= SEQUENCE { -# algorithm AlgorithmIdentifier, -# subjectPublicKey BIT STRING -# } -# -# id-dsa ID ::= { iso(1) member-body(2) us(840) x9-57(10040) x9cm(4) 1 } -# -# ; See RFC3279 -# Dss-Parms ::= SEQUENCE { -# p INTEGER, -# q INTEGER, -# g INTEGER -# } -# -# DSAPublicKey ::= INTEGER -# -# DSSPrivatKey_OpenSSL ::= SEQUENCE -# version INTEGER, -# p INTEGER, -# q INTEGER, -# g INTEGER, -# y INTEGER, -# x INTEGER -# } -# - -class DsaKey(object): - r"""Class defining an actual DSA key. - Do not instantiate directly. - Use :func:`generate`, :func:`construct` or :func:`import_key` instead. - - :ivar p: DSA modulus - :vartype p: integer - - :ivar q: Order of the subgroup - :vartype q: integer - - :ivar g: Generator - :vartype g: integer - - :ivar y: Public key - :vartype y: integer - - :ivar x: Private key - :vartype x: integer - - :undocumented: exportKey, publickey - """ - - _keydata = ['y', 'g', 'p', 'q', 'x'] - - def __init__(self, key_dict): - input_set = set(key_dict.keys()) - public_set = set(('y' , 'g', 'p', 'q')) - if not public_set.issubset(input_set): - raise ValueError("Some DSA components are missing = %s" % - str(public_set - input_set)) - extra_set = input_set - public_set - if extra_set and extra_set != set(('x',)): - raise ValueError("Unknown DSA components = %s" % - str(extra_set - set(('x',)))) - self._key = dict(key_dict) - - def _sign(self, m, k): - if not self.has_private(): - raise TypeError("DSA public key cannot be used for signing") - if not (1 < k < self.q): - raise ValueError("k is not between 2 and q-1") - - x, q, p, g = [self._key[comp] for comp in ['x', 'q', 'p', 'g']] - - blind_factor = Integer.random_range(min_inclusive=1, - max_exclusive=q) - inv_blind_k = (blind_factor * k).inverse(q) - blind_x = x * blind_factor - - r = pow(g, k, p) % q # r = (g**k mod p) mod q - s = (inv_blind_k * (blind_factor * m + blind_x * r)) % q - return map(int, (r, s)) - - def _verify(self, m, sig): - r, s = sig - y, q, p, g = [self._key[comp] for comp in ['y', 'q', 'p', 'g']] - if not (0 < r < q) or not (0 < s < q): - return False - w = Integer(s).inverse(q) - u1 = (w * m) % q - u2 = (w * r) % q - v = (pow(g, u1, p) * pow(y, u2, p) % p) % q - return v == r - - def has_private(self): - """Whether this is a DSA private key""" - - return 'x' in self._key - - def can_encrypt(self): # legacy - return False - - def can_sign(self): # legacy - return True - - def public_key(self): - """A matching DSA public key. - - Returns: - a new :class:`DsaKey` object - """ - - public_components = dict((k, self._key[k]) for k in ('y', 'g', 'p', 'q')) - return DsaKey(public_components) - - def __eq__(self, other): - if bool(self.has_private()) != bool(other.has_private()): - return False - - result = True - for comp in self._keydata: - result = result and (getattr(self._key, comp, None) == - getattr(other._key, comp, None)) - return result - - def __ne__(self, other): - return not self.__eq__(other) - - def __getstate__(self): - # DSA key is not pickable - from pickle import PicklingError - raise PicklingError - - def domain(self): - """The DSA domain parameters. - - Returns - tuple : (p,q,g) - """ - - return [int(self._key[comp]) for comp in ('p', 'q', 'g')] - - def __repr__(self): - attrs = [] - for k in self._keydata: - if k == 'p': - bits = Integer(self.p).size_in_bits() - attrs.append("p(%d)" % (bits,)) - elif hasattr(self, k): - attrs.append(k) - if self.has_private(): - attrs.append("private") - # PY3K: This is meant to be text, do not change to bytes (data) - return "<%s @0x%x %s>" % (self.__class__.__name__, id(self), ",".join(attrs)) - - def __getattr__(self, item): - try: - return int(self._key[item]) - except KeyError: - raise AttributeError(item) - - def export_key(self, format='PEM', pkcs8=None, passphrase=None, - protection=None, randfunc=None): - """Export this DSA key. - - Args: - format (string): - The encoding for the output: - - - *'PEM'* (default). ASCII as per `RFC1421`_/ `RFC1423`_. - - *'DER'*. Binary ASN.1 encoding. - - *'OpenSSH'*. ASCII one-liner as per `RFC4253`_. - Only suitable for public keys, not for private keys. - - passphrase (string): - *Private keys only*. The pass phrase to protect the output. - - pkcs8 (boolean): - *Private keys only*. If ``True`` (default), the key is encoded - with `PKCS#8`_. If ``False``, it is encoded in the custom - OpenSSL/OpenSSH container. - - protection (string): - *Only in combination with a pass phrase*. - The encryption scheme to use to protect the output. - - If :data:`pkcs8` takes value ``True``, this is the PKCS#8 - algorithm to use for deriving the secret and encrypting - the private DSA key. - For a complete list of algorithms, see :mod:`Crypto.IO.PKCS8`. - The default is *PBKDF2WithHMAC-SHA1AndDES-EDE3-CBC*. - - If :data:`pkcs8` is ``False``, the obsolete PEM encryption scheme is - used. It is based on MD5 for key derivation, and Triple DES for - encryption. Parameter :data:`protection` is then ignored. - - The combination ``format='DER'`` and ``pkcs8=False`` is not allowed - if a passphrase is present. - - randfunc (callable): - A function that returns random bytes. - By default it is :func:`Crypto.Random.get_random_bytes`. - - Returns: - byte string : the encoded key - - Raises: - ValueError : when the format is unknown or when you try to encrypt a private - key with *DER* format and OpenSSL/OpenSSH. - - .. warning:: - If you don't provide a pass phrase, the private key will be - exported in the clear! - - .. _RFC1421: http://www.ietf.org/rfc/rfc1421.txt - .. _RFC1423: http://www.ietf.org/rfc/rfc1423.txt - .. _RFC4253: http://www.ietf.org/rfc/rfc4253.txt - .. _`PKCS#8`: http://www.ietf.org/rfc/rfc5208.txt - """ - - if passphrase is not None: - passphrase = tobytes(passphrase) - - if randfunc is None: - randfunc = Random.get_random_bytes - - if format == 'OpenSSH': - tup1 = [self._key[x].to_bytes() for x in ('p', 'q', 'g', 'y')] - - def func(x): - if (bord(x[0]) & 0x80): - return bchr(0) + x - else: - return x - - tup2 = [func(x) for x in tup1] - keyparts = [b'ssh-dss'] + tup2 - keystring = b''.join( - [struct.pack(">I", len(kp)) + kp for kp in keyparts] - ) - return b'ssh-dss ' + binascii.b2a_base64(keystring)[:-1] - - # DER format is always used, even in case of PEM, which simply - # encodes it into BASE64. - params = DerSequence([self.p, self.q, self.g]) - if self.has_private(): - if pkcs8 is None: - pkcs8 = True - if pkcs8: - if not protection: - protection = 'PBKDF2WithHMAC-SHA1AndDES-EDE3-CBC' - private_key = DerInteger(self.x).encode() - binary_key = PKCS8.wrap( - private_key, oid, passphrase, - protection, key_params=params, - randfunc=randfunc - ) - if passphrase: - key_type = 'ENCRYPTED PRIVATE' - else: - key_type = 'PRIVATE' - passphrase = None - else: - if format != 'PEM' and passphrase: - raise ValueError("DSA private key cannot be encrypted") - ints = [0, self.p, self.q, self.g, self.y, self.x] - binary_key = DerSequence(ints).encode() - key_type = "DSA PRIVATE" - else: - if pkcs8: - raise ValueError("PKCS#8 is only meaningful for private keys") - - binary_key = _create_subject_public_key_info(oid, - DerInteger(self.y), params) - key_type = "PUBLIC" - - if format == 'DER': - return binary_key - if format == 'PEM': - pem_str = PEM.encode( - binary_key, key_type + " KEY", - passphrase, randfunc - ) - return tobytes(pem_str) - raise ValueError("Unknown key format '%s'. Cannot export the DSA key." % format) - - # Backward-compatibility - exportKey = export_key - publickey = public_key - - # Methods defined in PyCrypto that we don't support anymore - - def sign(self, M, K): - raise NotImplementedError("Use module Crypto.Signature.DSS instead") - - def verify(self, M, signature): - raise NotImplementedError("Use module Crypto.Signature.DSS instead") - - def encrypt(self, plaintext, K): - raise NotImplementedError - - def decrypt(self, ciphertext): - raise NotImplementedError - - def blind(self, M, B): - raise NotImplementedError - - def unblind(self, M, B): - raise NotImplementedError - - def size(self): - raise NotImplementedError - - -def _generate_domain(L, randfunc): - """Generate a new set of DSA domain parameters""" - - N = { 1024:160, 2048:224, 3072:256 }.get(L) - if N is None: - raise ValueError("Invalid modulus length (%d)" % L) - - outlen = SHA256.digest_size * 8 - n = (L + outlen - 1) // outlen - 1 # ceil(L/outlen) -1 - b_ = L - 1 - (n * outlen) - - # Generate q (A.1.1.2) - q = Integer(4) - upper_bit = 1 << (N - 1) - while test_probable_prime(q, randfunc) != PROBABLY_PRIME: - seed = randfunc(64) - U = Integer.from_bytes(SHA256.new(seed).digest()) & (upper_bit - 1) - q = U | upper_bit | 1 - - assert(q.size_in_bits() == N) - - # Generate p (A.1.1.2) - offset = 1 - upper_bit = 1 << (L - 1) - while True: - V = [ SHA256.new(seed + Integer(offset + j).to_bytes()).digest() - for j in iter_range(n + 1) ] - V = [ Integer.from_bytes(v) for v in V ] - W = sum([V[i] * (1 << (i * outlen)) for i in iter_range(n)], - (V[n] & ((1 << b_) - 1)) * (1 << (n * outlen))) - - X = Integer(W + upper_bit) # 2^{L-1} < X < 2^{L} - assert(X.size_in_bits() == L) - - c = X % (q * 2) - p = X - (c - 1) # 2q divides (p-1) - if p.size_in_bits() == L and \ - test_probable_prime(p, randfunc) == PROBABLY_PRIME: - break - offset += n + 1 - - # Generate g (A.2.3, index=1) - e = (p - 1) // q - for count in itertools.count(1): - U = seed + b"ggen" + bchr(1) + Integer(count).to_bytes() - W = Integer.from_bytes(SHA256.new(U).digest()) - g = pow(W, e, p) - if g != 1: - break - - return (p, q, g, seed) - - -def generate(bits, randfunc=None, domain=None): - """Generate a new DSA key pair. - - The algorithm follows Appendix A.1/A.2 and B.1 of `FIPS 186-4`_, - respectively for domain generation and key pair generation. - - Args: - bits (integer): - Key length, or size (in bits) of the DSA modulus *p*. - It must be 1024, 2048 or 3072. - - randfunc (callable): - Random number generation function; it accepts a single integer N - and return a string of random data N bytes long. - If not specified, :func:`Crypto.Random.get_random_bytes` is used. - - domain (tuple): - The DSA domain parameters *p*, *q* and *g* as a list of 3 - integers. Size of *p* and *q* must comply to `FIPS 186-4`_. - If not specified, the parameters are created anew. - - Returns: - :class:`DsaKey` : a new DSA key object - - Raises: - ValueError : when **bits** is too little, too big, or not a multiple of 64. - - .. _FIPS 186-4: http://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.186-4.pdf - """ - - if randfunc is None: - randfunc = Random.get_random_bytes - - if domain: - p, q, g = map(Integer, domain) - - ## Perform consistency check on domain parameters - # P and Q must be prime - fmt_error = test_probable_prime(p) == COMPOSITE - fmt_error = test_probable_prime(q) == COMPOSITE - # Verify Lagrange's theorem for sub-group - fmt_error |= ((p - 1) % q) != 0 - fmt_error |= g <= 1 or g >= p - fmt_error |= pow(g, q, p) != 1 - if fmt_error: - raise ValueError("Invalid DSA domain parameters") - else: - p, q, g, _ = _generate_domain(bits, randfunc) - - L = p.size_in_bits() - N = q.size_in_bits() - - if L != bits: - raise ValueError("Mismatch between size of modulus (%d)" - " and 'bits' parameter (%d)" % (L, bits)) - - if (L, N) not in [(1024, 160), (2048, 224), - (2048, 256), (3072, 256)]: - raise ValueError("Lengths of p and q (%d, %d) are not compatible" - "to FIPS 186-3" % (L, N)) - - if not 1 < g < p: - raise ValueError("Incorrent DSA generator") - - # B.1.1 - c = Integer.random(exact_bits=N + 64, randfunc=randfunc) - x = c % (q - 1) + 1 # 1 <= x <= q-1 - y = pow(g, x, p) - - key_dict = { 'y':y, 'g':g, 'p':p, 'q':q, 'x':x } - return DsaKey(key_dict) - - -def construct(tup, consistency_check=True): - """Construct a DSA key from a tuple of valid DSA components. - - Args: - tup (tuple): - A tuple of long integers, with 4 or 5 items - in the following order: - - 1. Public key (*y*). - 2. Sub-group generator (*g*). - 3. Modulus, finite field order (*p*). - 4. Sub-group order (*q*). - 5. Private key (*x*). Optional. - - consistency_check (boolean): - If ``True``, the library will verify that the provided components - fulfil the main DSA properties. - - Raises: - ValueError: when the key being imported fails the most basic DSA validity checks. - - Returns: - :class:`DsaKey` : a DSA key object - """ - - key_dict = dict(zip(('y', 'g', 'p', 'q', 'x'), map(Integer, tup))) - key = DsaKey(key_dict) - - fmt_error = False - if consistency_check: - # P and Q must be prime - fmt_error = test_probable_prime(key.p) == COMPOSITE - fmt_error = test_probable_prime(key.q) == COMPOSITE - # Verify Lagrange's theorem for sub-group - fmt_error |= ((key.p - 1) % key.q) != 0 - fmt_error |= key.g <= 1 or key.g >= key.p - fmt_error |= pow(key.g, key.q, key.p) != 1 - # Public key - fmt_error |= key.y <= 0 or key.y >= key.p - if hasattr(key, 'x'): - fmt_error |= key.x <= 0 or key.x >= key.q - fmt_error |= pow(key.g, key.x, key.p) != key.y - - if fmt_error: - raise ValueError("Invalid DSA key components") - - return key - - -# Dss-Parms ::= SEQUENCE { -# p OCTET STRING, -# q OCTET STRING, -# g OCTET STRING -# } -# DSAPublicKey ::= INTEGER -- public key, y - -def _import_openssl_private(encoded, passphrase, params): - if params: - raise ValueError("DSA private key already comes with parameters") - der = DerSequence().decode(encoded, nr_elements=6, only_ints_expected=True) - if der[0] != 0: - raise ValueError("No version found") - tup = [der[comp] for comp in (4, 3, 1, 2, 5)] - return construct(tup) - - -def _import_subjectPublicKeyInfo(encoded, passphrase, params): - - algoid, encoded_key, emb_params = _expand_subject_public_key_info(encoded) - if algoid != oid: - raise ValueError("No DSA subjectPublicKeyInfo") - if params and emb_params: - raise ValueError("Too many DSA parameters") - - y = DerInteger().decode(encoded_key).value - p, q, g = list(DerSequence().decode(params or emb_params)) - tup = (y, g, p, q) - return construct(tup) - - -def _import_x509_cert(encoded, passphrase, params): - - sp_info = _extract_subject_public_key_info(encoded) - return _import_subjectPublicKeyInfo(sp_info, None, params) - - -def _import_pkcs8(encoded, passphrase, params): - if params: - raise ValueError("PKCS#8 already includes parameters") - k = PKCS8.unwrap(encoded, passphrase) - if k[0] != oid: - raise ValueError("No PKCS#8 encoded DSA key") - x = DerInteger().decode(k[1]).value - p, q, g = list(DerSequence().decode(k[2])) - tup = (pow(g, x, p), g, p, q, x) - return construct(tup) - - -def _import_key_der(key_data, passphrase, params): - """Import a DSA key (public or private half), encoded in DER form.""" - - decodings = (_import_openssl_private, - _import_subjectPublicKeyInfo, - _import_x509_cert, - _import_pkcs8) - - for decoding in decodings: - try: - return decoding(key_data, passphrase, params) - except ValueError: - pass - - raise ValueError("DSA key format is not supported") - - -def import_key(extern_key, passphrase=None): - """Import a DSA key. - - Args: - extern_key (string or byte string): - The DSA key to import. - - The following formats are supported for a DSA **public** key: - - - X.509 certificate (binary DER or PEM) - - X.509 ``subjectPublicKeyInfo`` (binary DER or PEM) - - OpenSSH (ASCII one-liner, see `RFC4253`_) - - The following formats are supported for a DSA **private** key: - - - `PKCS#8`_ ``PrivateKeyInfo`` or ``EncryptedPrivateKeyInfo`` - DER SEQUENCE (binary or PEM) - - OpenSSL/OpenSSH custom format (binary or PEM) - - For details about the PEM encoding, see `RFC1421`_/`RFC1423`_. - - passphrase (string): - In case of an encrypted private key, this is the pass phrase - from which the decryption key is derived. - - Encryption may be applied either at the `PKCS#8`_ or at the PEM level. - - Returns: - :class:`DsaKey` : a DSA key object - - Raises: - ValueError : when the given key cannot be parsed (possibly because - the pass phrase is wrong). - - .. _RFC1421: http://www.ietf.org/rfc/rfc1421.txt - .. _RFC1423: http://www.ietf.org/rfc/rfc1423.txt - .. _RFC4253: http://www.ietf.org/rfc/rfc4253.txt - .. _PKCS#8: http://www.ietf.org/rfc/rfc5208.txt - """ - - extern_key = tobytes(extern_key) - if passphrase is not None: - passphrase = tobytes(passphrase) - - if extern_key.startswith(b'-----'): - # This is probably a PEM encoded key - (der, marker, enc_flag) = PEM.decode(tostr(extern_key), passphrase) - if enc_flag: - passphrase = None - return _import_key_der(der, passphrase, None) - - if extern_key.startswith(b'ssh-dss '): - # This is probably a public OpenSSH key - keystring = binascii.a2b_base64(extern_key.split(b' ')[1]) - keyparts = [] - while len(keystring) > 4: - length = struct.unpack(">I", keystring[:4])[0] - keyparts.append(keystring[4:4 + length]) - keystring = keystring[4 + length:] - if keyparts[0] == b"ssh-dss": - tup = [Integer.from_bytes(keyparts[x]) for x in (4, 3, 1, 2)] - return construct(tup) - - if len(extern_key) > 0 and bord(extern_key[0]) == 0x30: - # This is probably a DER encoded key - return _import_key_der(extern_key, passphrase, None) - - raise ValueError("DSA key format is not supported") - - -# Backward compatibility -importKey = import_key - -#: `Object ID`_ for a DSA key. -#: -#: id-dsa ID ::= { iso(1) member-body(2) us(840) x9-57(10040) x9cm(4) 1 } -#: -#: .. _`Object ID`: http://www.alvestrand.no/objectid/1.2.840.10040.4.1.html -oid = "1.2.840.10040.4.1" diff --git a/Crypto/PublicKey/DSA.pyi b/Crypto/PublicKey/DSA.pyi deleted file mode 100644 index 354ac1f..0000000 --- a/Crypto/PublicKey/DSA.pyi +++ /dev/null @@ -1,31 +0,0 @@ -from typing import Dict, Tuple, Callable, Union, Optional - -__all__ = ['generate', 'construct', 'DsaKey', 'import_key' ] - -RNG = Callable[[int], bytes] - -class DsaKey(object): - def __init__(self, key_dict: Dict[str, int]) -> None: ... - def has_private(self) -> bool: ... - def can_encrypt(self) -> bool: ... # legacy - def can_sign(self) -> bool: ... # legacy - def public_key(self) -> DsaKey: ... - def __eq__(self, other: object) -> bool: ... - def __ne__(self, other: object) -> bool: ... - def __getstate__(self) -> None: ... - def domain(self) -> Tuple[int, int, int]: ... - def __repr__(self) -> str: ... - def __getattr__(self, item: str) -> int: ... - def export_key(self, format: Optional[str]="PEM", pkcs8: Optional[bool]=None, passphrase: Optional[str]=None, - protection: Optional[str]=None, randfunc: Optional[RNG]=None) -> bytes: ... - # Backward-compatibility - exportKey = export_key - publickey = public_key - -def generate(bits: int, randfunc: Optional[RNG]=None, domain: Optional[Tuple[int, int, int]]=None) -> DsaKey: ... -def construct(tup: Union[Tuple[int, int, int, int], Tuple[int, int, int, int, int]], consistency_check: Optional[bool]=True) -> DsaKey: ... -def import_key(extern_key: Union[str, bytes], passphrase: Optional[str]=None) -> DsaKey: ... -# Backward compatibility -importKey = import_key - -oid: str diff --git a/Crypto/PublicKey/ECC.py b/Crypto/PublicKey/ECC.py deleted file mode 100644 index 415eced..0000000 --- a/Crypto/PublicKey/ECC.py +++ /dev/null @@ -1,1182 +0,0 @@ -# =================================================================== -# -# Copyright (c) 2015, Legrandin -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# =================================================================== - -from __future__ import print_function - -import re -import struct -import binascii -from collections import namedtuple - -from Crypto.Util.py3compat import bord, tobytes, tostr, bchr, is_string -from Crypto.Util.number import bytes_to_long, long_to_bytes - -from Crypto.Math.Numbers import Integer -from Crypto.Util.asn1 import (DerObjectId, DerOctetString, DerSequence, - DerBitString) - -from Crypto.PublicKey import (_expand_subject_public_key_info, - _create_subject_public_key_info, - _extract_subject_public_key_info) - -from Crypto.Util._raw_api import (load_pycryptodome_raw_lib, VoidPointer, - SmartPointer, c_size_t, c_uint8_ptr, - c_ulonglong) - -from Crypto.Random import get_random_bytes -from Crypto.Random.random import getrandbits - - -_ec_lib = load_pycryptodome_raw_lib("Crypto.PublicKey._ec_ws", """ -typedef void EcContext; -typedef void EcPoint; -int ec_ws_new_context(EcContext **pec_ctx, - const uint8_t *modulus, - const uint8_t *b, - const uint8_t *order, - size_t len, - uint64_t seed); -void ec_free_context(EcContext *ec_ctx); -int ec_ws_new_point(EcPoint **pecp, - const uint8_t *x, - const uint8_t *y, - size_t len, - const EcContext *ec_ctx); -void ec_free_point(EcPoint *ecp); -int ec_ws_get_xy(uint8_t *x, - uint8_t *y, - size_t len, - const EcPoint *ecp); -int ec_ws_double(EcPoint *p); -int ec_ws_add(EcPoint *ecpa, EcPoint *ecpb); -int ec_ws_scalar(EcPoint *ecp, - const uint8_t *k, - size_t len, - uint64_t seed); -int ec_ws_clone(EcPoint **pecp2, const EcPoint *ecp); -int ec_ws_copy(EcPoint *ecp1, const EcPoint *ecp2); -int ec_ws_cmp(const EcPoint *ecp1, const EcPoint *ecp2); -int ec_ws_neg(EcPoint *p); -int ec_ws_normalize(EcPoint *ecp); -int ec_ws_is_pai(EcPoint *ecp); -""") - -_Curve = namedtuple("_Curve", "p b order Gx Gy G modulus_bits oid context desc openssh") -_curves = {} - - -p256_names = ["p256", "NIST P-256", "P-256", "prime256v1", "secp256r1", - "nistp256"] - - -def init_p256(): - p = 0xffffffff00000001000000000000000000000000ffffffffffffffffffffffff - b = 0x5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b - order = 0xffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551 - Gx = 0x6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296 - Gy = 0x4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5 - - p256_modulus = long_to_bytes(p, 32) - p256_b = long_to_bytes(b, 32) - p256_order = long_to_bytes(order, 32) - - ec_p256_context = VoidPointer() - result = _ec_lib.ec_ws_new_context(ec_p256_context.address_of(), - c_uint8_ptr(p256_modulus), - c_uint8_ptr(p256_b), - c_uint8_ptr(p256_order), - c_size_t(len(p256_modulus)), - c_ulonglong(getrandbits(64)) - ) - if result: - raise ImportError("Error %d initializing P-256 context" % result) - - context = SmartPointer(ec_p256_context.get(), _ec_lib.ec_free_context) - p256 = _Curve(Integer(p), - Integer(b), - Integer(order), - Integer(Gx), - Integer(Gy), - None, - 256, - "1.2.840.10045.3.1.7", # ANSI X9.62 - context, - "NIST P-256", - "ecdsa-sha2-nistp256") - global p256_names - _curves.update(dict.fromkeys(p256_names, p256)) - - -init_p256() -del init_p256 - - -p384_names = ["p384", "NIST P-384", "P-384", "prime384v1", "secp384r1", - "nistp384"] - - -def init_p384(): - p = 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffff0000000000000000ffffffff - b = 0xb3312fa7e23ee7e4988e056be3f82d19181d9c6efe8141120314088f5013875ac656398d8a2ed19d2a85c8edd3ec2aef - order = 0xffffffffffffffffffffffffffffffffffffffffffffffffc7634d81f4372ddf581a0db248b0a77aecec196accc52973 - Gx = 0xaa87ca22be8b05378eb1c71ef320ad746e1d3b628ba79b9859f741e082542a385502f25dbf55296c3a545e3872760aB7 - Gy = 0x3617de4a96262c6f5d9e98bf9292dc29f8f41dbd289a147ce9da3113b5f0b8c00a60b1ce1d7e819d7a431d7c90ea0e5F - - p384_modulus = long_to_bytes(p, 48) - p384_b = long_to_bytes(b, 48) - p384_order = long_to_bytes(order, 48) - - ec_p384_context = VoidPointer() - result = _ec_lib.ec_ws_new_context(ec_p384_context.address_of(), - c_uint8_ptr(p384_modulus), - c_uint8_ptr(p384_b), - c_uint8_ptr(p384_order), - c_size_t(len(p384_modulus)), - c_ulonglong(getrandbits(64)) - ) - if result: - raise ImportError("Error %d initializing P-384 context" % result) - - context = SmartPointer(ec_p384_context.get(), _ec_lib.ec_free_context) - p384 = _Curve(Integer(p), - Integer(b), - Integer(order), - Integer(Gx), - Integer(Gy), - None, - 384, - "1.3.132.0.34", # SEC 2 - context, - "NIST P-384", - "ecdsa-sha2-nistp384") - global p384_names - _curves.update(dict.fromkeys(p384_names, p384)) - - -init_p384() -del init_p384 - - -p521_names = ["p521", "NIST P-521", "P-521", "prime521v1", "secp521r1", - "nistp521"] - - -def init_p521(): - p = 0x000001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff - b = 0x00000051953eb9618e1c9a1f929a21a0b68540eea2da725b99b315f3b8b489918ef109e156193951ec7e937b1652c0bd3bb1bf073573df883d2c34f1ef451fd46b503f00 - order = 0x000001fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa51868783bf2f966b7fcc0148f709a5d03bb5c9b8899c47aebb6fb71e91386409 - Gx = 0x000000c6858e06b70404e9cd9e3ecb662395b4429c648139053fb521f828af606b4d3dbaa14b5e77efe75928fe1dc127a2ffa8de3348b3c1856a429bf97e7e31c2e5bd66 - Gy = 0x0000011839296a789a3bc0045c8a5fb42c7d1bd998f54449579b446817afbd17273e662c97ee72995ef42640c550b9013fad0761353c7086a272c24088be94769fd16650 - - p521_modulus = long_to_bytes(p, 66) - p521_b = long_to_bytes(b, 66) - p521_order = long_to_bytes(order, 66) - - ec_p521_context = VoidPointer() - result = _ec_lib.ec_ws_new_context(ec_p521_context.address_of(), - c_uint8_ptr(p521_modulus), - c_uint8_ptr(p521_b), - c_uint8_ptr(p521_order), - c_size_t(len(p521_modulus)), - c_ulonglong(getrandbits(64)) - ) - if result: - raise ImportError("Error %d initializing P-521 context" % result) - - context = SmartPointer(ec_p521_context.get(), _ec_lib.ec_free_context) - p521 = _Curve(Integer(p), - Integer(b), - Integer(order), - Integer(Gx), - Integer(Gy), - None, - 521, - "1.3.132.0.35", # SEC 2 - context, - "NIST P-521", - "ecdsa-sha2-nistp521") - global p521_names - _curves.update(dict.fromkeys(p521_names, p521)) - - -init_p521() -del init_p521 - - -class UnsupportedEccFeature(ValueError): - pass - - -class EccPoint(object): - """A class to abstract a point over an Elliptic Curve. - - The class support special methods for: - - * Adding two points: ``R = S + T`` - * In-place addition: ``S += T`` - * Negating a point: ``R = -T`` - * Comparing two points: ``if S == T: ...`` - * Multiplying a point by a scalar: ``R = S*k`` - * In-place multiplication by a scalar: ``T *= k`` - - :ivar x: The affine X-coordinate of the ECC point - :vartype x: integer - - :ivar y: The affine Y-coordinate of the ECC point - :vartype y: integer - - :ivar xy: The tuple with X- and Y- coordinates - """ - - def __init__(self, x, y, curve="p256"): - - try: - self._curve = _curves[curve] - except KeyError: - raise ValueError("Unknown curve name %s" % str(curve)) - self._curve_name = curve - - modulus_bytes = self.size_in_bytes() - context = self._curve.context - - xb = long_to_bytes(x, modulus_bytes) - yb = long_to_bytes(y, modulus_bytes) - if len(xb) != modulus_bytes or len(yb) != modulus_bytes: - raise ValueError("Incorrect coordinate length") - - self._point = VoidPointer() - result = _ec_lib.ec_ws_new_point(self._point.address_of(), - c_uint8_ptr(xb), - c_uint8_ptr(yb), - c_size_t(modulus_bytes), - context.get()) - if result: - if result == 15: - raise ValueError("The EC point does not belong to the curve") - raise ValueError("Error %d while instantiating an EC point" % result) - - # Ensure that object disposal of this Python object will (eventually) - # free the memory allocated by the raw library for the EC point - self._point = SmartPointer(self._point.get(), - _ec_lib.ec_free_point) - - def set(self, point): - self._point = VoidPointer() - result = _ec_lib.ec_ws_clone(self._point.address_of(), - point._point.get()) - if result: - raise ValueError("Error %d while cloning an EC point" % result) - - self._point = SmartPointer(self._point.get(), - _ec_lib.ec_free_point) - return self - - def __eq__(self, point): - return 0 == _ec_lib.ec_ws_cmp(self._point.get(), point._point.get()) - - def __neg__(self): - np = self.copy() - result = _ec_lib.ec_ws_neg(np._point.get()) - if result: - raise ValueError("Error %d while inverting an EC point" % result) - return np - - def copy(self): - """Return a copy of this point.""" - x, y = self.xy - np = EccPoint(x, y, self._curve_name) - return np - - def is_point_at_infinity(self): - """``True`` if this is the point-at-infinity.""" - return self.xy == (0, 0) - - def point_at_infinity(self): - """Return the point-at-infinity for the curve this point is on.""" - return EccPoint(0, 0, self._curve_name) - - @property - def x(self): - return self.xy[0] - - @property - def y(self): - return self.xy[1] - - @property - def xy(self): - modulus_bytes = self.size_in_bytes() - xb = bytearray(modulus_bytes) - yb = bytearray(modulus_bytes) - result = _ec_lib.ec_ws_get_xy(c_uint8_ptr(xb), - c_uint8_ptr(yb), - c_size_t(modulus_bytes), - self._point.get()) - if result: - raise ValueError("Error %d while encoding an EC point" % result) - - return (Integer(bytes_to_long(xb)), Integer(bytes_to_long(yb))) - - def size_in_bytes(self): - """Size of each coordinate, in bytes.""" - return (self.size_in_bits() + 7) // 8 - - def size_in_bits(self): - """Size of each coordinate, in bits.""" - return self._curve.modulus_bits - - def double(self): - """Double this point (in-place operation). - - :Return: - :class:`EccPoint` : this same object (to enable chaining) - """ - - result = _ec_lib.ec_ws_double(self._point.get()) - if result: - raise ValueError("Error %d while doubling an EC point" % result) - return self - - def __iadd__(self, point): - """Add a second point to this one""" - - result = _ec_lib.ec_ws_add(self._point.get(), point._point.get()) - if result: - if result == 16: - raise ValueError("EC points are not on the same curve") - raise ValueError("Error %d while adding two EC points" % result) - return self - - def __add__(self, point): - """Return a new point, the addition of this one and another""" - - np = self.copy() - np += point - return np - - def __imul__(self, scalar): - """Multiply this point by a scalar""" - - if scalar < 0: - raise ValueError("Scalar multiplication is only defined for non-negative integers") - sb = long_to_bytes(scalar) - result = _ec_lib.ec_ws_scalar(self._point.get(), - c_uint8_ptr(sb), - c_size_t(len(sb)), - c_ulonglong(getrandbits(64))) - if result: - raise ValueError("Error %d during scalar multiplication" % result) - return self - - def __mul__(self, scalar): - """Return a new point, the scalar product of this one""" - - np = self.copy() - np *= scalar - return np - - def __rmul__(self, left_hand): - return self.__mul__(left_hand) - - -# Last piece of initialization -p256_G = EccPoint(_curves['p256'].Gx, _curves['p256'].Gy, "p256") -p256 = _curves['p256']._replace(G=p256_G) -_curves.update(dict.fromkeys(p256_names, p256)) -del p256_G, p256, p256_names - -p384_G = EccPoint(_curves['p384'].Gx, _curves['p384'].Gy, "p384") -p384 = _curves['p384']._replace(G=p384_G) -_curves.update(dict.fromkeys(p384_names, p384)) -del p384_G, p384, p384_names - -p521_G = EccPoint(_curves['p521'].Gx, _curves['p521'].Gy, "p521") -p521 = _curves['p521']._replace(G=p521_G) -_curves.update(dict.fromkeys(p521_names, p521)) -del p521_G, p521, p521_names - - -class EccKey(object): - r"""Class defining an ECC key. - Do not instantiate directly. - Use :func:`generate`, :func:`construct` or :func:`import_key` instead. - - :ivar curve: The name of the ECC as defined in :numref:`curve_names`. - :vartype curve: string - - :ivar pointQ: an ECC point representating the public component - :vartype pointQ: :class:`EccPoint` - - :ivar d: A scalar representating the private component - :vartype d: integer - """ - - def __init__(self, **kwargs): - """Create a new ECC key - - Keywords: - curve : string - It must be *"p256"*, *"P-256"*, *"prime256v1"* or *"secp256r1"*. - d : integer - Only for a private key. It must be in the range ``[1..order-1]``. - point : EccPoint - Mandatory for a public key. If provided for a private key, - the implementation will NOT check whether it matches ``d``. - """ - - kwargs_ = dict(kwargs) - curve_name = kwargs_.pop("curve", None) - self._d = kwargs_.pop("d", None) - self._point = kwargs_.pop("point", None) - if kwargs_: - raise TypeError("Unknown parameters: " + str(kwargs_)) - - if curve_name not in _curves: - raise ValueError("Unsupported curve (%s)", curve_name) - self._curve = _curves[curve_name] - - if self._d is None: - if self._point is None: - raise ValueError("Either private or public ECC component must be specified, not both") - else: - self._d = Integer(self._d) - if not 1 <= self._d < self._curve.order: - raise ValueError("Invalid ECC private component") - - self.curve = self._curve.desc - - def __eq__(self, other): - if other.has_private() != self.has_private(): - return False - - return other.pointQ == self.pointQ - - def __repr__(self): - if self.has_private(): - extra = ", d=%d" % int(self._d) - else: - extra = "" - x, y = self.pointQ.xy - return "EccKey(curve='%s', point_x=%d, point_y=%d%s)" % (self._curve.desc, x, y, extra) - - def has_private(self): - """``True`` if this key can be used for making signatures or decrypting data.""" - - return self._d is not None - - def _sign(self, z, k): - assert 0 < k < self._curve.order - - order = self._curve.order - blind = Integer.random_range(min_inclusive=1, - max_exclusive=order) - - blind_d = self._d * blind - inv_blind_k = (blind * k).inverse(order) - - r = (self._curve.G * k).x % order - s = inv_blind_k * (blind * z + blind_d * r) % order - return (r, s) - - def _verify(self, z, rs): - order = self._curve.order - sinv = rs[1].inverse(order) - point1 = self._curve.G * ((sinv * z) % order) - point2 = self.pointQ * ((sinv * rs[0]) % order) - return (point1 + point2).x == rs[0] - - @property - def d(self): - if not self.has_private(): - raise ValueError("This is not a private ECC key") - return self._d - - @property - def pointQ(self): - if self._point is None: - self._point = self._curve.G * self._d - return self._point - - def public_key(self): - """A matching ECC public key. - - Returns: - a new :class:`EccKey` object - """ - - return EccKey(curve=self._curve.desc, point=self.pointQ) - - def _export_subjectPublicKeyInfo(self, compress): - - # See 2.2 in RFC5480 and 2.3.3 in SEC1 - # The first byte is: - # - 0x02: compressed, only X-coordinate, Y-coordinate is even - # - 0x03: compressed, only X-coordinate, Y-coordinate is odd - # - 0x04: uncompressed, X-coordinate is followed by Y-coordinate - # - # PAI is in theory encoded as 0x00. - - modulus_bytes = self.pointQ.size_in_bytes() - - if compress: - first_byte = 2 + self.pointQ.y.is_odd() - public_key = (bchr(first_byte) + - self.pointQ.x.to_bytes(modulus_bytes)) - else: - public_key = (b'\x04' + - self.pointQ.x.to_bytes(modulus_bytes) + - self.pointQ.y.to_bytes(modulus_bytes)) - - unrestricted_oid = "1.2.840.10045.2.1" - return _create_subject_public_key_info(unrestricted_oid, - public_key, - DerObjectId(self._curve.oid)) - - def _export_private_der(self, include_ec_params=True): - - assert self.has_private() - - # ECPrivateKey ::= SEQUENCE { - # version INTEGER { ecPrivkeyVer1(1) } (ecPrivkeyVer1), - # privateKey OCTET STRING, - # parameters [0] ECParameters {{ NamedCurve }} OPTIONAL, - # publicKey [1] BIT STRING OPTIONAL - # } - - # Public key - uncompressed form - modulus_bytes = self.pointQ.size_in_bytes() - public_key = (b'\x04' + - self.pointQ.x.to_bytes(modulus_bytes) + - self.pointQ.y.to_bytes(modulus_bytes)) - - seq = [1, - DerOctetString(self.d.to_bytes(modulus_bytes)), - DerObjectId(self._curve.oid, explicit=0), - DerBitString(public_key, explicit=1)] - - if not include_ec_params: - del seq[2] - - return DerSequence(seq).encode() - - def _export_pkcs8(self, **kwargs): - from Crypto.IO import PKCS8 - - if kwargs.get('passphrase', None) is not None and 'protection' not in kwargs: - raise ValueError("At least the 'protection' parameter should be present") - - unrestricted_oid = "1.2.840.10045.2.1" - private_key = self._export_private_der(include_ec_params=False) - result = PKCS8.wrap(private_key, - unrestricted_oid, - key_params=DerObjectId(self._curve.oid), - **kwargs) - return result - - def _export_public_pem(self, compress): - from Crypto.IO import PEM - - encoded_der = self._export_subjectPublicKeyInfo(compress) - return PEM.encode(encoded_der, "PUBLIC KEY") - - def _export_private_pem(self, passphrase, **kwargs): - from Crypto.IO import PEM - - encoded_der = self._export_private_der() - return PEM.encode(encoded_der, "EC PRIVATE KEY", passphrase, **kwargs) - - def _export_private_clear_pkcs8_in_clear_pem(self): - from Crypto.IO import PEM - - encoded_der = self._export_pkcs8() - return PEM.encode(encoded_der, "PRIVATE KEY") - - def _export_private_encrypted_pkcs8_in_clear_pem(self, passphrase, **kwargs): - from Crypto.IO import PEM - - assert passphrase - if 'protection' not in kwargs: - raise ValueError("At least the 'protection' parameter should be present") - encoded_der = self._export_pkcs8(passphrase=passphrase, **kwargs) - return PEM.encode(encoded_der, "ENCRYPTED PRIVATE KEY") - - def _export_openssh(self, compress): - if self.has_private(): - raise ValueError("Cannot export OpenSSH private keys") - - desc = self._curve.openssh - modulus_bytes = self.pointQ.size_in_bytes() - - if compress: - first_byte = 2 + self.pointQ.y.is_odd() - public_key = (bchr(first_byte) + - self.pointQ.x.to_bytes(modulus_bytes)) - else: - public_key = (b'\x04' + - self.pointQ.x.to_bytes(modulus_bytes) + - self.pointQ.y.to_bytes(modulus_bytes)) - - middle = desc.split("-")[2] - comps = (tobytes(desc), tobytes(middle), public_key) - blob = b"".join([struct.pack(">I", len(x)) + x for x in comps]) - return desc + " " + tostr(binascii.b2a_base64(blob)) - - def export_key(self, **kwargs): - """Export this ECC key. - - Args: - format (string): - The format to use for encoding the key: - - - ``'DER'``. The key will be encoded in ASN.1 DER format (binary). - For a public key, the ASN.1 ``subjectPublicKeyInfo`` structure - defined in `RFC5480`_ will be used. - For a private key, the ASN.1 ``ECPrivateKey`` structure defined - in `RFC5915`_ is used instead (possibly within a PKCS#8 envelope, - see the ``use_pkcs8`` flag below). - - ``'PEM'``. The key will be encoded in a PEM_ envelope (ASCII). - - ``'OpenSSH'``. The key will be encoded in the OpenSSH_ format - (ASCII, public keys only). - - passphrase (byte string or string): - The passphrase to use for protecting the private key. - - use_pkcs8 (boolean): - Only relevant for private keys. - - If ``True`` (default and recommended), the `PKCS#8`_ representation - will be used. - - If ``False``, the much weaker `PEM encryption`_ mechanism will be used. - - protection (string): - When a private key is exported with password-protection - and PKCS#8 (both ``DER`` and ``PEM`` formats), this parameter MUST be - present and be a valid algorithm supported by :mod:`Crypto.IO.PKCS8`. - It is recommended to use ``PBKDF2WithHMAC-SHA1AndAES128-CBC``. - - compress (boolean): - If ``True``, a more compact representation of the public key - with the X-coordinate only is used. - - If ``False`` (default), the full public key will be exported. - - .. warning:: - If you don't provide a passphrase, the private key will be - exported in the clear! - - .. note:: - When exporting a private key with password-protection and `PKCS#8`_ - (both ``DER`` and ``PEM`` formats), any extra parameters - to ``export_key()`` will be passed to :mod:`Crypto.IO.PKCS8`. - - .. _PEM: http://www.ietf.org/rfc/rfc1421.txt - .. _`PEM encryption`: http://www.ietf.org/rfc/rfc1423.txt - .. _`PKCS#8`: http://www.ietf.org/rfc/rfc5208.txt - .. _OpenSSH: http://www.openssh.com/txt/rfc5656.txt - .. _RFC5480: https://tools.ietf.org/html/rfc5480 - .. _RFC5915: http://www.ietf.org/rfc/rfc5915.txt - - Returns: - A multi-line string (for PEM and OpenSSH) or bytes (for DER) with the encoded key. - """ - - args = kwargs.copy() - ext_format = args.pop("format") - if ext_format not in ("PEM", "DER", "OpenSSH"): - raise ValueError("Unknown format '%s'" % ext_format) - - compress = args.pop("compress", False) - - if self.has_private(): - passphrase = args.pop("passphrase", None) - if is_string(passphrase): - passphrase = tobytes(passphrase) - if not passphrase: - raise ValueError("Empty passphrase") - use_pkcs8 = args.pop("use_pkcs8", True) - if ext_format == "PEM": - if use_pkcs8: - if passphrase: - return self._export_private_encrypted_pkcs8_in_clear_pem(passphrase, **args) - else: - return self._export_private_clear_pkcs8_in_clear_pem() - else: - return self._export_private_pem(passphrase, **args) - elif ext_format == "DER": - # DER - if passphrase and not use_pkcs8: - raise ValueError("Private keys can only be encrpyted with DER using PKCS#8") - if use_pkcs8: - return self._export_pkcs8(passphrase=passphrase, **args) - else: - return self._export_private_der() - else: - raise ValueError("Private keys cannot be exported in OpenSSH format") - else: # Public key - if args: - raise ValueError("Unexpected parameters: '%s'" % args) - if ext_format == "PEM": - return self._export_public_pem(compress) - elif ext_format == "DER": - return self._export_subjectPublicKeyInfo(compress) - else: - return self._export_openssh(compress) - - -def generate(**kwargs): - """Generate a new private key on the given curve. - - Args: - - curve (string): - Mandatory. It must be a curve name defined in :numref:`curve_names`. - - randfunc (callable): - Optional. The RNG to read randomness from. - If ``None``, :func:`Crypto.Random.get_random_bytes` is used. - """ - - curve_name = kwargs.pop("curve") - curve = _curves[curve_name] - randfunc = kwargs.pop("randfunc", get_random_bytes) - if kwargs: - raise TypeError("Unknown parameters: " + str(kwargs)) - - d = Integer.random_range(min_inclusive=1, - max_exclusive=curve.order, - randfunc=randfunc) - - return EccKey(curve=curve_name, d=d) - - -def construct(**kwargs): - """Build a new ECC key (private or public) starting - from some base components. - - Args: - - curve (string): - Mandatory. It must be a curve name defined in :numref:`curve_names`. - - d (integer): - Only for a private key. It must be in the range ``[1..order-1]``. - - point_x (integer): - Mandatory for a public key. X coordinate (affine) of the ECC point. - - point_y (integer): - Mandatory for a public key. Y coordinate (affine) of the ECC point. - - Returns: - :class:`EccKey` : a new ECC key object - """ - - curve_name = kwargs["curve"] - curve = _curves[curve_name] - point_x = kwargs.pop("point_x", None) - point_y = kwargs.pop("point_y", None) - - if "point" in kwargs: - raise TypeError("Unknown keyword: point") - - if None not in (point_x, point_y): - # ValueError is raised if the point is not on the curve - kwargs["point"] = EccPoint(point_x, point_y, curve_name) - - # Validate that the private key matches the public one - d = kwargs.get("d", None) - if d is not None and "point" in kwargs: - pub_key = curve.G * d - if pub_key.xy != (point_x, point_y): - raise ValueError("Private and public ECC keys do not match") - - return EccKey(**kwargs) - - -def _import_public_der(curve_oid, ec_point): - """Convert an encoded EC point into an EccKey object - - curve_name: string with the OID of the curve - ec_point: byte string with the EC point (not DER encoded) - - """ - - for curve_name, curve in _curves.items(): - if curve.oid == curve_oid: - break - else: - raise UnsupportedEccFeature("Unsupported ECC curve (OID: %s)" % curve_oid) - - # See 2.2 in RFC5480 and 2.3.3 in SEC1 - # The first byte is: - # - 0x02: compressed, only X-coordinate, Y-coordinate is even - # - 0x03: compressed, only X-coordinate, Y-coordinate is odd - # - 0x04: uncompressed, X-coordinate is followed by Y-coordinate - # - # PAI is in theory encoded as 0x00. - - modulus_bytes = curve.p.size_in_bytes() - point_type = bord(ec_point[0]) - - # Uncompressed point - if point_type == 0x04: - if len(ec_point) != (1 + 2 * modulus_bytes): - raise ValueError("Incorrect EC point length") - x = Integer.from_bytes(ec_point[1:modulus_bytes+1]) - y = Integer.from_bytes(ec_point[modulus_bytes+1:]) - # Compressed point - elif point_type in (0x02, 0x3): - if len(ec_point) != (1 + modulus_bytes): - raise ValueError("Incorrect EC point length") - x = Integer.from_bytes(ec_point[1:]) - y = (x**3 - x*3 + curve.b).sqrt(curve.p) # Short Weierstrass - if point_type == 0x02 and y.is_odd(): - y = curve.p - y - if point_type == 0x03 and y.is_even(): - y = curve.p - y - else: - raise ValueError("Incorrect EC point encoding") - - return construct(curve=curve_name, point_x=x, point_y=y) - - -def _import_subjectPublicKeyInfo(encoded, *kwargs): - """Convert a subjectPublicKeyInfo into an EccKey object""" - - # See RFC5480 - - # Parse the generic subjectPublicKeyInfo structure - oid, ec_point, params = _expand_subject_public_key_info(encoded) - - # ec_point must be an encoded OCTET STRING - # params is encoded ECParameters - - # We accept id-ecPublicKey, id-ecDH, id-ecMQV without making any - # distiction for now. - - # Restrictions can be captured in the key usage certificate - # extension - unrestricted_oid = "1.2.840.10045.2.1" - ecdh_oid = "1.3.132.1.12" - ecmqv_oid = "1.3.132.1.13" - - if oid not in (unrestricted_oid, ecdh_oid, ecmqv_oid): - raise UnsupportedEccFeature("Unsupported ECC purpose (OID: %s)" % oid) - - # Parameters are mandatory for all three types - if not params: - raise ValueError("Missing ECC parameters") - - # ECParameters ::= CHOICE { - # namedCurve OBJECT IDENTIFIER - # -- implicitCurve NULL - # -- specifiedCurve SpecifiedECDomain - # } - # - # implicitCurve and specifiedCurve are not supported (as per RFC) - curve_oid = DerObjectId().decode(params).value - - return _import_public_der(curve_oid, ec_point) - - -def _import_private_der(encoded, passphrase, curve_oid=None): - - # See RFC5915 https://tools.ietf.org/html/rfc5915 - # - # ECPrivateKey ::= SEQUENCE { - # version INTEGER { ecPrivkeyVer1(1) } (ecPrivkeyVer1), - # privateKey OCTET STRING, - # parameters [0] ECParameters {{ NamedCurve }} OPTIONAL, - # publicKey [1] BIT STRING OPTIONAL - # } - - private_key = DerSequence().decode(encoded, nr_elements=(3, 4)) - if private_key[0] != 1: - raise ValueError("Incorrect ECC private key version") - - try: - parameters = DerObjectId(explicit=0).decode(private_key[2]).value - if curve_oid is not None and parameters != curve_oid: - raise ValueError("Curve mismatch") - curve_oid = parameters - except ValueError: - pass - - if curve_oid is None: - raise ValueError("No curve found") - - for curve_name, curve in _curves.items(): - if curve.oid == curve_oid: - break - else: - raise UnsupportedEccFeature("Unsupported ECC curve (OID: %s)" % curve_oid) - - scalar_bytes = DerOctetString().decode(private_key[1]).payload - modulus_bytes = curve.p.size_in_bytes() - if len(scalar_bytes) != modulus_bytes: - raise ValueError("Private key is too small") - 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 - public_key = _import_public_der(curve_oid, public_key_enc) - point_x = public_key.pointQ.x - point_y = public_key.pointQ.y - else: - point_x = point_y = None - - return construct(curve=curve_name, d=d, point_x=point_x, point_y=point_y) - - -def _import_pkcs8(encoded, passphrase): - from Crypto.IO import PKCS8 - - # From RFC5915, Section 1: - # - # Distributing an EC private key with PKCS#8 [RFC5208] involves including: - # a) id-ecPublicKey, id-ecDH, or id-ecMQV (from [RFC5480]) with the - # namedCurve as the parameters in the privateKeyAlgorithm field; and - # b) ECPrivateKey in the PrivateKey field, which is an OCTET STRING. - - algo_oid, private_key, params = PKCS8.unwrap(encoded, passphrase) - - # We accept id-ecPublicKey, id-ecDH, id-ecMQV without making any - # distiction for now. - unrestricted_oid = "1.2.840.10045.2.1" - ecdh_oid = "1.3.132.1.12" - ecmqv_oid = "1.3.132.1.13" - - if algo_oid not in (unrestricted_oid, ecdh_oid, ecmqv_oid): - raise UnsupportedEccFeature("Unsupported ECC purpose (OID: %s)" % algo_oid) - - curve_oid = DerObjectId().decode(params).value - - return _import_private_der(private_key, passphrase, curve_oid) - - -def _import_x509_cert(encoded, *kwargs): - - sp_info = _extract_subject_public_key_info(encoded) - return _import_subjectPublicKeyInfo(sp_info) - - -def _import_der(encoded, passphrase): - - try: - return _import_subjectPublicKeyInfo(encoded, passphrase) - except UnsupportedEccFeature as err: - raise err - except (ValueError, TypeError, IndexError): - pass - - try: - return _import_x509_cert(encoded, passphrase) - except UnsupportedEccFeature as err: - raise err - except (ValueError, TypeError, IndexError): - pass - - try: - return _import_private_der(encoded, passphrase) - except UnsupportedEccFeature as err: - raise err - except (ValueError, TypeError, IndexError): - pass - - try: - return _import_pkcs8(encoded, passphrase) - except UnsupportedEccFeature as err: - raise err - except (ValueError, TypeError, IndexError): - pass - - raise ValueError("Not an ECC DER key") - - -def _import_openssh_public(encoded): - keystring = binascii.a2b_base64(encoded.split(b' ')[1]) - - keyparts = [] - while len(keystring) > 4: - lk = struct.unpack(">I", keystring[:4])[0] - keyparts.append(keystring[4:4 + lk]) - keystring = keystring[4 + lk:] - - for curve_name, curve in _curves.items(): - middle = tobytes(curve.openssh.split("-")[2]) - if keyparts[1] == middle: - break - else: - raise ValueError("Unsupported ECC curve") - - return _import_public_der(curve.oid, keyparts[2]) - - -def _import_openssh_private_ecc(data, password): - - from ._openssh import (import_openssh_private_generic, - read_bytes, read_string, check_padding) - - ssh_name, decrypted = import_openssh_private_generic(data, password) - - name, decrypted = read_string(decrypted) - if name not in _curves: - raise UnsupportedEccFeature("Unsupported ECC curve %s" % name) - curve = _curves[name] - modulus_bytes = (curve.modulus_bits + 7) // 8 - - public_key, decrypted = read_bytes(decrypted) - - if bord(public_key[0]) != 4: - raise ValueError("Only uncompressed OpenSSH EC keys are supported") - if len(public_key) != 2 * modulus_bytes + 1: - raise ValueError("Incorrect public key length") - - point_x = Integer.from_bytes(public_key[1:1+modulus_bytes]) - point_y = Integer.from_bytes(public_key[1+modulus_bytes:]) - point = EccPoint(point_x, point_y, curve=name) - - private_key, decrypted = read_bytes(decrypted) - d = Integer.from_bytes(private_key) - - _, padded = read_string(decrypted) # Comment - check_padding(padded) - - return EccKey(curve=name, d=d, point=point) - - -def import_key(encoded, passphrase=None): - """Import an ECC key (public or private). - - Args: - encoded (bytes or multi-line string): - The ECC key to import. - - An ECC **public** key can be: - - - An X.509 certificate, binary (DER) or ASCII (PEM) - - An X.509 ``subjectPublicKeyInfo``, binary (DER) or ASCII (PEM) - - An OpenSSH line (e.g. the content of ``~/.ssh/id_ecdsa``, ASCII) - - An ECC **private** key can be: - - - In binary format (DER, see section 3 of `RFC5915`_ or `PKCS#8`_) - - In ASCII format (PEM or `OpenSSH 6.5+`_) - - Private keys can be in the clear or password-protected. - - For details about the PEM encoding, see `RFC1421`_/`RFC1423`_. - - passphrase (byte string): - The passphrase to use for decrypting a private key. - Encryption may be applied protected at the PEM level or at the PKCS#8 level. - This parameter is ignored if the key in input is not encrypted. - - Returns: - :class:`EccKey` : a new ECC key object - - Raises: - ValueError: when the given key cannot be parsed (possibly because - the pass phrase is wrong). - - .. _RFC1421: http://www.ietf.org/rfc/rfc1421.txt - .. _RFC1423: http://www.ietf.org/rfc/rfc1423.txt - .. _RFC5915: http://www.ietf.org/rfc/rfc5915.txt - .. _`PKCS#8`: http://www.ietf.org/rfc/rfc5208.txt - .. _`OpenSSH 6.5+`: https://flak.tedunangst.com/post/new-openssh-key-format-and-bcrypt-pbkdf - """ - - from Crypto.IO import PEM - - encoded = tobytes(encoded) - if passphrase is not None: - passphrase = tobytes(passphrase) - - # PEM - if encoded.startswith(b'-----BEGIN OPENSSH PRIVATE KEY'): - text_encoded = tostr(encoded) - openssh_encoded, marker, enc_flag = PEM.decode(text_encoded, passphrase) - result = _import_openssh_private_ecc(openssh_encoded, passphrase) - return result - - elif encoded.startswith(b'-----'): - - text_encoded = tostr(encoded) - - # Remove any EC PARAMETERS section - # Ignore its content because the curve type must be already given in the key - ecparams_start = "-----BEGIN EC PARAMETERS-----" - ecparams_end = "-----END EC PARAMETERS-----" - text_encoded = re.sub(ecparams_start + ".*?" + ecparams_end, "", - text_encoded, - flags=re.DOTALL) - - der_encoded, marker, enc_flag = PEM.decode(text_encoded, passphrase) - if enc_flag: - passphrase = None - try: - result = _import_der(der_encoded, passphrase) - except UnsupportedEccFeature as uef: - raise uef - except ValueError: - raise ValueError("Invalid DER encoding inside the PEM file") - return result - - # OpenSSH - if encoded.startswith(b'ecdsa-sha2-'): - return _import_openssh_public(encoded) - - # DER - if len(encoded) > 0 and bord(encoded[0]) == 0x30: - return _import_der(encoded, passphrase) - - raise ValueError("ECC key format is not supported") - - -if __name__ == "__main__": - - import time - - d = 0xc51e4753afdec1e6b6c6a5b992f43f8dd0c7a8933072708b6522468b2ffb06fd - - point = _curves['p256'].G.copy() - count = 3000 - - start = time.time() - for x in range(count): - pointX = point * d - print("(P-256 G)", (time.time() - start) / count * 1000, "ms") - - start = time.time() - for x in range(count): - pointX = pointX * d - print("(P-256 arbitrary point)", (time.time() - start) / count * 1000, "ms") diff --git a/Crypto/PublicKey/ECC.pyi b/Crypto/PublicKey/ECC.pyi deleted file mode 100644 index acf3164..0000000 --- a/Crypto/PublicKey/ECC.pyi +++ /dev/null @@ -1,62 +0,0 @@ -from typing import Union, Callable, Optional, NamedTuple, List, Tuple, Dict, NamedTuple, Any - -from Crypto.Math.Numbers import Integer - -RNG = Callable[[int], bytes] - -class UnsupportedEccFeature(ValueError): ... -class EccPoint(object): - def __init__(self, x: Union[int, Integer], y: Union[int, Integer], curve: Optional[str] = ...) -> None: ... - def set(self, point: EccPoint) -> EccPoint: ... - def __eq__(self, point: object) -> bool: ... - def __neg__(self) -> EccPoint: ... - def copy(self) -> EccPoint: ... - def is_point_at_infinity(self) -> bool: ... - def point_at_infinity(self) -> EccPoint: ... - @property - def x(self) -> int: ... - @property - def y(self) -> int: ... - @property - def xy(self) -> Tuple[int, int]: ... - def size_in_bytes(self) -> int: ... - def size_in_bits(self) -> int: ... - def double(self) -> EccPoint: ... - def __iadd__(self, point: EccPoint) -> EccPoint: ... - def __add__(self, point: EccPoint) -> EccPoint: ... - def __imul__(self, scalar: int) -> EccPoint: ... - def __mul__(self, scalar: int) -> EccPoint: ... - -class EccKey(object): - curve: str - def __init__(self, *, curve: str = ..., d: int = ..., point: EccPoint = ...) -> None: ... - def __eq__(self, other: object) -> bool: ... - def __repr__(self) -> str: ... - def has_private(self) -> bool: ... - @property - def d(self) -> int: ... - @property - def pointQ(self) -> EccPoint: ... - def public_key(self) -> EccKey: ... - def export_key(self, **kwargs: Union[str, bytes, bool]) -> str: ... - - -_Curve = NamedTuple("_Curve", [('p', Integer), - ('order', Integer), - ('b', Integer), - ('Gx', Integer), - ('Gy', Integer), - ('G', EccPoint), - ('modulus_bits', int), - ('oid', str), - ('context', Any), - ('desc', str), - ('openssh', str), - ]) - -_curves : Dict[str, _Curve] - - -def generate(**kwargs: Union[str, RNG]) -> EccKey: ... -def construct(**kwargs: Union[str, int]) -> EccKey: ... -def import_key(encoded: Union[bytes, str], passphrase: Optional[str]=None) -> EccKey: ... diff --git a/Crypto/PublicKey/ElGamal.py b/Crypto/PublicKey/ElGamal.py deleted file mode 100644 index 3b10840..0000000 --- a/Crypto/PublicKey/ElGamal.py +++ /dev/null @@ -1,286 +0,0 @@ -# -# ElGamal.py : ElGamal encryption/decryption and signatures -# -# Part of the Python Cryptography Toolkit -# -# Originally written by: A.M. Kuchling -# -# =================================================================== -# The contents of this file are dedicated to the public domain. To -# the extent that dedication to the public domain is not available, -# everyone is granted a worldwide, perpetual, royalty-free, -# non-exclusive license to exercise all rights associated with the -# contents of this file for any purpose whatsoever. -# No rights are reserved. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS -# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN -# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# =================================================================== - -__all__ = ['generate', 'construct', 'ElGamalKey'] - -from Crypto import Random -from Crypto.Math.Primality import ( generate_probable_safe_prime, - test_probable_prime, COMPOSITE ) -from Crypto.Math.Numbers import Integer - -# Generate an ElGamal key with N bits -def generate(bits, randfunc): - """Randomly generate a fresh, new ElGamal key. - - The key will be safe for use for both encryption and signature - (although it should be used for **only one** purpose). - - Args: - bits (int): - Key length, or size (in bits) of the modulus *p*. - The recommended value is 2048. - randfunc (callable): - Random number generation function; it should accept - a single integer *N* and return a string of random - *N* random bytes. - - Return: - an :class:`ElGamalKey` object - """ - - obj=ElGamalKey() - - # Generate a safe prime p - # See Algorithm 4.86 in Handbook of Applied Cryptography - obj.p = generate_probable_safe_prime(exact_bits=bits, randfunc=randfunc) - q = (obj.p - 1) >> 1 - - # Generate generator g - while 1: - # Choose a square residue; it will generate a cyclic group of order q. - obj.g = pow(Integer.random_range(min_inclusive=2, - max_exclusive=obj.p, - randfunc=randfunc), 2, obj.p) - - # We must avoid g=2 because of Bleichenbacher's attack described - # in "Generating ElGamal signatures without knowning the secret key", - # 1996 - if obj.g in (1, 2): - continue - - # Discard g if it divides p-1 because of the attack described - # in Note 11.67 (iii) in HAC - if (obj.p - 1) % obj.g == 0: - continue - - # g^{-1} must not divide p-1 because of Khadir's attack - # described in "Conditions of the generator for forging ElGamal - # signature", 2011 - ginv = obj.g.inverse(obj.p) - if (obj.p - 1) % ginv == 0: - continue - - # Found - break - - # Generate private key x - obj.x = Integer.random_range(min_inclusive=2, - max_exclusive=obj.p-1, - randfunc=randfunc) - # Generate public key y - obj.y = pow(obj.g, obj.x, obj.p) - return obj - -def construct(tup): - r"""Construct an ElGamal key from a tuple of valid ElGamal components. - - The modulus *p* must be a prime. - The following conditions must apply: - - .. math:: - - \begin{align} - &1 < g < p-1 \\ - &g^{p-1} = 1 \text{ mod } 1 \\ - &1 < x < p-1 \\ - &g^x = y \text{ mod } p - \end{align} - - Args: - tup (tuple): - A tuple with either 3 or 4 integers, - in the following order: - - 1. Modulus (*p*). - 2. Generator (*g*). - 3. Public key (*y*). - 4. Private key (*x*). Optional. - - Raises: - ValueError: when the key being imported fails the most basic ElGamal validity checks. - - Returns: - an :class:`ElGamalKey` object - """ - - obj=ElGamalKey() - if len(tup) not in [3,4]: - raise ValueError('argument for construct() wrong length') - for i in range(len(tup)): - field = obj._keydata[i] - setattr(obj, field, Integer(tup[i])) - - fmt_error = test_probable_prime(obj.p) == COMPOSITE - fmt_error |= obj.g<=1 or obj.g>=obj.p - fmt_error |= pow(obj.g, obj.p-1, obj.p)!=1 - fmt_error |= obj.y<1 or obj.y>=obj.p - if len(tup)==4: - fmt_error |= obj.x<=1 or obj.x>=obj.p - fmt_error |= pow(obj.g, obj.x, obj.p)!=obj.y - - if fmt_error: - raise ValueError("Invalid ElGamal key components") - - return obj - -class ElGamalKey(object): - r"""Class defining an ElGamal key. - Do not instantiate directly. - Use :func:`generate` or :func:`construct` instead. - - :ivar p: Modulus - :vartype d: integer - - :ivar g: Generator - :vartype e: integer - - :ivar y: Public key component - :vartype y: integer - - :ivar x: Private key component - :vartype x: integer - """ - - #: Dictionary of ElGamal parameters. - #: - #: A public key will only have the following entries: - #: - #: - **y**, the public key. - #: - **g**, the generator. - #: - **p**, the modulus. - #: - #: A private key will also have: - #: - #: - **x**, the private key. - _keydata=['p', 'g', 'y', 'x'] - - def __init__(self, randfunc=None): - if randfunc is None: - randfunc = Random.new().read - self._randfunc = randfunc - - def _encrypt(self, M, K): - a=pow(self.g, K, self.p) - b=( pow(self.y, K, self.p)*M ) % self.p - return [int(a), int(b)] - - def _decrypt(self, M): - if (not hasattr(self, 'x')): - raise TypeError('Private key not available in this object') - r = Integer.random_range(min_inclusive=2, - max_exclusive=self.p-1, - randfunc=self._randfunc) - a_blind = (pow(self.g, r, self.p) * M[0]) % self.p - ax=pow(a_blind, self.x, self.p) - plaintext_blind = (ax.inverse(self.p) * M[1] ) % self.p - plaintext = (plaintext_blind * pow(self.y, r, self.p)) % self.p - return int(plaintext) - - def _sign(self, M, K): - if (not hasattr(self, 'x')): - raise TypeError('Private key not available in this object') - p1=self.p-1 - K = Integer(K) - if (K.gcd(p1)!=1): - raise ValueError('Bad K value: GCD(K,p-1)!=1') - a=pow(self.g, K, self.p) - t=(Integer(M)-self.x*a) % p1 - while t<0: t=t+p1 - b=(t*K.inverse(p1)) % p1 - return [int(a), int(b)] - - def _verify(self, M, sig): - sig = [Integer(x) for x in sig] - if sig[0]<1 or sig[0]>self.p-1: - return 0 - v1=pow(self.y, sig[0], self.p) - v1=(v1*pow(sig[0], sig[1], self.p)) % self.p - v2=pow(self.g, M, self.p) - if v1==v2: - return 1 - return 0 - - def has_private(self): - """Whether this is an ElGamal private key""" - - if hasattr(self, 'x'): - return 1 - else: - return 0 - - def can_encrypt(self): - return True - - def can_sign(self): - return True - - def publickey(self): - """A matching ElGamal public key. - - Returns: - a new :class:`ElGamalKey` object - """ - return construct((self.p, self.g, self.y)) - - def __eq__(self, other): - if bool(self.has_private()) != bool(other.has_private()): - return False - - result = True - for comp in self._keydata: - result = result and (getattr(self.key, comp, None) == - getattr(other.key, comp, None)) - return result - - def __ne__(self, other): - return not self.__eq__(other) - - def __getstate__(self): - # ElGamal key is not pickable - from pickle import PicklingError - raise PicklingError - - # Methods defined in PyCrypto that we don't support anymore - - def sign(self, M, K): - raise NotImplementedError - - def verify(self, M, signature): - raise NotImplementedError - - def encrypt(self, plaintext, K): - raise NotImplementedError - - def decrypt(self, ciphertext): - raise NotImplementedError - - def blind(self, M, B): - raise NotImplementedError - - def unblind(self, M, B): - raise NotImplementedError - - def size(self): - raise NotImplementedError diff --git a/Crypto/PublicKey/ElGamal.pyi b/Crypto/PublicKey/ElGamal.pyi deleted file mode 100644 index 9048531..0000000 --- a/Crypto/PublicKey/ElGamal.pyi +++ /dev/null @@ -1,18 +0,0 @@ -from typing import Callable, Union, Tuple, Optional - -__all__ = ['generate', 'construct', 'ElGamalKey'] - -RNG = Callable[[int], bytes] - -def generate(bits: int, randfunc: RNG) -> ElGamalKey: ... -def construct(tup: Union[Tuple[int, int, int], Tuple[int, int, int, int]]) -> ElGamalKey: ... - -class ElGamalKey(object): - def __init__(self, randfunc: Optional[RNG]=None) -> None: ... - def has_private(self) -> bool: ... - def can_encrypt(self) -> bool: ... - def can_sign(self) -> bool: ... - def publickey(self) -> ElGamalKey: ... - def __eq__(self, other: object) -> bool: ... - def __ne__(self, other: object) -> bool: ... - def __getstate__(self) -> None: ... diff --git a/Crypto/PublicKey/RSA.py b/Crypto/PublicKey/RSA.py deleted file mode 100644 index fda3b2a..0000000 --- a/Crypto/PublicKey/RSA.py +++ /dev/null @@ -1,799 +0,0 @@ -# -*- coding: utf-8 -*- -# =================================================================== -# -# Copyright (c) 2016, Legrandin -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# =================================================================== - -__all__ = ['generate', 'construct', 'import_key', - 'RsaKey', 'oid'] - -import binascii -import struct - -from Crypto import Random -from Crypto.Util.py3compat import tobytes, bord, tostr -from Crypto.Util.asn1 import DerSequence - -from Crypto.Math.Numbers import Integer -from Crypto.Math.Primality import (test_probable_prime, - generate_probable_prime, COMPOSITE) - -from Crypto.PublicKey import (_expand_subject_public_key_info, - _create_subject_public_key_info, - _extract_subject_public_key_info) - - -class RsaKey(object): - r"""Class defining an actual RSA key. - Do not instantiate directly. - Use :func:`generate`, :func:`construct` or :func:`import_key` instead. - - :ivar n: RSA modulus - :vartype n: integer - - :ivar e: RSA public exponent - :vartype e: integer - - :ivar d: RSA private exponent - :vartype d: integer - - :ivar p: First factor of the RSA modulus - :vartype p: integer - - :ivar q: Second factor of the RSA modulus - :vartype q: integer - - :ivar u: Chinese remainder component (:math:`p^{-1} \text{mod } q`) - :vartype q: integer - - :undocumented: exportKey, publickey - """ - - def __init__(self, **kwargs): - """Build an RSA key. - - :Keywords: - n : integer - The modulus. - e : integer - The public exponent. - d : integer - The private exponent. Only required for private keys. - p : integer - The first factor of the modulus. Only required for private keys. - q : integer - The second factor of the modulus. Only required for private keys. - u : integer - The CRT coefficient (inverse of p modulo q). Only required for - private keys. - """ - - input_set = set(kwargs.keys()) - public_set = set(('n', 'e')) - private_set = public_set | set(('p', 'q', 'd', 'u')) - if input_set not in (private_set, public_set): - raise ValueError("Some RSA components are missing") - for component, value in kwargs.items(): - setattr(self, "_" + component, value) - if input_set == private_set: - self._dp = self._d % (self._p - 1) # = (e⁻¹) mod (p-1) - self._dq = self._d % (self._q - 1) # = (e⁻¹) mod (q-1) - - @property - def n(self): - return int(self._n) - - @property - def e(self): - return int(self._e) - - @property - def d(self): - if not self.has_private(): - raise AttributeError("No private exponent available for public keys") - return int(self._d) - - @property - def p(self): - if not self.has_private(): - raise AttributeError("No CRT component 'p' available for public keys") - return int(self._p) - - @property - def q(self): - if not self.has_private(): - raise AttributeError("No CRT component 'q' available for public keys") - return int(self._q) - - @property - def u(self): - if not self.has_private(): - raise AttributeError("No CRT component 'u' available for public keys") - return int(self._u) - - def size_in_bits(self): - """Size of the RSA modulus in bits""" - return self._n.size_in_bits() - - def size_in_bytes(self): - """The minimal amount of bytes that can hold the RSA modulus""" - return (self._n.size_in_bits() - 1) // 8 + 1 - - def _encrypt(self, plaintext): - if not 0 <= plaintext < self._n: - raise ValueError("Plaintext too large") - return int(pow(Integer(plaintext), self._e, self._n)) - - def _decrypt(self, ciphertext): - if not 0 <= ciphertext < self._n: - raise ValueError("Ciphertext too large") - if not self.has_private(): - raise TypeError("This is not a private key") - - # Blinded RSA decryption (to prevent timing attacks): - # Step 1: Generate random secret blinding factor r, - # such that 0 < r < n-1 - r = Integer.random_range(min_inclusive=1, max_exclusive=self._n) - # Step 2: Compute c' = c * r**e mod n - cp = Integer(ciphertext) * pow(r, self._e, self._n) % self._n - # Step 3: Compute m' = c'**d mod n (normal RSA decryption) - m1 = pow(cp, self._dp, self._p) - m2 = pow(cp, self._dq, self._q) - h = ((m2 - m1) * self._u) % self._q - mp = h * self._p + m1 - # Step 4: Compute m = m**(r-1) mod n - result = (r.inverse(self._n) * mp) % self._n - # Verify no faults occurred - if ciphertext != pow(result, self._e, self._n): - raise ValueError("Fault detected in RSA decryption") - return result - - def has_private(self): - """Whether this is an RSA private key""" - - return hasattr(self, "_d") - - def can_encrypt(self): # legacy - return True - - def can_sign(self): # legacy - return True - - def public_key(self): - """A matching RSA public key. - - Returns: - a new :class:`RsaKey` object - """ - return RsaKey(n=self._n, e=self._e) - - def __eq__(self, other): - if self.has_private() != other.has_private(): - return False - if self.n != other.n or self.e != other.e: - return False - if not self.has_private(): - return True - return (self.d == other.d) - - def __ne__(self, other): - return not (self == other) - - def __getstate__(self): - # RSA key is not pickable - from pickle import PicklingError - raise PicklingError - - def __repr__(self): - if self.has_private(): - extra = ", d=%d, p=%d, q=%d, u=%d" % (int(self._d), int(self._p), - int(self._q), int(self._u)) - else: - extra = "" - return "RsaKey(n=%d, e=%d%s)" % (int(self._n), int(self._e), extra) - - def __str__(self): - if self.has_private(): - key_type = "Private" - else: - key_type = "Public" - return "%s RSA key at 0x%X" % (key_type, id(self)) - - def export_key(self, format='PEM', passphrase=None, pkcs=1, - protection=None, randfunc=None): - """Export this RSA key. - - Args: - format (string): - The format to use for wrapping the key: - - - *'PEM'*. (*Default*) Text encoding, done according to `RFC1421`_/`RFC1423`_. - - *'DER'*. Binary encoding. - - *'OpenSSH'*. Textual encoding, done according to OpenSSH specification. - Only suitable for public keys (not private keys). - - passphrase (string): - (*For private keys only*) The pass phrase used for protecting the output. - - pkcs (integer): - (*For private keys only*) The ASN.1 structure to use for - serializing the key. Note that even in case of PEM - encoding, there is an inner ASN.1 DER structure. - - With ``pkcs=1`` (*default*), the private key is encoded in a - simple `PKCS#1`_ structure (``RSAPrivateKey``). - - With ``pkcs=8``, the private key is encoded in a `PKCS#8`_ structure - (``PrivateKeyInfo``). - - .. note:: - This parameter is ignored for a public key. - For DER and PEM, an ASN.1 DER ``SubjectPublicKeyInfo`` - structure is always used. - - protection (string): - (*For private keys only*) - The encryption scheme to use for protecting the private key. - - If ``None`` (default), the behavior depends on :attr:`format`: - - - For *'DER'*, the *PBKDF2WithHMAC-SHA1AndDES-EDE3-CBC* - scheme is used. The following operations are performed: - - 1. A 16 byte Triple DES key is derived from the passphrase - using :func:`Crypto.Protocol.KDF.PBKDF2` with 8 bytes salt, - and 1 000 iterations of :mod:`Crypto.Hash.HMAC`. - 2. The private key is encrypted using CBC. - 3. The encrypted key is encoded according to PKCS#8. - - - For *'PEM'*, the obsolete PEM encryption scheme is used. - It is based on MD5 for key derivation, and Triple DES for encryption. - - Specifying a value for :attr:`protection` is only meaningful for PKCS#8 - (that is, ``pkcs=8``) and only if a pass phrase is present too. - - The supported schemes for PKCS#8 are listed in the - :mod:`Crypto.IO.PKCS8` module (see :attr:`wrap_algo` parameter). - - randfunc (callable): - A function that provides random bytes. Only used for PEM encoding. - The default is :func:`Crypto.Random.get_random_bytes`. - - Returns: - byte string: the encoded key - - Raises: - ValueError:when the format is unknown or when you try to encrypt a private - key with *DER* format and PKCS#1. - - .. warning:: - If you don't provide a pass phrase, the private key will be - exported in the clear! - - .. _RFC1421: http://www.ietf.org/rfc/rfc1421.txt - .. _RFC1423: http://www.ietf.org/rfc/rfc1423.txt - .. _`PKCS#1`: http://www.ietf.org/rfc/rfc3447.txt - .. _`PKCS#8`: http://www.ietf.org/rfc/rfc5208.txt - """ - - if passphrase is not None: - passphrase = tobytes(passphrase) - - if randfunc is None: - randfunc = Random.get_random_bytes - - if format == 'OpenSSH': - e_bytes, n_bytes = [x.to_bytes() for x in (self._e, self._n)] - if bord(e_bytes[0]) & 0x80: - e_bytes = b'\x00' + e_bytes - if bord(n_bytes[0]) & 0x80: - n_bytes = b'\x00' + n_bytes - keyparts = [b'ssh-rsa', e_bytes, n_bytes] - keystring = b''.join([struct.pack(">I", len(kp)) + kp for kp in keyparts]) - return b'ssh-rsa ' + binascii.b2a_base64(keystring)[:-1] - - # DER format is always used, even in case of PEM, which simply - # encodes it into BASE64. - if self.has_private(): - binary_key = DerSequence([0, - self.n, - self.e, - self.d, - self.p, - self.q, - self.d % (self.p-1), - self.d % (self.q-1), - Integer(self.q).inverse(self.p) - ]).encode() - if pkcs == 1: - key_type = 'RSA PRIVATE KEY' - if format == 'DER' and passphrase: - raise ValueError("PKCS#1 private key cannot be encrypted") - else: # PKCS#8 - from Crypto.IO import PKCS8 - - if format == 'PEM' and protection is None: - key_type = 'PRIVATE KEY' - binary_key = PKCS8.wrap(binary_key, oid, None) - else: - key_type = 'ENCRYPTED PRIVATE KEY' - if not protection: - protection = 'PBKDF2WithHMAC-SHA1AndDES-EDE3-CBC' - binary_key = PKCS8.wrap(binary_key, oid, - passphrase, protection) - passphrase = None - else: - key_type = "PUBLIC KEY" - binary_key = _create_subject_public_key_info(oid, - DerSequence([self.n, - self.e]) - ) - - if format == 'DER': - return binary_key - if format == 'PEM': - from Crypto.IO import PEM - - pem_str = PEM.encode(binary_key, key_type, passphrase, randfunc) - return tobytes(pem_str) - - raise ValueError("Unknown key format '%s'. Cannot export the RSA key." % format) - - # Backward compatibility - exportKey = export_key - publickey = public_key - - # Methods defined in PyCrypto that we don't support anymore - def sign(self, M, K): - raise NotImplementedError("Use module Crypto.Signature.pkcs1_15 instead") - - def verify(self, M, signature): - raise NotImplementedError("Use module Crypto.Signature.pkcs1_15 instead") - - def encrypt(self, plaintext, K): - raise NotImplementedError("Use module Crypto.Cipher.PKCS1_OAEP instead") - - def decrypt(self, ciphertext): - raise NotImplementedError("Use module Crypto.Cipher.PKCS1_OAEP instead") - - def blind(self, M, B): - raise NotImplementedError - - def unblind(self, M, B): - raise NotImplementedError - - def size(self): - raise NotImplementedError - - -def generate(bits, randfunc=None, e=65537): - """Create a new RSA key pair. - - The algorithm closely follows NIST `FIPS 186-4`_ in its - sections B.3.1 and B.3.3. The modulus is the product of - two non-strong probable primes. - Each prime passes a suitable number of Miller-Rabin tests - with random bases and a single Lucas test. - - Args: - bits (integer): - Key length, or size (in bits) of the RSA modulus. - It must be at least 1024, but **2048 is recommended.** - The FIPS standard only defines 1024, 2048 and 3072. - randfunc (callable): - Function that returns random bytes. - The default is :func:`Crypto.Random.get_random_bytes`. - e (integer): - Public RSA exponent. It must be an odd positive integer. - It is typically a small number with very few ones in its - binary representation. - The FIPS standard requires the public exponent to be - at least 65537 (the default). - - Returns: an RSA key object (:class:`RsaKey`, with private key). - - .. _FIPS 186-4: http://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.186-4.pdf - """ - - if bits < 1024: - raise ValueError("RSA modulus length must be >= 1024") - if e % 2 == 0 or e < 3: - raise ValueError("RSA public exponent must be a positive, odd integer larger than 2.") - - if randfunc is None: - randfunc = Random.get_random_bytes - - d = n = Integer(1) - e = Integer(e) - - while n.size_in_bits() != bits and d < (1 << (bits // 2)): - # Generate the prime factors of n: p and q. - # By construciton, their product is always - # 2^{bits-1} < p*q < 2^bits. - size_q = bits // 2 - size_p = bits - size_q - - min_p = min_q = (Integer(1) << (2 * size_q - 1)).sqrt() - if size_q != size_p: - min_p = (Integer(1) << (2 * size_p - 1)).sqrt() - - def filter_p(candidate): - return candidate > min_p and (candidate - 1).gcd(e) == 1 - - p = generate_probable_prime(exact_bits=size_p, - randfunc=randfunc, - prime_filter=filter_p) - - min_distance = Integer(1) << (bits // 2 - 100) - - def filter_q(candidate): - return (candidate > min_q and - (candidate - 1).gcd(e) == 1 and - abs(candidate - p) > min_distance) - - q = generate_probable_prime(exact_bits=size_q, - randfunc=randfunc, - prime_filter=filter_q) - - n = p * q - lcm = (p - 1).lcm(q - 1) - d = e.inverse(lcm) - - if p > q: - p, q = q, p - - u = p.inverse(q) - - return RsaKey(n=n, e=e, d=d, p=p, q=q, u=u) - - -def construct(rsa_components, consistency_check=True): - r"""Construct an RSA key from a tuple of valid RSA components. - - The modulus **n** must be the product of two primes. - The public exponent **e** must be odd and larger than 1. - - In case of a private key, the following equations must apply: - - .. math:: - - \begin{align} - p*q &= n \\ - e*d &\equiv 1 ( \text{mod lcm} [(p-1)(q-1)]) \\ - p*u &\equiv 1 ( \text{mod } q) - \end{align} - - Args: - rsa_components (tuple): - A tuple of integers, with at least 2 and no - more than 6 items. The items come in the following order: - - 1. RSA modulus *n*. - 2. Public exponent *e*. - 3. Private exponent *d*. - Only required if the key is private. - 4. First factor of *n* (*p*). - Optional, but the other factor *q* must also be present. - 5. Second factor of *n* (*q*). Optional. - 6. CRT coefficient *q*, that is :math:`p^{-1} \text{mod }q`. Optional. - - consistency_check (boolean): - If ``True``, the library will verify that the provided components - fulfil the main RSA properties. - - Raises: - ValueError: when the key being imported fails the most basic RSA validity checks. - - Returns: An RSA key object (:class:`RsaKey`). - """ - - class InputComps(object): - pass - - input_comps = InputComps() - for (comp, value) in zip(('n', 'e', 'd', 'p', 'q', 'u'), rsa_components): - setattr(input_comps, comp, Integer(value)) - - n = input_comps.n - e = input_comps.e - if not hasattr(input_comps, 'd'): - key = RsaKey(n=n, e=e) - else: - d = input_comps.d - if hasattr(input_comps, 'q'): - p = input_comps.p - q = input_comps.q - else: - # Compute factors p and q from the private exponent d. - # We assume that n has no more than two factors. - # See 8.2.2(i) in Handbook of Applied Cryptography. - ktot = d * e - 1 - # The quantity d*e-1 is a multiple of phi(n), even, - # and can be represented as t*2^s. - t = ktot - while t % 2 == 0: - t //= 2 - # Cycle through all multiplicative inverses in Zn. - # The algorithm is non-deterministic, but there is a 50% chance - # any candidate a leads to successful factoring. - # See "Digitalized Signatures and Public Key Functions as Intractable - # as Factorization", M. Rabin, 1979 - spotted = False - a = Integer(2) - while not spotted and a < 100: - k = Integer(t) - # Cycle through all values a^{t*2^i}=a^k - while k < ktot: - cand = pow(a, k, n) - # Check if a^k is a non-trivial root of unity (mod n) - if cand != 1 and cand != (n - 1) and pow(cand, 2, n) == 1: - # We have found a number such that (cand-1)(cand+1)=0 (mod n). - # Either of the terms divides n. - p = Integer(n).gcd(cand + 1) - spotted = True - break - k *= 2 - # This value was not any good... let's try another! - a += 2 - if not spotted: - raise ValueError("Unable to compute factors p and q from exponent d.") - # Found ! - assert ((n % p) == 0) - q = n // p - - if hasattr(input_comps, 'u'): - u = input_comps.u - else: - u = p.inverse(q) - - # Build key object - key = RsaKey(n=n, e=e, d=d, p=p, q=q, u=u) - - # Verify consistency of the key - if consistency_check: - - # Modulus and public exponent must be coprime - if e <= 1 or e >= n: - raise ValueError("Invalid RSA public exponent") - if Integer(n).gcd(e) != 1: - raise ValueError("RSA public exponent is not coprime to modulus") - - # For RSA, modulus must be odd - if not n & 1: - raise ValueError("RSA modulus is not odd") - - if key.has_private(): - # Modulus and private exponent must be coprime - if d <= 1 or d >= n: - raise ValueError("Invalid RSA private exponent") - if Integer(n).gcd(d) != 1: - raise ValueError("RSA private exponent is not coprime to modulus") - # Modulus must be product of 2 primes - if p * q != n: - raise ValueError("RSA factors do not match modulus") - if test_probable_prime(p) == COMPOSITE: - raise ValueError("RSA factor p is composite") - if test_probable_prime(q) == COMPOSITE: - raise ValueError("RSA factor q is composite") - # See Carmichael theorem - phi = (p - 1) * (q - 1) - lcm = phi // (p - 1).gcd(q - 1) - if (e * d % int(lcm)) != 1: - raise ValueError("Invalid RSA condition") - if hasattr(key, 'u'): - # CRT coefficient - if u <= 1 or u >= q: - raise ValueError("Invalid RSA component u") - if (p * u % q) != 1: - raise ValueError("Invalid RSA component u with p") - - return key - - -def _import_pkcs1_private(encoded, *kwargs): - # RSAPrivateKey ::= SEQUENCE { - # version Version, - # modulus INTEGER, -- n - # publicExponent INTEGER, -- e - # privateExponent INTEGER, -- d - # prime1 INTEGER, -- p - # prime2 INTEGER, -- q - # exponent1 INTEGER, -- d mod (p-1) - # exponent2 INTEGER, -- d mod (q-1) - # coefficient INTEGER -- (inverse of q) mod p - # } - # - # Version ::= INTEGER - der = DerSequence().decode(encoded, nr_elements=9, only_ints_expected=True) - if der[0] != 0: - raise ValueError("No PKCS#1 encoding of an RSA private key") - return construct(der[1:6] + [Integer(der[4]).inverse(der[5])]) - - -def _import_pkcs1_public(encoded, *kwargs): - # RSAPublicKey ::= SEQUENCE { - # modulus INTEGER, -- n - # publicExponent INTEGER -- e - # } - der = DerSequence().decode(encoded, nr_elements=2, only_ints_expected=True) - return construct(der) - - -def _import_subjectPublicKeyInfo(encoded, *kwargs): - - algoid, encoded_key, params = _expand_subject_public_key_info(encoded) - if algoid != oid or params is not None: - raise ValueError("No RSA subjectPublicKeyInfo") - return _import_pkcs1_public(encoded_key) - - -def _import_x509_cert(encoded, *kwargs): - - sp_info = _extract_subject_public_key_info(encoded) - return _import_subjectPublicKeyInfo(sp_info) - - -def _import_pkcs8(encoded, passphrase): - from Crypto.IO import PKCS8 - - k = PKCS8.unwrap(encoded, passphrase) - if k[0] != oid: - raise ValueError("No PKCS#8 encoded RSA key") - return _import_keyDER(k[1], passphrase) - - -def _import_keyDER(extern_key, passphrase): - """Import an RSA key (public or private half), encoded in DER form.""" - - decodings = (_import_pkcs1_private, - _import_pkcs1_public, - _import_subjectPublicKeyInfo, - _import_x509_cert, - _import_pkcs8) - - for decoding in decodings: - try: - return decoding(extern_key, passphrase) - except ValueError: - pass - - raise ValueError("RSA key format is not supported") - - -def _import_openssh_private_rsa(data, password): - - from ._openssh import (import_openssh_private_generic, - read_bytes, read_string, check_padding) - - ssh_name, decrypted = import_openssh_private_generic(data, password) - - if ssh_name != "ssh-rsa": - raise ValueError("This SSH key is not RSA") - - n, decrypted = read_bytes(decrypted) - e, decrypted = read_bytes(decrypted) - d, decrypted = read_bytes(decrypted) - iqmp, decrypted = read_bytes(decrypted) - p, decrypted = read_bytes(decrypted) - q, decrypted = read_bytes(decrypted) - - _, padded = read_string(decrypted) # Comment - check_padding(padded) - - build = [Integer.from_bytes(x) for x in (n, e, d, q, p, iqmp)] - return construct(build) - - -def import_key(extern_key, passphrase=None): - """Import an RSA key (public or private). - - Args: - extern_key (string or byte string): - The RSA key to import. - - The following formats are supported for an RSA **public key**: - - - X.509 certificate (binary or PEM format) - - X.509 ``subjectPublicKeyInfo`` DER SEQUENCE (binary or PEM - encoding) - - `PKCS#1`_ ``RSAPublicKey`` DER SEQUENCE (binary or PEM encoding) - - An OpenSSH line (e.g. the content of ``~/.ssh/id_ecdsa``, ASCII) - - The following formats are supported for an RSA **private key**: - - - PKCS#1 ``RSAPrivateKey`` DER SEQUENCE (binary or PEM encoding) - - `PKCS#8`_ ``PrivateKeyInfo`` or ``EncryptedPrivateKeyInfo`` - DER SEQUENCE (binary or PEM encoding) - - OpenSSH (text format, introduced in `OpenSSH 6.5`_) - - For details about the PEM encoding, see `RFC1421`_/`RFC1423`_. - - passphrase (string or byte string): - For private keys only, the pass phrase that encrypts the key. - - Returns: An RSA key object (:class:`RsaKey`). - - Raises: - ValueError/IndexError/TypeError: - When the given key cannot be parsed (possibly because the pass - phrase is wrong). - - .. _RFC1421: http://www.ietf.org/rfc/rfc1421.txt - .. _RFC1423: http://www.ietf.org/rfc/rfc1423.txt - .. _`PKCS#1`: http://www.ietf.org/rfc/rfc3447.txt - .. _`PKCS#8`: http://www.ietf.org/rfc/rfc5208.txt - .. _`OpenSSH 6.5`: https://flak.tedunangst.com/post/new-openssh-key-format-and-bcrypt-pbkdf - """ - - from Crypto.IO import PEM - - extern_key = tobytes(extern_key) - if passphrase is not None: - passphrase = tobytes(passphrase) - - if extern_key.startswith(b'-----BEGIN OPENSSH PRIVATE KEY'): - text_encoded = tostr(extern_key) - openssh_encoded, marker, enc_flag = PEM.decode(text_encoded, passphrase) - result = _import_openssh_private_rsa(openssh_encoded, passphrase) - return result - - if extern_key.startswith(b'-----'): - # This is probably a PEM encoded key. - (der, marker, enc_flag) = PEM.decode(tostr(extern_key), passphrase) - if enc_flag: - passphrase = None - return _import_keyDER(der, passphrase) - - if extern_key.startswith(b'ssh-rsa '): - # This is probably an OpenSSH key - keystring = binascii.a2b_base64(extern_key.split(b' ')[1]) - keyparts = [] - while len(keystring) > 4: - length = struct.unpack(">I", keystring[:4])[0] - keyparts.append(keystring[4:4 + length]) - keystring = keystring[4 + length:] - e = Integer.from_bytes(keyparts[1]) - n = Integer.from_bytes(keyparts[2]) - return construct([n, e]) - - if len(extern_key) > 0 and bord(extern_key[0]) == 0x30: - # This is probably a DER encoded key - return _import_keyDER(extern_key, passphrase) - - raise ValueError("RSA key format is not supported") - - -# Backward compatibility -importKey = import_key - -#: `Object ID`_ for the RSA encryption algorithm. This OID often indicates -#: a generic RSA key, even when such key will be actually used for digital -#: signatures. -#: -#: .. _`Object ID`: http://www.alvestrand.no/objectid/1.2.840.113549.1.1.1.html -oid = "1.2.840.113549.1.1.1" diff --git a/Crypto/PublicKey/RSA.pyi b/Crypto/PublicKey/RSA.pyi deleted file mode 100644 index d436acf..0000000 --- a/Crypto/PublicKey/RSA.pyi +++ /dev/null @@ -1,51 +0,0 @@ -from typing import Callable, Union, Tuple, Optional - -__all__ = ['generate', 'construct', 'import_key', - 'RsaKey', 'oid'] - -RNG = Callable[[int], bytes] - -class RsaKey(object): - def __init__(self, **kwargs: int) -> None: ... - @property - def n(self) -> int: ... - @property - def e(self) -> int: ... - @property - def d(self) -> int: ... - @property - def p(self) -> int: ... - @property - def q(self) -> int: ... - @property - def u(self) -> int: ... - def size_in_bits(self) -> int: ... - def size_in_bytes(self) -> int: ... - def has_private(self) -> bool: ... - def can_encrypt(self) -> bool: ... # legacy - def can_sign(self) -> bool:... # legacy - def public_key(self) -> RsaKey: ... - def __eq__(self, other: object) -> bool: ... - def __ne__(self, other: object) -> bool: ... - def __getstate__(self) -> None: ... - def __repr__(self) -> str: ... - def __str__(self) -> str: ... - def export_key(self, format: Optional[str]="PEM", passphrase: Optional[str]=None, pkcs: Optional[int]=1, - protection: Optional[str]=None, randfunc: Optional[RNG]=None) -> bytes: ... - - # Backward compatibility - exportKey = export_key - publickey = public_key - -def generate(bits: int, randfunc: Optional[RNG]=None, e: Optional[int]=65537) -> RsaKey: ... -def construct(rsa_components: Union[Tuple[int, int], # n, e - Tuple[int, int, int], # n, e, d - Tuple[int, int, int, int, int], # n, e, d, p, q - Tuple[int, int, int, int, int, int]], # n, e, d, p, q, crt_q - consistency_check: Optional[bool]=True) -> RsaKey: ... -def import_key(extern_key: Union[str, bytes], passphrase: Optional[str]=None) -> RsaKey: ... - -# Backward compatibility -importKey = import_key - -oid: str diff --git a/Crypto/PublicKey/__init__.py b/Crypto/PublicKey/__init__.py deleted file mode 100644 index c9ff59b..0000000 --- a/Crypto/PublicKey/__init__.py +++ /dev/null @@ -1,95 +0,0 @@ -# -*- coding: utf-8 -*- -# -# =================================================================== -# The contents of this file are dedicated to the public domain. To -# the extent that dedication to the public domain is not available, -# everyone is granted a worldwide, perpetual, royalty-free, -# non-exclusive license to exercise all rights associated with the -# contents of this file for any purpose whatsoever. -# No rights are reserved. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS -# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN -# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# =================================================================== - -from Crypto.Util.asn1 import (DerSequence, DerInteger, DerBitString, - DerObjectId, DerNull) - - -def _expand_subject_public_key_info(encoded): - """Parse a SubjectPublicKeyInfo structure. - - It returns a triple with: - * OID (string) - * encoded public key (bytes) - * Algorithm parameters (bytes or None) - """ - - # - # SubjectPublicKeyInfo ::= SEQUENCE { - # algorithm AlgorithmIdentifier, - # subjectPublicKey BIT STRING - # } - # - # AlgorithmIdentifier ::= SEQUENCE { - # algorithm OBJECT IDENTIFIER, - # parameters ANY DEFINED BY algorithm OPTIONAL - # } - # - - spki = DerSequence().decode(encoded, nr_elements=2) - algo = DerSequence().decode(spki[0], nr_elements=(1,2)) - algo_oid = DerObjectId().decode(algo[0]) - spk = DerBitString().decode(spki[1]).value - - if len(algo) == 1: - algo_params = None - else: - try: - DerNull().decode(algo[1]) - algo_params = None - except: - algo_params = algo[1] - - return algo_oid.value, spk, algo_params - - -def _create_subject_public_key_info(algo_oid, secret_key, params=None): - - if params is None: - params = DerNull() - - spki = DerSequence([ - DerSequence([ - DerObjectId(algo_oid), - params]), - DerBitString(secret_key) - ]) - return spki.encode() - - -def _extract_subject_public_key_info(x509_certificate): - """Extract subjectPublicKeyInfo from a DER X.509 certificate.""" - - certificate = DerSequence().decode(x509_certificate, nr_elements=3) - tbs_certificate = DerSequence().decode(certificate[0], - nr_elements=range(6, 11)) - - index = 5 - try: - tbs_certificate[0] + 1 - # Version not present - version = 1 - except TypeError: - version = DerInteger(explicit=0).decode(tbs_certificate[0]).value - if version not in (2, 3): - raise ValueError("Incorrect X.509 certificate version") - index = 6 - - return tbs_certificate[index] diff --git a/Crypto/PublicKey/__init__.pyi b/Crypto/PublicKey/__init__.pyi deleted file mode 100644 index e69de29..0000000 diff --git a/Crypto/PublicKey/_ec_ws.abi3.so b/Crypto/PublicKey/_ec_ws.abi3.so deleted file mode 100644 index f7655f6022d79083066a72f9459a82594f3098ae..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1019608 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

CfC#Rl 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

$Ct3U&(fmYWIes63N|TT9W+q)VF(tvj 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

=J?6N$Zp2@HBPGqzDr;awOR(Z?+EFLNE{gZH)S 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 }Lfouf{NvnZV#o`?FrXTBr6T@kX4{wSKq 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 -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# =================================================================== - -import struct - -from Crypto.Cipher import AES -from Crypto.Hash import SHA512 -from Crypto.Protocol.KDF import _bcrypt_hash -from Crypto.Util.strxor import strxor -from Crypto.Util.py3compat import tostr, bchr, bord - - -def read_int4(data): - if len(data) < 4: - raise ValueError("Insufficient data") - value = struct.unpack(">I", data[:4])[0] - return value, data[4:] - - -def read_bytes(data): - size, data = read_int4(data) - if len(data) < size: - raise ValueError("Insufficient data (V)") - return data[:size], data[size:] - - -def read_string(data): - s, d = read_bytes(data) - return tostr(s), d - - -def check_padding(pad): - for v, x in enumerate(pad): - if bord(x) != ((v + 1) & 0xFF): - raise ValueError("Incorrect padding") - - -def import_openssh_private_generic(data, password): - # https://cvsweb.openbsd.org/cgi-bin/cvsweb/src/usr.bin/ssh/PROTOCOL.key?annotate=HEAD - # https://github.com/openssh/openssh-portable/blob/master/sshkey.c - # https://coolaj86.com/articles/the-openssh-private-key-format/ - # https://coolaj86.com/articles/the-ssh-public-key-format/ - - if not data.startswith(b'openssh-key-v1\x00'): - raise ValueError("Incorrect magic value") - data = data[15:] - - ciphername, data = read_string(data) - kdfname, data = read_string(data) - kdfoptions, data = read_bytes(data) - number_of_keys, data = read_int4(data) - - if number_of_keys != 1: - raise ValueError("We only handle 1 key at a time") - - _, data = read_string(data) # Public key - encrypted, data = read_bytes(data) - if data: - raise ValueError("Too much data") - - if len(encrypted) % 8 != 0: - raise ValueError("Incorrect payload length") - - # Decrypt if necessary - if ciphername == 'none': - decrypted = encrypted - else: - if (ciphername, kdfname) != ('aes256-ctr', 'bcrypt'): - raise ValueError("Unsupported encryption scheme %s/%s" % (ciphername, kdfname)) - - salt, kdfoptions = read_bytes(kdfoptions) - iterations, kdfoptions = read_int4(kdfoptions) - - if len(salt) != 16: - raise ValueError("Incorrect salt length") - if kdfoptions: - raise ValueError("Too much data in kdfoptions") - - pwd_sha512 = SHA512.new(password).digest() - # We need 32+16 = 48 bytes, therefore 2 bcrypt outputs are sufficient - stripes = [] - constant = b"OxychromaticBlowfishSwatDynamite" - for count in range(1, 3): - salt_sha512 = SHA512.new(salt + struct.pack(">I", count)).digest() - out_le = _bcrypt_hash(pwd_sha512, 6, salt_sha512, constant, False) - out = struct.pack("IIIIIIII", out_le)) - acc = bytearray(out) - for _ in range(1, iterations): - out_le = _bcrypt_hash(pwd_sha512, 6, SHA512.new(out).digest(), constant, False) - out = struct.pack("IIIIIIII", out_le)) - strxor(acc, out, output=acc) - stripes.append(acc[:24]) - - result = b"".join([bchr(a)+bchr(b) for (a, b) in zip(*stripes)]) - - cipher = AES.new(result[:32], - AES.MODE_CTR, - nonce=b"", - initial_value=result[32:32+16]) - decrypted = cipher.decrypt(encrypted) - - checkint1, decrypted = read_int4(decrypted) - checkint2, decrypted = read_int4(decrypted) - if checkint1 != checkint2: - raise ValueError("Incorrect checksum") - ssh_name, decrypted = read_string(decrypted) - - return ssh_name, decrypted diff --git a/Crypto/PublicKey/_openssh.pyi b/Crypto/PublicKey/_openssh.pyi deleted file mode 100644 index 15f3677..0000000 --- a/Crypto/PublicKey/_openssh.pyi +++ /dev/null @@ -1,7 +0,0 @@ -from typing import Tuple - -def read_int4(data: bytes) -> Tuple[int, bytes]: ... -def read_bytes(data: bytes) -> Tuple[bytes, bytes]: ... -def read_string(data: bytes) -> Tuple[str, bytes]: ... -def check_padding(pad: bytes) -> None: ... -def import_openssh_private_generic(data: bytes, password: bytes) -> Tuple[str, bytes]: ... diff --git a/Crypto/Random/__init__.py b/Crypto/Random/__init__.py deleted file mode 100644 index 0f83a07..0000000 --- a/Crypto/Random/__init__.py +++ /dev/null @@ -1,57 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Random/__init__.py : PyCrypto random number generation -# -# =================================================================== -# The contents of this file are dedicated to the public domain. To -# the extent that dedication to the public domain is not available, -# everyone is granted a worldwide, perpetual, royalty-free, -# non-exclusive license to exercise all rights associated with the -# contents of this file for any purpose whatsoever. -# No rights are reserved. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS -# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN -# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# =================================================================== - -__all__ = ['new', 'get_random_bytes'] - -from os import urandom - -class _UrandomRNG(object): - - def read(self, n): - """Return a random byte string of the desired size.""" - return urandom(n) - - def flush(self): - """Method provided for backward compatibility only.""" - pass - - def reinit(self): - """Method provided for backward compatibility only.""" - pass - - def close(self): - """Method provided for backward compatibility only.""" - pass - - -def new(*args, **kwargs): - """Return a file-like object that outputs cryptographically random bytes.""" - return _UrandomRNG() - - -def atfork(): - pass - - -#: Function that returns a random byte string of the desired size. -get_random_bytes = urandom - diff --git a/Crypto/Random/__init__.pyi b/Crypto/Random/__init__.pyi deleted file mode 100644 index ddc5b9b..0000000 --- a/Crypto/Random/__init__.pyi +++ /dev/null @@ -1,19 +0,0 @@ -from typing import Any - -__all__ = ['new', 'get_random_bytes'] - -from os import urandom - -class _UrandomRNG(object): - - def read(self, n: int) -> bytes:... - def flush(self) -> None: ... - def reinit(self) -> None: ... - def close(self) -> None: ... - -def new(*args: Any, **kwargs: Any) -> _UrandomRNG: ... - -def atfork() -> None: ... - -get_random_bytes = urandom - diff --git a/Crypto/Random/__pycache__/__init__.cpython-36.pyc b/Crypto/Random/__pycache__/__init__.cpython-36.pyc deleted file mode 100644 index bf789aefa28be227ed51cfb1176a97ce8d58e758..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1346 zcmcgrv2NQi5T$5KR-6P#nxR8cfE_v*XsiH1+9fCgq-dtPK#DA02wJ3N#j@yY3kAq5>rSa|>%B}lZbT{d zf=^aX*`EMR20`7cn$;BF9|ncs49va(r^q;vWK3lsDL{8*M|NR`?PUb>X3M|ZZS$)J z@p5#LA`lLo(ayna49<~n!Ce6Sg7wj*a+N8WV9kFF`7!HEUS>>BnVTslmCcQk%;sw~ z90Uf>XF%(&RmHRp%J0M==&!4!vL-2XDvIPrm}FX&smpa~6R|wZDp6+ZnXZyTEDjg* zcPDS>*SE2z}G4=Le1FLTHFaJj0xMhW>6sr!29daqUE5R+*DSsXZ{ z`9hJU#3JeX=#z3YE!ooOn_NOAQ*GEpr1M*0Bun*TDO^6ui`=c4E{oN0~)LNvo@zD{luigw9r-!TAcnlC!ZY+dUecs zDHe+Jy3hGS%c{V5hx4zMD4LAv1B%&3w}WmM9g42y@NP^9?gf~ac}(LjK7Mu6VyGe% z$!Giw@7Iw#;(OuarWdApp$?0Du9%)&tJFao2*-5gmX)(C^;*r0Sk7_~d$DTwj>Qf^ z8rUJiWVVh_W|@6V6*&x%LnG@AKUjJsV$ZITWDCTX?*$nN2ZEj-Z@>a`0P$!L*FDaG rARH&v*7t24H5GY^208d|4U+gTczoJi$@}LBkM|JM9lCcAhjI7^r1djE diff --git a/Crypto/Random/random.py b/Crypto/Random/random.py deleted file mode 100644 index 5389b3b..0000000 --- a/Crypto/Random/random.py +++ /dev/null @@ -1,138 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Random/random.py : Strong alternative for the standard 'random' module -# -# Written in 2008 by Dwayne C. Litzenberger -# -# =================================================================== -# The contents of this file are dedicated to the public domain. To -# the extent that dedication to the public domain is not available, -# everyone is granted a worldwide, perpetual, royalty-free, -# non-exclusive license to exercise all rights associated with the -# contents of this file for any purpose whatsoever. -# No rights are reserved. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS -# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN -# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# =================================================================== - -__all__ = ['StrongRandom', 'getrandbits', 'randrange', 'randint', 'choice', 'shuffle', 'sample'] - -from Crypto import Random - -from Crypto.Util.py3compat import is_native_int - -class StrongRandom(object): - def __init__(self, rng=None, randfunc=None): - if randfunc is None and rng is None: - self._randfunc = None - elif randfunc is not None and rng is None: - self._randfunc = randfunc - elif randfunc is None and rng is not None: - self._randfunc = rng.read - else: - raise ValueError("Cannot specify both 'rng' and 'randfunc'") - - def getrandbits(self, k): - """Return an integer with k random bits.""" - - if self._randfunc is None: - self._randfunc = Random.new().read - mask = (1 << k) - 1 - return mask & bytes_to_long(self._randfunc(ceil_div(k, 8))) - - def randrange(self, *args): - """randrange([start,] stop[, step]): - Return a randomly-selected element from range(start, stop, step).""" - if len(args) == 3: - (start, stop, step) = args - elif len(args) == 2: - (start, stop) = args - step = 1 - elif len(args) == 1: - (stop,) = args - start = 0 - step = 1 - else: - raise TypeError("randrange expected at most 3 arguments, got %d" % (len(args),)) - if (not is_native_int(start) or not is_native_int(stop) or not - is_native_int(step)): - raise TypeError("randrange requires integer arguments") - if step == 0: - raise ValueError("randrange step argument must not be zero") - - num_choices = ceil_div(stop - start, step) - if num_choices < 0: - num_choices = 0 - if num_choices < 1: - raise ValueError("empty range for randrange(%r, %r, %r)" % (start, stop, step)) - - # Pick a random number in the range of possible numbers - r = num_choices - while r >= num_choices: - r = self.getrandbits(size(num_choices)) - - return start + (step * r) - - def randint(self, a, b): - """Return a random integer N such that a <= N <= b.""" - if not is_native_int(a) or not is_native_int(b): - raise TypeError("randint requires integer arguments") - N = self.randrange(a, b+1) - assert a <= N <= b - return N - - def choice(self, seq): - """Return a random element from a (non-empty) sequence. - - If the seqence is empty, raises IndexError. - """ - if len(seq) == 0: - raise IndexError("empty sequence") - return seq[self.randrange(len(seq))] - - def shuffle(self, x): - """Shuffle the sequence in place.""" - # Fisher-Yates shuffle. O(n) - # See http://en.wikipedia.org/wiki/Fisher-Yates_shuffle - # Working backwards from the end of the array, we choose a random item - # from the remaining items until all items have been chosen. - for i in range(len(x)-1, 0, -1): # iterate from len(x)-1 downto 1 - j = self.randrange(0, i+1) # choose random j such that 0 <= j <= i - x[i], x[j] = x[j], x[i] # exchange x[i] and x[j] - - def sample(self, population, k): - """Return a k-length list of unique elements chosen from the population sequence.""" - - num_choices = len(population) - if k > num_choices: - raise ValueError("sample larger than population") - - retval = [] - selected = {} # we emulate a set using a dict here - for i in range(k): - r = None - while r is None or r in selected: - r = self.randrange(num_choices) - retval.append(population[r]) - selected[r] = 1 - return retval - -_r = StrongRandom() -getrandbits = _r.getrandbits -randrange = _r.randrange -randint = _r.randint -choice = _r.choice -shuffle = _r.shuffle -sample = _r.sample - -# These are at the bottom to avoid problems with recursive imports -from Crypto.Util.number import ceil_div, bytes_to_long, long_to_bytes, size - -# vim:set ts=4 sw=4 sts=4 expandtab: diff --git a/Crypto/Random/random.pyi b/Crypto/Random/random.pyi deleted file mode 100644 index f873c4a..0000000 --- a/Crypto/Random/random.pyi +++ /dev/null @@ -1,20 +0,0 @@ -from typing import Callable, Tuple, Union, Sequence, Any, Optional - -__all__ = ['StrongRandom', 'getrandbits', 'randrange', 'randint', 'choice', 'shuffle', 'sample'] - -class StrongRandom(object): - def __init__(self, rng: Optional[Any]=None, randfunc: Optional[Callable]=None) -> None: ... # TODO What is rng? - def getrandbits(self, k: int) -> int: ... - def randrange(self, start: int, stop: int = ..., step: int = ...) -> int: ... - def randint(self, a: int, b: int) -> int: ... - def choice(self, seq: Sequence) -> object: ... - def shuffle(self, x: Sequence) -> None: ... - def sample(self, population: Sequence, k: int) -> list: ... - -_r = StrongRandom() -getrandbits = _r.getrandbits -randrange = _r.randrange -randint = _r.randint -choice = _r.choice -shuffle = _r.shuffle -sample = _r.sample diff --git a/Crypto/SelfTest/Cipher/__init__.py b/Crypto/SelfTest/Cipher/__init__.py deleted file mode 100644 index 05fc139..0000000 --- a/Crypto/SelfTest/Cipher/__init__.py +++ /dev/null @@ -1,60 +0,0 @@ -# -*- coding: utf-8 -*- -# -# SelfTest/Cipher/__init__.py: Self-test for cipher modules -# -# Written in 2008 by Dwayne C. Litzenberger -# -# =================================================================== -# The contents of this file are dedicated to the public domain. To -# the extent that dedication to the public domain is not available, -# everyone is granted a worldwide, perpetual, royalty-free, -# non-exclusive license to exercise all rights associated with the -# contents of this file for any purpose whatsoever. -# No rights are reserved. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS -# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN -# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# =================================================================== - -"""Self-test for cipher modules""" - -__revision__ = "$Id$" - -def get_tests(config={}): - tests = [] - from Crypto.SelfTest.Cipher import test_AES; tests += test_AES.get_tests(config=config) - from Crypto.SelfTest.Cipher import test_ARC2; tests += test_ARC2.get_tests(config=config) - from Crypto.SelfTest.Cipher import test_ARC4; tests += test_ARC4.get_tests(config=config) - from Crypto.SelfTest.Cipher import test_Blowfish; tests += test_Blowfish.get_tests(config=config) - from Crypto.SelfTest.Cipher import test_CAST; tests += test_CAST.get_tests(config=config) - from Crypto.SelfTest.Cipher import test_DES3; tests += test_DES3.get_tests(config=config) - from Crypto.SelfTest.Cipher import test_DES; tests += test_DES.get_tests(config=config) - from Crypto.SelfTest.Cipher import test_Salsa20; tests += test_Salsa20.get_tests(config=config) - from Crypto.SelfTest.Cipher import test_ChaCha20; tests += test_ChaCha20.get_tests(config=config) - from Crypto.SelfTest.Cipher import test_ChaCha20_Poly1305; tests += test_ChaCha20_Poly1305.get_tests(config=config) - from Crypto.SelfTest.Cipher import test_pkcs1_15; tests += test_pkcs1_15.get_tests(config=config) - from Crypto.SelfTest.Cipher import test_pkcs1_oaep; tests += test_pkcs1_oaep.get_tests(config=config) - from Crypto.SelfTest.Cipher import test_OCB; tests += test_OCB.get_tests(config=config) - from Crypto.SelfTest.Cipher import test_CBC; tests += test_CBC.get_tests(config=config) - from Crypto.SelfTest.Cipher import test_CFB; tests += test_CFB.get_tests(config=config) - from Crypto.SelfTest.Cipher import test_OpenPGP; tests += test_OpenPGP.get_tests(config=config) - from Crypto.SelfTest.Cipher import test_OFB; tests += test_OFB.get_tests(config=config) - from Crypto.SelfTest.Cipher import test_CTR; tests += test_CTR.get_tests(config=config) - from Crypto.SelfTest.Cipher import test_CCM; tests += test_CCM.get_tests(config=config) - from Crypto.SelfTest.Cipher import test_EAX; tests += test_EAX.get_tests(config=config) - from Crypto.SelfTest.Cipher import test_GCM; tests += test_GCM.get_tests(config=config) - from Crypto.SelfTest.Cipher import test_SIV; tests += test_SIV.get_tests(config=config) - return tests - -if __name__ == '__main__': - import unittest - suite = lambda: unittest.TestSuite(get_tests()) - unittest.main(defaultTest='suite') - -# vim:set ts=4 sw=4 sts=4 expandtab: diff --git a/Crypto/SelfTest/Cipher/__pycache__/__init__.cpython-36.pyc b/Crypto/SelfTest/Cipher/__pycache__/__init__.cpython-36.pyc deleted file mode 100644 index 08e0399117b92ffd51f2d6bee5a272c64d7bd4f2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1845 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 diff --git a/Crypto/SelfTest/Cipher/__pycache__/test_AES.cpython-36.pyc b/Crypto/SelfTest/Cipher/__pycache__/test_AES.cpython-36.pyc deleted file mode 100644 index 8867590aab4b6670dabe13b3cf35977ed2cef387..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 61291 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 CcuS7} diff --git a/Crypto/SelfTest/Cipher/__pycache__/test_ARC2.cpython-36.pyc b/Crypto/SelfTest/Cipher/__pycache__/test_ARC2.cpython-36.pyc deleted file mode 100644 index 4d48ce41d90165b5e98a202b7cd604cce1bcfbdc..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4207 zcmbVPOLN@D5yk-f=8{^`)YG!VIEv#faST6Qc`wnW)692*{B2INxvU}mvW z$RewfqOMBimOqe7{t~V^@tm7Z=^iY1mz128jjHJ#eBJZSOm|OX)|#JhcwgP5?lndE zw=(lwhyHD7LzgHDQ$mFirglk4;8*LaJuTFFrLaU0FLlekN?3t@nN^@wd6m^z{W(d? ztik4>H369)BMa;TYq5(nNSQ6N*Vxh-tmiWd!5~2ZvgV<82Ow% zU=P_Ad&ItAU$Q^2uUN>wW`AVguy0w!zT3VM*6u3o1Ge!@VH=$6){nKY0mz5!E+BWu z$Q&Rav5x`yc#JeVN=n%8*(c9PIL{Z@y~pa`i7+P~`IK!wQ^E^i-D3CIXU_?ELVc*T z>A~9%c{g3j_%K@@jyf4%P6uLnUF`2=gVpuU-VPV5?>|^KPtft3Z8axxUW$_)(I$Bb z6?scP_k=AT$DU`UL13Al&(rjv{@}xP({%k6n5MBg9qz(* zOgC^Glg4`LI|+5CO7G+^ayw4!`OKoW#lROvYJ_+G-vox6`Z@*S1g7rzc4C`p!ec$= zrsFW08hkp7fAUwDC2zT=oyHdTea|)mZu|LVM|XWUa1%H1blZbp!?Qf=Mg6n&ttX~# ztmt_Q_C*;_ZJ2>N)OV&zL#BYCo4TdjI#B6e-U@WvFdWl~Et`X9lc~AP7{f44%d&09 zaa|A0bmm&f%dGYz$6Droaw72oJBib!A;_QtZfKbRHxj}BIS4oXrB?lKL z&YTIdco*!%?@-)A@xAfHuj>x9BA%+i_a7Y32Ik=XQMNal9!c~~1)2cl`uCD3i!O_ejt=_ek*Uy+zkw3AX3X0 zJ_22?2|f%LhC2h1aS;`JeO0DE#f{?;Q?v!OL>g+1ERZH?s)cOg8}`*DvIM#%a;(KZhesQAlW3&PvDHk#-2* znXGcG9D|MQS5Ny{?O53+o`N<|S1OybfWW!OIZm*c;AOW*AM+^g4wAqw(I%) znTxhW!PkRcZ_pQ8FgCBFdBkW&^9tSD<9#Mev^>{xU+@8d0sXYIU1WhARW2quTXpjK zHqVOb{{htF+JkX`CgUN##wp=@(xaVz6une8in9+kc=j_DT>x7qn{6$xjryGoXASFH zARppC2}w7T5OO(K|MJ?qUD}Hoz4cFA2sA}}i+EZ718I|R4sM!s)Xk8qT@rW~5KR>G zD6nb*TEqT@35xX@(2EExPSDp1bP0h=6ZCR{O5Q7oO0KH~D*M+aDE`en<$ZmE-Y8JX z`^E%)vp^;9PY_*3@zVm8yl+j=pB1QF@68GN^8%H;Z%rny zJ1?;gRD&;ZR1IUbPT^98cZz9(7Fi&_Uy&Sw$@M*1QQTf`q3?$oh>}`UTWYgfAx#Y$ eIsaQCDruG!kUzdvw8h%u{Nh{9xdwcIYvjMTW|?UK diff --git a/Crypto/SelfTest/Cipher/__pycache__/test_ARC4.cpython-36.pyc b/Crypto/SelfTest/Cipher/__pycache__/test_ARC4.cpython-36.pyc deleted file mode 100644 index ecf9caeff398348cc5f22c485ca7f1a473463b5a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 19295 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 diff --git a/Crypto/SelfTest/Cipher/__pycache__/test_Blowfish.cpython-36.pyc b/Crypto/SelfTest/Cipher/__pycache__/test_Blowfish.cpython-36.pyc deleted file mode 100644 index 89fbdbe46129eb789a4cbd46ed20b6a2eb373547..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5646 zcmbtY>z5oyb)VPn&aPIL8DgVfw{+>5>I{(#~xg7X=aZmmSggT=Rb*Z=69d+^D-|TJmNBu5igU!L# z+-MH`Q}i@lr(dIAr_a+D=r`y$>5KFw`ZE0%{Wkp$eT9CPeviINzfWJIKcGLPKcZ*o zkLm054SJUTgr1{6r9Y!Tr@x@Tq`#uSroW-TrN5)Ur+=V-q;Jx<=%47H>0jty>EGzz z=|AW{>D!m`(foTm^hx^EwGMqMb~hFd`=cR{Ptzfg!y{yIy_33hjUK<&9WBKZ^u(3k z=R4JZKfjmH&}Xl8M$4Fel0HXIUhiTby$3q0-+A<|2jXVBdm1Oxvy;8`X*`>Ds- z{oU!#x%2D0mt%GAzRjIS()#4`4S1+?akX0yLV3Bu_wab6UJVPY8yU$4lU<;Z#^r^49eyp>8=m9lz8-8@HN)h$=Ol4)y+io6KU zs?t%tVr6orDnynQG6-j3v&StBDXRE2i1zRax1lyuOgvqV}eVI0IK&z?7`z;>i? zWh|0}9HE1gCU~t<3?{HwjSD7wUiA)f%FSuMJQaWWN?<+T! ziYW42=T;JQv2&dYh>nq|bj>QPkh#&eNKgS?xy`V(P-HG7U0CRnDhVx(ChJK0Xc{>V z){`ot%3&pT5s0L8LOYdbNC;$0j6~k41cO|eJGRH?a5*AIKJyZ~GV6>l?fIaRl+~64BDkqNbF0y+^HDg&!8Xx-Vk|)E5aklO z;HnTZC#)%86n7*HDk-Sc!l6WGrl26G-)O*TgbRJ2O%Tl{ga`!V1saO~UNm#j;&Yd?FxzDtYSy`g<7x353GYUjq!gvu8;{?|t`t|8s=WqmNmIa@SpnR~}M^T@7 z@vNrCU@zVSa9L?oo^1V^mzu|Zfkzx_CHGDw8&D6ged(DRHHe;;(2CKptq28t^ZMJ( zRfvjAg=xysMYJDV)Nj1~>pIdlv7e?+?Aq2cuiTKefbrF zYf|aV#X=Qj%m~f2zT>;C5qL9sEOIf+wROls^rJh!`zndr!J8Gmg-|@9bk-O3TVKh# z3>kvL!7D{XRhR<3I@ND`Wh)i(IogDm9H9|83YkpxU9WVlM!qAl(2O-qS2k#y>bJl0 z)rRXqlsV<3jW;@Xp6YYo%X*7?5k_bo(4D=>@Fo>C3bw7)puIsVp_}3L&V_?|@%?fC19AJ(^m5t7 zEWY@A4)=N7lXrm}bT&HE?zFejpAM*d2mxn0c$zyLbYDEye_@O|tm0zD0&n!0@F{$C zzFzi|Nvx(H^6Qg0sh2+NH}~R&s@kb4o>lj^<0BOtUk^Wc|9dWsFPy)RPooo@V4v$$ zpTWTYJ+$_)uhusG_NBGm{psbMZMC+!9*+5Qc5Q+)?%lh-yy7p#$y$5RUE?$GgE#`O zwI|*+J`RtM54Y!b_v?jfZ<{Au0kn76yV|AU)!spOqkqsl>|W)N^7o)c4hA&1-n%-7kk1|T4+e+5 zCd6|GbJS`0?#4XhGqZXxo;6))rQRy{NY=638CgdoFUT5B7h8*H5xUw$Ycc4jr51yh zdFYsjwZrMs(GKQk<}=3j9$`&Fp1AnGoRIp)3TVR`WY_#o0dM)SB3=?)J<()%bq%7c$3aF5al5SWE394&`_t&F%J0`F+VZ%-NiKkQuU<{ieH4s?S9jv%jW`73c8Hh0P^W3K&46OGjc_-touYiGOqD(1C4XpzUq zr>V^T6_@n0sb}Lh?|LLV@hMi z@LijJE0DkEYY@hc?o{6Zspp!10am-C6Zl=~_co_2YqejoyDRSg4F`Z5NyYWhZ~%tP zFEZgR0XV@t+uCr)z)1#9wKMpu`hl4lFVfP?;DW1O)h;>B{0}nWmluS-n)%l-`Jong zE%UEq^7Vg34>LL20zbn19ZY_-1@2`2Ell3p0zbw)=YO@@0(UY0 z<4oS(0(Ucij>%dJ2<9b|tOXSFoUN5<0n2>Oq-X(t4OZ`9^3E3Ew`}!pCik?!PcVNk zlb>vX`9 zfnS*c#ti)G4B#0EGXU37MKeHTAk6@m7`QwGtTV7N16*NXa|YOAV0#AGVPJO#_$UL_ z3@~9}Is@!6@bC=q2m>FR0rnYqbO!i10|zs}RR%u6z^Qs+Jf@v;Jg&Zu=h3T={>Xc1 zy1t2Hj6yft_0#4EH9C1T)*gA<*AMrC(U2?tyvIT8F&2EC$umrzWb!OXJ>c$io3_%P ucJAQQxad&_gZ?)Uu}+)hFVvS0q5ADmu1eaG@}38%JU_x}MMLq^;H diff --git a/Crypto/SelfTest/Cipher/__pycache__/test_CAST.cpython-36.pyc b/Crypto/SelfTest/Cipher/__pycache__/test_CAST.cpython-36.pyc deleted file mode 100644 index 812eea9f0768efa1b425abd7c8e0f61692fb82b9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2246 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 diff --git a/Crypto/SelfTest/Cipher/__pycache__/test_CTR.cpython-36.pyc b/Crypto/SelfTest/Cipher/__pycache__/test_CTR.cpython-36.pyc deleted file mode 100644 index fb7d7ed24ffa4b9745cf51b9092659f767d047c4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 15376 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 diff --git a/Crypto/SelfTest/Cipher/__pycache__/test_ChaCha20.cpython-36.pyc b/Crypto/SelfTest/Cipher/__pycache__/test_ChaCha20.cpython-36.pyc deleted file mode 100644 index 8e6e235e3701aa5a7f7c5259d6158d4b37d447c8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 15428 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 K)m0lGYW^4hz&r*3 diff --git a/Crypto/SelfTest/Cipher/__pycache__/test_ChaCha20_Poly1305.cpython-36.pyc b/Crypto/SelfTest/Cipher/__pycache__/test_ChaCha20_Poly1305.cpython-36.pyc deleted file mode 100644 index c2b081fd0d39f71dc5a9d115aff3beef9e574b0e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 22682 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 GN&O$F9070u diff --git a/Crypto/SelfTest/Cipher/__pycache__/test_DES.cpython-36.pyc b/Crypto/SelfTest/Cipher/__pycache__/test_DES.cpython-36.pyc deleted file mode 100644 index af93aa89146e91ec634e8d538fe9daef7f54471e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 12019 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�KF5WoiYo|EeVv84VR9^S;_+VpAo!T&o2 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 CJBjN6 diff --git a/Crypto/SelfTest/Cipher/__pycache__/test_OCB.cpython-36.pyc b/Crypto/SelfTest/Cipher/__pycache__/test_OCB.cpython-36.pyc deleted file mode 100644 index 4c5cf01498e077d509a1e899e50486cac126997f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 19096 zcmd6PX^ky%GqSJ!m+wC1Rp(N)r@JMPGkno(!QflNTnpdK+O(U8ij$nMUX zx;iqeRb5tv1l2-XU|@g+gwQVHW&m-s%WaYXGnR$D4+wTafN|9R!m$0NA1l81JTmgA z%IY2#!|1kr;o;%#;r{%+?>&F+QTohG#eU!GTOZ!cWd0&E^e>O}HT=5&2PDjd(t4&L zu2Mtd`)nhNYj!=ik#FQT3XOt9&vWa=jZ&kuAvffWa-+<7`Sr@iRAY+Mh4tx;nZ^vK zi|ex+XBuZXU0R>pINLbOX?cBq<6Pq$(&eynFVk4~(o8rNPT$Lf)9viqLx;J>dF0H5 zv&flEaxNg}OgM*}xg_UeCv!sz&xZ5&q{hSTOX0bfve93mhtfLrd?9=YEx!(B9|_Ng z7haa|HtBk1>EaQ_n^|7U#-&^B-Sy6myK#AEGf6JxVreBV^|n^-_S)Szzp{EOT9RV9 z+lzL$qUI{nGwWNMH=Dh!CKo}*ne|S$*F^DNbG6lNcafE=`PZr1^>@|2%vZJQYL?!K ze{{{^=i=8r57Nu5NxkfT=1>Zym!-AbzH~^P%r2vPK5X?`OZjLD<>K6C`-4$|Qu(Oe z3eo*suXQsnuD3UD_HMnJiO%BL7oNLvrxjgUZ*AVZvVFIAYim=#vff$gr!QMqx}9G8 zZQHHYms&U5-79W%ce}TB<$8Pl#`Ea^6}Pi}s~uh8u{`V6FK^$CXK%JKxYo^P)Y=TU zHr|G}ba^yVbPnlN{L+6kvTOKte*&bPAu(!X+qqB*vxnJ69;sZIN2-8Sf%A%CF)U%4 zN}(Kq7Ws_!O=Wg|83afb042jo|j1V)@zC72-fQF1^&g z+r*R|&0!32d2?%Xwaxd_bT8AC(Cw;(Tl!bTkEVrZ^aDuHjP7UFvbg4O&0}732T~8? z4GV|agY3SvR@~1XO7G7e|zr?tLRjPqScOT*`6M#^@5>vm}pkHF^}e(PJQSDPd#uFx^cL zF{`_ji=L!%PZ4~rq`*OZkU!`?GLTk@AG?F9iUiTe*W%u+mE8H=%g{D z77uA`AQuM%X>RNQ5m(v*C*O^Zb;;ypq;JysC$))O&>#NJr8N7I@ za+3V8&O}e(d0bgp-vT0ZJ9}+bvN(sq$Fo9#mbVhX$q!U0F7lAo%y0BcpOSTIC%g7*Jj-&bj zf0&odzsN$#h|m?j!vJ@xl6rc&Nw;6lCzi0Vd_>Ryog#3KOFNq{ZEk&VGe|NT z<(+Q3*=lz;J4+>2*NEJgiQ+f`(=IT7lD3=Mt*Eup?zN*X9O^!c=3&2}pm~VY;wX!b zS4+7>DoWl1bBXYA*9!|kt*bz-ar=~m50UK^$T}Tnfp_^sARdbk{DkBlB6qv^Lf=P- zme68cO6+)oU(pq0f;;pqdMBk%GidPqXl@z9SiBN>it{&i;4+Xki;GdayR+UKm#N2v zOzo_%Hxski+1hL-ok8+0>UK#)GT_{KG6`=U<=f`Osww}-GNcgK!_6_SvFAnh92|m* z9byRpxhny@q_uLAmm5`7QeNS)4V4+L*KZ5;*c(g1u94flyLTGcG1F<%heVO*ATbHV z&v8CJ#(ZpddT`78oNQttl5p}vsFG^wth4}UVOH9E(-PDQ?1NZ^GuXV-qQOazrEU`#fwe-bESH zLUL84CxU3C(bLC?kRvS25?Q3Bf-pt_E=Ma6``UdS*j9fL0&3E(s4y;JBP}U)s;py7izi zp*&`)R{`gzux2Y94y;o|h7fFIBPCW4%-*HxcwQ{MFTc0fS-&iz3tVh6Uk5B@t>8&m zr1pz~uk@0k6$Wv(G1b|;(^~I@#LaOwvm!Q!3j82ybZ0>_U^MATMXbmk9%b-Qjg-kb zR7#ml27fXXA7&t=F#ZH1hZ*5Vj(baZJ_N$#9VK8pScpw_D&sO@IbsgVM?M zcOThD{rwVS&Fq29?Lnr29(RBqa(EUVM0s}+rSeIsd6X)nTzMbm?94&=_9wAE;+(?_ z-J^Gq^ZhbS7|KmS+Nr(gUdZfzJUoZqyfU#jj}7%^Zn!tENVoH8e=56AqFgrV&jQL- z@Sf?UKNXaH8a?7X?oow%l;5v#k1}gBC_Q_a5z&%YGPnOE@rM?c_vTwWu%es2&T0$p z?IJ<`5!uh^bs!1Wjl}6lpee-FT?F}P=A+V$EMdnznP#pheGGH+vCLu4L+lRA>ilv# z>ExIY>~Q5rkhlq>@#4Y(s$fD;=|YBUooxeVWehBGhFDtRsL1KFK7Cc7+Wd!#k z3X%xPq)^HiDpx7uxVp8m{mf@^-xcrMtB>mGM!VZZkgv%tbuVAVBCECDedh8C!iO(4 zceV#PgXRQaWd(*aXlKRCulIWZo55-B5(jqVeuJN(zL0-I@tnQOudO%2?9fP#NKe^5 z9g*f7aRlo;rQS@0+>@gZg9u-?!WARJoahB2WZ0swCh|TaR57B(U-UIZ-VXvFjcnX& zt8<29WfRdkF79kYqT0gnv6J^sddCwWaZvz{@VehZ*|e@-nqu6J%Osag5=WLqhVVv3 zgw-gp*C<8p8w}v@rK-gJxWJPdy@}Gf)#Jf7u>u~IfL}u4E-fN6`HDo)P9ZnBfK+x4 zUL#plvar+AY)<4QR+jU|SIVPJr;<-|mD+(lhC3)IEmZ(_NCCuX6^vAlmM>{4-^+7w zPQtZF<=6!;>=yuhTo!OsV3!E>D0K)OIw&GlhCL~9ZBbX$gzE`c3Tpb1>{Wz%_Gur3 z)B7?7R@t6ll|7UzvvVaUEtgRzKlGH|BA}+2fFA*2DTSR1dNPH!r-UU#pC^v_>%>@x zdpk9;w^Jwfc4}=JoP%=+TEVg=doYbRQvY)M)6@fYx%2%fOqUeui(mXA>&MbeT&9hS zRur}Fa$s0QV%S$BeG?I54r{(hx9oV6yb4c_7TVDw$kGgpZ=*=@@|9L22`VE66Wa>0 zTtTwLj`d0_E(v*7Mf8)xLj5ca39)+;%e2iv%Y*(iBQ7B_l?a4E7m+uvX$m7bwo{B!L08oZSpDZtV|19u{=vP?usWx^OQ1||# z4W4$GT^4qq(gV?l4?y;LjRh|m8LzcTgKoS+6%#HstM!E9XFXm4yqckgttueJ)w`A1WRjXQm1K&r0{ND5`xxD$o+wl@$V zMTpu&ZV+U5y&8Oli%u{gvE1m~1c7@oon{xsEj%cmSEAJGk$QwzG zGO=*-;taaO`(qSmTr04LO(`tY$XK7aXC~3^B%>5khZ&$1VrvP`&~D{}EZKySVH3ob zhFvGx*Bc37v&PT_4~YPKpl@Tv5DVSTW~Y}1%KDp_Vgc9`ZkSJMLjse@O|yl7HQ-bQ zHe$~iVy)PLe9(4Nev=%f{3hX@$hmYs5`0ghlEQ(Qz-g?#nA82z>~65JA8>hkqK`Vn z<)_gr5my`I_x(01#nFI%2;lzAelIb54sYu-dp2S9-aC#l`oUX0nbqXw-;dQSo+Qqb zwt&;kUoM%5_85y#*@R)2X&}ff!^1p1Nqk>FF1}(Zk!-~$QcFV~VWf~*Y?v#@7&#=d zlbWI#$&3KQy$9yr2uOgJ2n-NNK>1GriA2;Bc<2KLTn^5`f}S0dQNWm*EXo5u5B$^D zh#F$sOYrIj?KW(;dbe&9n>pN=fSJ z1r=9BB70>*VSbW(4WY1Tj7_Q9V-^1-IwZn{1B1$Fy2#?#SH@)brrElI#clIOXS20_ zNIaTGb&3;`Lk$i|dru$Z%PCF#^W+f=&_94jeKRw}qi=qVJUXF?lX*nbHd&5HoyNeb zI9Z7Z`%jaE^W(rI?C5vW*a$l^w3G7Wv3VbYA5kG4$%tjF-)AJJKs2A9IyTbM=_8FE z2#k-7SvU$HO9`rJp*Gc0UnfKCw4LYe)X! z4lBJ2nHzbO*rOetF!Pcey*&iHZpt_-2=D~Z=0vO*R|=S5R|zrWJeMs;Yy0`WR|e$B z)1DE|kr4!AH3~$zPl}}I_M2ZA>?W6%h3`NL(#Yw$9!q)>F@^jLw&p5gtC;Pdg|d?; zgn{WAiX^)i@f7ydZ*7IV#E6>oo-z)AY>9oTr*Iz^MTv3e?~Ox3x`CbO&NkL1ebgH4 zlzxgPa1rg$hBJ0b0a-;XmjtLMF#|lQNPF4@fj*`2bfQNr>bK%$lU0?$oF+rK*V)}g zgyb=`nDhnS*rzi!{ES?}+Xh19lN|8Ww(ed+8xSS5F^e`N3f9wv-`-8a;Au?gh-_QWVhNyK-zA`yScJt)(-U!=T7yx%hSWL3ZziWQ;Z^9ZbU3cREj$X0INn z2l*=IiM9=4hWhh#OsV*Q6K|n&2m&+NKgv`{W|6>X%;<2|11)$NztVY%uAwd7s_Ab6 z?@mS&a^&gdb^hO~y}5KHIR#0&sf!%S#VM8)!Y+B(g>19Fego>ut&-0~d9P^oZ;bxkKcG zM0SagI!7NS^7TaS5%~y_ZzM9{1Ekw zp62qaD4PDG?q0)>Hy`_P)lh2W!sSLje6~>t-`6OHc38#t7^Tn&-;S#sz9YPfYdQQ9 z#1I?tEY#;cH&$)U)SssfqD4hfR7F#C#ZXMeQf#HFI7&^aE3V=xz7oV2>-AdAajI3@ zwk*>$3|-eWRaF$;H;xzWs%a>8JqQA~TJs#=b6wNal$z_Ps_OgJ#0J!OZv5r3VpTPz zu3M&Ew*pHwYbJVH_iBo#*A2g}*EG|1om!v<)c}1~oQbV#@nTg~R69U}dZ1KQ&9+rj z3u>NkIYtdbR3_HdW5qB%&vNhSFd??%?JX$ib7S_v=!A=UDtQ3fvf9gbz(nF zjL{8jORZauqWMS}hNacKs%1D;w`SEHdtzM+{c`tu^i1-teT^muA0*VcQB_UVRYNsZOSR+YR2RHZ zY+b3kRog{v+q6{0@TyfqaedXn+$oM_>ovou)>N>~(OgTz%qXTBn6_?Oo*n3}qtxq= zTYIwLR^vs>b2ZJZDYhE8YTXHJ7jy0CbtO=JRq_0ZBXi>CApCU?W$d741-|3xzUz86 zWXgg})dJ14T+jCuS9i?1>gq0}#|(7Ma16Z2Q86GexvoN(G2M1Bxu3Q8+H2*aT2&pj zrsBP-hmi#F2kIX5$Tb{GgHU0b9m|DQ2A--{Yldal>Ynb}itT9Von?4_4QgyCx(XdL zYX+%y0R3017L?l5U5ivaFdeOCJ2gWyChJf=UJU#yBulCLKHgO|Jr&x64w!Y<@wA$* zP2{p0e?W5#tsc0xtwZ}Y-L2JKtL6qCl+80qPdsQp1j5$QcRv90Atk0BsD`f9T`#Dc zzUq0tUU$`M%?uzzbyM>#Q#TC5Grh@N_u}XNf4QzH8st;MoNK0LX?DErnJ$#eHmZ?1h1;sY(+N>2ONMP`qt!G@#96;bUnvYt0sD4s6OxoXyG`9?*n(xmx;3y#M_3U zY7Rbka&){2Z1fe+#x&TF3>RtD(>#Z)2!`)F0l~NDVHQohYWpT;fJ}prlwEi0O4aZU zNRg*odd<}>pp{u8*n+lT2I@da2j(e&GDDkSkZLeYRTwA>h6*AIqXi=r-%=p}HN)3c zD7|S0bwx+IPA1CoEm!lrz=6D5zODm=tw61zcLrJm<7>b_!}lEBsKPWju5Hz=8eV3q zW?*=#>v=}t)m$S`v|5diJOMgv-+>5Wc1`GnuhcEqQUgF&-~l{p+R7T04^V3tZM&v> zRUaT%1x8mr&Gaw|vVMx`nU-JkG~3kNs#S+^(>3%fzGxbxCr-`PfNO5O2D#96$kWj^ zYI05md^&ZzjvlZikuk;`xR$T@fo}Mk5zpD4;bRI7!!&^&bwBl?=`?2QLw_DOqvsWN ze;=MI&hx$axdWV~z)8Q%KF(?5+-07=)I2EQz)=y0f(mqa4=JQ6mBm4%kt0a-g-Q-5 z7wM>xIKP2oMRZaUIpW|FMF`46=PAlKPa&`2qy_K((V|xz4?3wOoWtOjruei5oy;gB zo+r*f;uHo>PEx?y(w23yp6mQAjwdm}siO3?_ze4w+Qji9 zeCd2g9a;oDO8uavfe1amg;Ko0Oa1@;*}5Fn&i3vk-<7pmVZ@P>H=s()XMS z)CwJ_8yjIDN!Q8!hLJ{3QTv!&wqd$>u2 z3?E0am=!24B1CP!kO~@(`=){h5#+9Jk9oeOH5oNG4XHlbr$EUR=#I`gfwscrn90Mwm2&cPt|0II;>H7$pcA}usb{<6d z5-w2y()qt6ZA6wTBwE^Q6RnEaI{Qs(j@$eUrBbnqK1;V8N;qAlw4bEW@Lpr~62xgC z6{mjcL~+tmaUwLMEeRLD?sou}Uy*jd2~!MVdPREi>)wxVo;iMrzbpX60G?gKKEuV# z0-ef2SQux$^1UqWH5?Rn|6dPZbb1Sz z1relHWqh+z-Y)~?7=0jaWe5k-bR{vw73g+>wu%eAe9~h1zAZjjJH`99GuAVl4Tcpu}dpcUyN!XT83 zFLX{qMSc0zeDp8Sj9>_J<(qJe+;67bZ%N6^BKKR<3@-a^BKH-_cZ4_on0%BKP~!46g7=k^8SGmovD+zZSXQPr08; z$q$I!A51g2!VihuAEsQ+_!OmnMCAS`rGG3XKQ3}#O*6Q{Pl()~q+HJ63O|M0rMc+$ zDEHqJ`F$dPK;%CV`Hw{Y6OsQ+V}5vYhdABID=Nj9(BL{O}hk_m@NlSK*9*BQm%OXZ+itD!)user2c% zXZ-3=70&oIWZ>(He-rr=B7aKc^F;oP$e)8C>OU52`*nKs8$^DK$nOyO z9FgB9^6!WYTp~`*Q{G2Gz5p%m(%j0Wd=8E?{lDKeKUS`P-@o?j(|s2I#kJpV|2~UN zFM6Kl=V!QG)W}yjC3?d&pFG>TH#al%7c|IUK9qpsA`L5&rh$GU zjd-23jDve+)Z#;y91-N^@nK7Gb!+oR=ce$gx5KD@sH7i&TT zPzTbvi{-29t&Nqi^~_&VC+Ho~-+;u0F4bF-@YiVCH(J0*YHR7yIJ?!2vr#+xYbqqK z;EYUnwbO~HPwdS$9vc4GZ~LxJpYF7J0@MpsiZTAnC{+S!jC>rpxwEm-ju`hF4<`-v z|6mWk9BiVojjc^)cVi}bF8+=Wn~BC$lJ~Aw_ZI&tA&wt6Wa_+&zgILiM}jS^1V`vg yoF{HiV3Rln{LJGh*Cip55%k7)ByeST#^{WFPR`GNDD$Dr9Oza2R;Fc9>hA$#s_?S_ diff --git a/Crypto/SelfTest/Cipher/__pycache__/test_OFB.cpython-36.pyc b/Crypto/SelfTest/Cipher/__pycache__/test_OFB.cpython-36.pyc deleted file mode 100644 index 9eb57d3f319e7a119f11f8b80bc10d43b8d8d4ed..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6812 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 DeU2Z< diff --git a/Crypto/SelfTest/Cipher/__pycache__/test_pkcs1_oaep.cpython-36.pyc b/Crypto/SelfTest/Cipher/__pycache__/test_pkcs1_oaep.cpython-36.pyc deleted file mode 100644 index b91abf33cfe9dc134ff83fabd993ba77ef596ae3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 19328 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 jcCX?wtIlh@R -# -# =================================================================== -# The contents of this file are dedicated to the public domain. To -# the extent that dedication to the public domain is not available, -# everyone is granted a worldwide, perpetual, royalty-free, -# non-exclusive license to exercise all rights associated with the -# contents of this file for any purpose whatsoever. -# No rights are reserved. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS -# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN -# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# =================================================================== - -"""Self-testing for PyCrypto hash modules""" - -import unittest -from binascii import a2b_hex, b2a_hex, hexlify - -from Crypto.Util.py3compat import b -from Crypto.Util.strxor import strxor_c - -class _NoDefault: pass # sentinel object -def _extract(d, k, default=_NoDefault): - """Get an item from a dictionary, and remove it from the dictionary.""" - try: - retval = d[k] - except KeyError: - if default is _NoDefault: - raise - return default - del d[k] - return retval - -# Generic cipher test case -class CipherSelfTest(unittest.TestCase): - - def __init__(self, module, params): - unittest.TestCase.__init__(self) - self.module = module - - # Extract the parameters - params = params.copy() - self.description = _extract(params, 'description') - self.key = b(_extract(params, 'key')) - self.plaintext = b(_extract(params, 'plaintext')) - self.ciphertext = b(_extract(params, 'ciphertext')) - self.module_name = _extract(params, 'module_name', None) - self.assoc_data = _extract(params, 'assoc_data', None) - self.mac = _extract(params, 'mac', None) - if self.assoc_data: - self.mac = b(self.mac) - - mode = _extract(params, 'mode', None) - self.mode_name = str(mode) - - if mode is not None: - # Block cipher - self.mode = getattr(self.module, "MODE_" + mode) - - self.iv = _extract(params, 'iv', None) - if self.iv is None: - self.iv = _extract(params, 'nonce', None) - if self.iv is not None: - self.iv = b(self.iv) - - else: - # Stream cipher - self.mode = None - self.iv = _extract(params, 'iv', None) - if self.iv is not None: - self.iv = b(self.iv) - - self.extra_params = params - - def shortDescription(self): - return self.description - - def _new(self): - params = self.extra_params.copy() - key = a2b_hex(self.key) - - old_style = [] - if self.mode is not None: - old_style = [ self.mode ] - if self.iv is not None: - old_style += [ a2b_hex(self.iv) ] - - return self.module.new(key, *old_style, **params) - - def isMode(self, name): - if not hasattr(self.module, "MODE_"+name): - return False - return self.mode == getattr(self.module, "MODE_"+name) - - def runTest(self): - plaintext = a2b_hex(self.plaintext) - ciphertext = a2b_hex(self.ciphertext) - assoc_data = [] - if self.assoc_data: - assoc_data = [ a2b_hex(b(x)) for x in self.assoc_data] - - ct = None - pt = None - - # - # Repeat the same encryption or decryption twice and verify - # that the result is always the same - # - for i in range(2): - cipher = self._new() - decipher = self._new() - - # Only AEAD modes - for comp in assoc_data: - cipher.update(comp) - decipher.update(comp) - - ctX = b2a_hex(cipher.encrypt(plaintext)) - ptX = b2a_hex(decipher.decrypt(ciphertext)) - - if ct: - self.assertEqual(ct, ctX) - self.assertEqual(pt, ptX) - ct, pt = ctX, ptX - - self.assertEqual(self.ciphertext, ct) # encrypt - self.assertEqual(self.plaintext, pt) # decrypt - - if self.mac: - mac = b2a_hex(cipher.digest()) - self.assertEqual(self.mac, mac) - decipher.verify(a2b_hex(self.mac)) - -class CipherStreamingSelfTest(CipherSelfTest): - - def shortDescription(self): - desc = self.module_name - if self.mode is not None: - desc += " in %s mode" % (self.mode_name,) - return "%s should behave like a stream cipher" % (desc,) - - def runTest(self): - plaintext = a2b_hex(self.plaintext) - ciphertext = a2b_hex(self.ciphertext) - - # The cipher should work like a stream cipher - - # Test counter mode encryption, 3 bytes at a time - ct3 = [] - cipher = self._new() - for i in range(0, len(plaintext), 3): - ct3.append(cipher.encrypt(plaintext[i:i+3])) - ct3 = b2a_hex(b("").join(ct3)) - self.assertEqual(self.ciphertext, ct3) # encryption (3 bytes at a time) - - # Test counter mode decryption, 3 bytes at a time - pt3 = [] - cipher = self._new() - for i in range(0, len(ciphertext), 3): - pt3.append(cipher.encrypt(ciphertext[i:i+3])) - # PY3K: This is meant to be text, do not change to bytes (data) - pt3 = b2a_hex(b("").join(pt3)) - self.assertEqual(self.plaintext, pt3) # decryption (3 bytes at a time) - - -class RoundtripTest(unittest.TestCase): - def __init__(self, module, params): - from Crypto import Random - unittest.TestCase.__init__(self) - self.module = module - self.iv = Random.get_random_bytes(module.block_size) - self.key = b(params['key']) - self.plaintext = 100 * b(params['plaintext']) - self.module_name = params.get('module_name', None) - - def shortDescription(self): - return """%s .decrypt() output of .encrypt() should not be garbled""" % (self.module_name,) - - def runTest(self): - - ## ECB mode - mode = self.module.MODE_ECB - encryption_cipher = self.module.new(a2b_hex(self.key), mode) - ciphertext = encryption_cipher.encrypt(self.plaintext) - decryption_cipher = self.module.new(a2b_hex(self.key), mode) - decrypted_plaintext = decryption_cipher.decrypt(ciphertext) - self.assertEqual(self.plaintext, decrypted_plaintext) - - -class IVLengthTest(unittest.TestCase): - def __init__(self, module, params): - unittest.TestCase.__init__(self) - self.module = module - self.key = b(params['key']) - - def shortDescription(self): - return "Check that all modes except MODE_ECB and MODE_CTR require an IV of the proper length" - - def runTest(self): - self.assertRaises(TypeError, self.module.new, a2b_hex(self.key), - self.module.MODE_ECB, b("")) - - def _dummy_counter(self): - return "\0" * self.module.block_size - - -class NoDefaultECBTest(unittest.TestCase): - def __init__(self, module, params): - unittest.TestCase.__init__(self) - self.module = module - self.key = b(params['key']) - - def runTest(self): - self.assertRaises(TypeError, self.module.new, a2b_hex(self.key)) - - -class BlockSizeTest(unittest.TestCase): - def __init__(self, module, params): - unittest.TestCase.__init__(self) - self.module = module - self.key = a2b_hex(b(params['key'])) - - def runTest(self): - cipher = self.module.new(self.key, self.module.MODE_ECB) - self.assertEqual(cipher.block_size, self.module.block_size) - - -class ByteArrayTest(unittest.TestCase): - """Verify we can use bytearray's for encrypting and decrypting""" - - def __init__(self, module, params): - unittest.TestCase.__init__(self) - self.module = module - - # Extract the parameters - params = params.copy() - self.description = _extract(params, 'description') - self.key = b(_extract(params, 'key')) - self.plaintext = b(_extract(params, 'plaintext')) - self.ciphertext = b(_extract(params, 'ciphertext')) - self.module_name = _extract(params, 'module_name', None) - self.assoc_data = _extract(params, 'assoc_data', None) - self.mac = _extract(params, 'mac', None) - if self.assoc_data: - self.mac = b(self.mac) - - mode = _extract(params, 'mode', None) - self.mode_name = str(mode) - - if mode is not None: - # Block cipher - self.mode = getattr(self.module, "MODE_" + mode) - - self.iv = _extract(params, 'iv', None) - if self.iv is None: - self.iv = _extract(params, 'nonce', None) - if self.iv is not None: - self.iv = b(self.iv) - else: - # Stream cipher - self.mode = None - self.iv = _extract(params, 'iv', None) - if self.iv is not None: - self.iv = b(self.iv) - - self.extra_params = params - - def _new(self): - params = self.extra_params.copy() - key = a2b_hex(self.key) - - old_style = [] - if self.mode is not None: - old_style = [ self.mode ] - if self.iv is not None: - old_style += [ a2b_hex(self.iv) ] - - return self.module.new(key, *old_style, **params) - - def runTest(self): - - plaintext = a2b_hex(self.plaintext) - ciphertext = a2b_hex(self.ciphertext) - assoc_data = [] - if self.assoc_data: - assoc_data = [ bytearray(a2b_hex(b(x))) for x in self.assoc_data] - - cipher = self._new() - decipher = self._new() - - # Only AEAD modes - for comp in assoc_data: - cipher.update(comp) - decipher.update(comp) - - ct = b2a_hex(cipher.encrypt(bytearray(plaintext))) - pt = b2a_hex(decipher.decrypt(bytearray(ciphertext))) - - self.assertEqual(self.ciphertext, ct) # encrypt - self.assertEqual(self.plaintext, pt) # decrypt - - if self.mac: - mac = b2a_hex(cipher.digest()) - self.assertEqual(self.mac, mac) - decipher.verify(bytearray(a2b_hex(self.mac))) - - -class MemoryviewTest(unittest.TestCase): - """Verify we can use memoryviews for encrypting and decrypting""" - - def __init__(self, module, params): - unittest.TestCase.__init__(self) - self.module = module - - # Extract the parameters - params = params.copy() - self.description = _extract(params, 'description') - self.key = b(_extract(params, 'key')) - self.plaintext = b(_extract(params, 'plaintext')) - self.ciphertext = b(_extract(params, 'ciphertext')) - self.module_name = _extract(params, 'module_name', None) - self.assoc_data = _extract(params, 'assoc_data', None) - self.mac = _extract(params, 'mac', None) - if self.assoc_data: - self.mac = b(self.mac) - - mode = _extract(params, 'mode', None) - self.mode_name = str(mode) - - if mode is not None: - # Block cipher - self.mode = getattr(self.module, "MODE_" + mode) - - self.iv = _extract(params, 'iv', None) - if self.iv is None: - self.iv = _extract(params, 'nonce', None) - if self.iv is not None: - self.iv = b(self.iv) - else: - # Stream cipher - self.mode = None - self.iv = _extract(params, 'iv', None) - if self.iv is not None: - self.iv = b(self.iv) - - self.extra_params = params - - def _new(self): - params = self.extra_params.copy() - key = a2b_hex(self.key) - - old_style = [] - if self.mode is not None: - old_style = [ self.mode ] - if self.iv is not None: - old_style += [ a2b_hex(self.iv) ] - - return self.module.new(key, *old_style, **params) - - def runTest(self): - - plaintext = a2b_hex(self.plaintext) - ciphertext = a2b_hex(self.ciphertext) - assoc_data = [] - if self.assoc_data: - assoc_data = [ memoryview(a2b_hex(b(x))) for x in self.assoc_data] - - cipher = self._new() - decipher = self._new() - - # Only AEAD modes - for comp in assoc_data: - cipher.update(comp) - decipher.update(comp) - - ct = b2a_hex(cipher.encrypt(memoryview(plaintext))) - pt = b2a_hex(decipher.decrypt(memoryview(ciphertext))) - - self.assertEqual(self.ciphertext, ct) # encrypt - self.assertEqual(self.plaintext, pt) # decrypt - - if self.mac: - mac = b2a_hex(cipher.digest()) - self.assertEqual(self.mac, mac) - decipher.verify(memoryview(a2b_hex(self.mac))) - - -def make_block_tests(module, module_name, test_data, additional_params=dict()): - tests = [] - extra_tests_added = False - for i in range(len(test_data)): - row = test_data[i] - - # Build the "params" dictionary with - # - plaintext - # - ciphertext - # - key - # - mode (default is ECB) - # - (optionally) description - # - (optionally) any other parameter that this cipher mode requires - params = {} - if len(row) == 3: - (params['plaintext'], params['ciphertext'], params['key']) = row - elif len(row) == 4: - (params['plaintext'], params['ciphertext'], params['key'], params['description']) = row - elif len(row) == 5: - (params['plaintext'], params['ciphertext'], params['key'], params['description'], extra_params) = row - params.update(extra_params) - else: - raise AssertionError("Unsupported tuple size %d" % (len(row),)) - - if not "mode" in params: - params["mode"] = "ECB" - - # Build the display-name for the test - p2 = params.copy() - p_key = _extract(p2, 'key') - p_plaintext = _extract(p2, 'plaintext') - p_ciphertext = _extract(p2, 'ciphertext') - p_mode = _extract(p2, 'mode') - p_description = _extract(p2, 'description', None) - - if p_description is not None: - description = p_description - elif p_mode == 'ECB' and not p2: - description = "p=%s, k=%s" % (p_plaintext, p_key) - else: - description = "p=%s, k=%s, %r" % (p_plaintext, p_key, p2) - name = "%s #%d: %s" % (module_name, i+1, description) - params['description'] = name - params['module_name'] = module_name - params.update(additional_params) - - # Add extra test(s) to the test suite before the current test - if not extra_tests_added: - tests += [ - RoundtripTest(module, params), - IVLengthTest(module, params), - NoDefaultECBTest(module, params), - ByteArrayTest(module, params), - BlockSizeTest(module, params), - ] - extra_tests_added = True - - # Add the current test to the test suite - tests.append(CipherSelfTest(module, params)) - - return tests - -def make_stream_tests(module, module_name, test_data): - tests = [] - extra_tests_added = False - for i in range(len(test_data)): - row = test_data[i] - - # Build the "params" dictionary - params = {} - if len(row) == 3: - (params['plaintext'], params['ciphertext'], params['key']) = row - elif len(row) == 4: - (params['plaintext'], params['ciphertext'], params['key'], params['description']) = row - elif len(row) == 5: - (params['plaintext'], params['ciphertext'], params['key'], params['description'], extra_params) = row - params.update(extra_params) - else: - raise AssertionError("Unsupported tuple size %d" % (len(row),)) - - # Build the display-name for the test - p2 = params.copy() - p_key = _extract(p2, 'key') - p_plaintext = _extract(p2, 'plaintext') - p_ciphertext = _extract(p2, 'ciphertext') - p_description = _extract(p2, 'description', None) - - if p_description is not None: - description = p_description - elif not p2: - description = "p=%s, k=%s" % (p_plaintext, p_key) - else: - description = "p=%s, k=%s, %r" % (p_plaintext, p_key, p2) - name = "%s #%d: %s" % (module_name, i+1, description) - params['description'] = name - params['module_name'] = module_name - - # Add extra test(s) to the test suite before the current test - if not extra_tests_added: - tests += [ - ByteArrayTest(module, params), - ] - - import sys - if sys.version[:3] != '2.6': - tests.append(MemoryviewTest(module, params)) - extra_tests_added = True - - # Add the test to the test suite - tests.append(CipherSelfTest(module, params)) - tests.append(CipherStreamingSelfTest(module, params)) - return tests - -# vim:set ts=4 sw=4 sts=4 expandtab: diff --git a/Crypto/SelfTest/Cipher/test_AES.py b/Crypto/SelfTest/Cipher/test_AES.py deleted file mode 100644 index 116deec..0000000 --- a/Crypto/SelfTest/Cipher/test_AES.py +++ /dev/null @@ -1,1351 +0,0 @@ -# -*- coding: utf-8 -*- -# -# SelfTest/Cipher/AES.py: Self-test for the AES cipher -# -# Written in 2008 by Dwayne C. Litzenberger -# -# =================================================================== -# The contents of this file are dedicated to the public domain. To -# the extent that dedication to the public domain is not available, -# everyone is granted a worldwide, perpetual, royalty-free, -# non-exclusive license to exercise all rights associated with the -# contents of this file for any purpose whatsoever. -# No rights are reserved. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS -# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN -# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# =================================================================== - -"""Self-test suite for Crypto.Cipher.AES""" - -from __future__ import print_function - -import unittest -from Crypto.Hash import SHA256 -from Crypto.Cipher import AES -from Crypto.Util.py3compat import * -from binascii import hexlify - -# This is a list of (plaintext, ciphertext, key[, description[, params]]) tuples. -test_data = [ - # FIPS PUB 197 test vectors - # http://csrc.nist.gov/publications/fips/fips197/fips-197.pdf - - ('00112233445566778899aabbccddeeff', '69c4e0d86a7b0430d8cdb78070b4c55a', - '000102030405060708090a0b0c0d0e0f', 'FIPS 197 C.1 (AES-128)'), - - ('00112233445566778899aabbccddeeff', 'dda97ca4864cdfe06eaf70a0ec0d7191', - '000102030405060708090a0b0c0d0e0f1011121314151617', - 'FIPS 197 C.2 (AES-192)'), - - ('00112233445566778899aabbccddeeff', '8ea2b7ca516745bfeafc49904b496089', - '000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f', - 'FIPS 197 C.3 (AES-256)'), - - # Rijndael128 test vectors - # Downloaded 2008-09-13 from - # http://www.iaik.tugraz.at/Research/krypto/AES/old/~rijmen/rijndael/testvalues.tar.gz - - # ecb_tbl.txt, KEYSIZE=128 - ('506812a45f08c889b97f5980038b8359', 'd8f532538289ef7d06b506a4fd5be9c9', - '00010203050607080a0b0c0d0f101112', - 'ecb-tbl-128: I=1'), - ('5c6d71ca30de8b8b00549984d2ec7d4b', '59ab30f4d4ee6e4ff9907ef65b1fb68c', - '14151617191a1b1c1e1f202123242526', - 'ecb-tbl-128: I=2'), - ('53f3f4c64f8616e4e7c56199f48f21f6', 'bf1ed2fcb2af3fd41443b56d85025cb1', - '28292a2b2d2e2f30323334353738393a', - 'ecb-tbl-128: I=3'), - ('a1eb65a3487165fb0f1c27ff9959f703', '7316632d5c32233edcb0780560eae8b2', - '3c3d3e3f41424344464748494b4c4d4e', - 'ecb-tbl-128: I=4'), - ('3553ecf0b1739558b08e350a98a39bfa', '408c073e3e2538072b72625e68b8364b', - '50515253555657585a5b5c5d5f606162', - 'ecb-tbl-128: I=5'), - ('67429969490b9711ae2b01dc497afde8', 'e1f94dfa776597beaca262f2f6366fea', - '64656667696a6b6c6e6f707173747576', - 'ecb-tbl-128: I=6'), - ('93385c1f2aec8bed192f5a8e161dd508', 'f29e986c6a1c27d7b29ffd7ee92b75f1', - '78797a7b7d7e7f80828384858788898a', - 'ecb-tbl-128: I=7'), - ('b5bf946be19beb8db3983b5f4c6e8ddb', '131c886a57f8c2e713aba6955e2b55b5', - '8c8d8e8f91929394969798999b9c9d9e', - 'ecb-tbl-128: I=8'), - ('41321ee10e21bd907227c4450ff42324', 'd2ab7662df9b8c740210e5eeb61c199d', - 'a0a1a2a3a5a6a7a8aaabacadafb0b1b2', - 'ecb-tbl-128: I=9'), - ('00a82f59c91c8486d12c0a80124f6089', '14c10554b2859c484cab5869bbe7c470', - 'b4b5b6b7b9babbbcbebfc0c1c3c4c5c6', - 'ecb-tbl-128: I=10'), - ('7ce0fd076754691b4bbd9faf8a1372fe', 'db4d498f0a49cf55445d502c1f9ab3b5', - 'c8c9cacbcdcecfd0d2d3d4d5d7d8d9da', - 'ecb-tbl-128: I=11'), - ('23605a8243d07764541bc5ad355b3129', '6d96fef7d66590a77a77bb2056667f7f', - 'dcdddedfe1e2e3e4e6e7e8e9ebecedee', - 'ecb-tbl-128: I=12'), - ('12a8cfa23ea764fd876232b4e842bc44', '316fb68edba736c53e78477bf913725c', - 'f0f1f2f3f5f6f7f8fafbfcfdfe010002', - 'ecb-tbl-128: I=13'), - ('bcaf32415e8308b3723e5fdd853ccc80', '6936f2b93af8397fd3a771fc011c8c37', - '04050607090a0b0c0e0f101113141516', - 'ecb-tbl-128: I=14'), - ('89afae685d801ad747ace91fc49adde0', 'f3f92f7a9c59179c1fcc2c2ba0b082cd', - '2c2d2e2f31323334363738393b3c3d3e', - 'ecb-tbl-128: I=15'), - ('f521d07b484357c4a69e76124a634216', '6a95ea659ee3889158e7a9152ff04ebc', - '40414243454647484a4b4c4d4f505152', - 'ecb-tbl-128: I=16'), - ('3e23b3bc065bcc152407e23896d77783', '1959338344e945670678a5d432c90b93', - '54555657595a5b5c5e5f606163646566', - 'ecb-tbl-128: I=17'), - ('79f0fba002be1744670e7e99290d8f52', 'e49bddd2369b83ee66e6c75a1161b394', - '68696a6b6d6e6f70727374757778797a', - 'ecb-tbl-128: I=18'), - ('da23fe9d5bd63e1d72e3dafbe21a6c2a', 'd3388f19057ff704b70784164a74867d', - '7c7d7e7f81828384868788898b8c8d8e', - 'ecb-tbl-128: I=19'), - ('e3f5698ba90b6a022efd7db2c7e6c823', '23aa03e2d5e4cd24f3217e596480d1e1', - 'a4a5a6a7a9aaabacaeafb0b1b3b4b5b6', - 'ecb-tbl-128: I=20'), - ('bdc2691d4f1b73d2700679c3bcbf9c6e', 'c84113d68b666ab2a50a8bdb222e91b9', - 'e0e1e2e3e5e6e7e8eaebecedeff0f1f2', - 'ecb-tbl-128: I=21'), - ('ba74e02093217ee1ba1b42bd5624349a', 'ac02403981cd4340b507963db65cb7b6', - '08090a0b0d0e0f10121314151718191a', - 'ecb-tbl-128: I=22'), - ('b5c593b5851c57fbf8b3f57715e8f680', '8d1299236223359474011f6bf5088414', - '6c6d6e6f71727374767778797b7c7d7e', - 'ecb-tbl-128: I=23'), - ('3da9bd9cec072381788f9387c3bbf4ee', '5a1d6ab8605505f7977e55b9a54d9b90', - '80818283858687888a8b8c8d8f909192', - 'ecb-tbl-128: I=24'), - ('4197f3051121702ab65d316b3c637374', '72e9c2d519cf555e4208805aabe3b258', - '94959697999a9b9c9e9fa0a1a3a4a5a6', - 'ecb-tbl-128: I=25'), - ('9f46c62ec4f6ee3f6e8c62554bc48ab7', 'a8f3e81c4a23a39ef4d745dffe026e80', - 'a8a9aaabadaeafb0b2b3b4b5b7b8b9ba', - 'ecb-tbl-128: I=26'), - ('0220673fe9e699a4ebc8e0dbeb6979c8', '546f646449d31458f9eb4ef5483aee6c', - 'bcbdbebfc1c2c3c4c6c7c8c9cbcccdce', - 'ecb-tbl-128: I=27'), - ('b2b99171337ded9bc8c2c23ff6f18867', '4dbe4bc84ac797c0ee4efb7f1a07401c', - 'd0d1d2d3d5d6d7d8dadbdcdddfe0e1e2', - 'ecb-tbl-128: I=28'), - ('a7facf4e301e984e5efeefd645b23505', '25e10bfb411bbd4d625ac8795c8ca3b3', - 'e4e5e6e7e9eaebeceeeff0f1f3f4f5f6', - 'ecb-tbl-128: I=29'), - ('f7c762e4a9819160fd7acfb6c4eedcdd', '315637405054ec803614e43def177579', - 'f8f9fafbfdfefe00020304050708090a', - 'ecb-tbl-128: I=30'), - ('9b64fc21ea08709f4915436faa70f1be', '60c5bc8a1410247295c6386c59e572a8', - '0c0d0e0f11121314161718191b1c1d1e', - 'ecb-tbl-128: I=31'), - ('52af2c3de07ee6777f55a4abfc100b3f', '01366fc8ca52dfe055d6a00a76471ba6', - '20212223252627282a2b2c2d2f303132', - 'ecb-tbl-128: I=32'), - ('2fca001224386c57aa3f968cbe2c816f', 'ecc46595516ec612449c3f581e7d42ff', - '34353637393a3b3c3e3f404143444546', - 'ecb-tbl-128: I=33'), - ('4149c73658a4a9c564342755ee2c132f', '6b7ffe4c602a154b06ee9c7dab5331c9', - '48494a4b4d4e4f50525354555758595a', - 'ecb-tbl-128: I=34'), - ('af60005a00a1772f7c07a48a923c23d2', '7da234c14039a240dd02dd0fbf84eb67', - '5c5d5e5f61626364666768696b6c6d6e', - 'ecb-tbl-128: I=35'), - ('6fccbc28363759914b6f0280afaf20c6', 'c7dc217d9e3604ffe7e91f080ecd5a3a', - '70717273757677787a7b7c7d7f808182', - 'ecb-tbl-128: I=36'), - ('7d82a43ddf4fefa2fc5947499884d386', '37785901863f5c81260ea41e7580cda5', - '84858687898a8b8c8e8f909193949596', - 'ecb-tbl-128: I=37'), - ('5d5a990eaab9093afe4ce254dfa49ef9', 'a07b9338e92ed105e6ad720fccce9fe4', - '98999a9b9d9e9fa0a2a3a4a5a7a8a9aa', - 'ecb-tbl-128: I=38'), - ('4cd1e2fd3f4434b553aae453f0ed1a02', 'ae0fb9722418cc21a7da816bbc61322c', - 'acadaeafb1b2b3b4b6b7b8b9bbbcbdbe', - 'ecb-tbl-128: I=39'), - ('5a2c9a9641d4299125fa1b9363104b5e', 'c826a193080ff91ffb21f71d3373c877', - 'c0c1c2c3c5c6c7c8cacbcccdcfd0d1d2', - 'ecb-tbl-128: I=40'), - ('b517fe34c0fa217d341740bfd4fe8dd4', '1181b11b0e494e8d8b0aa6b1d5ac2c48', - 'd4d5d6d7d9dadbdcdedfe0e1e3e4e5e6', - 'ecb-tbl-128: I=41'), - ('014baf2278a69d331d5180103643e99a', '6743c3d1519ab4f2cd9a78ab09a511bd', - 'e8e9eaebedeeeff0f2f3f4f5f7f8f9fa', - 'ecb-tbl-128: I=42'), - ('b529bd8164f20d0aa443d4932116841c', 'dc55c076d52bacdf2eefd952946a439d', - 'fcfdfeff01020304060708090b0c0d0e', - 'ecb-tbl-128: I=43'), - ('2e596dcbb2f33d4216a1176d5bd1e456', '711b17b590ffc72b5c8e342b601e8003', - '10111213151617181a1b1c1d1f202122', - 'ecb-tbl-128: I=44'), - ('7274a1ea2b7ee2424e9a0e4673689143', '19983bb0950783a537e1339f4aa21c75', - '24252627292a2b2c2e2f303133343536', - 'ecb-tbl-128: I=45'), - ('ae20020bd4f13e9d90140bee3b5d26af', '3ba7762e15554169c0f4fa39164c410c', - '38393a3b3d3e3f40424344454748494a', - 'ecb-tbl-128: I=46'), - ('baac065da7ac26e855e79c8849d75a02', 'a0564c41245afca7af8aa2e0e588ea89', - '4c4d4e4f51525354565758595b5c5d5e', - 'ecb-tbl-128: I=47'), - ('7c917d8d1d45fab9e2540e28832540cc', '5e36a42a2e099f54ae85ecd92e2381ed', - '60616263656667686a6b6c6d6f707172', - 'ecb-tbl-128: I=48'), - ('bde6f89e16daadb0e847a2a614566a91', '770036f878cd0f6ca2268172f106f2fe', - '74757677797a7b7c7e7f808183848586', - 'ecb-tbl-128: I=49'), - ('c9de163725f1f5be44ebb1db51d07fbc', '7e4e03908b716116443ccf7c94e7c259', - '88898a8b8d8e8f90929394959798999a', - 'ecb-tbl-128: I=50'), - ('3af57a58f0c07dffa669572b521e2b92', '482735a48c30613a242dd494c7f9185d', - '9c9d9e9fa1a2a3a4a6a7a8a9abacadae', - 'ecb-tbl-128: I=51'), - ('3d5ebac306dde4604f1b4fbbbfcdae55', 'b4c0f6c9d4d7079addf9369fc081061d', - 'b0b1b2b3b5b6b7b8babbbcbdbfc0c1c2', - 'ecb-tbl-128: I=52'), - ('c2dfa91bceb76a1183c995020ac0b556', 'd5810fe0509ac53edcd74f89962e6270', - 'c4c5c6c7c9cacbcccecfd0d1d3d4d5d6', - 'ecb-tbl-128: I=53'), - ('c70f54305885e9a0746d01ec56c8596b', '03f17a16b3f91848269ecdd38ebb2165', - 'd8d9dadbdddedfe0e2e3e4e5e7e8e9ea', - 'ecb-tbl-128: I=54'), - ('c4f81b610e98012ce000182050c0c2b2', 'da1248c3180348bad4a93b4d9856c9df', - 'ecedeeeff1f2f3f4f6f7f8f9fbfcfdfe', - 'ecb-tbl-128: I=55'), - ('eaab86b1d02a95d7404eff67489f97d4', '3d10d7b63f3452c06cdf6cce18be0c2c', - '00010203050607080a0b0c0d0f101112', - 'ecb-tbl-128: I=56'), - ('7c55bdb40b88870b52bec3738de82886', '4ab823e7477dfddc0e6789018fcb6258', - '14151617191a1b1c1e1f202123242526', - 'ecb-tbl-128: I=57'), - ('ba6eaa88371ff0a3bd875e3f2a975ce0', 'e6478ba56a77e70cfdaa5c843abde30e', - '28292a2b2d2e2f30323334353738393a', - 'ecb-tbl-128: I=58'), - ('08059130c4c24bd30cf0575e4e0373dc', '1673064895fbeaf7f09c5429ff75772d', - '3c3d3e3f41424344464748494b4c4d4e', - 'ecb-tbl-128: I=59'), - ('9a8eab004ef53093dfcf96f57e7eda82', '4488033ae9f2efd0ca9383bfca1a94e9', - '50515253555657585a5b5c5d5f606162', - 'ecb-tbl-128: I=60'), - ('0745b589e2400c25f117b1d796c28129', '978f3b8c8f9d6f46626cac3c0bcb9217', - '64656667696a6b6c6e6f707173747576', - 'ecb-tbl-128: I=61'), - ('2f1777781216cec3f044f134b1b92bbe', 'e08c8a7e582e15e5527f1d9e2eecb236', - '78797a7b7d7e7f80828384858788898a', - 'ecb-tbl-128: I=62'), - ('353a779ffc541b3a3805d90ce17580fc', 'cec155b76ac5ffda4cf4f9ca91e49a7a', - '8c8d8e8f91929394969798999b9c9d9e', - 'ecb-tbl-128: I=63'), - ('1a1eae4415cefcf08c4ac1c8f68bea8f', 'd5ac7165763225dd2a38cdc6862c29ad', - 'a0a1a2a3a5a6a7a8aaabacadafb0b1b2', - 'ecb-tbl-128: I=64'), - ('e6e7e4e5b0b3b2b5d4d5aaab16111013', '03680fe19f7ce7275452020be70e8204', - 'b4b5b6b7b9babbbcbebfc0c1c3c4c5c6', - 'ecb-tbl-128: I=65'), - ('f8f9fafbfbf8f9e677767170efe0e1e2', '461df740c9781c388e94bb861ceb54f6', - 'c8c9cacbcdcecfd0d2d3d4d5d7d8d9da', - 'ecb-tbl-128: I=66'), - ('63626160a1a2a3a445444b4a75727370', '451bd60367f96483042742219786a074', - 'dcdddedfe1e2e3e4e6e7e8e9ebecedee', - 'ecb-tbl-128: I=67'), - ('717073720605040b2d2c2b2a05fafbf9', 'e4dfa42671a02e57ef173b85c0ea9f2b', - 'f0f1f2f3f5f6f7f8fafbfcfdfe010002', - 'ecb-tbl-128: I=68'), - ('78797a7beae9e8ef3736292891969794', 'ed11b89e76274282227d854700a78b9e', - '04050607090a0b0c0e0f101113141516', - 'ecb-tbl-128: I=69'), - ('838281803231300fdddcdbdaa0afaead', '433946eaa51ea47af33895f2b90b3b75', - '18191a1b1d1e1f20222324252728292a', - 'ecb-tbl-128: I=70'), - ('18191a1bbfbcbdba75747b7a7f78797a', '6bc6d616a5d7d0284a5910ab35022528', - '2c2d2e2f31323334363738393b3c3d3e', - 'ecb-tbl-128: I=71'), - ('848586879b989996a3a2a5a4849b9a99', 'd2a920ecfe919d354b5f49eae9719c98', - '40414243454647484a4b4c4d4f505152', - 'ecb-tbl-128: I=72'), - ('0001020322212027cacbf4f551565754', '3a061b17f6a92885efbd0676985b373d', - '54555657595a5b5c5e5f606163646566', - 'ecb-tbl-128: I=73'), - ('cecfcccdafacadb2515057564a454447', 'fadeec16e33ea2f4688499d157e20d8f', - '68696a6b6d6e6f70727374757778797a', - 'ecb-tbl-128: I=74'), - ('92939091cdcecfc813121d1c80878685', '5cdefede59601aa3c3cda36fa6b1fa13', - '7c7d7e7f81828384868788898b8c8d8e', - 'ecb-tbl-128: I=75'), - ('d2d3d0d16f6c6d6259585f5ed1eeefec', '9574b00039844d92ebba7ee8719265f8', - '90919293959697989a9b9c9d9fa0a1a2', - 'ecb-tbl-128: I=76'), - ('acadaeaf878485820f0e1110d5d2d3d0', '9a9cf33758671787e5006928188643fa', - 'a4a5a6a7a9aaabacaeafb0b1b3b4b5b6', - 'ecb-tbl-128: I=77'), - ('9091929364676619e6e7e0e1757a7b78', '2cddd634c846ba66bb46cbfea4a674f9', - 'b8b9babbbdbebfc0c2c3c4c5c7c8c9ca', - 'ecb-tbl-128: I=78'), - ('babbb8b98a89888f74757a7b92959497', 'd28bae029393c3e7e26e9fafbbb4b98f', - 'cccdcecfd1d2d3d4d6d7d8d9dbdcddde', - 'ecb-tbl-128: I=79'), - ('8d8c8f8e6e6d6c633b3a3d3ccad5d4d7', 'ec27529b1bee0a9ab6a0d73ebc82e9b7', - 'e0e1e2e3e5e6e7e8eaebecedeff0f1f2', - 'ecb-tbl-128: I=80'), - ('86878485010203040808f7f767606162', '3cb25c09472aff6ee7e2b47ccd7ccb17', - 'f4f5f6f7f9fafbfcfefe010103040506', - 'ecb-tbl-128: I=81'), - ('8e8f8c8d656667788a8b8c8d010e0f0c', 'dee33103a7283370d725e44ca38f8fe5', - '08090a0b0d0e0f10121314151718191a', - 'ecb-tbl-128: I=82'), - ('c8c9cacb858687807a7b7475e7e0e1e2', '27f9bcd1aac64bffc11e7815702c1a69', - '1c1d1e1f21222324262728292b2c2d2e', - 'ecb-tbl-128: I=83'), - ('6d6c6f6e5053525d8c8d8a8badd2d3d0', '5df534ffad4ed0749a9988e9849d0021', - '30313233353637383a3b3c3d3f404142', - 'ecb-tbl-128: I=84'), - ('28292a2b393a3b3c0607181903040506', 'a48bee75db04fb60ca2b80f752a8421b', - '44454647494a4b4c4e4f505153545556', - 'ecb-tbl-128: I=85'), - ('a5a4a7a6b0b3b28ddbdadddcbdb2b3b0', '024c8cf70bc86ee5ce03678cb7af45f9', - '58595a5b5d5e5f60626364656768696a', - 'ecb-tbl-128: I=86'), - ('323330316467666130313e3f2c2b2a29', '3c19ac0f8a3a3862ce577831301e166b', - '6c6d6e6f71727374767778797b7c7d7e', - 'ecb-tbl-128: I=87'), - ('27262524080b0a05171611100b141516', 'c5e355b796a57421d59ca6be82e73bca', - '80818283858687888a8b8c8d8f909192', - 'ecb-tbl-128: I=88'), - ('040506074142434435340b0aa3a4a5a6', 'd94033276417abfb05a69d15b6e386e2', - '94959697999a9b9c9e9fa0a1a3a4a5a6', - 'ecb-tbl-128: I=89'), - ('242526271112130c61606766bdb2b3b0', '24b36559ea3a9b9b958fe6da3e5b8d85', - 'a8a9aaabadaeafb0b2b3b4b5b7b8b9ba', - 'ecb-tbl-128: I=90'), - ('4b4a4948252627209e9f9091cec9c8cb', '20fd4feaa0e8bf0cce7861d74ef4cb72', - 'bcbdbebfc1c2c3c4c6c7c8c9cbcccdce', - 'ecb-tbl-128: I=91'), - ('68696a6b6665646b9f9e9998d9e6e7e4', '350e20d5174277b9ec314c501570a11d', - 'd0d1d2d3d5d6d7d8dadbdcdddfe0e1e2', - 'ecb-tbl-128: I=92'), - ('34353637c5c6c7c0f0f1eeef7c7b7a79', '87a29d61b7c604d238fe73045a7efd57', - 'e4e5e6e7e9eaebeceeeff0f1f3f4f5f6', - 'ecb-tbl-128: I=93'), - ('32333031c2c1c13f0d0c0b0a050a0b08', '2c3164c1cc7d0064816bdc0faa362c52', - 'f8f9fafbfdfefe00020304050708090a', - 'ecb-tbl-128: I=94'), - ('cdcccfcebebdbcbbabaaa5a4181f1e1d', '195fe5e8a05a2ed594f6e4400eee10b3', - '0c0d0e0f11121314161718191b1c1d1e', - 'ecb-tbl-128: I=95'), - ('212023223635343ba0a1a6a7445b5a59', 'e4663df19b9a21a5a284c2bd7f905025', - '20212223252627282a2b2c2d2f303132', - 'ecb-tbl-128: I=96'), - ('0e0f0c0da8abaaad2f2e515002050407', '21b88714cfb4e2a933bd281a2c4743fd', - '34353637393a3b3c3e3f404143444546', - 'ecb-tbl-128: I=97'), - ('070605042a2928378e8f8889bdb2b3b0', 'cbfc3980d704fd0fc54378ab84e17870', - '48494a4b4d4e4f50525354555758595a', - 'ecb-tbl-128: I=98'), - ('cbcac9c893909196a9a8a7a6a5a2a3a0', 'bc5144baa48bdeb8b63e22e03da418ef', - '5c5d5e5f61626364666768696b6c6d6e', - 'ecb-tbl-128: I=99'), - ('80818283c1c2c3cc9c9d9a9b0cf3f2f1', '5a1dbaef1ee2984b8395da3bdffa3ccc', - '70717273757677787a7b7c7d7f808182', - 'ecb-tbl-128: I=100'), - ('1213101125262720fafbe4e5b1b6b7b4', 'f0b11cd0729dfcc80cec903d97159574', - '84858687898a8b8c8e8f909193949596', - 'ecb-tbl-128: I=101'), - ('7f7e7d7c3033320d97969190222d2c2f', '9f95314acfddc6d1914b7f19a9cc8209', - '98999a9b9d9e9fa0a2a3a4a5a7a8a9aa', - 'ecb-tbl-128: I=102'), - ('4e4f4c4d484b4a4d81808f8e53545556', '595736f6f0f70914a94e9e007f022519', - 'acadaeafb1b2b3b4b6b7b8b9bbbcbdbe', - 'ecb-tbl-128: I=103'), - ('dcdddedfb0b3b2bd15141312a1bebfbc', '1f19f57892cae586fcdfb4c694deb183', - 'c0c1c2c3c5c6c7c8cacbcccdcfd0d1d2', - 'ecb-tbl-128: I=104'), - ('93929190282b2a2dc4c5fafb92959497', '540700ee1f6f3dab0b3eddf6caee1ef5', - 'd4d5d6d7d9dadbdcdedfe0e1e3e4e5e6', - 'ecb-tbl-128: I=105'), - ('f5f4f7f6c4c7c6d9373631307e717073', '14a342a91019a331687a2254e6626ca2', - 'e8e9eaebedeeeff0f2f3f4f5f7f8f9fa', - 'ecb-tbl-128: I=106'), - ('93929190b6b5b4b364656a6b05020300', '7b25f3c3b2eea18d743ef283140f29ff', - 'fcfdfeff01020304060708090b0c0d0e', - 'ecb-tbl-128: I=107'), - ('babbb8b90d0e0f00a4a5a2a3043b3a39', '46c2587d66e5e6fa7f7ca6411ad28047', - '10111213151617181a1b1c1d1f202122', - 'ecb-tbl-128: I=108'), - ('d8d9dadb7f7c7d7a10110e0f787f7e7d', '09470e72229d954ed5ee73886dfeeba9', - '24252627292a2b2c2e2f303133343536', - 'ecb-tbl-128: I=109'), - ('fefffcfdefeced923b3a3d3c6768696a', 'd77c03de92d4d0d79ef8d4824ef365eb', - '38393a3b3d3e3f40424344454748494a', - 'ecb-tbl-128: I=110'), - ('d6d7d4d58a89888f96979899a5a2a3a0', '1d190219f290e0f1715d152d41a23593', - '4c4d4e4f51525354565758595b5c5d5e', - 'ecb-tbl-128: I=111'), - ('18191a1ba8abaaa5303136379b848586', 'a2cd332ce3a0818769616292e87f757b', - '60616263656667686a6b6c6d6f707172', - 'ecb-tbl-128: I=112'), - ('6b6a6968a4a7a6a1d6d72829b0b7b6b5', 'd54afa6ce60fbf9341a3690e21385102', - '74757677797a7b7c7e7f808183848586', - 'ecb-tbl-128: I=113'), - ('000102038a89889755545352a6a9a8ab', '06e5c364ded628a3f5e05e613e356f46', - '88898a8b8d8e8f90929394959798999a', - 'ecb-tbl-128: I=114'), - ('2d2c2f2eb3b0b1b6b6b7b8b9f2f5f4f7', 'eae63c0e62556dac85d221099896355a', - '9c9d9e9fa1a2a3a4a6a7a8a9abacadae', - 'ecb-tbl-128: I=115'), - ('979695943536373856575051e09f9e9d', '1fed060e2c6fc93ee764403a889985a2', - 'b0b1b2b3b5b6b7b8babbbcbdbfc0c1c2', - 'ecb-tbl-128: I=116'), - ('a4a5a6a7989b9a9db1b0afae7a7d7c7f', 'c25235c1a30fdec1c7cb5c5737b2a588', - 'c4c5c6c7c9cacbcccecfd0d1d3d4d5d6', - 'ecb-tbl-128: I=117'), - ('c1c0c3c2686b6a55a8a9aeafeae5e4e7', '796dbef95147d4d30873ad8b7b92efc0', - 'd8d9dadbdddedfe0e2e3e4e5e7e8e9ea', - 'ecb-tbl-128: I=118'), - ('c1c0c3c2141716118c8d828364636261', 'cbcf0fb34d98d0bd5c22ce37211a46bf', - 'ecedeeeff1f2f3f4f6f7f8f9fbfcfdfe', - 'ecb-tbl-128: I=119'), - ('93929190cccfcec196979091e0fffefd', '94b44da6466126cafa7c7fd09063fc24', - '00010203050607080a0b0c0d0f101112', - 'ecb-tbl-128: I=120'), - ('b4b5b6b7f9fafbfc25241b1a6e69686b', 'd78c5b5ebf9b4dbda6ae506c5074c8fe', - '14151617191a1b1c1e1f202123242526', - 'ecb-tbl-128: I=121'), - ('868784850704051ac7c6c1c08788898a', '6c27444c27204b043812cf8cf95f9769', - '28292a2b2d2e2f30323334353738393a', - 'ecb-tbl-128: I=122'), - ('f4f5f6f7aaa9a8affdfcf3f277707172', 'be94524ee5a2aa50bba8b75f4c0aebcf', - '3c3d3e3f41424344464748494b4c4d4e', - 'ecb-tbl-128: I=123'), - ('d3d2d1d00605040bc3c2c5c43e010003', 'a0aeaae91ba9f31f51aeb3588cf3a39e', - '50515253555657585a5b5c5d5f606162', - 'ecb-tbl-128: I=124'), - ('73727170424140476a6b74750d0a0b08', '275297779c28266ef9fe4c6a13c08488', - '64656667696a6b6c6e6f707173747576', - 'ecb-tbl-128: I=125'), - ('c2c3c0c10a0908f754555253a1aeafac', '86523d92bb8672cb01cf4a77fd725882', - '78797a7b7d7e7f80828384858788898a', - 'ecb-tbl-128: I=126'), - ('6d6c6f6ef8fbfafd82838c8df8fffefd', '4b8327640e9f33322a04dd96fcbf9a36', - '8c8d8e8f91929394969798999b9c9d9e', - 'ecb-tbl-128: I=127'), - ('f5f4f7f684878689a6a7a0a1d2cdcccf', 'ce52af650d088ca559425223f4d32694', - 'a0a1a2a3a5a6a7a8aaabacadafb0b1b2', - 'ecb-tbl-128: I=128'), - - # ecb_tbl.txt, KEYSIZE=192 - ('2d33eef2c0430a8a9ebf45e809c40bb6', 'dff4945e0336df4c1c56bc700eff837f', - '00010203050607080a0b0c0d0f10111214151617191a1b1c', - 'ecb-tbl-192: I=1'), - ('6aa375d1fa155a61fb72353e0a5a8756', 'b6fddef4752765e347d5d2dc196d1252', - '1e1f20212324252628292a2b2d2e2f30323334353738393a', - 'ecb-tbl-192: I=2'), - ('bc3736518b9490dcb8ed60eb26758ed4', 'd23684e3d963b3afcf1a114aca90cbd6', - '3c3d3e3f41424344464748494b4c4d4e5051525355565758', - 'ecb-tbl-192: I=3'), - ('aa214402b46cffb9f761ec11263a311e', '3a7ac027753e2a18c2ceab9e17c11fd0', - '5a5b5c5d5f60616264656667696a6b6c6e6f707173747576', - 'ecb-tbl-192: I=4'), - ('02aea86e572eeab66b2c3af5e9a46fd6', '8f6786bd007528ba26603c1601cdd0d8', - '78797a7b7d7e7f80828384858788898a8c8d8e8f91929394', - 'ecb-tbl-192: I=5'), - ('e2aef6acc33b965c4fa1f91c75ff6f36', 'd17d073b01e71502e28b47ab551168b3', - '969798999b9c9d9ea0a1a2a3a5a6a7a8aaabacadafb0b1b2', - 'ecb-tbl-192: I=6'), - ('0659df46427162b9434865dd9499f91d', 'a469da517119fab95876f41d06d40ffa', - 'b4b5b6b7b9babbbcbebfc0c1c3c4c5c6c8c9cacbcdcecfd0', - 'ecb-tbl-192: I=7'), - ('49a44239c748feb456f59c276a5658df', '6091aa3b695c11f5c0b6ad26d3d862ff', - 'd2d3d4d5d7d8d9dadcdddedfe1e2e3e4e6e7e8e9ebecedee', - 'ecb-tbl-192: I=8'), - ('66208f6e9d04525bdedb2733b6a6be37', '70f9e67f9f8df1294131662dc6e69364', - 'f0f1f2f3f5f6f7f8fafbfcfdfe01000204050607090a0b0c', - 'ecb-tbl-192: I=9'), - ('3393f8dfc729c97f5480b950bc9666b0', 'd154dcafad8b207fa5cbc95e9996b559', - '0e0f10111314151618191a1b1d1e1f20222324252728292a', - 'ecb-tbl-192: I=10'), - ('606834c8ce063f3234cf1145325dbd71', '4934d541e8b46fa339c805a7aeb9e5da', - '2c2d2e2f31323334363738393b3c3d3e4041424345464748', - 'ecb-tbl-192: I=11'), - ('fec1c04f529bbd17d8cecfcc4718b17f', '62564c738f3efe186e1a127a0c4d3c61', - '4a4b4c4d4f50515254555657595a5b5c5e5f606163646566', - 'ecb-tbl-192: I=12'), - ('32df99b431ed5dc5acf8caf6dc6ce475', '07805aa043986eb23693e23bef8f3438', - '68696a6b6d6e6f70727374757778797a7c7d7e7f81828384', - 'ecb-tbl-192: I=13'), - ('7fdc2b746f3f665296943b83710d1f82', 'df0b4931038bade848dee3b4b85aa44b', - '868788898b8c8d8e90919293959697989a9b9c9d9fa0a1a2', - 'ecb-tbl-192: I=14'), - ('8fba1510a3c5b87e2eaa3f7a91455ca2', '592d5fded76582e4143c65099309477c', - 'a4a5a6a7a9aaabacaeafb0b1b3b4b5b6b8b9babbbdbebfc0', - 'ecb-tbl-192: I=15'), - ('2c9b468b1c2eed92578d41b0716b223b', 'c9b8d6545580d3dfbcdd09b954ed4e92', - 'c2c3c4c5c7c8c9cacccdcecfd1d2d3d4d6d7d8d9dbdcddde', - 'ecb-tbl-192: I=16'), - ('0a2bbf0efc6bc0034f8a03433fca1b1a', '5dccd5d6eb7c1b42acb008201df707a0', - 'e0e1e2e3e5e6e7e8eaebecedeff0f1f2f4f5f6f7f9fafbfc', - 'ecb-tbl-192: I=17'), - ('25260e1f31f4104d387222e70632504b', 'a2a91682ffeb6ed1d34340946829e6f9', - 'fefe01010304050608090a0b0d0e0f10121314151718191a', - 'ecb-tbl-192: I=18'), - ('c527d25a49f08a5228d338642ae65137', 'e45d185b797000348d9267960a68435d', - '1c1d1e1f21222324262728292b2c2d2e3031323335363738', - 'ecb-tbl-192: I=19'), - ('3b49fc081432f5890d0e3d87e884a69e', '45e060dae5901cda8089e10d4f4c246b', - '3a3b3c3d3f40414244454647494a4b4c4e4f505153545556', - 'ecb-tbl-192: I=20'), - ('d173f9ed1e57597e166931df2754a083', 'f6951afacc0079a369c71fdcff45df50', - '58595a5b5d5e5f60626364656768696a6c6d6e6f71727374', - 'ecb-tbl-192: I=21'), - ('8c2b7cafa5afe7f13562daeae1adede0', '9e95e00f351d5b3ac3d0e22e626ddad6', - '767778797b7c7d7e80818283858687888a8b8c8d8f909192', - 'ecb-tbl-192: I=22'), - ('aaf4ec8c1a815aeb826cab741339532c', '9cb566ff26d92dad083b51fdc18c173c', - '94959697999a9b9c9e9fa0a1a3a4a5a6a8a9aaabadaeafb0', - 'ecb-tbl-192: I=23'), - ('40be8c5d9108e663f38f1a2395279ecf', 'c9c82766176a9b228eb9a974a010b4fb', - 'd0d1d2d3d5d6d7d8dadbdcdddfe0e1e2e4e5e6e7e9eaebec', - 'ecb-tbl-192: I=24'), - ('0c8ad9bc32d43e04716753aa4cfbe351', 'd8e26aa02945881d5137f1c1e1386e88', - '2a2b2c2d2f30313234353637393a3b3c3e3f404143444546', - 'ecb-tbl-192: I=25'), - ('1407b1d5f87d63357c8dc7ebbaebbfee', 'c0e024ccd68ff5ffa4d139c355a77c55', - '48494a4b4d4e4f50525354555758595a5c5d5e5f61626364', - 'ecb-tbl-192: I=26'), - ('e62734d1ae3378c4549e939e6f123416', '0b18b3d16f491619da338640df391d43', - '84858687898a8b8c8e8f90919394959698999a9b9d9e9fa0', - 'ecb-tbl-192: I=27'), - ('5a752cff2a176db1a1de77f2d2cdee41', 'dbe09ac8f66027bf20cb6e434f252efc', - 'a2a3a4a5a7a8a9aaacadaeafb1b2b3b4b6b7b8b9bbbcbdbe', - 'ecb-tbl-192: I=28'), - ('a9c8c3a4eabedc80c64730ddd018cd88', '6d04e5e43c5b9cbe05feb9606b6480fe', - 'c0c1c2c3c5c6c7c8cacbcccdcfd0d1d2d4d5d6d7d9dadbdc', - 'ecb-tbl-192: I=29'), - ('ee9b3dbbdb86180072130834d305999a', 'dd1d6553b96be526d9fee0fbd7176866', - '1a1b1c1d1f20212224252627292a2b2c2e2f303133343536', - 'ecb-tbl-192: I=30'), - ('a7fa8c3586b8ebde7568ead6f634a879', '0260ca7e3f979fd015b0dd4690e16d2a', - '38393a3b3d3e3f40424344454748494a4c4d4e4f51525354', - 'ecb-tbl-192: I=31'), - ('37e0f4a87f127d45ac936fe7ad88c10a', '9893734de10edcc8a67c3b110b8b8cc6', - '929394959798999a9c9d9e9fa1a2a3a4a6a7a8a9abacadae', - 'ecb-tbl-192: I=32'), - ('3f77d8b5d92bac148e4e46f697a535c5', '93b30b750516b2d18808d710c2ee84ef', - '464748494b4c4d4e50515253555657585a5b5c5d5f606162', - 'ecb-tbl-192: I=33'), - ('d25ebb686c40f7e2c4da1014936571ca', '16f65fa47be3cb5e6dfe7c6c37016c0e', - '828384858788898a8c8d8e8f91929394969798999b9c9d9e', - 'ecb-tbl-192: I=34'), - ('4f1c769d1e5b0552c7eca84dea26a549', 'f3847210d5391e2360608e5acb560581', - 'a0a1a2a3a5a6a7a8aaabacadafb0b1b2b4b5b6b7b9babbbc', - 'ecb-tbl-192: I=35'), - ('8548e2f882d7584d0fafc54372b6633a', '8754462cd223366d0753913e6af2643d', - 'bebfc0c1c3c4c5c6c8c9cacbcdcecfd0d2d3d4d5d7d8d9da', - 'ecb-tbl-192: I=36'), - ('87d7a336cb476f177cd2a51af2a62cdf', '1ea20617468d1b806a1fd58145462017', - 'dcdddedfe1e2e3e4e6e7e8e9ebecedeef0f1f2f3f5f6f7f8', - 'ecb-tbl-192: I=37'), - ('03b1feac668c4e485c1065dfc22b44ee', '3b155d927355d737c6be9dda60136e2e', - 'fafbfcfdfe01000204050607090a0b0c0e0f101113141516', - 'ecb-tbl-192: I=38'), - ('bda15e66819fa72d653a6866aa287962', '26144f7b66daa91b6333dbd3850502b3', - '18191a1b1d1e1f20222324252728292a2c2d2e2f31323334', - 'ecb-tbl-192: I=39'), - ('4d0c7a0d2505b80bf8b62ceb12467f0a', 'e4f9a4ab52ced8134c649bf319ebcc90', - '363738393b3c3d3e40414243454647484a4b4c4d4f505152', - 'ecb-tbl-192: I=40'), - ('626d34c9429b37211330986466b94e5f', 'b9ddd29ac6128a6cab121e34a4c62b36', - '54555657595a5b5c5e5f60616364656668696a6b6d6e6f70', - 'ecb-tbl-192: I=41'), - ('333c3e6bf00656b088a17e5ff0e7f60a', '6fcddad898f2ce4eff51294f5eaaf5c9', - '727374757778797a7c7d7e7f81828384868788898b8c8d8e', - 'ecb-tbl-192: I=42'), - ('687ed0cdc0d2a2bc8c466d05ef9d2891', 'c9a6fe2bf4028080bea6f7fc417bd7e3', - '90919293959697989a9b9c9d9fa0a1a2a4a5a6a7a9aaabac', - 'ecb-tbl-192: I=43'), - ('487830e78cc56c1693e64b2a6660c7b6', '6a2026846d8609d60f298a9c0673127f', - 'aeafb0b1b3b4b5b6b8b9babbbdbebfc0c2c3c4c5c7c8c9ca', - 'ecb-tbl-192: I=44'), - ('7a48d6b7b52b29392aa2072a32b66160', '2cb25c005e26efea44336c4c97a4240b', - 'cccdcecfd1d2d3d4d6d7d8d9dbdcdddee0e1e2e3e5e6e7e8', - 'ecb-tbl-192: I=45'), - ('907320e64c8c5314d10f8d7a11c8618d', '496967ab8680ddd73d09a0e4c7dcc8aa', - 'eaebecedeff0f1f2f4f5f6f7f9fafbfcfefe010103040506', - 'ecb-tbl-192: I=46'), - ('b561f2ca2d6e65a4a98341f3ed9ff533', 'd5af94de93487d1f3a8c577cb84a66a4', - '08090a0b0d0e0f10121314151718191a1c1d1e1f21222324', - 'ecb-tbl-192: I=47'), - ('df769380d212792d026f049e2e3e48ef', '84bdac569cae2828705f267cc8376e90', - '262728292b2c2d2e30313233353637383a3b3c3d3f404142', - 'ecb-tbl-192: I=48'), - ('79f374bc445bdabf8fccb8843d6054c6', 'f7401dda5ad5ab712b7eb5d10c6f99b6', - '44454647494a4b4c4e4f50515354555658595a5b5d5e5f60', - 'ecb-tbl-192: I=49'), - ('4e02f1242fa56b05c68dbae8fe44c9d6', '1c9d54318539ebd4c3b5b7e37bf119f0', - '626364656768696a6c6d6e6f71727374767778797b7c7d7e', - 'ecb-tbl-192: I=50'), - ('cf73c93cbff57ac635a6f4ad2a4a1545', 'aca572d65fb2764cffd4a6eca090ea0d', - '80818283858687888a8b8c8d8f90919294959697999a9b9c', - 'ecb-tbl-192: I=51'), - ('9923548e2875750725b886566784c625', '36d9c627b8c2a886a10ccb36eae3dfbb', - '9e9fa0a1a3a4a5a6a8a9aaabadaeafb0b2b3b4b5b7b8b9ba', - 'ecb-tbl-192: I=52'), - ('4888336b723a022c9545320f836a4207', '010edbf5981e143a81d646e597a4a568', - 'bcbdbebfc1c2c3c4c6c7c8c9cbcccdced0d1d2d3d5d6d7d8', - 'ecb-tbl-192: I=53'), - ('f84d9a5561b0608b1160dee000c41ba8', '8db44d538dc20cc2f40f3067fd298e60', - 'dadbdcdddfe0e1e2e4e5e6e7e9eaebeceeeff0f1f3f4f5f6', - 'ecb-tbl-192: I=54'), - ('c23192a0418e30a19b45ae3e3625bf22', '930eb53bc71e6ac4b82972bdcd5aafb3', - 'f8f9fafbfdfefe00020304050708090a0c0d0e0f11121314', - 'ecb-tbl-192: I=55'), - ('b84e0690b28b0025381ad82a15e501a7', '6c42a81edcbc9517ccd89c30c95597b4', - '161718191b1c1d1e20212223252627282a2b2c2d2f303132', - 'ecb-tbl-192: I=56'), - ('acef5e5c108876c4f06269f865b8f0b0', 'da389847ad06df19d76ee119c71e1dd3', - '34353637393a3b3c3e3f40414344454648494a4b4d4e4f50', - 'ecb-tbl-192: I=57'), - ('0f1b3603e0f5ddea4548246153a5e064', 'e018fdae13d3118f9a5d1a647a3f0462', - '525354555758595a5c5d5e5f61626364666768696b6c6d6e', - 'ecb-tbl-192: I=58'), - ('fbb63893450d42b58c6d88cd3c1809e3', '2aa65db36264239d3846180fabdfad20', - '70717273757677787a7b7c7d7f80818284858687898a8b8c', - 'ecb-tbl-192: I=59'), - ('4bef736df150259dae0c91354e8a5f92', '1472163e9a4f780f1ceb44b07ecf4fdb', - '8e8f90919394959698999a9b9d9e9fa0a2a3a4a5a7a8a9aa', - 'ecb-tbl-192: I=60'), - ('7d2d46242056ef13d3c3fc93c128f4c7', 'c8273fdc8f3a9f72e91097614b62397c', - 'acadaeafb1b2b3b4b6b7b8b9bbbcbdbec0c1c2c3c5c6c7c8', - 'ecb-tbl-192: I=61'), - ('e9c1ba2df415657a256edb33934680fd', '66c8427dcd733aaf7b3470cb7d976e3f', - 'cacbcccdcfd0d1d2d4d5d6d7d9dadbdcdedfe0e1e3e4e5e6', - 'ecb-tbl-192: I=62'), - ('e23ee277b0aa0a1dfb81f7527c3514f1', '146131cb17f1424d4f8da91e6f80c1d0', - 'e8e9eaebedeeeff0f2f3f4f5f7f8f9fafcfdfeff01020304', - 'ecb-tbl-192: I=63'), - ('3e7445b0b63caaf75e4a911e12106b4c', '2610d0ad83659081ae085266a88770dc', - '060708090b0c0d0e10111213151617181a1b1c1d1f202122', - 'ecb-tbl-192: I=64'), - ('767774752023222544455a5be6e1e0e3', '38a2b5a974b0575c5d733917fb0d4570', - '24252627292a2b2c2e2f30313334353638393a3b3d3e3f40', - 'ecb-tbl-192: I=65'), - ('72737475717e7f7ce9e8ebea696a6b6c', 'e21d401ebc60de20d6c486e4f39a588b', - '424344454748494a4c4d4e4f51525354565758595b5c5d5e', - 'ecb-tbl-192: I=66'), - ('dfdedddc25262728c9c8cfcef1eeefec', 'e51d5f88c670b079c0ca1f0c2c4405a2', - '60616263656667686a6b6c6d6f70717274757677797a7b7c', - 'ecb-tbl-192: I=67'), - ('fffe0100707776755f5e5d5c7675746b', '246a94788a642fb3d1b823c8762380c8', - '7e7f80818384858688898a8b8d8e8f90929394959798999a', - 'ecb-tbl-192: I=68'), - ('e0e1e2e3424140479f9e9190292e2f2c', 'b80c391c5c41a4c3b30c68e0e3d7550f', - '9c9d9e9fa1a2a3a4a6a7a8a9abacadaeb0b1b2b3b5b6b7b8', - 'ecb-tbl-192: I=69'), - ('2120272690efeeed3b3a39384e4d4c4b', 'b77c4754fc64eb9a1154a9af0bb1f21c', - 'babbbcbdbfc0c1c2c4c5c6c7c9cacbcccecfd0d1d3d4d5d6', - 'ecb-tbl-192: I=70'), - ('ecedeeef5350516ea1a0a7a6a3acadae', 'fb554de520d159a06bf219fc7f34a02f', - 'd8d9dadbdddedfe0e2e3e4e5e7e8e9eaecedeeeff1f2f3f4', - 'ecb-tbl-192: I=71'), - ('32333c3d25222320e9e8ebeacecdccc3', 'a89fba152d76b4927beed160ddb76c57', - 'f6f7f8f9fbfcfdfe00010203050607080a0b0c0d0f101112', - 'ecb-tbl-192: I=72'), - ('40414243626160678a8bb4b511161714', '5676eab4a98d2e8473b3f3d46424247c', - '14151617191a1b1c1e1f20212324252628292a2b2d2e2f30', - 'ecb-tbl-192: I=73'), - ('94959293f5fafbf81f1e1d1c7c7f7e79', '4e8f068bd7ede52a639036ec86c33568', - '323334353738393a3c3d3e3f41424344464748494b4c4d4e', - 'ecb-tbl-192: I=74'), - ('bebfbcbd191a1b14cfcec9c8546b6a69', 'f0193c4d7aff1791ee4c07eb4a1824fc', - '50515253555657585a5b5c5d5f60616264656667696a6b6c', - 'ecb-tbl-192: I=75'), - ('2c2d3233898e8f8cbbbab9b8333031ce', 'ac8686eeca9ba761afe82d67b928c33f', - '6e6f70717374757678797a7b7d7e7f80828384858788898a', - 'ecb-tbl-192: I=76'), - ('84858687bfbcbdba37363938fdfafbf8', '5faf8573e33b145b6a369cd3606ab2c9', - '8c8d8e8f91929394969798999b9c9d9ea0a1a2a3a5a6a7a8', - 'ecb-tbl-192: I=77'), - ('828384857669686b909192930b08090e', '31587e9944ab1c16b844ecad0df2e7da', - 'aaabacadafb0b1b2b4b5b6b7b9babbbcbebfc0c1c3c4c5c6', - 'ecb-tbl-192: I=78'), - ('bebfbcbd9695948b707176779e919093', 'd017fecd91148aba37f6f3068aa67d8a', - 'c8c9cacbcdcecfd0d2d3d4d5d7d8d9dadcdddedfe1e2e3e4', - 'ecb-tbl-192: I=79'), - ('8b8a85846067666521202322d0d3d2dd', '788ef2f021a73cba2794b616078a8500', - 'e6e7e8e9ebecedeef0f1f2f3f5f6f7f8fafbfcfdfe010002', - 'ecb-tbl-192: I=80'), - ('76777475f1f2f3f4f8f9e6e777707172', '5d1ef20dced6bcbc12131ac7c54788aa', - '04050607090a0b0c0e0f10111314151618191a1b1d1e1f20', - 'ecb-tbl-192: I=81'), - ('a4a5a2a34f404142b4b5b6b727242522', 'b3c8cf961faf9ea05fdde6d1e4d8f663', - '222324252728292a2c2d2e2f31323334363738393b3c3d3e', - 'ecb-tbl-192: I=82'), - ('94959697e1e2e3ec16171011839c9d9e', '143075c70605861c7fac6526199e459f', - '40414243454647484a4b4c4d4f50515254555657595a5b5c', - 'ecb-tbl-192: I=83'), - ('03023d3c06010003dedfdcddfffcfde2', 'a5ae12eade9a87268d898bfc8fc0252a', - '5e5f60616364656668696a6b6d6e6f70727374757778797a', - 'ecb-tbl-192: I=84'), - ('10111213f1f2f3f4cecfc0c1dbdcddde', '0924f7cf2e877a4819f5244a360dcea9', - '7c7d7e7f81828384868788898b8c8d8e9091929395969798', - 'ecb-tbl-192: I=85'), - ('67666160724d4c4f1d1c1f1e73707176', '3d9e9635afcc3e291cc7ab3f27d1c99a', - '9a9b9c9d9fa0a1a2a4a5a6a7a9aaabacaeafb0b1b3b4b5b6', - 'ecb-tbl-192: I=86'), - ('e6e7e4e5a8abaad584858283909f9e9d', '9d80feebf87510e2b8fb98bb54fd788c', - 'b8b9babbbdbebfc0c2c3c4c5c7c8c9cacccdcecfd1d2d3d4', - 'ecb-tbl-192: I=87'), - ('71707f7e565150537d7c7f7e6162636c', '5f9d1a082a1a37985f174002eca01309', - 'd6d7d8d9dbdcdddee0e1e2e3e5e6e7e8eaebecedeff0f1f2', - 'ecb-tbl-192: I=88'), - ('64656667212223245555aaaa03040506', 'a390ebb1d1403930184a44b4876646e4', - 'f4f5f6f7f9fafbfcfefe01010304050608090a0b0d0e0f10', - 'ecb-tbl-192: I=89'), - ('9e9f9899aba4a5a6cfcecdcc2b28292e', '700fe918981c3195bb6c4bcb46b74e29', - '121314151718191a1c1d1e1f21222324262728292b2c2d2e', - 'ecb-tbl-192: I=90'), - ('c7c6c5c4d1d2d3dc626364653a454447', '907984406f7bf2d17fb1eb15b673d747', - '30313233353637383a3b3c3d3f40414244454647494a4b4c', - 'ecb-tbl-192: I=91'), - ('f6f7e8e9e0e7e6e51d1c1f1e5b585966', 'c32a956dcfc875c2ac7c7cc8b8cc26e1', - '4e4f50515354555658595a5b5d5e5f60626364656768696a', - 'ecb-tbl-192: I=92'), - ('bcbdbebf5d5e5f5868696667f4f3f2f1', '02646e2ebfa9b820cf8424e9b9b6eb51', - '6c6d6e6f71727374767778797b7c7d7e8081828385868788', - 'ecb-tbl-192: I=93'), - ('40414647b0afaead9b9a99989b98999e', '621fda3a5bbd54c6d3c685816bd4ead8', - '8a8b8c8d8f90919294959697999a9b9c9e9fa0a1a3a4a5a6', - 'ecb-tbl-192: I=94'), - ('69686b6a0201001f0f0e0908b4bbbab9', 'd4e216040426dfaf18b152469bc5ac2f', - 'a8a9aaabadaeafb0b2b3b4b5b7b8b9babcbdbebfc1c2c3c4', - 'ecb-tbl-192: I=95'), - ('c7c6c9c8d8dfdedd5a5b5859bebdbcb3', '9d0635b9d33b6cdbd71f5d246ea17cc8', - 'c6c7c8c9cbcccdced0d1d2d3d5d6d7d8dadbdcdddfe0e1e2', - 'ecb-tbl-192: I=96'), - ('dedfdcdd787b7a7dfffee1e0b2b5b4b7', '10abad1bd9bae5448808765583a2cc1a', - 'e4e5e6e7e9eaebeceeeff0f1f3f4f5f6f8f9fafbfdfefe00', - 'ecb-tbl-192: I=97'), - ('4d4c4b4a606f6e6dd0d1d2d3fbf8f9fe', '6891889e16544e355ff65a793c39c9a8', - '020304050708090a0c0d0e0f11121314161718191b1c1d1e', - 'ecb-tbl-192: I=98'), - ('b7b6b5b4d7d4d5dae5e4e3e2e1fefffc', 'cc735582e68072c163cd9ddf46b91279', - '20212223252627282a2b2c2d2f30313234353637393a3b3c', - 'ecb-tbl-192: I=99'), - ('cecfb0b1f7f0f1f2aeafacad3e3d3c23', 'c5c68b9aeeb7f878df578efa562f9574', - '3e3f40414344454648494a4b4d4e4f50525354555758595a', - 'ecb-tbl-192: I=100'), - ('cacbc8c9cdcecfc812131c1d494e4f4c', '5f4764395a667a47d73452955d0d2ce8', - '5c5d5e5f61626364666768696b6c6d6e7071727375767778', - 'ecb-tbl-192: I=101'), - ('9d9c9b9ad22d2c2fb1b0b3b20c0f0e09', '701448331f66106cefddf1eb8267c357', - '7a7b7c7d7f80818284858687898a8b8c8e8f909193949596', - 'ecb-tbl-192: I=102'), - ('7a7b787964676659959493924f404142', 'cb3ee56d2e14b4e1941666f13379d657', - '98999a9b9d9e9fa0a2a3a4a5a7a8a9aaacadaeafb1b2b3b4', - 'ecb-tbl-192: I=103'), - ('aaaba4a5cec9c8cb1f1e1d1caba8a9a6', '9fe16efd18ab6e1981191851fedb0764', - 'b6b7b8b9bbbcbdbec0c1c2c3c5c6c7c8cacbcccdcfd0d1d2', - 'ecb-tbl-192: I=104'), - ('93929190282b2a2dc4c5fafb92959497', '3dc9ba24e1b223589b147adceb4c8e48', - 'd4d5d6d7d9dadbdcdedfe0e1e3e4e5e6e8e9eaebedeeeff0', - 'ecb-tbl-192: I=105'), - ('efeee9e8ded1d0d339383b3a888b8a8d', '1c333032682e7d4de5e5afc05c3e483c', - 'f2f3f4f5f7f8f9fafcfdfeff01020304060708090b0c0d0e', - 'ecb-tbl-192: I=106'), - ('7f7e7d7ca2a1a0af78797e7f112e2f2c', 'd593cc99a95afef7e92038e05a59d00a', - '10111213151617181a1b1c1d1f20212224252627292a2b2c', - 'ecb-tbl-192: I=107'), - ('84859a9b2b2c2d2e868784852625245b', '51e7f96f53b4353923452c222134e1ec', - '2e2f30313334353638393a3b3d3e3f40424344454748494a', - 'ecb-tbl-192: I=108'), - ('b0b1b2b3070405026869666710171615', '4075b357a1a2b473400c3b25f32f81a4', - '4c4d4e4f51525354565758595b5c5d5e6061626365666768', - 'ecb-tbl-192: I=109'), - ('acadaaabbda2a3a00d0c0f0e595a5b5c', '302e341a3ebcd74f0d55f61714570284', - '6a6b6c6d6f70717274757677797a7b7c7e7f808183848586', - 'ecb-tbl-192: I=110'), - ('121310115655544b5253545569666764', '57abdd8231280da01c5042b78cf76522', - '88898a8b8d8e8f90929394959798999a9c9d9e9fa1a2a3a4', - 'ecb-tbl-192: I=111'), - ('dedfd0d166616063eaebe8e94142434c', '17f9ea7eea17ac1adf0e190fef799e92', - 'a6a7a8a9abacadaeb0b1b2b3b5b6b7b8babbbcbdbfc0c1c2', - 'ecb-tbl-192: I=112'), - ('dbdad9d81417161166677879e0e7e6e5', '2e1bdd563dd87ee5c338dd6d098d0a7a', - 'c4c5c6c7c9cacbcccecfd0d1d3d4d5d6d8d9dadbdddedfe0', - 'ecb-tbl-192: I=113'), - ('6a6b6c6de0efeeed2b2a2928c0c3c2c5', 'eb869996e6f8bfb2bfdd9e0c4504dbb2', - 'e2e3e4e5e7e8e9eaecedeeeff1f2f3f4f6f7f8f9fbfcfdfe', - 'ecb-tbl-192: I=114'), - ('b1b0b3b21714151a1a1b1c1d5649484b', 'c2e01549e9decf317468b3e018c61ba8', - '00010203050607080a0b0c0d0f10111214151617191a1b1c', - 'ecb-tbl-192: I=115'), - ('39380706a3a4a5a6c4c5c6c77271706f', '8da875d033c01dd463b244a1770f4a22', - '1e1f20212324252628292a2b2d2e2f30323334353738393a', - 'ecb-tbl-192: I=116'), - ('5c5d5e5f1013121539383736e2e5e4e7', '8ba0dcf3a186844f026d022f8839d696', - '3c3d3e3f41424344464748494b4c4d4e5051525355565758', - 'ecb-tbl-192: I=117'), - ('43424544ead5d4d72e2f2c2d64676661', 'e9691ff9a6cc6970e51670a0fd5b88c1', - '5a5b5c5d5f60616264656667696a6b6c6e6f707173747576', - 'ecb-tbl-192: I=118'), - ('55545756989b9a65f8f9feff18171615', 'f2baec06faeed30f88ee63ba081a6e5b', - '78797a7b7d7e7f80828384858788898a8c8d8e8f91929394', - 'ecb-tbl-192: I=119'), - ('05040b0a525554573c3d3e3f4a494847', '9c39d4c459ae5753394d6094adc21e78', - '969798999b9c9d9ea0a1a2a3a5a6a7a8aaabacadafb0b1b2', - 'ecb-tbl-192: I=120'), - ('14151617595a5b5c8584fbfa8e89888b', '6345b532a11904502ea43ba99c6bd2b2', - 'b4b5b6b7b9babbbcbebfc0c1c3c4c5c6c8c9cacbcdcecfd0', - 'ecb-tbl-192: I=121'), - ('7c7d7a7bfdf2f3f029282b2a51525354', '5ffae3061a95172e4070cedce1e428c8', - 'd2d3d4d5d7d8d9dadcdddedfe1e2e3e4e6e7e8e9ebecedee', - 'ecb-tbl-192: I=122'), - ('38393a3b1e1d1c1341404746c23d3c3e', '0a4566be4cdf9adce5dec865b5ab34cd', - 'f0f1f2f3f5f6f7f8fafbfcfdfe01000204050607090a0b0c', - 'ecb-tbl-192: I=123'), - ('8d8c939240474645818083827c7f7e41', 'ca17fcce79b7404f2559b22928f126fb', - '0e0f10111314151618191a1b1d1e1f20222324252728292a', - 'ecb-tbl-192: I=124'), - ('3b3a39381a19181f32333c3d45424340', '97ca39b849ed73a6470a97c821d82f58', - '2c2d2e2f31323334363738393b3c3d3e4041424345464748', - 'ecb-tbl-192: I=125'), - ('f0f1f6f738272625828380817f7c7d7a', '8198cb06bc684c6d3e9b7989428dcf7a', - '4a4b4c4d4f50515254555657595a5b5c5e5f606163646566', - 'ecb-tbl-192: I=126'), - ('89888b8a0407061966676061141b1a19', 'f53c464c705ee0f28d9a4c59374928bd', - '68696a6b6d6e6f70727374757778797a7c7d7e7f81828384', - 'ecb-tbl-192: I=127'), - ('d3d2dddcaaadacaf9c9d9e9fe8ebeae5', '9adb3d4cca559bb98c3e2ed73dbf1154', - '868788898b8c8d8e90919293959697989a9b9c9d9fa0a1a2', - 'ecb-tbl-192: I=128'), - - # ecb_tbl.txt, KEYSIZE=256 - ('834eadfccac7e1b30664b1aba44815ab', '1946dabf6a03a2a2c3d0b05080aed6fc', - '00010203050607080a0b0c0d0f10111214151617191a1b1c1e1f202123242526', - 'ecb-tbl-256: I=1'), - ('d9dc4dba3021b05d67c0518f72b62bf1', '5ed301d747d3cc715445ebdec62f2fb4', - '28292a2b2d2e2f30323334353738393a3c3d3e3f41424344464748494b4c4d4e', - 'ecb-tbl-256: I=2'), - ('a291d86301a4a739f7392173aa3c604c', '6585c8f43d13a6beab6419fc5935b9d0', - '50515253555657585a5b5c5d5f60616264656667696a6b6c6e6f707173747576', - 'ecb-tbl-256: I=3'), - ('4264b2696498de4df79788a9f83e9390', '2a5b56a596680fcc0e05f5e0f151ecae', - '78797a7b7d7e7f80828384858788898a8c8d8e8f91929394969798999b9c9d9e', - 'ecb-tbl-256: I=4'), - ('ee9932b3721804d5a83ef5949245b6f6', 'f5d6ff414fd2c6181494d20c37f2b8c4', - 'a0a1a2a3a5a6a7a8aaabacadafb0b1b2b4b5b6b7b9babbbcbebfc0c1c3c4c5c6', - 'ecb-tbl-256: I=5'), - ('e6248f55c5fdcbca9cbbb01c88a2ea77', '85399c01f59fffb5204f19f8482f00b8', - 'c8c9cacbcdcecfd0d2d3d4d5d7d8d9dadcdddedfe1e2e3e4e6e7e8e9ebecedee', - 'ecb-tbl-256: I=6'), - ('b8358e41b9dff65fd461d55a99266247', '92097b4c88a041ddf98144bc8d22e8e7', - 'f0f1f2f3f5f6f7f8fafbfcfdfe01000204050607090a0b0c0e0f101113141516', - 'ecb-tbl-256: I=7'), - ('f0e2d72260af58e21e015ab3a4c0d906', '89bd5b73b356ab412aef9f76cea2d65c', - '18191a1b1d1e1f20222324252728292a2c2d2e2f31323334363738393b3c3d3e', - 'ecb-tbl-256: I=8'), - ('475b8b823ce8893db3c44a9f2a379ff7', '2536969093c55ff9454692f2fac2f530', - '40414243454647484a4b4c4d4f50515254555657595a5b5c5e5f606163646566', - 'ecb-tbl-256: I=9'), - ('688f5281945812862f5f3076cf80412f', '07fc76a872843f3f6e0081ee9396d637', - '68696a6b6d6e6f70727374757778797a7c7d7e7f81828384868788898b8c8d8e', - 'ecb-tbl-256: I=10'), - ('08d1d2bc750af553365d35e75afaceaa', 'e38ba8ec2aa741358dcc93e8f141c491', - '90919293959697989a9b9c9d9fa0a1a2a4a5a6a7a9aaabacaeafb0b1b3b4b5b6', - 'ecb-tbl-256: I=11'), - ('8707121f47cc3efceca5f9a8474950a1', 'd028ee23e4a89075d0b03e868d7d3a42', - 'b8b9babbbdbebfc0c2c3c4c5c7c8c9cacccdcecfd1d2d3d4d6d7d8d9dbdcddde', - 'ecb-tbl-256: I=12'), - ('e51aa0b135dba566939c3b6359a980c5', '8cd9423dfc459e547155c5d1d522e540', - 'e0e1e2e3e5e6e7e8eaebecedeff0f1f2f4f5f6f7f9fafbfcfefe010103040506', - 'ecb-tbl-256: I=13'), - ('069a007fc76a459f98baf917fedf9521', '080e9517eb1677719acf728086040ae3', - '08090a0b0d0e0f10121314151718191a1c1d1e1f21222324262728292b2c2d2e', - 'ecb-tbl-256: I=14'), - ('726165c1723fbcf6c026d7d00b091027', '7c1700211a3991fc0ecded0ab3e576b0', - '30313233353637383a3b3c3d3f40414244454647494a4b4c4e4f505153545556', - 'ecb-tbl-256: I=15'), - ('d7c544de91d55cfcde1f84ca382200ce', 'dabcbcc855839251db51e224fbe87435', - '58595a5b5d5e5f60626364656768696a6c6d6e6f71727374767778797b7c7d7e', - 'ecb-tbl-256: I=16'), - ('fed3c9a161b9b5b2bd611b41dc9da357', '68d56fad0406947a4dd27a7448c10f1d', - '80818283858687888a8b8c8d8f90919294959697999a9b9c9e9fa0a1a3a4a5a6', - 'ecb-tbl-256: I=17'), - ('4f634cdc6551043409f30b635832cf82', 'da9a11479844d1ffee24bbf3719a9925', - 'a8a9aaabadaeafb0b2b3b4b5b7b8b9babcbdbebfc1c2c3c4c6c7c8c9cbcccdce', - 'ecb-tbl-256: I=18'), - ('109ce98db0dfb36734d9f3394711b4e6', '5e4ba572f8d23e738da9b05ba24b8d81', - 'd0d1d2d3d5d6d7d8dadbdcdddfe0e1e2e4e5e6e7e9eaebeceeeff0f1f3f4f5f6', - 'ecb-tbl-256: I=19'), - ('4ea6dfaba2d8a02ffdffa89835987242', 'a115a2065d667e3f0b883837a6e903f8', - '70717273757677787a7b7c7d7f80818284858687898a8b8c8e8f909193949596', - 'ecb-tbl-256: I=20'), - ('5ae094f54af58e6e3cdbf976dac6d9ef', '3e9e90dc33eac2437d86ad30b137e66e', - '98999a9b9d9e9fa0a2a3a4a5a7a8a9aaacadaeafb1b2b3b4b6b7b8b9bbbcbdbe', - 'ecb-tbl-256: I=21'), - ('764d8e8e0f29926dbe5122e66354fdbe', '01ce82d8fbcdae824cb3c48e495c3692', - 'c0c1c2c3c5c6c7c8cacbcccdcfd0d1d2d4d5d6d7d9dadbdcdedfe0e1e3e4e5e6', - 'ecb-tbl-256: I=22'), - ('3f0418f888cdf29a982bf6b75410d6a9', '0c9cff163ce936faaf083cfd3dea3117', - 'e8e9eaebedeeeff0f2f3f4f5f7f8f9fafcfdfeff01020304060708090b0c0d0e', - 'ecb-tbl-256: I=23'), - ('e4a3e7cb12cdd56aa4a75197a9530220', '5131ba9bd48f2bba85560680df504b52', - '10111213151617181a1b1c1d1f20212224252627292a2b2c2e2f303133343536', - 'ecb-tbl-256: I=24'), - ('211677684aac1ec1a160f44c4ebf3f26', '9dc503bbf09823aec8a977a5ad26ccb2', - '38393a3b3d3e3f40424344454748494a4c4d4e4f51525354565758595b5c5d5e', - 'ecb-tbl-256: I=25'), - ('d21e439ff749ac8f18d6d4b105e03895', '9a6db0c0862e506a9e397225884041d7', - '60616263656667686a6b6c6d6f70717274757677797a7b7c7e7f808183848586', - 'ecb-tbl-256: I=26'), - ('d9f6ff44646c4725bd4c0103ff5552a7', '430bf9570804185e1ab6365fc6a6860c', - '88898a8b8d8e8f90929394959798999a9c9d9e9fa1a2a3a4a6a7a8a9abacadae', - 'ecb-tbl-256: I=27'), - ('0b1256c2a00b976250cfc5b0c37ed382', '3525ebc02f4886e6a5a3762813e8ce8a', - 'b0b1b2b3b5b6b7b8babbbcbdbfc0c1c2c4c5c6c7c9cacbcccecfd0d1d3d4d5d6', - 'ecb-tbl-256: I=28'), - ('b056447ffc6dc4523a36cc2e972a3a79', '07fa265c763779cce224c7bad671027b', - 'd8d9dadbdddedfe0e2e3e4e5e7e8e9eaecedeeeff1f2f3f4f6f7f8f9fbfcfdfe', - 'ecb-tbl-256: I=29'), - ('5e25ca78f0de55802524d38da3fe4456', 'e8b72b4e8be243438c9fff1f0e205872', - '00010203050607080a0b0c0d0f10111214151617191a1b1c1e1f202123242526', - 'ecb-tbl-256: I=30'), - ('a5bcf4728fa5eaad8567c0dc24675f83', '109d4f999a0e11ace1f05e6b22cbcb50', - '28292a2b2d2e2f30323334353738393a3c3d3e3f41424344464748494b4c4d4e', - 'ecb-tbl-256: I=31'), - ('814e59f97ed84646b78b2ca022e9ca43', '45a5e8d4c3ed58403ff08d68a0cc4029', - '50515253555657585a5b5c5d5f60616264656667696a6b6c6e6f707173747576', - 'ecb-tbl-256: I=32'), - ('15478beec58f4775c7a7f5d4395514d7', '196865964db3d417b6bd4d586bcb7634', - '78797a7b7d7e7f80828384858788898a8c8d8e8f91929394969798999b9c9d9e', - 'ecb-tbl-256: I=33'), - ('253548ffca461c67c8cbc78cd59f4756', '60436ad45ac7d30d99195f815d98d2ae', - 'a0a1a2a3a5a6a7a8aaabacadafb0b1b2b4b5b6b7b9babbbcbebfc0c1c3c4c5c6', - 'ecb-tbl-256: I=34'), - ('fd7ad8d73b9b0f8cc41600640f503d65', 'bb07a23f0b61014b197620c185e2cd75', - 'c8c9cacbcdcecfd0d2d3d4d5d7d8d9dadcdddedfe1e2e3e4e6e7e8e9ebecedee', - 'ecb-tbl-256: I=35'), - ('06199de52c6cbf8af954cd65830bcd56', '5bc0b2850129c854423aff0751fe343b', - 'f0f1f2f3f5f6f7f8fafbfcfdfe01000204050607090a0b0c0e0f101113141516', - 'ecb-tbl-256: I=36'), - ('f17c4ffe48e44c61bd891e257e725794', '7541a78f96738e6417d2a24bd2beca40', - '18191a1b1d1e1f20222324252728292a2c2d2e2f31323334363738393b3c3d3e', - 'ecb-tbl-256: I=37'), - ('9a5b4a402a3e8a59be6bf5cd8154f029', 'b0a303054412882e464591f1546c5b9e', - '40414243454647484a4b4c4d4f50515254555657595a5b5c5e5f606163646566', - 'ecb-tbl-256: I=38'), - ('79bd40b91a7e07dc939d441782ae6b17', '778c06d8a355eeee214fcea14b4e0eef', - '68696a6b6d6e6f70727374757778797a7c7d7e7f81828384868788898b8c8d8e', - 'ecb-tbl-256: I=39'), - ('d8ceaaf8976e5fbe1012d8c84f323799', '09614206d15cbace63227d06db6beebb', - '90919293959697989a9b9c9d9fa0a1a2a4a5a6a7a9aaabacaeafb0b1b3b4b5b6', - 'ecb-tbl-256: I=40'), - ('3316e2751e2e388b083da23dd6ac3fbe', '41b97fb20e427a9fdbbb358d9262255d', - 'b8b9babbbdbebfc0c2c3c4c5c7c8c9cacccdcecfd1d2d3d4d6d7d8d9dbdcddde', - 'ecb-tbl-256: I=41'), - ('8b7cfbe37de7dca793521819242c5816', 'c1940f703d845f957652c2d64abd7adf', - 'e0e1e2e3e5e6e7e8eaebecedeff0f1f2f4f5f6f7f9fafbfcfefe010103040506', - 'ecb-tbl-256: I=42'), - ('f23f033c0eebf8ec55752662fd58ce68', 'd2d44fcdae5332343366db297efcf21b', - '08090a0b0d0e0f10121314151718191a1c1d1e1f21222324262728292b2c2d2e', - 'ecb-tbl-256: I=43'), - ('59eb34f6c8bdbacc5fc6ad73a59a1301', 'ea8196b79dbe167b6aa9896e287eed2b', - '30313233353637383a3b3c3d3f40414244454647494a4b4c4e4f505153545556', - 'ecb-tbl-256: I=44'), - ('dcde8b6bd5cf7cc22d9505e3ce81261a', 'd6b0b0c4ba6c7dbe5ed467a1e3f06c2d', - '58595a5b5d5e5f60626364656768696a6c6d6e6f71727374767778797b7c7d7e', - 'ecb-tbl-256: I=45'), - ('e33cf7e524fed781e7042ff9f4b35dc7', 'ec51eb295250c22c2fb01816fb72bcae', - '80818283858687888a8b8c8d8f90919294959697999a9b9c9e9fa0a1a3a4a5a6', - 'ecb-tbl-256: I=46'), - ('27963c8facdf73062867d164df6d064c', 'aded6630a07ce9c7408a155d3bd0d36f', - 'a8a9aaabadaeafb0b2b3b4b5b7b8b9babcbdbebfc1c2c3c4c6c7c8c9cbcccdce', - 'ecb-tbl-256: I=47'), - ('77b1ce386b551b995f2f2a1da994eef8', '697c9245b9937f32f5d1c82319f0363a', - 'd0d1d2d3d5d6d7d8dadbdcdddfe0e1e2e4e5e6e7e9eaebeceeeff0f1f3f4f5f6', - 'ecb-tbl-256: I=48'), - ('f083388b013679efcf0bb9b15d52ae5c', 'aad5ad50c6262aaec30541a1b7b5b19c', - 'f8f9fafbfdfefe00020304050708090a0c0d0e0f11121314161718191b1c1d1e', - 'ecb-tbl-256: I=49'), - ('c5009e0dab55db0abdb636f2600290c8', '7d34b893855341ec625bd6875ac18c0d', - '20212223252627282a2b2c2d2f30313234353637393a3b3c3e3f404143444546', - 'ecb-tbl-256: I=50'), - ('7804881e26cd532d8514d3683f00f1b9', '7ef05105440f83862f5d780e88f02b41', - '48494a4b4d4e4f50525354555758595a5c5d5e5f61626364666768696b6c6d6e', - 'ecb-tbl-256: I=51'), - ('46cddcd73d1eb53e675ca012870a92a3', 'c377c06403382061af2c9c93a8e70df6', - '70717273757677787a7b7c7d7f80818284858687898a8b8c8e8f909193949596', - 'ecb-tbl-256: I=52'), - ('a9fb44062bb07fe130a8e8299eacb1ab', '1dbdb3ffdc052dacc83318853abc6de5', - '98999a9b9d9e9fa0a2a3a4a5a7a8a9aaacadaeafb1b2b3b4b6b7b8b9bbbcbdbe', - 'ecb-tbl-256: I=53'), - ('2b6ff8d7a5cc3a28a22d5a6f221af26b', '69a6eab00432517d0bf483c91c0963c7', - 'c0c1c2c3c5c6c7c8cacbcccdcfd0d1d2d4d5d6d7d9dadbdcdedfe0e1e3e4e5e6', - 'ecb-tbl-256: I=54'), - ('1a9527c29b8add4b0e3e656dbb2af8b4', '0797f41dc217c80446e1d514bd6ab197', - 'e8e9eaebedeeeff0f2f3f4f5f7f8f9fafcfdfeff01020304060708090b0c0d0e', - 'ecb-tbl-256: I=55'), - ('7f99cf2c75244df015eb4b0c1050aeae', '9dfd76575902a637c01343c58e011a03', - '10111213151617181a1b1c1d1f20212224252627292a2b2c2e2f303133343536', - 'ecb-tbl-256: I=56'), - ('e84ff85b0d9454071909c1381646c4ed', 'acf4328ae78f34b9fa9b459747cc2658', - '38393a3b3d3e3f40424344454748494a4c4d4e4f51525354565758595b5c5d5e', - 'ecb-tbl-256: I=57'), - ('89afd40f99521280d5399b12404f6db4', 'b0479aea12bac4fe2384cf98995150c6', - '60616263656667686a6b6c6d6f70717274757677797a7b7c7e7f808183848586', - 'ecb-tbl-256: I=58'), - ('a09ef32dbc5119a35ab7fa38656f0329', '9dd52789efe3ffb99f33b3da5030109a', - '88898a8b8d8e8f90929394959798999a9c9d9e9fa1a2a3a4a6a7a8a9abacadae', - 'ecb-tbl-256: I=59'), - ('61773457f068c376c7829b93e696e716', 'abbb755e4621ef8f1214c19f649fb9fd', - 'b0b1b2b3b5b6b7b8babbbcbdbfc0c1c2c4c5c6c7c9cacbcccecfd0d1d3d4d5d6', - 'ecb-tbl-256: I=60'), - ('a34f0cae726cce41dd498747d891b967', 'da27fb8174357bce2bed0e7354f380f9', - 'd8d9dadbdddedfe0e2e3e4e5e7e8e9eaecedeeeff1f2f3f4f6f7f8f9fbfcfdfe', - 'ecb-tbl-256: I=61'), - ('856f59496c7388ee2d2b1a27b7697847', 'c59a0663f0993838f6e5856593bdc5ef', - '00010203050607080a0b0c0d0f10111214151617191a1b1c1e1f202123242526', - 'ecb-tbl-256: I=62'), - ('cb090c593ef7720bd95908fb93b49df4', 'ed60b264b5213e831607a99c0ce5e57e', - '28292a2b2d2e2f30323334353738393a3c3d3e3f41424344464748494b4c4d4e', - 'ecb-tbl-256: I=63'), - ('a0ac75cd2f1923d460fc4d457ad95baf', 'e50548746846f3eb77b8c520640884ed', - '50515253555657585a5b5c5d5f60616264656667696a6b6c6e6f707173747576', - 'ecb-tbl-256: I=64'), - ('2a2b282974777689e8e9eeef525d5c5f', '28282cc7d21d6a2923641e52d188ef0c', - '78797a7b7d7e7f80828384858788898a8c8d8e8f91929394969798999b9c9d9e', - 'ecb-tbl-256: I=65'), - ('909192939390919e0f0e09089788898a', '0dfa5b02abb18e5a815305216d6d4f8e', - 'a0a1a2a3a5a6a7a8aaabacadafb0b1b2b4b5b6b7b9babbbcbebfc0c1c3c4c5c6', - 'ecb-tbl-256: I=66'), - ('777675748d8e8f907170777649464744', '7359635c0eecefe31d673395fb46fb99', - 'c8c9cacbcdcecfd0d2d3d4d5d7d8d9dadcdddedfe1e2e3e4e6e7e8e9ebecedee', - 'ecb-tbl-256: I=67'), - ('717073720605040b2d2c2b2a05fafbf9', '73c679f7d5aef2745c9737bb4c47fb36', - 'f0f1f2f3f5f6f7f8fafbfcfdfe01000204050607090a0b0c0e0f101113141516', - 'ecb-tbl-256: I=68'), - ('64656667fefdfcc31b1a1d1ca5aaaba8', 'b192bd472a4d2eafb786e97458967626', - '18191a1b1d1e1f20222324252728292a2c2d2e2f31323334363738393b3c3d3e', - 'ecb-tbl-256: I=69'), - ('dbdad9d86a696867b5b4b3b2c8d7d6d5', '0ec327f6c8a2b147598ca3fde61dc6a4', - '40414243454647484a4b4c4d4f50515254555657595a5b5c5e5f606163646566', - 'ecb-tbl-256: I=70'), - ('5c5d5e5fe3e0e1fe31303736333c3d3e', 'fc418eb3c41b859b38d4b6f646629729', - '68696a6b6d6e6f70727374757778797a7c7d7e7f81828384868788898b8c8d8e', - 'ecb-tbl-256: I=71'), - ('545556574b48494673727574546b6a69', '30249e5ac282b1c981ea64b609f3a154', - '90919293959697989a9b9c9d9fa0a1a2a4a5a6a7a9aaabacaeafb0b1b3b4b5b6', - 'ecb-tbl-256: I=72'), - ('ecedeeefc6c5c4bb56575051f5fafbf8', '5e6e08646d12150776bb43c2d78a9703', - 'b8b9babbbdbebfc0c2c3c4c5c7c8c9cacccdcecfd1d2d3d4d6d7d8d9dbdcddde', - 'ecb-tbl-256: I=73'), - ('464744452724252ac9c8cfced2cdcccf', 'faeb3d5de652cd3447dceb343f30394a', - 'e0e1e2e3e5e6e7e8eaebecedeff0f1f2f4f5f6f7f9fafbfcfefe010103040506', - 'ecb-tbl-256: I=74'), - ('e6e7e4e54142435c878681801c131211', 'a8e88706823f6993ef80d05c1c7b2cf0', - '08090a0b0d0e0f10121314151718191a1c1d1e1f21222324262728292b2c2d2e', - 'ecb-tbl-256: I=75'), - ('72737071cfcccdc2f9f8fffe710e0f0c', '8ced86677e6e00a1a1b15968f2d3cce6', - '30313233353637383a3b3c3d3f40414244454647494a4b4c4e4f505153545556', - 'ecb-tbl-256: I=76'), - ('505152537370714ec3c2c5c4010e0f0c', '9fc7c23858be03bdebb84e90db6786a9', - '58595a5b5d5e5f60626364656768696a6c6d6e6f71727374767778797b7c7d7e', - 'ecb-tbl-256: I=77'), - ('a8a9aaab5c5f5e51aeafa8a93d222320', 'b4fbd65b33f70d8cf7f1111ac4649c36', - '80818283858687888a8b8c8d8f90919294959697999a9b9c9e9fa0a1a3a4a5a6', - 'ecb-tbl-256: I=78'), - ('dedfdcddf6f5f4eb10111617fef1f0f3', 'c5c32d5ed03c4b53cc8c1bd0ef0dbbf6', - 'a8a9aaabadaeafb0b2b3b4b5b7b8b9babcbdbebfc1c2c3c4c6c7c8c9cbcccdce', - 'ecb-tbl-256: I=79'), - ('bdbcbfbe5e5d5c530b0a0d0cfac5c4c7', 'd1a7f03b773e5c212464b63709c6a891', - 'd0d1d2d3d5d6d7d8dadbdcdddfe0e1e2e4e5e6e7e9eaebeceeeff0f1f3f4f5f6', - 'ecb-tbl-256: I=80'), - ('8a8b8889050606f8f4f5f2f3636c6d6e', '6b7161d8745947ac6950438ea138d028', - 'f8f9fafbfdfefe00020304050708090a0c0d0e0f11121314161718191b1c1d1e', - 'ecb-tbl-256: I=81'), - ('a6a7a4a54d4e4f40b2b3b4b539262724', 'fd47a9f7e366ee7a09bc508b00460661', - '20212223252627282a2b2c2d2f30313234353637393a3b3c3e3f404143444546', - 'ecb-tbl-256: I=82'), - ('9c9d9e9fe9eaebf40e0f08099b949596', '00d40b003dc3a0d9310b659b98c7e416', - '48494a4b4d4e4f50525354555758595a5c5d5e5f61626364666768696b6c6d6e', - 'ecb-tbl-256: I=83'), - ('2d2c2f2e1013121dcccdcacbed121310', 'eea4c79dcc8e2bda691f20ac48be0717', - '70717273757677787a7b7c7d7f80818284858687898a8b8c8e8f909193949596', - 'ecb-tbl-256: I=84'), - ('f4f5f6f7edeeefd0eaebecedf7f8f9fa', 'e78f43b11c204403e5751f89d05a2509', - '98999a9b9d9e9fa0a2a3a4a5a7a8a9aaacadaeafb1b2b3b4b6b7b8b9bbbcbdbe', - 'ecb-tbl-256: I=85'), - ('3d3c3f3e282b2a2573727574150a0b08', 'd0f0e3d1f1244bb979931e38dd1786ef', - 'c0c1c2c3c5c6c7c8cacbcccdcfd0d1d2d4d5d6d7d9dadbdcdedfe0e1e3e4e5e6', - 'ecb-tbl-256: I=86'), - ('b6b7b4b5f8fbfae5b4b5b2b3a0afaead', '042e639dc4e1e4dde7b75b749ea6f765', - 'e8e9eaebedeeeff0f2f3f4f5f7f8f9fafcfdfeff01020304060708090b0c0d0e', - 'ecb-tbl-256: I=87'), - ('b7b6b5b4989b9a95878681809ba4a5a6', 'bc032fdd0efe29503a980a7d07ab46a8', - '10111213151617181a1b1c1d1f20212224252627292a2b2c2e2f303133343536', - 'ecb-tbl-256: I=88'), - ('a8a9aaabe5e6e798e9e8efee4748494a', '0c93ac949c0da6446effb86183b6c910', - '38393a3b3d3e3f40424344454748494a4c4d4e4f51525354565758595b5c5d5e', - 'ecb-tbl-256: I=89'), - ('ecedeeefd9dadbd4b9b8bfbe657a7b78', 'e0d343e14da75c917b4a5cec4810d7c2', - '60616263656667686a6b6c6d6f70717274757677797a7b7c7e7f808183848586', - 'ecb-tbl-256: I=90'), - ('7f7e7d7c696a6b74cacbcccd929d9c9f', '0eafb821748408279b937b626792e619', - '88898a8b8d8e8f90929394959798999a9c9d9e9fa1a2a3a4a6a7a8a9abacadae', - 'ecb-tbl-256: I=91'), - ('08090a0b0605040bfffef9f8b9c6c7c4', 'fa1ac6e02d23b106a1fef18b274a553f', - 'b0b1b2b3b5b6b7b8babbbcbdbfc0c1c2c4c5c6c7c9cacbcccecfd0d1d3d4d5d6', - 'ecb-tbl-256: I=92'), - ('08090a0bf1f2f3ccfcfdfafb68676665', '0dadfe019cd12368075507df33c1a1e9', - 'd8d9dadbdddedfe0e2e3e4e5e7e8e9eaecedeeeff1f2f3f4f6f7f8f9fbfcfdfe', - 'ecb-tbl-256: I=93'), - ('cacbc8c93a393837050403020d121310', '3a0879b414465d9ffbaf86b33a63a1b9', - '00010203050607080a0b0c0d0f10111214151617191a1b1c1e1f202123242526', - 'ecb-tbl-256: I=94'), - ('e9e8ebea8281809f8f8e8988343b3a39', '62199fadc76d0be1805d3ba0b7d914bf', - '28292a2b2d2e2f30323334353738393a3c3d3e3f41424344464748494b4c4d4e', - 'ecb-tbl-256: I=95'), - ('515053524645444bd0d1d6d7340b0a09', '1b06d6c5d333e742730130cf78e719b4', - '50515253555657585a5b5c5d5f60616264656667696a6b6c6e6f707173747576', - 'ecb-tbl-256: I=96'), - ('42434041ecefee1193929594c6c9c8cb', 'f1f848824c32e9dcdcbf21580f069329', - '78797a7b7d7e7f80828384858788898a8c8d8e8f91929394969798999b9c9d9e', - 'ecb-tbl-256: I=97'), - ('efeeedecc2c1c0cf76777071455a5b58', '1a09050cbd684f784d8e965e0782f28a', - 'a0a1a2a3a5a6a7a8aaabacadafb0b1b2b4b5b6b7b9babbbcbebfc0c1c3c4c5c6', - 'ecb-tbl-256: I=98'), - ('5f5e5d5c3f3c3d221d1c1b1a19161714', '79c2969e7ded2ba7d088f3f320692360', - 'c8c9cacbcdcecfd0d2d3d4d5d7d8d9dadcdddedfe1e2e3e4e6e7e8e9ebecedee', - 'ecb-tbl-256: I=99'), - ('000102034142434c1c1d1a1b8d727371', '091a658a2f7444c16accb669450c7b63', - 'f0f1f2f3f5f6f7f8fafbfcfdfe01000204050607090a0b0c0e0f101113141516', - 'ecb-tbl-256: I=100'), - ('8e8f8c8db1b2b38c56575051050a0b08', '97c1e3a72cca65fa977d5ed0e8a7bbfc', - '18191a1b1d1e1f20222324252728292a2c2d2e2f31323334363738393b3c3d3e', - 'ecb-tbl-256: I=101'), - ('a7a6a5a4e8ebeae57f7e7978cad5d4d7', '70c430c6db9a17828937305a2df91a2a', - '40414243454647484a4b4c4d4f50515254555657595a5b5c5e5f606163646566', - 'ecb-tbl-256: I=102'), - ('8a8b888994979689454443429f909192', '629553457fbe2479098571c7c903fde8', - '68696a6b6d6e6f70727374757778797a7c7d7e7f81828384868788898b8c8d8e', - 'ecb-tbl-256: I=103'), - ('8c8d8e8fe0e3e2ed45444342f1cecfcc', 'a25b25a61f612669e7d91265c7d476ba', - '90919293959697989a9b9c9d9fa0a1a2a4a5a6a7a9aaabacaeafb0b1b3b4b5b6', - 'ecb-tbl-256: I=104'), - ('fffefdfc4c4f4e31d8d9dedfb6b9b8bb', 'eb7e4e49b8ae0f024570dda293254fed', - 'b8b9babbbdbebfc0c2c3c4c5c7c8c9cacccdcecfd1d2d3d4d6d7d8d9dbdcddde', - 'ecb-tbl-256: I=105'), - ('fdfcfffecccfcec12f2e29286679787b', '38fe15d61cca84516e924adce5014f67', - 'e0e1e2e3e5e6e7e8eaebecedeff0f1f2f4f5f6f7f9fafbfcfefe010103040506', - 'ecb-tbl-256: I=106'), - ('67666564bab9b8a77071767719161714', '3ad208492249108c9f3ebeb167ad0583', - '08090a0b0d0e0f10121314151718191a1c1d1e1f21222324262728292b2c2d2e', - 'ecb-tbl-256: I=107'), - ('9a9b98992d2e2f2084858283245b5a59', '299ba9f9bf5ab05c3580fc26edd1ed12', - '30313233353637383a3b3c3d3f40414244454647494a4b4c4e4f505153545556', - 'ecb-tbl-256: I=108'), - ('a4a5a6a70b0809365c5d5a5b2c232221', '19dc705b857a60fb07717b2ea5717781', - '58595a5b5d5e5f60626364656768696a6c6d6e6f71727374767778797b7c7d7e', - 'ecb-tbl-256: I=109'), - ('464744455754555af3f2f5f4afb0b1b2', 'ffc8aeb885b5efcad06b6dbebf92e76b', - '80818283858687888a8b8c8d8f90919294959697999a9b9c9e9fa0a1a3a4a5a6', - 'ecb-tbl-256: I=110'), - ('323330317675746b7273747549464744', 'f58900c5e0b385253ff2546250a0142b', - 'a8a9aaabadaeafb0b2b3b4b5b7b8b9babcbdbebfc1c2c3c4c6c7c8c9cbcccdce', - 'ecb-tbl-256: I=111'), - ('a8a9aaab181b1a15808186872b141516', '2ee67b56280bc462429cee6e3370cbc1', - 'd0d1d2d3d5d6d7d8dadbdcdddfe0e1e2e4e5e6e7e9eaebeceeeff0f1f3f4f5f6', - 'ecb-tbl-256: I=112'), - ('e7e6e5e4202323ddaaabacad343b3a39', '20db650a9c8e9a84ab4d25f7edc8f03f', - 'f8f9fafbfdfefe00020304050708090a0c0d0e0f11121314161718191b1c1d1e', - 'ecb-tbl-256: I=113'), - ('a8a9aaab2221202fedecebea1e010003', '3c36da169525cf818843805f25b78ae5', - '20212223252627282a2b2c2d2f30313234353637393a3b3c3e3f404143444546', - 'ecb-tbl-256: I=114'), - ('f9f8fbfa5f5c5d42424344450e010003', '9a781d960db9e45e37779042fea51922', - '48494a4b4d4e4f50525354555758595a5c5d5e5f61626364666768696b6c6d6e', - 'ecb-tbl-256: I=115'), - ('57565554f5f6f7f89697909120dfdedd', '6560395ec269c672a3c288226efdba77', - '70717273757677787a7b7c7d7f80818284858687898a8b8c8e8f909193949596', - 'ecb-tbl-256: I=116'), - ('f8f9fafbcccfcef1dddcdbda0e010003', '8c772b7a189ac544453d5916ebb27b9a', - '98999a9b9d9e9fa0a2a3a4a5a7a8a9aaacadaeafb1b2b3b4b6b7b8b9bbbcbdbe', - 'ecb-tbl-256: I=117'), - ('d9d8dbda7073727d80818687c2dddcdf', '77ca5468cc48e843d05f78eed9d6578f', - 'c0c1c2c3c5c6c7c8cacbcccdcfd0d1d2d4d5d6d7d9dadbdcdedfe0e1e3e4e5e6', - 'ecb-tbl-256: I=118'), - ('c5c4c7c6080b0a1588898e8f68676665', '72cdcc71dc82c60d4429c9e2d8195baa', - 'e8e9eaebedeeeff0f2f3f4f5f7f8f9fafcfdfeff01020304060708090b0c0d0e', - 'ecb-tbl-256: I=119'), - ('83828180dcdfded186878081f0cfcecd', '8080d68ce60e94b40b5b8b69eeb35afa', - '10111213151617181a1b1c1d1f20212224252627292a2b2c2e2f303133343536', - 'ecb-tbl-256: I=120'), - ('98999a9bdddedfa079787f7e0a050407', '44222d3cde299c04369d58ac0eba1e8e', - '38393a3b3d3e3f40424344454748494a4c4d4e4f51525354565758595b5c5d5e', - 'ecb-tbl-256: I=121'), - ('cecfcccd4f4c4d429f9e9998dfc0c1c2', '9b8721b0a8dfc691c5bc5885dbfcb27a', - '60616263656667686a6b6c6d6f70717274757677797a7b7c7e7f808183848586', - 'ecb-tbl-256: I=122'), - ('404142436665647b29282f2eaba4a5a6', '0dc015ce9a3a3414b5e62ec643384183', - '88898a8b8d8e8f90929394959798999a9c9d9e9fa1a2a3a4a6a7a8a9abacadae', - 'ecb-tbl-256: I=123'), - ('33323130e6e5e4eb23222524dea1a0a3', '705715448a8da412025ce38345c2a148', - 'b0b1b2b3b5b6b7b8babbbcbdbfc0c1c2c4c5c6c7c9cacbcccecfd0d1d3d4d5d6', - 'ecb-tbl-256: I=124'), - ('cfcecdccf6f5f4cbe6e7e0e199969794', 'c32b5b0b6fbae165266c569f4b6ecf0b', - 'd8d9dadbdddedfe0e2e3e4e5e7e8e9eaecedeeeff1f2f3f4f6f7f8f9fbfcfdfe', - 'ecb-tbl-256: I=125'), - ('babbb8b97271707fdcdddadb29363734', '4dca6c75192a01ddca9476af2a521e87', - '00010203050607080a0b0c0d0f10111214151617191a1b1c1e1f202123242526', - 'ecb-tbl-256: I=126'), - ('c9c8cbca4447465926272021545b5a59', '058691e627ecbc36ac07b6db423bd698', - '28292a2b2d2e2f30323334353738393a3c3d3e3f41424344464748494b4c4d4e', - 'ecb-tbl-256: I=127'), - ('050407067477767956575051221d1c1f', '7444527095838fe080fc2bcdd30847eb', - '50515253555657585a5b5c5d5f60616264656667696a6b6c6e6f707173747576', - 'ecb-tbl-256: I=128'), - - # FIPS PUB 800-38A test vectors, 2001 edition. Annex F. - - ('6bc1bee22e409f96e93d7e117393172a'+'ae2d8a571e03ac9c9eb76fac45af8e51'+ - '30c81c46a35ce411e5fbc1191a0a52ef'+'f69f2445df4f9b17ad2b417be66c3710', - '3ad77bb40d7a3660a89ecaf32466ef97'+'f5d3d58503b9699de785895a96fdbaaf'+ - '43b1cd7f598ece23881b00e3ed030688'+'7b0c785e27e8ad3f8223207104725dd4', - '2b7e151628aed2a6abf7158809cf4f3c', - 'NIST 800-38A, F.1.1, ECB and AES-128'), - - ('6bc1bee22e409f96e93d7e117393172a'+'ae2d8a571e03ac9c9eb76fac45af8e51'+ - '30c81c46a35ce411e5fbc1191a0a52ef'+'f69f2445df4f9b17ad2b417be66c3710', - 'bd334f1d6e45f25ff712a214571fa5cc'+'974104846d0ad3ad7734ecb3ecee4eef'+ - 'ef7afd2270e2e60adce0ba2face6444e'+'9a4b41ba738d6c72fb16691603c18e0e', - '8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b', - 'NIST 800-38A, F.1.3, ECB and AES-192'), - - ('6bc1bee22e409f96e93d7e117393172a'+'ae2d8a571e03ac9c9eb76fac45af8e51'+ - '30c81c46a35ce411e5fbc1191a0a52ef'+'f69f2445df4f9b17ad2b417be66c3710', - 'f3eed1bdb5d2a03c064b5a7e3db181f8'+'591ccb10d410ed26dc5ba74a31362870'+ - 'b6ed21b99ca6f4f9f153e7b1beafed1d'+'23304b7a39f9f3ff067d8d8f9e24ecc7', - '603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4', - 'NIST 800-38A, F.1.3, ECB and AES-256'), - -] - -test_data_8_lanes = [] -for td in test_data: - test_data_8_lanes.append((td[0] * 8, td[1] * 8, td[2], td[3])) -test_data += test_data_8_lanes - -class TestMultipleBlocks(unittest.TestCase): - - def __init__(self, use_aesni): - unittest.TestCase.__init__(self) - self.use_aesni = use_aesni - - def runTest(self): - # Encrypt data which is 8*2+4 bytes long, so as to trigger (for the - # AESNI variant) both the path that parallelizes 8 lanes and the one - # that processes data serially - - tvs = [ - (b'a' * 16, 'c0b27011eb15bf144d2fc9fae80ea16d4c231cb230416c5fac02e6835ad9d7d0'), - (b'a' * 24, 'df8435ce361a78c535b41dcb57da952abbf9ee5954dc6fbcd75fd00fa626915d'), - (b'a' * 32, '211402de6c80db1f92ba255881178e1f70783b8cfd3b37808205e48b80486cd8') - ] - - for key, expected in tvs: - - cipher = AES.new(key, AES.MODE_ECB, use_aesni=self.use_aesni) - h = SHA256.new() - - pt = b"".join([ tobytes('{0:016x}'.format(x)) for x in range(20) ]) - ct = cipher.encrypt(pt) - self.assertEqual(SHA256.new(ct).hexdigest(), expected) - - -class TestIncompleteBlocks(unittest.TestCase): - - def __init__(self, use_aesni): - unittest.TestCase.__init__(self) - self.use_aesni = use_aesni - - def runTest(self): - # Encrypt data with length not multiple of 16 bytes - - cipher = AES.new(b'4'*16, AES.MODE_ECB, use_aesni=self.use_aesni) - - for msg_len in range(1, 16): - self.assertRaises(ValueError, cipher.encrypt, b'1' * msg_len) - self.assertRaises(ValueError, cipher.encrypt, b'1' * (msg_len+16)) - self.assertRaises(ValueError, cipher.decrypt, b'1' * msg_len) - self.assertRaises(ValueError, cipher.decrypt, b'1' * (msg_len+16)) - - self.assertEqual(cipher.encrypt(b''), b'') - self.assertEqual(cipher.decrypt(b''), b'') - - -class TestOutput(unittest.TestCase): - - def __init__(self, use_aesni): - unittest.TestCase.__init__(self) - self.use_aesni = use_aesni - - def runTest(self): - # Encrypt/Decrypt data and test output parameter - - cipher = AES.new(b'4'*16, AES.MODE_ECB, use_aesni=self.use_aesni) - - pt = b'5' * 16 - ct = cipher.encrypt(pt) - - output = bytearray(16) - res = cipher.encrypt(pt, output=output) - self.assertEqual(ct, output) - self.assertEqual(res, None) - - res = cipher.decrypt(ct, output=output) - self.assertEqual(pt, output) - self.assertEqual(res, None) - - output = memoryview(bytearray(16)) - cipher.encrypt(pt, output=output) - self.assertEqual(ct, output) - - cipher.decrypt(ct, output=output) - self.assertEqual(pt, output) - - self.assertRaises(TypeError, cipher.encrypt, pt, output=b'0'*16) - self.assertRaises(TypeError, cipher.decrypt, ct, output=b'0'*16) - - shorter_output = bytearray(15) - self.assertRaises(ValueError, cipher.encrypt, pt, output=shorter_output) - self.assertRaises(ValueError, cipher.decrypt, ct, output=shorter_output) - - -def get_tests(config={}): - from Crypto.Util import _cpu_features - from .common import make_block_tests - - tests = make_block_tests(AES, "AES", test_data, {'use_aesni': False}) - tests += [ TestMultipleBlocks(False) ] - tests += [ TestIncompleteBlocks(False) ] - if _cpu_features.have_aes_ni(): - # Run tests with AES-NI instructions if they are available. - tests += make_block_tests(AES, "AESNI", test_data, {'use_aesni': True}) - tests += [ TestMultipleBlocks(True) ] - tests += [ TestIncompleteBlocks(True) ] - tests += [ TestOutput(True) ] - else: - print("Skipping AESNI tests") - return tests - -if __name__ == '__main__': - import unittest - suite = lambda: unittest.TestSuite(get_tests()) - unittest.main(defaultTest='suite') - -# vim:set ts=4 sw=4 sts=4 expandtab: diff --git a/Crypto/SelfTest/Cipher/test_ARC2.py b/Crypto/SelfTest/Cipher/test_ARC2.py deleted file mode 100644 index fd9448c..0000000 --- a/Crypto/SelfTest/Cipher/test_ARC2.py +++ /dev/null @@ -1,167 +0,0 @@ -# -*- coding: utf-8 -*- -# -# SelfTest/Cipher/ARC2.py: Self-test for the Alleged-RC2 cipher -# -# Written in 2008 by Dwayne C. Litzenberger -# -# =================================================================== -# The contents of this file are dedicated to the public domain. To -# the extent that dedication to the public domain is not available, -# everyone is granted a worldwide, perpetual, royalty-free, -# non-exclusive license to exercise all rights associated with the -# contents of this file for any purpose whatsoever. -# No rights are reserved. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS -# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN -# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# =================================================================== - -"""Self-test suite for Crypto.Cipher.ARC2""" - -import unittest - -from Crypto.Util.py3compat import b, bchr - -from Crypto.Cipher import ARC2 - -# This is a list of (plaintext, ciphertext, key[, description[, extra_params]]) tuples. -test_data = [ - # Test vectors from RFC 2268 - - # 63-bit effective key length - ('0000000000000000', 'ebb773f993278eff', '0000000000000000', - 'RFC2268-1', dict(effective_keylen=63)), - - # 64-bit effective key length - ('ffffffffffffffff', '278b27e42e2f0d49', 'ffffffffffffffff', - 'RFC2268-2', dict(effective_keylen=64)), - ('1000000000000001', '30649edf9be7d2c2', '3000000000000000', - 'RFC2268-3', dict(effective_keylen=64)), - #('0000000000000000', '61a8a244adacccf0', '88', - # 'RFC2268-4', dict(effective_keylen=64)), - ('0000000000000000', '6ccf4308974c267f', '88bca90e90875a', - 'RFC2268-5', dict(effective_keylen=64)), - ('0000000000000000', '1a807d272bbe5db1', '88bca90e90875a7f0f79c384627bafb2', - 'RFC2268-6', dict(effective_keylen=64)), - - # 128-bit effective key length - ('0000000000000000', '2269552ab0f85ca6', '88bca90e90875a7f0f79c384627bafb2', - "RFC2268-7", dict(effective_keylen=128)), - ('0000000000000000', '5b78d3a43dfff1f1', - '88bca90e90875a7f0f79c384627bafb216f80a6f85920584c42fceb0be255daf1e', - "RFC2268-8", dict(effective_keylen=129)), - - # Test vectors from PyCrypto 2.0.1's testdata.py - # 1024-bit effective key length - ('0000000000000000', '624fb3e887419e48', '5068696c6970476c617373', - 'PCTv201-0'), - ('ffffffffffffffff', '79cadef44c4a5a85', '5068696c6970476c617373', - 'PCTv201-1'), - ('0001020304050607', '90411525b34e4c2c', '5068696c6970476c617373', - 'PCTv201-2'), - ('0011223344556677', '078656aaba61cbfb', '5068696c6970476c617373', - 'PCTv201-3'), - ('0000000000000000', 'd7bcc5dbb4d6e56a', 'ffffffffffffffff', - 'PCTv201-4'), - ('ffffffffffffffff', '7259018ec557b357', 'ffffffffffffffff', - 'PCTv201-5'), - ('0001020304050607', '93d20a497f2ccb62', 'ffffffffffffffff', - 'PCTv201-6'), - ('0011223344556677', 'cb15a7f819c0014d', 'ffffffffffffffff', - 'PCTv201-7'), - ('0000000000000000', '63ac98cdf3843a7a', 'ffffffffffffffff5065746572477265656e6177617953e5ffe553', - 'PCTv201-8'), - ('ffffffffffffffff', '3fb49e2fa12371dd', 'ffffffffffffffff5065746572477265656e6177617953e5ffe553', - 'PCTv201-9'), - ('0001020304050607', '46414781ab387d5f', 'ffffffffffffffff5065746572477265656e6177617953e5ffe553', - 'PCTv201-10'), - ('0011223344556677', 'be09dc81feaca271', 'ffffffffffffffff5065746572477265656e6177617953e5ffe553', - 'PCTv201-11'), - ('0000000000000000', 'e64221e608be30ab', '53e5ffe553', - 'PCTv201-12'), - ('ffffffffffffffff', '862bc60fdcd4d9a9', '53e5ffe553', - 'PCTv201-13'), - ('0001020304050607', '6a34da50fa5e47de', '53e5ffe553', - 'PCTv201-14'), - ('0011223344556677', '584644c34503122c', '53e5ffe553', - 'PCTv201-15'), -] - -class BufferOverflowTest(unittest.TestCase): - # Test a buffer overflow found in older versions of PyCrypto - - def runTest(self): - """ARC2 with keylength > 128""" - key = b("x") * 16384 - self.assertRaises(ValueError, ARC2.new, key, ARC2.MODE_ECB) - -class KeyLength(unittest.TestCase): - - def runTest(self): - ARC2.new(b'\x00' * 16, ARC2.MODE_ECB, effective_keylen=40) - self.assertRaises(ValueError, ARC2.new, bchr(0) * 4, ARC2.MODE_ECB) - self.assertRaises(ValueError, ARC2.new, bchr(0) * 129, ARC2.MODE_ECB) - - self.assertRaises(ValueError, ARC2.new, bchr(0) * 16, ARC2.MODE_ECB, - effective_keylen=39) - self.assertRaises(ValueError, ARC2.new, bchr(0) * 16, ARC2.MODE_ECB, - effective_keylen=1025) - - -class TestOutput(unittest.TestCase): - - def runTest(self): - # Encrypt/Decrypt data and test output parameter - - cipher = ARC2.new(b'4'*16, ARC2.MODE_ECB) - - pt = b'5' * 16 - ct = cipher.encrypt(pt) - - output = bytearray(16) - res = cipher.encrypt(pt, output=output) - self.assertEqual(ct, output) - self.assertEqual(res, None) - - res = cipher.decrypt(ct, output=output) - self.assertEqual(pt, output) - self.assertEqual(res, None) - - output = memoryview(bytearray(16)) - cipher.encrypt(pt, output=output) - self.assertEqual(ct, output) - - cipher.decrypt(ct, output=output) - self.assertEqual(pt, output) - - self.assertRaises(TypeError, cipher.encrypt, pt, output=b'0'*16) - self.assertRaises(TypeError, cipher.decrypt, ct, output=b'0'*16) - - shorter_output = bytearray(7) - self.assertRaises(ValueError, cipher.encrypt, pt, output=shorter_output) - self.assertRaises(ValueError, cipher.decrypt, ct, output=shorter_output) - - -def get_tests(config={}): - from Crypto.Cipher import ARC2 - from .common import make_block_tests - - tests = make_block_tests(ARC2, "ARC2", test_data) - tests.append(BufferOverflowTest()) - tests.append(KeyLength()) - tests += [TestOutput()] - - return tests - -if __name__ == '__main__': - import unittest - suite = lambda: unittest.TestSuite(get_tests()) - unittest.main(defaultTest='suite') - -# vim:set ts=4 sw=4 sts=4 expandtab: diff --git a/Crypto/SelfTest/Cipher/test_ARC4.py b/Crypto/SelfTest/Cipher/test_ARC4.py deleted file mode 100644 index 856cf4a..0000000 --- a/Crypto/SelfTest/Cipher/test_ARC4.py +++ /dev/null @@ -1,466 +0,0 @@ -# -*- coding: utf-8 -*- -# -# SelfTest/Cipher/ARC4.py: Self-test for the Alleged-RC4 cipher -# -# Written in 2008 by Dwayne C. Litzenberger -# -# =================================================================== -# The contents of this file are dedicated to the public domain. To -# the extent that dedication to the public domain is not available, -# everyone is granted a worldwide, perpetual, royalty-free, -# non-exclusive license to exercise all rights associated with the -# contents of this file for any purpose whatsoever. -# No rights are reserved. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS -# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN -# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# =================================================================== - -"""Self-test suite for Crypto.Cipher.ARC4""" - -__revision__ = "$Id$" - -from Crypto.Util.py3compat import * -from Crypto.SelfTest.st_common import * -from binascii import unhexlify - -from Crypto.Cipher import ARC4 - -# This is a list of (plaintext, ciphertext, key[, description]) tuples. -test_data = [ - # Test vectors from Eric Rescorla's message with the subject - # "RC4 compatibility testing", sent to the cipherpunks mailing list on - # September 13, 1994. - # http://cypherpunks.venona.com/date/1994/09/msg00420.html - - ('0123456789abcdef', '75b7878099e0c596', '0123456789abcdef', - 'Test vector 0'), - - ('0000000000000000', '7494c2e7104b0879', '0123456789abcdef', - 'Test vector 1'), - - ('0000000000000000', 'de188941a3375d3a', '0000000000000000', - 'Test vector 2'), - - #('00000000000000000000', 'd6a141a7ec3c38dfbd61', 'ef012345', - # 'Test vector 3'), - - ('01' * 512, - '7595c3e6114a09780c4ad452338e1ffd9a1be9498f813d76533449b6778dcad8' - + 'c78a8d2ba9ac66085d0e53d59c26c2d1c490c1ebbe0ce66d1b6b1b13b6b919b8' - + '47c25a91447a95e75e4ef16779cde8bf0a95850e32af9689444fd377108f98fd' - + 'cbd4e726567500990bcc7e0ca3c4aaa304a387d20f3b8fbbcd42a1bd311d7a43' - + '03dda5ab078896ae80c18b0af66dff319616eb784e495ad2ce90d7f772a81747' - + 'b65f62093b1e0db9e5ba532fafec47508323e671327df9444432cb7367cec82f' - + '5d44c0d00b67d650a075cd4b70dedd77eb9b10231b6b5b741347396d62897421' - + 'd43df9b42e446e358e9c11a9b2184ecbef0cd8e7a877ef968f1390ec9b3d35a5' - + '585cb009290e2fcde7b5ec66d9084be44055a619d9dd7fc3166f9487f7cb2729' - + '12426445998514c15d53a18c864ce3a2b7555793988126520eacf2e3066e230c' - + '91bee4dd5304f5fd0405b35bd99c73135d3d9bc335ee049ef69b3867bf2d7bd1' - + 'eaa595d8bfc0066ff8d31509eb0c6caa006c807a623ef84c3d33c195d23ee320' - + 'c40de0558157c822d4b8c569d849aed59d4e0fd7f379586b4b7ff684ed6a189f' - + '7486d49b9c4bad9ba24b96abf924372c8a8fffb10d55354900a77a3db5f205e1' - + 'b99fcd8660863a159ad4abe40fa48934163ddde542a6585540fd683cbfd8c00f' - + '12129a284deacc4cdefe58be7137541c047126c8d49e2755ab181ab7e940b0c0', - '0123456789abcdef', - "Test vector 4"), -] - -class RFC6229_Tests(unittest.TestCase): - # Test vectors from RFC 6229. Each test vector is a tuple with two items: - # the ARC4 key and a dictionary. The dictionary has keystream offsets as keys - # and the 16-byte keystream starting at the relevant offset as value. - rfc6229_data = [ - # Page 3 - ( - '0102030405', - { - 0: 'b2 39 63 05 f0 3d c0 27 cc c3 52 4a 0a 11 18 a8', - 16: '69 82 94 4f 18 fc 82 d5 89 c4 03 a4 7a 0d 09 19', - 240: '28 cb 11 32 c9 6c e2 86 42 1d ca ad b8 b6 9e ae', - 256: '1c fc f6 2b 03 ed db 64 1d 77 df cf 7f 8d 8c 93', - 496: '42 b7 d0 cd d9 18 a8 a3 3d d5 17 81 c8 1f 40 41', - 512: '64 59 84 44 32 a7 da 92 3c fb 3e b4 98 06 61 f6', - 752: 'ec 10 32 7b de 2b ee fd 18 f9 27 76 80 45 7e 22', - 768: 'eb 62 63 8d 4f 0b a1 fe 9f ca 20 e0 5b f8 ff 2b', - 1008:'45 12 90 48 e6 a0 ed 0b 56 b4 90 33 8f 07 8d a5', - 1024:'30 ab bc c7 c2 0b 01 60 9f 23 ee 2d 5f 6b b7 df', - 1520:'32 94 f7 44 d8 f9 79 05 07 e7 0f 62 e5 bb ce ea', - 1536:'d8 72 9d b4 18 82 25 9b ee 4f 82 53 25 f5 a1 30', - 2032:'1e b1 4a 0c 13 b3 bf 47 fa 2a 0b a9 3a d4 5b 8b', - 2048:'cc 58 2f 8b a9 f2 65 e2 b1 be 91 12 e9 75 d2 d7', - 3056:'f2 e3 0f 9b d1 02 ec bf 75 aa ad e9 bc 35 c4 3c', - 3072:'ec 0e 11 c4 79 dc 32 9d c8 da 79 68 fe 96 56 81', - 4080:'06 83 26 a2 11 84 16 d2 1f 9d 04 b2 cd 1c a0 50', - 4096:'ff 25 b5 89 95 99 67 07 e5 1f bd f0 8b 34 d8 75' - } - ), - # Page 4 - ( - '01020304050607', - { - 0: '29 3f 02 d4 7f 37 c9 b6 33 f2 af 52 85 fe b4 6b', - 16: 'e6 20 f1 39 0d 19 bd 84 e2 e0 fd 75 20 31 af c1', - 240: '91 4f 02 53 1c 92 18 81 0d f6 0f 67 e3 38 15 4c', - 256: 'd0 fd b5 83 07 3c e8 5a b8 39 17 74 0e c0 11 d5', - 496: '75 f8 14 11 e8 71 cf fa 70 b9 0c 74 c5 92 e4 54', - 512: '0b b8 72 02 93 8d ad 60 9e 87 a5 a1 b0 79 e5 e4', - 752: 'c2 91 12 46 b6 12 e7 e7 b9 03 df ed a1 da d8 66', - 768: '32 82 8f 91 50 2b 62 91 36 8d e8 08 1d e3 6f c2', - 1008:'f3 b9 a7 e3 b2 97 bf 9a d8 04 51 2f 90 63 ef f1', - 1024:'8e cb 67 a9 ba 1f 55 a5 a0 67 e2 b0 26 a3 67 6f', - 1520:'d2 aa 90 2b d4 2d 0d 7c fd 34 0c d4 58 10 52 9f', - 1536:'78 b2 72 c9 6e 42 ea b4 c6 0b d9 14 e3 9d 06 e3', - 2032:'f4 33 2f d3 1a 07 93 96 ee 3c ee 3f 2a 4f f0 49', - 2048:'05 45 97 81 d4 1f da 7f 30 c1 be 7e 12 46 c6 23', - 3056:'ad fd 38 68 b8 e5 14 85 d5 e6 10 01 7e 3d d6 09', - 3072:'ad 26 58 1c 0c 5b e4 5f 4c ea 01 db 2f 38 05 d5', - 4080:'f3 17 2c ef fc 3b 3d 99 7c 85 cc d5 af 1a 95 0c', - 4096:'e7 4b 0b 97 31 22 7f d3 7c 0e c0 8a 47 dd d8 b8' - } - ), - ( - '0102030405060708', - { - 0: '97 ab 8a 1b f0 af b9 61 32 f2 f6 72 58 da 15 a8', - 16: '82 63 ef db 45 c4 a1 86 84 ef 87 e6 b1 9e 5b 09', - 240: '96 36 eb c9 84 19 26 f4 f7 d1 f3 62 bd df 6e 18', - 256: 'd0 a9 90 ff 2c 05 fe f5 b9 03 73 c9 ff 4b 87 0a', - 496: '73 23 9f 1d b7 f4 1d 80 b6 43 c0 c5 25 18 ec 63', - 512: '16 3b 31 99 23 a6 bd b4 52 7c 62 61 26 70 3c 0f', - 752: '49 d6 c8 af 0f 97 14 4a 87 df 21 d9 14 72 f9 66', - 768: '44 17 3a 10 3b 66 16 c5 d5 ad 1c ee 40 c8 63 d0', - 1008:'27 3c 9c 4b 27 f3 22 e4 e7 16 ef 53 a4 7d e7 a4', - 1024:'c6 d0 e7 b2 26 25 9f a9 02 34 90 b2 61 67 ad 1d', - 1520:'1f e8 98 67 13 f0 7c 3d 9a e1 c1 63 ff 8c f9 d3', - 1536:'83 69 e1 a9 65 61 0b e8 87 fb d0 c7 91 62 aa fb', - 2032:'0a 01 27 ab b4 44 84 b9 fb ef 5a bc ae 1b 57 9f', - 2048:'c2 cd ad c6 40 2e 8e e8 66 e1 f3 7b db 47 e4 2c', - 3056:'26 b5 1e a3 7d f8 e1 d6 f7 6f c3 b6 6a 74 29 b3', - 3072:'bc 76 83 20 5d 4f 44 3d c1 f2 9d da 33 15 c8 7b', - 4080:'d5 fa 5a 34 69 d2 9a aa f8 3d 23 58 9d b8 c8 5b', - 4096:'3f b4 6e 2c 8f 0f 06 8e dc e8 cd cd 7d fc 58 62' - } - ), - # Page 5 - ( - '0102030405060708090a', - { - 0: 'ed e3 b0 46 43 e5 86 cc 90 7d c2 18 51 70 99 02', - 16: '03 51 6b a7 8f 41 3b eb 22 3a a5 d4 d2 df 67 11', - 240: '3c fd 6c b5 8e e0 fd de 64 01 76 ad 00 00 04 4d', - 256: '48 53 2b 21 fb 60 79 c9 11 4c 0f fd 9c 04 a1 ad', - 496: '3e 8c ea 98 01 71 09 97 90 84 b1 ef 92 f9 9d 86', - 512: 'e2 0f b4 9b db 33 7e e4 8b 8d 8d c0 f4 af ef fe', - 752: '5c 25 21 ea cd 79 66 f1 5e 05 65 44 be a0 d3 15', - 768: 'e0 67 a7 03 19 31 a2 46 a6 c3 87 5d 2f 67 8a cb', - 1008:'a6 4f 70 af 88 ae 56 b6 f8 75 81 c0 e2 3e 6b 08', - 1024:'f4 49 03 1d e3 12 81 4e c6 f3 19 29 1f 4a 05 16', - 1520:'bd ae 85 92 4b 3c b1 d0 a2 e3 3a 30 c6 d7 95 99', - 1536:'8a 0f ed db ac 86 5a 09 bc d1 27 fb 56 2e d6 0a', - 2032:'b5 5a 0a 5b 51 a1 2a 8b e3 48 99 c3 e0 47 51 1a', - 2048:'d9 a0 9c ea 3c e7 5f e3 96 98 07 03 17 a7 13 39', - 3056:'55 22 25 ed 11 77 f4 45 84 ac 8c fa 6c 4e b5 fc', - 3072:'7e 82 cb ab fc 95 38 1b 08 09 98 44 21 29 c2 f8', - 4080:'1f 13 5e d1 4c e6 0a 91 36 9d 23 22 be f2 5e 3c', - 4096:'08 b6 be 45 12 4a 43 e2 eb 77 95 3f 84 dc 85 53' - } - ), - ( - '0102030405060708090a0b0c0d0e0f10', - { - 0: '9a c7 cc 9a 60 9d 1e f7 b2 93 28 99 cd e4 1b 97', - 16: '52 48 c4 95 90 14 12 6a 6e 8a 84 f1 1d 1a 9e 1c', - 240: '06 59 02 e4 b6 20 f6 cc 36 c8 58 9f 66 43 2f 2b', - 256: 'd3 9d 56 6b c6 bc e3 01 07 68 15 15 49 f3 87 3f', - 496: 'b6 d1 e6 c4 a5 e4 77 1c ad 79 53 8d f2 95 fb 11', - 512: 'c6 8c 1d 5c 55 9a 97 41 23 df 1d bc 52 a4 3b 89', - 752: 'c5 ec f8 8d e8 97 fd 57 fe d3 01 70 1b 82 a2 59', - 768: 'ec cb e1 3d e1 fc c9 1c 11 a0 b2 6c 0b c8 fa 4d', - 1008:'e7 a7 25 74 f8 78 2a e2 6a ab cf 9e bc d6 60 65', - 1024:'bd f0 32 4e 60 83 dc c6 d3 ce dd 3c a8 c5 3c 16', - 1520:'b4 01 10 c4 19 0b 56 22 a9 61 16 b0 01 7e d2 97', - 1536:'ff a0 b5 14 64 7e c0 4f 63 06 b8 92 ae 66 11 81', - 2032:'d0 3d 1b c0 3c d3 3d 70 df f9 fa 5d 71 96 3e bd', - 2048:'8a 44 12 64 11 ea a7 8b d5 1e 8d 87 a8 87 9b f5', - 3056:'fa be b7 60 28 ad e2 d0 e4 87 22 e4 6c 46 15 a3', - 3072:'c0 5d 88 ab d5 03 57 f9 35 a6 3c 59 ee 53 76 23', - 4080:'ff 38 26 5c 16 42 c1 ab e8 d3 c2 fe 5e 57 2b f8', - 4096:'a3 6a 4c 30 1a e8 ac 13 61 0c cb c1 22 56 ca cc' - } - ), - # Page 6 - ( - '0102030405060708090a0b0c0d0e0f101112131415161718', - { - 0: '05 95 e5 7f e5 f0 bb 3c 70 6e da c8 a4 b2 db 11', - 16: 'df de 31 34 4a 1a f7 69 c7 4f 07 0a ee 9e 23 26', - 240: 'b0 6b 9b 1e 19 5d 13 d8 f4 a7 99 5c 45 53 ac 05', - 256: '6b d2 37 8e c3 41 c9 a4 2f 37 ba 79 f8 8a 32 ff', - 496: 'e7 0b ce 1d f7 64 5a db 5d 2c 41 30 21 5c 35 22', - 512: '9a 57 30 c7 fc b4 c9 af 51 ff da 89 c7 f1 ad 22', - 752: '04 85 05 5f d4 f6 f0 d9 63 ef 5a b9 a5 47 69 82', - 768: '59 1f c6 6b cd a1 0e 45 2b 03 d4 55 1f 6b 62 ac', - 1008:'27 53 cc 83 98 8a fa 3e 16 88 a1 d3 b4 2c 9a 02', - 1024:'93 61 0d 52 3d 1d 3f 00 62 b3 c2 a3 bb c7 c7 f0', - 1520:'96 c2 48 61 0a ad ed fe af 89 78 c0 3d e8 20 5a', - 1536:'0e 31 7b 3d 1c 73 b9 e9 a4 68 8f 29 6d 13 3a 19', - 2032:'bd f0 e6 c3 cc a5 b5 b9 d5 33 b6 9c 56 ad a1 20', - 2048:'88 a2 18 b6 e2 ec e1 e6 24 6d 44 c7 59 d1 9b 10', - 3056:'68 66 39 7e 95 c1 40 53 4f 94 26 34 21 00 6e 40', - 3072:'32 cb 0a 1e 95 42 c6 b3 b8 b3 98 ab c3 b0 f1 d5', - 4080:'29 a0 b8 ae d5 4a 13 23 24 c6 2e 42 3f 54 b4 c8', - 4096:'3c b0 f3 b5 02 0a 98 b8 2a f9 fe 15 44 84 a1 68' - } - ), - ( - '0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20', - { - 0: 'ea a6 bd 25 88 0b f9 3d 3f 5d 1e 4c a2 61 1d 91', - 16: 'cf a4 5c 9f 7e 71 4b 54 bd fa 80 02 7c b1 43 80', - 240: '11 4a e3 44 de d7 1b 35 f2 e6 0f eb ad 72 7f d8', - 256: '02 e1 e7 05 6b 0f 62 39 00 49 64 22 94 3e 97 b6', - 496: '91 cb 93 c7 87 96 4e 10 d9 52 7d 99 9c 6f 93 6b', - 512: '49 b1 8b 42 f8 e8 36 7c be b5 ef 10 4b a1 c7 cd', - 752: '87 08 4b 3b a7 00 ba de 95 56 10 67 27 45 b3 74', - 768: 'e7 a7 b9 e9 ec 54 0d 5f f4 3b db 12 79 2d 1b 35', - 1008:'c7 99 b5 96 73 8f 6b 01 8c 76 c7 4b 17 59 bd 90', - 1024:'7f ec 5b fd 9f 9b 89 ce 65 48 30 90 92 d7 e9 58', - 1520:'40 f2 50 b2 6d 1f 09 6a 4a fd 4c 34 0a 58 88 15', - 1536:'3e 34 13 5c 79 db 01 02 00 76 76 51 cf 26 30 73', - 2032:'f6 56 ab cc f8 8d d8 27 02 7b 2c e9 17 d4 64 ec', - 2048:'18 b6 25 03 bf bc 07 7f ba bb 98 f2 0d 98 ab 34', - 3056:'8a ed 95 ee 5b 0d cb fb ef 4e b2 1d 3a 3f 52 f9', - 3072:'62 5a 1a b0 0e e3 9a 53 27 34 6b dd b0 1a 9c 18', - 4080:'a1 3a 7c 79 c7 e1 19 b5 ab 02 96 ab 28 c3 00 b9', - 4096:'f3 e4 c0 a2 e0 2d 1d 01 f7 f0 a7 46 18 af 2b 48' - } - ), - # Page 7 - ( - '833222772a', - { - 0: '80 ad 97 bd c9 73 df 8a 2e 87 9e 92 a4 97 ef da', - 16: '20 f0 60 c2 f2 e5 12 65 01 d3 d4 fe a1 0d 5f c0', - 240: 'fa a1 48 e9 90 46 18 1f ec 6b 20 85 f3 b2 0e d9', - 256: 'f0 da f5 ba b3 d5 96 83 98 57 84 6f 73 fb fe 5a', - 496: '1c 7e 2f c4 63 92 32 fe 29 75 84 b2 96 99 6b c8', - 512: '3d b9 b2 49 40 6c c8 ed ff ac 55 cc d3 22 ba 12', - 752: 'e4 f9 f7 e0 06 61 54 bb d1 25 b7 45 56 9b c8 97', - 768: '75 d5 ef 26 2b 44 c4 1a 9c f6 3a e1 45 68 e1 b9', - 1008:'6d a4 53 db f8 1e 82 33 4a 3d 88 66 cb 50 a1 e3', - 1024:'78 28 d0 74 11 9c ab 5c 22 b2 94 d7 a9 bf a0 bb', - 1520:'ad b8 9c ea 9a 15 fb e6 17 29 5b d0 4b 8c a0 5c', - 1536:'62 51 d8 7f d4 aa ae 9a 7e 4a d5 c2 17 d3 f3 00', - 2032:'e7 11 9b d6 dd 9b 22 af e8 f8 95 85 43 28 81 e2', - 2048:'78 5b 60 fd 7e c4 e9 fc b6 54 5f 35 0d 66 0f ab', - 3056:'af ec c0 37 fd b7 b0 83 8e b3 d7 0b cd 26 83 82', - 3072:'db c1 a7 b4 9d 57 35 8c c9 fa 6d 61 d7 3b 7c f0', - 4080:'63 49 d1 26 a3 7a fc ba 89 79 4f 98 04 91 4f dc', - 4096:'bf 42 c3 01 8c 2f 7c 66 bf de 52 49 75 76 81 15' - } - ), - ( - '1910833222772a', - { - 0: 'bc 92 22 db d3 27 4d 8f c6 6d 14 cc bd a6 69 0b', - 16: '7a e6 27 41 0c 9a 2b e6 93 df 5b b7 48 5a 63 e3', - 240: '3f 09 31 aa 03 de fb 30 0f 06 01 03 82 6f 2a 64', - 256: 'be aa 9e c8 d5 9b b6 81 29 f3 02 7c 96 36 11 81', - 496: '74 e0 4d b4 6d 28 64 8d 7d ee 8a 00 64 b0 6c fe', - 512: '9b 5e 81 c6 2f e0 23 c5 5b e4 2f 87 bb f9 32 b8', - 752: 'ce 17 8f c1 82 6e fe cb c1 82 f5 79 99 a4 61 40', - 768: '8b df 55 cd 55 06 1c 06 db a6 be 11 de 4a 57 8a', - 1008:'62 6f 5f 4d ce 65 25 01 f3 08 7d 39 c9 2c c3 49', - 1024:'42 da ac 6a 8f 9a b9 a7 fd 13 7c 60 37 82 56 82', - 1520:'cc 03 fd b7 91 92 a2 07 31 2f 53 f5 d4 dc 33 d9', - 1536:'f7 0f 14 12 2a 1c 98 a3 15 5d 28 b8 a0 a8 a4 1d', - 2032:'2a 3a 30 7a b2 70 8a 9c 00 fe 0b 42 f9 c2 d6 a1', - 2048:'86 26 17 62 7d 22 61 ea b0 b1 24 65 97 ca 0a e9', - 3056:'55 f8 77 ce 4f 2e 1d db bf 8e 13 e2 cd e0 fd c8', - 3072:'1b 15 56 cb 93 5f 17 33 37 70 5f bb 5d 50 1f c1', - 4080:'ec d0 e9 66 02 be 7f 8d 50 92 81 6c cc f2 c2 e9', - 4096:'02 78 81 fa b4 99 3a 1c 26 20 24 a9 4f ff 3f 61' - } - ), - # Page 8 - ( - '641910833222772a', - { - 0: 'bb f6 09 de 94 13 17 2d 07 66 0c b6 80 71 69 26', - 16: '46 10 1a 6d ab 43 11 5d 6c 52 2b 4f e9 36 04 a9', - 240: 'cb e1 ff f2 1c 96 f3 ee f6 1e 8f e0 54 2c bd f0', - 256: '34 79 38 bf fa 40 09 c5 12 cf b4 03 4b 0d d1 a7', - 496: '78 67 a7 86 d0 0a 71 47 90 4d 76 dd f1 e5 20 e3', - 512: '8d 3e 9e 1c ae fc cc b3 fb f8 d1 8f 64 12 0b 32', - 752: '94 23 37 f8 fd 76 f0 fa e8 c5 2d 79 54 81 06 72', - 768: 'b8 54 8c 10 f5 16 67 f6 e6 0e 18 2f a1 9b 30 f7', - 1008:'02 11 c7 c6 19 0c 9e fd 12 37 c3 4c 8f 2e 06 c4', - 1024:'bd a6 4f 65 27 6d 2a ac b8 f9 02 12 20 3a 80 8e', - 1520:'bd 38 20 f7 32 ff b5 3e c1 93 e7 9d 33 e2 7c 73', - 1536:'d0 16 86 16 86 19 07 d4 82 e3 6c da c8 cf 57 49', - 2032:'97 b0 f0 f2 24 b2 d2 31 71 14 80 8f b0 3a f7 a0', - 2048:'e5 96 16 e4 69 78 79 39 a0 63 ce ea 9a f9 56 d1', - 3056:'c4 7e 0d c1 66 09 19 c1 11 01 20 8f 9e 69 aa 1f', - 3072:'5a e4 f1 28 96 b8 37 9a 2a ad 89 b5 b5 53 d6 b0', - 4080:'6b 6b 09 8d 0c 29 3b c2 99 3d 80 bf 05 18 b6 d9', - 4096:'81 70 cc 3c cd 92 a6 98 62 1b 93 9d d3 8f e7 b9' - } - ), - ( - '8b37641910833222772a', - { - 0: 'ab 65 c2 6e dd b2 87 60 0d b2 fd a1 0d 1e 60 5c', - 16: 'bb 75 90 10 c2 96 58 f2 c7 2d 93 a2 d1 6d 29 30', - 240: 'b9 01 e8 03 6e d1 c3 83 cd 3c 4c 4d d0 a6 ab 05', - 256: '3d 25 ce 49 22 92 4c 55 f0 64 94 33 53 d7 8a 6c', - 496: '12 c1 aa 44 bb f8 7e 75 e6 11 f6 9b 2c 38 f4 9b', - 512: '28 f2 b3 43 4b 65 c0 98 77 47 00 44 c6 ea 17 0d', - 752: 'bd 9e f8 22 de 52 88 19 61 34 cf 8a f7 83 93 04', - 768: '67 55 9c 23 f0 52 15 84 70 a2 96 f7 25 73 5a 32', - 1008:'8b ab 26 fb c2 c1 2b 0f 13 e2 ab 18 5e ab f2 41', - 1024:'31 18 5a 6d 69 6f 0c fa 9b 42 80 8b 38 e1 32 a2', - 1520:'56 4d 3d ae 18 3c 52 34 c8 af 1e 51 06 1c 44 b5', - 1536:'3c 07 78 a7 b5 f7 2d 3c 23 a3 13 5c 7d 67 b9 f4', - 2032:'f3 43 69 89 0f cf 16 fb 51 7d ca ae 44 63 b2 dd', - 2048:'02 f3 1c 81 e8 20 07 31 b8 99 b0 28 e7 91 bf a7', - 3056:'72 da 64 62 83 22 8c 14 30 08 53 70 17 95 61 6f', - 3072:'4e 0a 8c 6f 79 34 a7 88 e2 26 5e 81 d6 d0 c8 f4', - 4080:'43 8d d5 ea fe a0 11 1b 6f 36 b4 b9 38 da 2a 68', - 4096:'5f 6b fc 73 81 58 74 d9 71 00 f0 86 97 93 57 d8' - } - ), - # Page 9 - ( - 'ebb46227c6cc8b37641910833222772a', - { - 0: '72 0c 94 b6 3e df 44 e1 31 d9 50 ca 21 1a 5a 30', - 16: 'c3 66 fd ea cf 9c a8 04 36 be 7c 35 84 24 d2 0b', - 240: 'b3 39 4a 40 aa bf 75 cb a4 22 82 ef 25 a0 05 9f', - 256: '48 47 d8 1d a4 94 2d bc 24 9d ef c4 8c 92 2b 9f', - 496: '08 12 8c 46 9f 27 53 42 ad da 20 2b 2b 58 da 95', - 512: '97 0d ac ef 40 ad 98 72 3b ac 5d 69 55 b8 17 61', - 752: '3c b8 99 93 b0 7b 0c ed 93 de 13 d2 a1 10 13 ac', - 768: 'ef 2d 67 6f 15 45 c2 c1 3d c6 80 a0 2f 4a db fe', - 1008:'b6 05 95 51 4f 24 bc 9f e5 22 a6 ca d7 39 36 44', - 1024:'b5 15 a8 c5 01 17 54 f5 90 03 05 8b db 81 51 4e', - 1520:'3c 70 04 7e 8c bc 03 8e 3b 98 20 db 60 1d a4 95', - 1536:'11 75 da 6e e7 56 de 46 a5 3e 2b 07 56 60 b7 70', - 2032:'00 a5 42 bb a0 21 11 cc 2c 65 b3 8e bd ba 58 7e', - 2048:'58 65 fd bb 5b 48 06 41 04 e8 30 b3 80 f2 ae de', - 3056:'34 b2 1a d2 ad 44 e9 99 db 2d 7f 08 63 f0 d9 b6', - 3072:'84 a9 21 8f c3 6e 8a 5f 2c cf be ae 53 a2 7d 25', - 4080:'a2 22 1a 11 b8 33 cc b4 98 a5 95 40 f0 54 5f 4a', - 4096:'5b be b4 78 7d 59 e5 37 3f db ea 6c 6f 75 c2 9b' - } - ), - ( - 'c109163908ebe51debb46227c6cc8b37641910833222772a', - { - 0: '54 b6 4e 6b 5a 20 b5 e2 ec 84 59 3d c7 98 9d a7', - 16: 'c1 35 ee e2 37 a8 54 65 ff 97 dc 03 92 4f 45 ce', - 240: 'cf cc 92 2f b4 a1 4a b4 5d 61 75 aa bb f2 d2 01', - 256: '83 7b 87 e2 a4 46 ad 0e f7 98 ac d0 2b 94 12 4f', - 496: '17 a6 db d6 64 92 6a 06 36 b3 f4 c3 7a 4f 46 94', - 512: '4a 5f 9f 26 ae ee d4 d4 a2 5f 63 2d 30 52 33 d9', - 752: '80 a3 d0 1e f0 0c 8e 9a 42 09 c1 7f 4e eb 35 8c', - 768: 'd1 5e 7d 5f fa aa bc 02 07 bf 20 0a 11 77 93 a2', - 1008:'34 96 82 bf 58 8e aa 52 d0 aa 15 60 34 6a ea fa', - 1024:'f5 85 4c db 76 c8 89 e3 ad 63 35 4e 5f 72 75 e3', - 1520:'53 2c 7c ec cb 39 df 32 36 31 84 05 a4 b1 27 9c', - 1536:'ba ef e6 d9 ce b6 51 84 22 60 e0 d1 e0 5e 3b 90', - 2032:'e8 2d 8c 6d b5 4e 3c 63 3f 58 1c 95 2b a0 42 07', - 2048:'4b 16 e5 0a bd 38 1b d7 09 00 a9 cd 9a 62 cb 23', - 3056:'36 82 ee 33 bd 14 8b d9 f5 86 56 cd 8f 30 d9 fb', - 3072:'1e 5a 0b 84 75 04 5d 9b 20 b2 62 86 24 ed fd 9e', - 4080:'63 ed d6 84 fb 82 62 82 fe 52 8f 9c 0e 92 37 bc', - 4096:'e4 dd 2e 98 d6 96 0f ae 0b 43 54 54 56 74 33 91' - } - ), - # Page 10 - ( - '1ada31d5cf688221c109163908ebe51debb46227c6cc8b37641910833222772a', - { - 0: 'dd 5b cb 00 18 e9 22 d4 94 75 9d 7c 39 5d 02 d3', - 16: 'c8 44 6f 8f 77 ab f7 37 68 53 53 eb 89 a1 c9 eb', - 240: 'af 3e 30 f9 c0 95 04 59 38 15 15 75 c3 fb 90 98', - 256: 'f8 cb 62 74 db 99 b8 0b 1d 20 12 a9 8e d4 8f 0e', - 496: '25 c3 00 5a 1c b8 5d e0 76 25 98 39 ab 71 98 ab', - 512: '9d cb c1 83 e8 cb 99 4b 72 7b 75 be 31 80 76 9c', - 752: 'a1 d3 07 8d fa 91 69 50 3e d9 d4 49 1d ee 4e b2', - 768: '85 14 a5 49 58 58 09 6f 59 6e 4b cd 66 b1 06 65', - 1008:'5f 40 d5 9e c1 b0 3b 33 73 8e fa 60 b2 25 5d 31', - 1024:'34 77 c7 f7 64 a4 1b ac ef f9 0b f1 4f 92 b7 cc', - 1520:'ac 4e 95 36 8d 99 b9 eb 78 b8 da 8f 81 ff a7 95', - 1536:'8c 3c 13 f8 c2 38 8b b7 3f 38 57 6e 65 b7 c4 46', - 2032:'13 c4 b9 c1 df b6 65 79 ed dd 8a 28 0b 9f 73 16', - 2048:'dd d2 78 20 55 01 26 69 8e fa ad c6 4b 64 f6 6e', - 3056:'f0 8f 2e 66 d2 8e d1 43 f3 a2 37 cf 9d e7 35 59', - 3072:'9e a3 6c 52 55 31 b8 80 ba 12 43 34 f5 7b 0b 70', - 4080:'d5 a3 9e 3d fc c5 02 80 ba c4 a6 b5 aa 0d ca 7d', - 4096:'37 0b 1c 1f e6 55 91 6d 97 fd 0d 47 ca 1d 72 b8' - } - ) - ] - - def test_keystream(self): - for tv in self.rfc6229_data: - key = unhexlify(b((tv[0]))) - cipher = ARC4.new(key) - count = 0 - for offset in range(0,4096+1,16): - ct = cipher.encrypt(b('\x00')*16) - expected = tv[1].get(offset) - if expected: - expected = unhexlify(b(expected.replace(" ",''))) - self.assertEquals(ct, expected) - count += 1 - self.assertEqual(count, len(tv[1])) - -class Drop_Tests(unittest.TestCase): - key = b('\xAA')*16 - data = b('\x00')*5000 - - def setUp(self): - self.cipher = ARC4.new(self.key) - - def test_drop256_encrypt(self): - cipher_drop = ARC4.new(self.key, 256) - ct_drop = cipher_drop.encrypt(self.data[:16]) - ct = self.cipher.encrypt(self.data)[256:256+16] - self.assertEquals(ct_drop, ct) - - def test_drop256_decrypt(self): - cipher_drop = ARC4.new(self.key, 256) - pt_drop = cipher_drop.decrypt(self.data[:16]) - pt = self.cipher.decrypt(self.data)[256:256+16] - self.assertEquals(pt_drop, pt) - - -class KeyLength(unittest.TestCase): - - def runTest(self): - self.assertRaises(ValueError, ARC4.new, bchr(0) * 4) - self.assertRaises(ValueError, ARC4.new, bchr(0) * 257) - - -def get_tests(config={}): - from .common import make_stream_tests - tests = make_stream_tests(ARC4, "ARC4", test_data) - tests += list_test_cases(RFC6229_Tests) - tests += list_test_cases(Drop_Tests) - tests.append(KeyLength()) - return tests - -if __name__ == '__main__': - import unittest - suite = lambda: unittest.TestSuite(get_tests()) - unittest.main(defaultTest='suite') - -# vim:set ts=4 sw=4 sts=4 expandtab: diff --git a/Crypto/SelfTest/Cipher/test_Blowfish.py b/Crypto/SelfTest/Cipher/test_Blowfish.py deleted file mode 100644 index 4ce3a41..0000000 --- a/Crypto/SelfTest/Cipher/test_Blowfish.py +++ /dev/null @@ -1,160 +0,0 @@ -# -*- coding: utf-8 -*- -# -# SelfTest/Cipher/test_Blowfish.py: Self-test for the Blowfish cipher -# -# Written in 2008 by Dwayne C. Litzenberger -# -# =================================================================== -# The contents of this file are dedicated to the public domain. To -# the extent that dedication to the public domain is not available, -# everyone is granted a worldwide, perpetual, royalty-free, -# non-exclusive license to exercise all rights associated with the -# contents of this file for any purpose whatsoever. -# No rights are reserved. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS -# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN -# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# =================================================================== - -"""Self-test suite for Crypto.Cipher.Blowfish""" - -import unittest - -from Crypto.Util.py3compat import bchr - -from Crypto.Cipher import Blowfish - -# This is a list of (plaintext, ciphertext, key) tuples. -test_data = [ - # Test vectors from http://www.schneier.com/code/vectors.txt - ('0000000000000000', '4ef997456198dd78', '0000000000000000'), - ('ffffffffffffffff', '51866fd5b85ecb8a', 'ffffffffffffffff'), - ('1000000000000001', '7d856f9a613063f2', '3000000000000000'), - ('1111111111111111', '2466dd878b963c9d', '1111111111111111'), - ('1111111111111111', '61f9c3802281b096', '0123456789abcdef'), - ('0123456789abcdef', '7d0cc630afda1ec7', '1111111111111111'), - ('0000000000000000', '4ef997456198dd78', '0000000000000000'), - ('0123456789abcdef', '0aceab0fc6a0a28d', 'fedcba9876543210'), - ('01a1d6d039776742', '59c68245eb05282b', '7ca110454a1a6e57'), - ('5cd54ca83def57da', 'b1b8cc0b250f09a0', '0131d9619dc1376e'), - ('0248d43806f67172', '1730e5778bea1da4', '07a1133e4a0b2686'), - ('51454b582ddf440a', 'a25e7856cf2651eb', '3849674c2602319e'), - ('42fd443059577fa2', '353882b109ce8f1a', '04b915ba43feb5b6'), - ('059b5e0851cf143a', '48f4d0884c379918', '0113b970fd34f2ce'), - ('0756d8e0774761d2', '432193b78951fc98', '0170f175468fb5e6'), - ('762514b829bf486a', '13f04154d69d1ae5', '43297fad38e373fe'), - ('3bdd119049372802', '2eedda93ffd39c79', '07a7137045da2a16'), - ('26955f6835af609a', 'd887e0393c2da6e3', '04689104c2fd3b2f'), - ('164d5e404f275232', '5f99d04f5b163969', '37d06bb516cb7546'), - ('6b056e18759f5cca', '4a057a3b24d3977b', '1f08260d1ac2465e'), - ('004bd6ef09176062', '452031c1e4fada8e', '584023641aba6176'), - ('480d39006ee762f2', '7555ae39f59b87bd', '025816164629b007'), - ('437540c8698f3cfa', '53c55f9cb49fc019', '49793ebc79b3258f'), - ('072d43a077075292', '7a8e7bfa937e89a3', '4fb05e1515ab73a7'), - ('02fe55778117f12a', 'cf9c5d7a4986adb5', '49e95d6d4ca229bf'), - ('1d9d5c5018f728c2', 'd1abb290658bc778', '018310dc409b26d6'), - ('305532286d6f295a', '55cb3774d13ef201', '1c587f1c13924fef'), - ('0123456789abcdef', 'fa34ec4847b268b2', '0101010101010101'), - ('0123456789abcdef', 'a790795108ea3cae', '1f1f1f1f0e0e0e0e'), - ('0123456789abcdef', 'c39e072d9fac631d', 'e0fee0fef1fef1fe'), - ('ffffffffffffffff', '014933e0cdaff6e4', '0000000000000000'), - ('0000000000000000', 'f21e9a77b71c49bc', 'ffffffffffffffff'), - ('0000000000000000', '245946885754369a', '0123456789abcdef'), - ('ffffffffffffffff', '6b5c5a9c5d9e0a5a', 'fedcba9876543210'), - #('fedcba9876543210', 'f9ad597c49db005e', 'f0'), - #('fedcba9876543210', 'e91d21c1d961a6d6', 'f0e1'), - #('fedcba9876543210', 'e9c2b70a1bc65cf3', 'f0e1d2'), - ('fedcba9876543210', 'be1e639408640f05', 'f0e1d2c3'), - ('fedcba9876543210', 'b39e44481bdb1e6e', 'f0e1d2c3b4'), - ('fedcba9876543210', '9457aa83b1928c0d', 'f0e1d2c3b4a5'), - ('fedcba9876543210', '8bb77032f960629d', 'f0e1d2c3b4a596'), - ('fedcba9876543210', 'e87a244e2cc85e82', 'f0e1d2c3b4a59687'), - ('fedcba9876543210', '15750e7a4f4ec577', 'f0e1d2c3b4a5968778'), - ('fedcba9876543210', '122ba70b3ab64ae0', 'f0e1d2c3b4a596877869'), - ('fedcba9876543210', '3a833c9affc537f6', 'f0e1d2c3b4a5968778695a'), - ('fedcba9876543210', '9409da87a90f6bf2', 'f0e1d2c3b4a5968778695a4b'), - ('fedcba9876543210', '884f80625060b8b4', 'f0e1d2c3b4a5968778695a4b3c'), - ('fedcba9876543210', '1f85031c19e11968', 'f0e1d2c3b4a5968778695a4b3c2d'), - ('fedcba9876543210', '79d9373a714ca34f', 'f0e1d2c3b4a5968778695a4b3c2d1e'), - ('fedcba9876543210', '93142887ee3be15c', - 'f0e1d2c3b4a5968778695a4b3c2d1e0f'), - ('fedcba9876543210', '03429e838ce2d14b', - 'f0e1d2c3b4a5968778695a4b3c2d1e0f00'), - ('fedcba9876543210', 'a4299e27469ff67b', - 'f0e1d2c3b4a5968778695a4b3c2d1e0f0011'), - ('fedcba9876543210', 'afd5aed1c1bc96a8', - 'f0e1d2c3b4a5968778695a4b3c2d1e0f001122'), - ('fedcba9876543210', '10851c0e3858da9f', - 'f0e1d2c3b4a5968778695a4b3c2d1e0f00112233'), - ('fedcba9876543210', 'e6f51ed79b9db21f', - 'f0e1d2c3b4a5968778695a4b3c2d1e0f0011223344'), - ('fedcba9876543210', '64a6e14afd36b46f', - 'f0e1d2c3b4a5968778695a4b3c2d1e0f001122334455'), - ('fedcba9876543210', '80c7d7d45a5479ad', - 'f0e1d2c3b4a5968778695a4b3c2d1e0f00112233445566'), - ('fedcba9876543210', '05044b62fa52d080', - 'f0e1d2c3b4a5968778695a4b3c2d1e0f0011223344556677'), -] - - -class KeyLength(unittest.TestCase): - - def runTest(self): - self.assertRaises(ValueError, Blowfish.new, bchr(0) * 3, - Blowfish.MODE_ECB) - self.assertRaises(ValueError, Blowfish.new, bchr(0) * 57, - Blowfish.MODE_ECB) - - -class TestOutput(unittest.TestCase): - - def runTest(self): - # Encrypt/Decrypt data and test output parameter - - cipher = Blowfish.new(b'4'*16, Blowfish.MODE_ECB) - - pt = b'5' * 16 - ct = cipher.encrypt(pt) - - output = bytearray(16) - res = cipher.encrypt(pt, output=output) - self.assertEqual(ct, output) - self.assertEqual(res, None) - - res = cipher.decrypt(ct, output=output) - self.assertEqual(pt, output) - self.assertEqual(res, None) - - output = memoryview(bytearray(16)) - cipher.encrypt(pt, output=output) - self.assertEqual(ct, output) - - cipher.decrypt(ct, output=output) - self.assertEqual(pt, output) - - self.assertRaises(TypeError, cipher.encrypt, pt, output=b'0'*16) - self.assertRaises(TypeError, cipher.decrypt, ct, output=b'0'*16) - - shorter_output = bytearray(7) - self.assertRaises(ValueError, cipher.encrypt, pt, output=shorter_output) - self.assertRaises(ValueError, cipher.decrypt, ct, output=shorter_output) - - -def get_tests(config={}): - from .common import make_block_tests - tests = make_block_tests(Blowfish, "Blowfish", test_data) - tests.append(KeyLength()) - tests += [TestOutput()] - return tests - - -if __name__ == '__main__': - import unittest - suite = lambda: unittest.TestSuite(get_tests()) - unittest.main(defaultTest='suite') diff --git a/Crypto/SelfTest/Cipher/test_CAST.py b/Crypto/SelfTest/Cipher/test_CAST.py deleted file mode 100644 index ff13bd4..0000000 --- a/Crypto/SelfTest/Cipher/test_CAST.py +++ /dev/null @@ -1,101 +0,0 @@ -# -*- coding: utf-8 -*- -# -# SelfTest/Cipher/CAST.py: Self-test for the CAST-128 (CAST5) cipher -# -# Written in 2008 by Dwayne C. Litzenberger -# -# =================================================================== -# The contents of this file are dedicated to the public domain. To -# the extent that dedication to the public domain is not available, -# everyone is granted a worldwide, perpetual, royalty-free, -# non-exclusive license to exercise all rights associated with the -# contents of this file for any purpose whatsoever. -# No rights are reserved. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS -# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN -# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# =================================================================== - -"""Self-test suite for Crypto.Cipher.CAST""" - -import unittest - -from Crypto.Util.py3compat import bchr - -from Crypto.Cipher import CAST - -# This is a list of (plaintext, ciphertext, key) tuples. -test_data = [ - # Test vectors from RFC 2144, B.1 - ('0123456789abcdef', '238b4fe5847e44b2', - '0123456712345678234567893456789a', - '128-bit key'), - - ('0123456789abcdef', 'eb6a711a2c02271b', - '01234567123456782345', - '80-bit key'), - - ('0123456789abcdef', '7ac816d16e9b302e', - '0123456712', - '40-bit key'), -] - - -class KeyLength(unittest.TestCase): - - def runTest(self): - self.assertRaises(ValueError, CAST.new, bchr(0) * 4, CAST.MODE_ECB) - self.assertRaises(ValueError, CAST.new, bchr(0) * 17, CAST.MODE_ECB) - - -class TestOutput(unittest.TestCase): - - def runTest(self): - # Encrypt/Decrypt data and test output parameter - - cipher = CAST.new(b'4'*16, CAST.MODE_ECB) - - pt = b'5' * 16 - ct = cipher.encrypt(pt) - - output = bytearray(16) - res = cipher.encrypt(pt, output=output) - self.assertEqual(ct, output) - self.assertEqual(res, None) - - res = cipher.decrypt(ct, output=output) - self.assertEqual(pt, output) - self.assertEqual(res, None) - - output = memoryview(bytearray(16)) - cipher.encrypt(pt, output=output) - self.assertEqual(ct, output) - - cipher.decrypt(ct, output=output) - self.assertEqual(pt, output) - - self.assertRaises(TypeError, cipher.encrypt, pt, output=b'0'*16) - self.assertRaises(TypeError, cipher.decrypt, ct, output=b'0'*16) - - shorter_output = bytearray(7) - self.assertRaises(ValueError, cipher.encrypt, pt, output=shorter_output) - self.assertRaises(ValueError, cipher.decrypt, ct, output=shorter_output) - - -def get_tests(config={}): - from .common import make_block_tests - - tests = make_block_tests(CAST, "CAST", test_data) - tests.append(KeyLength()) - tests.append(TestOutput()) - return tests - -if __name__ == '__main__': - suite = lambda: unittest.TestSuite(get_tests()) - unittest.main(defaultTest='suite') diff --git a/Crypto/SelfTest/Cipher/test_CBC.py b/Crypto/SelfTest/Cipher/test_CBC.py deleted file mode 100644 index c82e8e5..0000000 --- a/Crypto/SelfTest/Cipher/test_CBC.py +++ /dev/null @@ -1,555 +0,0 @@ -# =================================================================== -# -# Copyright (c) 2014, Legrandin -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# =================================================================== - -import unittest -from binascii import unhexlify - -from Crypto.SelfTest.loader import load_test_vectors -from Crypto.SelfTest.st_common import list_test_cases -from Crypto.Util.py3compat import tobytes, is_string -from Crypto.Cipher import AES, DES3, DES -from Crypto.Hash import SHAKE128 - - -def get_tag_random(tag, length): - return SHAKE128.new(data=tobytes(tag)).read(length) - -class BlockChainingTests(unittest.TestCase): - - key_128 = get_tag_random("key_128", 16) - key_192 = get_tag_random("key_192", 24) - iv_128 = get_tag_random("iv_128", 16) - iv_64 = get_tag_random("iv_64", 8) - data_128 = get_tag_random("data_128", 16) - - def test_loopback_128(self): - cipher = AES.new(self.key_128, self.aes_mode, self.iv_128) - pt = get_tag_random("plaintext", 16 * 100) - ct = cipher.encrypt(pt) - - cipher = AES.new(self.key_128, self.aes_mode, self.iv_128) - pt2 = cipher.decrypt(ct) - self.assertEqual(pt, pt2) - - def test_loopback_64(self): - cipher = DES3.new(self.key_192, self.des3_mode, self.iv_64) - pt = get_tag_random("plaintext", 8 * 100) - ct = cipher.encrypt(pt) - - cipher = DES3.new(self.key_192, self.des3_mode, self.iv_64) - pt2 = cipher.decrypt(ct) - self.assertEqual(pt, pt2) - - def test_iv(self): - # If not passed, the iv is created randomly - cipher = AES.new(self.key_128, self.aes_mode) - iv1 = cipher.iv - cipher = AES.new(self.key_128, self.aes_mode) - iv2 = cipher.iv - self.assertNotEqual(iv1, iv2) - self.assertEqual(len(iv1), 16) - - # IV can be passed in uppercase or lowercase - cipher = AES.new(self.key_128, self.aes_mode, self.iv_128) - ct = cipher.encrypt(self.data_128) - - cipher = AES.new(self.key_128, self.aes_mode, iv=self.iv_128) - self.assertEquals(ct, cipher.encrypt(self.data_128)) - - cipher = AES.new(self.key_128, self.aes_mode, IV=self.iv_128) - self.assertEquals(ct, cipher.encrypt(self.data_128)) - - def test_iv_must_be_bytes(self): - self.assertRaises(TypeError, AES.new, self.key_128, self.aes_mode, - iv = u'test1234567890-*') - - def test_only_one_iv(self): - # Only one IV/iv keyword allowed - self.assertRaises(TypeError, AES.new, self.key_128, self.aes_mode, - iv=self.iv_128, IV=self.iv_128) - - def test_iv_with_matching_length(self): - self.assertRaises(ValueError, AES.new, self.key_128, self.aes_mode, - b"") - self.assertRaises(ValueError, AES.new, self.key_128, self.aes_mode, - self.iv_128[:15]) - self.assertRaises(ValueError, AES.new, self.key_128, self.aes_mode, - self.iv_128 + b"0") - - def test_block_size_128(self): - cipher = AES.new(self.key_128, self.aes_mode, self.iv_128) - self.assertEqual(cipher.block_size, AES.block_size) - - def test_block_size_64(self): - cipher = DES3.new(self.key_192, self.des3_mode, self.iv_64) - self.assertEqual(cipher.block_size, DES3.block_size) - - def test_unaligned_data_128(self): - cipher = AES.new(self.key_128, self.aes_mode, self.iv_128) - for wrong_length in range(1,16): - self.assertRaises(ValueError, cipher.encrypt, b"5" * wrong_length) - - cipher = AES.new(self.key_128, self.aes_mode, self.iv_128) - for wrong_length in range(1,16): - self.assertRaises(ValueError, cipher.decrypt, b"5" * wrong_length) - - def test_unaligned_data_64(self): - cipher = DES3.new(self.key_192, self.des3_mode, self.iv_64) - for wrong_length in range(1,8): - self.assertRaises(ValueError, cipher.encrypt, b"5" * wrong_length) - - cipher = DES3.new(self.key_192, self.des3_mode, self.iv_64) - for wrong_length in range(1,8): - self.assertRaises(ValueError, cipher.decrypt, b"5" * wrong_length) - - def test_IV_iv_attributes(self): - data = get_tag_random("data", 16 * 100) - for func in "encrypt", "decrypt": - cipher = AES.new(self.key_128, self.aes_mode, self.iv_128) - getattr(cipher, func)(data) - self.assertEqual(cipher.iv, self.iv_128) - self.assertEqual(cipher.IV, self.iv_128) - - def test_unknown_parameters(self): - self.assertRaises(TypeError, AES.new, self.key_128, self.aes_mode, - self.iv_128, 7) - self.assertRaises(TypeError, AES.new, self.key_128, self.aes_mode, - iv=self.iv_128, unknown=7) - # But some are only known by the base cipher (e.g. use_aesni consumed by the AES module) - AES.new(self.key_128, self.aes_mode, iv=self.iv_128, use_aesni=False) - - def test_null_encryption_decryption(self): - for func in "encrypt", "decrypt": - cipher = AES.new(self.key_128, self.aes_mode, self.iv_128) - result = getattr(cipher, func)(b"") - self.assertEqual(result, b"") - - def test_either_encrypt_or_decrypt(self): - cipher = AES.new(self.key_128, self.aes_mode, self.iv_128) - cipher.encrypt(b"") - self.assertRaises(TypeError, cipher.decrypt, b"") - - cipher = AES.new(self.key_128, self.aes_mode, self.iv_128) - cipher.decrypt(b"") - self.assertRaises(TypeError, cipher.encrypt, b"") - - def test_data_must_be_bytes(self): - cipher = AES.new(self.key_128, self.aes_mode, self.iv_128) - self.assertRaises(TypeError, cipher.encrypt, u'test1234567890-*') - - cipher = AES.new(self.key_128, self.aes_mode, self.iv_128) - self.assertRaises(TypeError, cipher.decrypt, u'test1234567890-*') - - def test_bytearray(self): - data = b"1" * 16 - data_ba = bytearray(data) - - # Encrypt - key_ba = bytearray(self.key_128) - iv_ba = bytearray(self.iv_128) - - cipher1 = AES.new(self.key_128, self.aes_mode, self.iv_128) - ref1 = cipher1.encrypt(data) - - cipher2 = AES.new(key_ba, self.aes_mode, iv_ba) - key_ba[:3] = b'\xFF\xFF\xFF' - iv_ba[:3] = b'\xFF\xFF\xFF' - ref2 = cipher2.encrypt(data_ba) - - self.assertEqual(ref1, ref2) - self.assertEqual(cipher1.iv, cipher2.iv) - - # Decrypt - key_ba = bytearray(self.key_128) - iv_ba = bytearray(self.iv_128) - - cipher3 = AES.new(self.key_128, self.aes_mode, self.iv_128) - ref3 = cipher3.decrypt(data) - - cipher4 = AES.new(key_ba, self.aes_mode, iv_ba) - key_ba[:3] = b'\xFF\xFF\xFF' - iv_ba[:3] = b'\xFF\xFF\xFF' - ref4 = cipher4.decrypt(data_ba) - - self.assertEqual(ref3, ref4) - - def test_memoryview(self): - data = b"1" * 16 - data_mv = memoryview(bytearray(data)) - - # Encrypt - key_mv = memoryview(bytearray(self.key_128)) - iv_mv = memoryview(bytearray(self.iv_128)) - - cipher1 = AES.new(self.key_128, self.aes_mode, self.iv_128) - ref1 = cipher1.encrypt(data) - - cipher2 = AES.new(key_mv, self.aes_mode, iv_mv) - key_mv[:3] = b'\xFF\xFF\xFF' - iv_mv[:3] = b'\xFF\xFF\xFF' - ref2 = cipher2.encrypt(data_mv) - - self.assertEqual(ref1, ref2) - self.assertEqual(cipher1.iv, cipher2.iv) - - # Decrypt - key_mv = memoryview(bytearray(self.key_128)) - iv_mv = memoryview(bytearray(self.iv_128)) - - cipher3 = AES.new(self.key_128, self.aes_mode, self.iv_128) - ref3 = cipher3.decrypt(data) - - cipher4 = AES.new(key_mv, self.aes_mode, iv_mv) - key_mv[:3] = b'\xFF\xFF\xFF' - iv_mv[:3] = b'\xFF\xFF\xFF' - ref4 = cipher4.decrypt(data_mv) - - self.assertEqual(ref3, ref4) - - def test_output_param(self): - - pt = b'5' * 16 - cipher = AES.new(b'4'*16, self.aes_mode, iv=self.iv_128) - ct = cipher.encrypt(pt) - - output = bytearray(16) - cipher = AES.new(b'4'*16, self.aes_mode, iv=self.iv_128) - res = cipher.encrypt(pt, output=output) - self.assertEqual(ct, output) - self.assertEqual(res, None) - - cipher = AES.new(b'4'*16, self.aes_mode, iv=self.iv_128) - res = cipher.decrypt(ct, output=output) - self.assertEqual(pt, output) - self.assertEqual(res, None) - - - def test_output_param_same_buffer(self): - - pt = b'5' * 16 - cipher = AES.new(b'4'*16, self.aes_mode, iv=self.iv_128) - ct = cipher.encrypt(pt) - - pt_ba = bytearray(pt) - cipher = AES.new(b'4'*16, self.aes_mode, iv=self.iv_128) - res = cipher.encrypt(pt_ba, output=pt_ba) - self.assertEqual(ct, pt_ba) - self.assertEqual(res, None) - - ct_ba = bytearray(ct) - cipher = AES.new(b'4'*16, self.aes_mode, iv=self.iv_128) - res = cipher.decrypt(ct_ba, output=ct_ba) - self.assertEqual(pt, ct_ba) - self.assertEqual(res, None) - - - def test_output_param_memoryview(self): - - pt = b'5' * 16 - cipher = AES.new(b'4'*16, self.aes_mode, iv=self.iv_128) - ct = cipher.encrypt(pt) - - output = memoryview(bytearray(16)) - cipher = AES.new(b'4'*16, self.aes_mode, iv=self.iv_128) - cipher.encrypt(pt, output=output) - self.assertEqual(ct, output) - - cipher = AES.new(b'4'*16, self.aes_mode, iv=self.iv_128) - cipher.decrypt(ct, output=output) - self.assertEqual(pt, output) - - def test_output_param_neg(self): - - pt = b'5' * 16 - cipher = AES.new(b'4'*16, self.aes_mode, iv=self.iv_128) - ct = cipher.encrypt(pt) - - cipher = AES.new(b'4'*16, self.aes_mode, iv=self.iv_128) - self.assertRaises(TypeError, cipher.encrypt, pt, output=b'0'*16) - - cipher = AES.new(b'4'*16, self.aes_mode, iv=self.iv_128) - self.assertRaises(TypeError, cipher.decrypt, ct, output=b'0'*16) - - shorter_output = bytearray(15) - cipher = AES.new(b'4'*16, self.aes_mode, iv=self.iv_128) - self.assertRaises(ValueError, cipher.encrypt, pt, output=shorter_output) - cipher = AES.new(b'4'*16, self.aes_mode, iv=self.iv_128) - self.assertRaises(ValueError, cipher.decrypt, ct, output=shorter_output) - - -class CbcTests(BlockChainingTests): - aes_mode = AES.MODE_CBC - des3_mode = DES3.MODE_CBC - - -class NistBlockChainingVectors(unittest.TestCase): - - def _do_kat_aes_test(self, file_name): - - test_vectors = load_test_vectors(("Cipher", "AES"), - file_name, - "AES CBC KAT", - { "count" : lambda x: int(x) } ) - if test_vectors is None: - return - - direction = None - for tv in test_vectors: - - # The test vector file contains some directive lines - if is_string(tv): - direction = tv - continue - - self.description = tv.desc - - cipher = AES.new(tv.key, self.aes_mode, tv.iv) - if direction == "[ENCRYPT]": - self.assertEqual(cipher.encrypt(tv.plaintext), tv.ciphertext) - elif direction == "[DECRYPT]": - self.assertEqual(cipher.decrypt(tv.ciphertext), tv.plaintext) - else: - assert False - - # See Section 6.4.2 in AESAVS - def _do_mct_aes_test(self, file_name): - - test_vectors = load_test_vectors(("Cipher", "AES"), - file_name, - "AES CBC Montecarlo", - { "count" : lambda x: int(x) } ) - if test_vectors is None: - return - - direction = None - for tv in test_vectors: - - # The test vector file contains some directive lines - if is_string(tv): - direction = tv - continue - - self.description = tv.desc - cipher = AES.new(tv.key, self.aes_mode, tv.iv) - - if direction == '[ENCRYPT]': - cts = [ tv.iv ] - for count in range(1000): - cts.append(cipher.encrypt(tv.plaintext)) - tv.plaintext = cts[-2] - self.assertEqual(cts[-1], tv.ciphertext) - elif direction == '[DECRYPT]': - pts = [ tv.iv] - for count in range(1000): - pts.append(cipher.decrypt(tv.ciphertext)) - tv.ciphertext = pts[-2] - self.assertEqual(pts[-1], tv.plaintext) - else: - assert False - - def _do_tdes_test(self, file_name): - - test_vectors = load_test_vectors(("Cipher", "TDES"), - file_name, - "TDES CBC KAT", - { "count" : lambda x: int(x) } ) - if test_vectors is None: - return - - direction = None - for tv in test_vectors: - - # The test vector file contains some directive lines - if is_string(tv): - direction = tv - continue - - self.description = tv.desc - if hasattr(tv, "keys"): - cipher = DES.new(tv.keys, self.des_mode, tv.iv) - else: - if tv.key1 != tv.key3: - key = tv.key1 + tv.key2 + tv.key3 # Option 3 - else: - key = tv.key1 + tv.key2 # Option 2 - cipher = DES3.new(key, self.des3_mode, tv.iv) - - if direction == "[ENCRYPT]": - self.assertEqual(cipher.encrypt(tv.plaintext), tv.ciphertext) - elif direction == "[DECRYPT]": - self.assertEqual(cipher.decrypt(tv.ciphertext), tv.plaintext) - else: - assert False - - -class NistCbcVectors(NistBlockChainingVectors): - aes_mode = AES.MODE_CBC - des_mode = DES.MODE_CBC - des3_mode = DES3.MODE_CBC - - -# Create one test method per file -nist_aes_kat_mmt_files = ( - # KAT - "CBCGFSbox128.rsp", - "CBCGFSbox192.rsp", - "CBCGFSbox256.rsp", - "CBCKeySbox128.rsp", - "CBCKeySbox192.rsp", - "CBCKeySbox256.rsp", - "CBCVarKey128.rsp", - "CBCVarKey192.rsp", - "CBCVarKey256.rsp", - "CBCVarTxt128.rsp", - "CBCVarTxt192.rsp", - "CBCVarTxt256.rsp", - # MMT - "CBCMMT128.rsp", - "CBCMMT192.rsp", - "CBCMMT256.rsp", - ) -nist_aes_mct_files = ( - "CBCMCT128.rsp", - "CBCMCT192.rsp", - "CBCMCT256.rsp", - ) - -for file_name in nist_aes_kat_mmt_files: - def new_func(self, file_name=file_name): - self._do_kat_aes_test(file_name) - setattr(NistCbcVectors, "test_AES_" + file_name, new_func) - -for file_name in nist_aes_mct_files: - def new_func(self, file_name=file_name): - self._do_mct_aes_test(file_name) - setattr(NistCbcVectors, "test_AES_" + file_name, new_func) -del file_name, new_func - -nist_tdes_files = ( - "TCBCMMT2.rsp", # 2TDES - "TCBCMMT3.rsp", # 3TDES - "TCBCinvperm.rsp", # Single DES - "TCBCpermop.rsp", - "TCBCsubtab.rsp", - "TCBCvarkey.rsp", - "TCBCvartext.rsp", - ) - -for file_name in nist_tdes_files: - def new_func(self, file_name=file_name): - self._do_tdes_test(file_name) - setattr(NistCbcVectors, "test_TDES_" + file_name, new_func) - -# END OF NIST CBC TEST VECTORS - - -class SP800TestVectors(unittest.TestCase): - """Class exercising the CBC test vectors found in Section F.2 - of NIST SP 800-3A""" - - def test_aes_128(self): - key = '2b7e151628aed2a6abf7158809cf4f3c' - iv = '000102030405060708090a0b0c0d0e0f' - plaintext = '6bc1bee22e409f96e93d7e117393172a' +\ - 'ae2d8a571e03ac9c9eb76fac45af8e51' +\ - '30c81c46a35ce411e5fbc1191a0a52ef' +\ - 'f69f2445df4f9b17ad2b417be66c3710' - ciphertext = '7649abac8119b246cee98e9b12e9197d' +\ - '5086cb9b507219ee95db113a917678b2' +\ - '73bed6b8e3c1743b7116e69e22229516' +\ - '3ff1caa1681fac09120eca307586e1a7' - - key = unhexlify(key) - iv = unhexlify(iv) - plaintext = unhexlify(plaintext) - ciphertext = unhexlify(ciphertext) - - cipher = AES.new(key, AES.MODE_CBC, iv) - self.assertEqual(cipher.encrypt(plaintext), ciphertext) - cipher = AES.new(key, AES.MODE_CBC, iv) - self.assertEqual(cipher.decrypt(ciphertext), plaintext) - - def test_aes_192(self): - key = '8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b' - iv = '000102030405060708090a0b0c0d0e0f' - plaintext = '6bc1bee22e409f96e93d7e117393172a' +\ - 'ae2d8a571e03ac9c9eb76fac45af8e51' +\ - '30c81c46a35ce411e5fbc1191a0a52ef' +\ - 'f69f2445df4f9b17ad2b417be66c3710' - ciphertext = '4f021db243bc633d7178183a9fa071e8' +\ - 'b4d9ada9ad7dedf4e5e738763f69145a' +\ - '571b242012fb7ae07fa9baac3df102e0' +\ - '08b0e27988598881d920a9e64f5615cd' - - key = unhexlify(key) - iv = unhexlify(iv) - plaintext = unhexlify(plaintext) - ciphertext = unhexlify(ciphertext) - - cipher = AES.new(key, AES.MODE_CBC, iv) - self.assertEqual(cipher.encrypt(plaintext), ciphertext) - cipher = AES.new(key, AES.MODE_CBC, iv) - self.assertEqual(cipher.decrypt(ciphertext), plaintext) - - def test_aes_256(self): - key = '603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4' - iv = '000102030405060708090a0b0c0d0e0f' - plaintext = '6bc1bee22e409f96e93d7e117393172a' +\ - 'ae2d8a571e03ac9c9eb76fac45af8e51' +\ - '30c81c46a35ce411e5fbc1191a0a52ef' +\ - 'f69f2445df4f9b17ad2b417be66c3710' - ciphertext = 'f58c4c04d6e5f1ba779eabfb5f7bfbd6' +\ - '9cfc4e967edb808d679f777bc6702c7d' +\ - '39f23369a9d9bacfa530e26304231461' +\ - 'b2eb05e2c39be9fcda6c19078c6a9d1b' - - key = unhexlify(key) - iv = unhexlify(iv) - plaintext = unhexlify(plaintext) - ciphertext = unhexlify(ciphertext) - - cipher = AES.new(key, AES.MODE_CBC, iv) - self.assertEqual(cipher.encrypt(plaintext), ciphertext) - cipher = AES.new(key, AES.MODE_CBC, iv) - self.assertEqual(cipher.decrypt(ciphertext), plaintext) - - -def get_tests(config={}): - tests = [] - tests += list_test_cases(CbcTests) - if config.get('slow_tests'): - tests += list_test_cases(NistCbcVectors) - tests += list_test_cases(SP800TestVectors) - return tests - - -if __name__ == '__main__': - suite = lambda: unittest.TestSuite(get_tests()) - unittest.main(defaultTest='suite') diff --git a/Crypto/SelfTest/Cipher/test_CCM.py b/Crypto/SelfTest/Cipher/test_CCM.py deleted file mode 100644 index 5c84d44..0000000 --- a/Crypto/SelfTest/Cipher/test_CCM.py +++ /dev/null @@ -1,930 +0,0 @@ -# =================================================================== -# -# Copyright (c) 2015, Legrandin -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# =================================================================== - -import unittest -from binascii import unhexlify - -from Crypto.SelfTest.st_common import list_test_cases -from Crypto.SelfTest.loader import load_test_vectors_wycheproof -from Crypto.Util.py3compat import tobytes, bchr -from Crypto.Cipher import AES -from Crypto.Hash import SHAKE128 - -from Crypto.Util.strxor import strxor - - -def get_tag_random(tag, length): - return SHAKE128.new(data=tobytes(tag)).read(length) - - -class CcmTests(unittest.TestCase): - - key_128 = get_tag_random("key_128", 16) - nonce_96 = get_tag_random("nonce_128", 12) - data_128 = get_tag_random("data_128", 16) - - def test_loopback_128(self): - cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96) - pt = get_tag_random("plaintext", 16 * 100) - ct = cipher.encrypt(pt) - - cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96) - pt2 = cipher.decrypt(ct) - self.assertEqual(pt, pt2) - - def test_nonce(self): - # If not passed, the nonce is created randomly - cipher = AES.new(self.key_128, AES.MODE_CCM) - nonce1 = cipher.nonce - cipher = AES.new(self.key_128, AES.MODE_CCM) - nonce2 = cipher.nonce - self.assertEqual(len(nonce1), 11) - self.assertNotEqual(nonce1, nonce2) - - cipher = AES.new(self.key_128, AES.MODE_CCM, self.nonce_96) - ct = cipher.encrypt(self.data_128) - - cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96) - self.assertEquals(ct, cipher.encrypt(self.data_128)) - - def test_nonce_must_be_bytes(self): - self.assertRaises(TypeError, AES.new, self.key_128, AES.MODE_CCM, - nonce=u'test12345678') - - def test_nonce_length(self): - self.assertRaises(ValueError, AES.new, self.key_128, AES.MODE_CCM, - nonce=b"") - self.assertRaises(ValueError, AES.new, self.key_128, AES.MODE_CCM, - nonce=bchr(1) * 6) - self.assertRaises(ValueError, AES.new, self.key_128, AES.MODE_CCM, - nonce=bchr(1) * 14) - for x in range(7, 13 + 1): - AES.new(self.key_128, AES.MODE_CCM, nonce=bchr(1) * x) - - def test_block_size(self): - cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96) - self.assertEqual(cipher.block_size, AES.block_size) - - def test_nonce_attribute(self): - cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96) - self.assertEqual(cipher.nonce, self.nonce_96) - - # By default, a 11 bytes long nonce is randomly generated - nonce1 = AES.new(self.key_128, AES.MODE_CCM).nonce - nonce2 = AES.new(self.key_128, AES.MODE_CCM).nonce - self.assertEqual(len(nonce1), 11) - self.assertNotEqual(nonce1, nonce2) - - def test_unknown_parameters(self): - self.assertRaises(TypeError, AES.new, self.key_128, AES.MODE_CCM, - self.nonce_96, 7) - self.assertRaises(TypeError, AES.new, self.key_128, AES.MODE_CCM, - nonce=self.nonce_96, unknown=7) - - # But some are only known by the base cipher - # (e.g. use_aesni consumed by the AES module) - AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96, - use_aesni=False) - - def test_null_encryption_decryption(self): - for func in "encrypt", "decrypt": - cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96) - result = getattr(cipher, func)(b"") - self.assertEqual(result, b"") - - def test_either_encrypt_or_decrypt(self): - cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96) - cipher.encrypt(b"") - self.assertRaises(TypeError, cipher.decrypt, b"") - - cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96) - cipher.decrypt(b"") - self.assertRaises(TypeError, cipher.encrypt, b"") - - def test_data_must_be_bytes(self): - cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96) - self.assertRaises(TypeError, cipher.encrypt, u'test1234567890-*') - - cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96) - self.assertRaises(TypeError, cipher.decrypt, u'test1234567890-*') - - def test_mac_len(self): - # Invalid MAC length - for mac_len in range(3, 17 + 1, 2): - self.assertRaises(ValueError, AES.new, self.key_128, AES.MODE_CCM, - nonce=self.nonce_96, mac_len=mac_len) - - # Valid MAC length - for mac_len in range(4, 16 + 1, 2): - cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96, - mac_len=mac_len) - _, mac = cipher.encrypt_and_digest(self.data_128) - self.assertEqual(len(mac), mac_len) - - # Default MAC length - cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96) - _, mac = cipher.encrypt_and_digest(self.data_128) - self.assertEqual(len(mac), 16) - - def test_invalid_mac(self): - from Crypto.Util.strxor import strxor_c - cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96) - ct, mac = cipher.encrypt_and_digest(self.data_128) - - invalid_mac = strxor_c(mac, 0x01) - - cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96) - self.assertRaises(ValueError, cipher.decrypt_and_verify, ct, - invalid_mac) - - def test_hex_mac(self): - cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96) - mac_hex = cipher.hexdigest() - self.assertEqual(cipher.digest(), unhexlify(mac_hex)) - - cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96) - cipher.hexverify(mac_hex) - - def test_longer_assoc_data_than_declared(self): - # More than zero - cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96, - assoc_len=0) - self.assertRaises(ValueError, cipher.update, b"1") - - # Too large - cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96, - assoc_len=15) - self.assertRaises(ValueError, cipher.update, self.data_128) - - def test_shorter_assoc_data_than_expected(self): - # With plaintext - cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96, - assoc_len=17) - cipher.update(self.data_128) - self.assertRaises(ValueError, cipher.encrypt, self.data_128) - - # With empty plaintext - cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96, - assoc_len=17) - cipher.update(self.data_128) - self.assertRaises(ValueError, cipher.digest) - - # With ciphertext - cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96, - assoc_len=17) - cipher.update(self.data_128) - self.assertRaises(ValueError, cipher.decrypt, self.data_128) - - # With empty ciphertext - cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96) - cipher.update(self.data_128) - mac = cipher.digest() - - cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96, - assoc_len=17) - cipher.update(self.data_128) - self.assertRaises(ValueError, cipher.verify, mac) - - def test_shorter_and_longer_plaintext_than_declared(self): - cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96, - msg_len=17) - cipher.encrypt(self.data_128) - self.assertRaises(ValueError, cipher.digest) - - cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96, - msg_len=15) - self.assertRaises(ValueError, cipher.encrypt, self.data_128) - - def test_shorter_ciphertext_than_declared(self): - cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96) - ct, mac = cipher.encrypt_and_digest(self.data_128) - - cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96, - msg_len=17) - cipher.decrypt(ct) - self.assertRaises(ValueError, cipher.verify, mac) - - cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96, - msg_len=15) - self.assertRaises(ValueError, cipher.decrypt, ct) - - def test_message_chunks(self): - # Validate that both associated data and plaintext/ciphertext - # can be broken up in chunks of arbitrary length - - auth_data = get_tag_random("authenticated data", 127) - plaintext = get_tag_random("plaintext", 127) - - cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96) - cipher.update(auth_data) - ciphertext, ref_mac = cipher.encrypt_and_digest(plaintext) - - def break_up(data, chunk_length): - return [data[i:i+chunk_length] for i in range(0, len(data), - chunk_length)] - - # Encryption - for chunk_length in 1, 2, 3, 7, 10, 13, 16, 40, 80, 128: - - cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96, - msg_len=127, assoc_len=127) - - for chunk in break_up(auth_data, chunk_length): - cipher.update(chunk) - pt2 = b"" - for chunk in break_up(ciphertext, chunk_length): - pt2 += cipher.decrypt(chunk) - self.assertEqual(plaintext, pt2) - cipher.verify(ref_mac) - - # Decryption - for chunk_length in 1, 2, 3, 7, 10, 13, 16, 40, 80, 128: - - cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96, - msg_len=127, assoc_len=127) - - for chunk in break_up(auth_data, chunk_length): - cipher.update(chunk) - ct2 = b"" - for chunk in break_up(plaintext, chunk_length): - ct2 += cipher.encrypt(chunk) - self.assertEqual(ciphertext, ct2) - self.assertEquals(cipher.digest(), ref_mac) - - def test_bytearray(self): - - # Encrypt - key_ba = bytearray(self.key_128) - nonce_ba = bytearray(self.nonce_96) - header_ba = bytearray(self.data_128) - data_ba = bytearray(self.data_128) - - cipher1 = AES.new(self.key_128, - AES.MODE_CCM, - nonce=self.nonce_96) - cipher1.update(self.data_128) - ct = cipher1.encrypt(self.data_128) - tag = cipher1.digest() - - cipher2 = AES.new(key_ba, - AES.MODE_CCM, - nonce=nonce_ba) - key_ba[:3] = b"\xFF\xFF\xFF" - nonce_ba[:3] = b"\xFF\xFF\xFF" - cipher2.update(header_ba) - header_ba[:3] = b"\xFF\xFF\xFF" - ct_test = cipher2.encrypt(data_ba) - data_ba[:3] = b"\xFF\xFF\xFF" - tag_test = cipher2.digest() - - self.assertEqual(ct, ct_test) - self.assertEqual(tag, tag_test) - self.assertEqual(cipher1.nonce, cipher2.nonce) - - # Decrypt - key_ba = bytearray(self.key_128) - nonce_ba = bytearray(self.nonce_96) - header_ba = bytearray(self.data_128) - del data_ba - - cipher4 = AES.new(key_ba, - AES.MODE_CCM, - nonce=nonce_ba) - key_ba[:3] = b"\xFF\xFF\xFF" - nonce_ba[:3] = b"\xFF\xFF\xFF" - cipher4.update(header_ba) - header_ba[:3] = b"\xFF\xFF\xFF" - pt_test = cipher4.decrypt_and_verify(bytearray(ct_test), bytearray(tag_test)) - - self.assertEqual(self.data_128, pt_test) - - def test_memoryview(self): - - # Encrypt - key_mv = memoryview(bytearray(self.key_128)) - nonce_mv = memoryview(bytearray(self.nonce_96)) - header_mv = memoryview(bytearray(self.data_128)) - data_mv = memoryview(bytearray(self.data_128)) - - cipher1 = AES.new(self.key_128, - AES.MODE_CCM, - nonce=self.nonce_96) - cipher1.update(self.data_128) - ct = cipher1.encrypt(self.data_128) - tag = cipher1.digest() - - cipher2 = AES.new(key_mv, - AES.MODE_CCM, - nonce=nonce_mv) - key_mv[:3] = b"\xFF\xFF\xFF" - nonce_mv[:3] = b"\xFF\xFF\xFF" - cipher2.update(header_mv) - header_mv[:3] = b"\xFF\xFF\xFF" - ct_test = cipher2.encrypt(data_mv) - data_mv[:3] = b"\xFF\xFF\xFF" - tag_test = cipher2.digest() - - self.assertEqual(ct, ct_test) - self.assertEqual(tag, tag_test) - self.assertEqual(cipher1.nonce, cipher2.nonce) - - # Decrypt - key_mv = memoryview(bytearray(self.key_128)) - nonce_mv = memoryview(bytearray(self.nonce_96)) - header_mv = memoryview(bytearray(self.data_128)) - del data_mv - - cipher4 = AES.new(key_mv, - AES.MODE_CCM, - nonce=nonce_mv) - key_mv[:3] = b"\xFF\xFF\xFF" - nonce_mv[:3] = b"\xFF\xFF\xFF" - cipher4.update(header_mv) - header_mv[:3] = b"\xFF\xFF\xFF" - pt_test = cipher4.decrypt_and_verify(memoryview(ct_test), memoryview(tag_test)) - - self.assertEqual(self.data_128, pt_test) - - def test_output_param(self): - - pt = b'5' * 16 - cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96) - ct = cipher.encrypt(pt) - tag = cipher.digest() - - output = bytearray(16) - cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96) - res = cipher.encrypt(pt, output=output) - self.assertEqual(ct, output) - self.assertEqual(res, None) - - cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96) - res = cipher.decrypt(ct, output=output) - self.assertEqual(pt, output) - self.assertEqual(res, None) - - cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96) - res, tag_out = cipher.encrypt_and_digest(pt, output=output) - self.assertEqual(ct, output) - self.assertEqual(res, None) - self.assertEqual(tag, tag_out) - - cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96) - res = cipher.decrypt_and_verify(ct, tag, output=output) - self.assertEqual(pt, output) - self.assertEqual(res, None) - - def test_output_param_memoryview(self): - - pt = b'5' * 16 - cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96) - ct = cipher.encrypt(pt) - - output = memoryview(bytearray(16)) - cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96) - cipher.encrypt(pt, output=output) - self.assertEqual(ct, output) - - cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96) - cipher.decrypt(ct, output=output) - self.assertEqual(pt, output) - - def test_output_param_neg(self): - - pt = b'5' * 16 - cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96) - ct = cipher.encrypt(pt) - - cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96) - self.assertRaises(TypeError, cipher.encrypt, pt, output=b'0'*16) - - cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96) - self.assertRaises(TypeError, cipher.decrypt, ct, output=b'0'*16) - - shorter_output = bytearray(15) - cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96) - self.assertRaises(ValueError, cipher.encrypt, pt, output=shorter_output) - cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96) - self.assertRaises(ValueError, cipher.decrypt, ct, output=shorter_output) - - -class CcmFSMTests(unittest.TestCase): - - key_128 = get_tag_random("key_128", 16) - nonce_96 = get_tag_random("nonce_128", 12) - data_128 = get_tag_random("data_128", 16) - - def test_valid_init_encrypt_decrypt_digest_verify(self): - # No authenticated data, fixed plaintext - for assoc_len in (None, 0): - for msg_len in (None, len(self.data_128)): - # Verify path INIT->ENCRYPT->DIGEST - cipher = AES.new(self.key_128, AES.MODE_CCM, - nonce=self.nonce_96, - assoc_len=assoc_len, - msg_len=msg_len) - ct = cipher.encrypt(self.data_128) - mac = cipher.digest() - - # Verify path INIT->DECRYPT->VERIFY - cipher = AES.new(self.key_128, AES.MODE_CCM, - nonce=self.nonce_96, - assoc_len=assoc_len, - msg_len=msg_len) - cipher.decrypt(ct) - cipher.verify(mac) - - def test_valid_init_update_digest_verify(self): - # No plaintext, fixed authenticated data - for assoc_len in (None, len(self.data_128)): - for msg_len in (None, 0): - # Verify path INIT->UPDATE->DIGEST - cipher = AES.new(self.key_128, AES.MODE_CCM, - nonce=self.nonce_96, - assoc_len=assoc_len, - msg_len=msg_len) - cipher.update(self.data_128) - mac = cipher.digest() - - # Verify path INIT->UPDATE->VERIFY - cipher = AES.new(self.key_128, AES.MODE_CCM, - nonce=self.nonce_96, - assoc_len=assoc_len, - msg_len=msg_len) - cipher.update(self.data_128) - cipher.verify(mac) - - def test_valid_full_path(self): - # Fixed authenticated data, fixed plaintext - for assoc_len in (None, len(self.data_128)): - for msg_len in (None, len(self.data_128)): - # Verify path INIT->UPDATE->ENCRYPT->DIGEST - cipher = AES.new(self.key_128, AES.MODE_CCM, - nonce=self.nonce_96, - assoc_len=assoc_len, - msg_len=msg_len) - cipher.update(self.data_128) - ct = cipher.encrypt(self.data_128) - mac = cipher.digest() - - # Verify path INIT->UPDATE->DECRYPT->VERIFY - cipher = AES.new(self.key_128, AES.MODE_CCM, - nonce=self.nonce_96, - assoc_len=assoc_len, - msg_len=msg_len) - cipher.update(self.data_128) - cipher.decrypt(ct) - cipher.verify(mac) - - def test_valid_init_digest(self): - # Verify path INIT->DIGEST - cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96) - cipher.digest() - - def test_valid_init_verify(self): - # Verify path INIT->VERIFY - cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96) - mac = cipher.digest() - - cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96) - cipher.verify(mac) - - def test_valid_multiple_encrypt_or_decrypt(self): - # Only possible if msg_len is declared in advance - for method_name in "encrypt", "decrypt": - for auth_data in (None, b"333", self.data_128, - self.data_128 + b"3"): - if auth_data is None: - assoc_len = None - else: - assoc_len = len(auth_data) - cipher = AES.new(self.key_128, AES.MODE_CCM, - nonce=self.nonce_96, - msg_len=64, - assoc_len=assoc_len) - if auth_data is not None: - cipher.update(auth_data) - method = getattr(cipher, method_name) - method(self.data_128) - method(self.data_128) - method(self.data_128) - method(self.data_128) - - def test_valid_multiple_digest_or_verify(self): - # Multiple calls to digest - cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96) - cipher.update(self.data_128) - first_mac = cipher.digest() - for x in range(4): - self.assertEqual(first_mac, cipher.digest()) - - # Multiple calls to verify - cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96) - cipher.update(self.data_128) - for x in range(5): - cipher.verify(first_mac) - - def test_valid_encrypt_and_digest_decrypt_and_verify(self): - # encrypt_and_digest - cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96) - cipher.update(self.data_128) - ct, mac = cipher.encrypt_and_digest(self.data_128) - - # decrypt_and_verify - cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96) - cipher.update(self.data_128) - pt = cipher.decrypt_and_verify(ct, mac) - self.assertEqual(self.data_128, pt) - - def test_invalid_multiple_encrypt_decrypt_without_msg_len(self): - # Once per method, with or without assoc. data - for method_name in "encrypt", "decrypt": - for assoc_data_present in (True, False): - cipher = AES.new(self.key_128, AES.MODE_CCM, - nonce=self.nonce_96) - if assoc_data_present: - cipher.update(self.data_128) - method = getattr(cipher, method_name) - method(self.data_128) - self.assertRaises(TypeError, method, self.data_128) - - def test_invalid_mixing_encrypt_decrypt(self): - # Once per method, with or without assoc. data - for method1_name, method2_name in (("encrypt", "decrypt"), - ("decrypt", "encrypt")): - for assoc_data_present in (True, False): - cipher = AES.new(self.key_128, AES.MODE_CCM, - nonce=self.nonce_96, - msg_len=32) - if assoc_data_present: - cipher.update(self.data_128) - getattr(cipher, method1_name)(self.data_128) - self.assertRaises(TypeError, getattr(cipher, method2_name), - self.data_128) - - def test_invalid_encrypt_or_update_after_digest(self): - for method_name in "encrypt", "update": - cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96) - cipher.encrypt(self.data_128) - cipher.digest() - self.assertRaises(TypeError, getattr(cipher, method_name), - self.data_128) - - cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96) - cipher.encrypt_and_digest(self.data_128) - - def test_invalid_decrypt_or_update_after_verify(self): - cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96) - ct = cipher.encrypt(self.data_128) - mac = cipher.digest() - - for method_name in "decrypt", "update": - cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96) - cipher.decrypt(ct) - cipher.verify(mac) - self.assertRaises(TypeError, getattr(cipher, method_name), - self.data_128) - - cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96) - cipher.decrypt_and_verify(ct, mac) - self.assertRaises(TypeError, getattr(cipher, method_name), - self.data_128) - - -class TestVectors(unittest.TestCase): - """Class exercising the CCM test vectors found in Appendix C - of NIST SP 800-38C and in RFC 3610""" - - # List of test vectors, each made up of: - # - authenticated data - # - plaintext - # - ciphertext - # - MAC - # - AES key - # - nonce - test_vectors_hex = [ - # NIST SP 800 38C - ( '0001020304050607', - '20212223', - '7162015b', - '4dac255d', - '404142434445464748494a4b4c4d4e4f', - '10111213141516'), - ( '000102030405060708090a0b0c0d0e0f', - '202122232425262728292a2b2c2d2e2f', - 'd2a1f0e051ea5f62081a7792073d593d', - '1fc64fbfaccd', - '404142434445464748494a4b4c4d4e4f', - '1011121314151617'), - ( '000102030405060708090a0b0c0d0e0f10111213', - '202122232425262728292a2b2c2d2e2f3031323334353637', - 'e3b201a9f5b71a7a9b1ceaeccd97e70b6176aad9a4428aa5', - '484392fbc1b09951', - '404142434445464748494a4b4c4d4e4f', - '101112131415161718191a1b'), - ( (''.join(["%02X" % (x*16+y) for x in range(0,16) for y in range(0,16)]))*256, - '202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f', - '69915dad1e84c6376a68c2967e4dab615ae0fd1faec44cc484828529463ccf72', - 'b4ac6bec93e8598e7f0dadbcea5b', - '404142434445464748494a4b4c4d4e4f', - '101112131415161718191a1b1c'), - # RFC3610 - ( '0001020304050607', - '08090a0b0c0d0e0f101112131415161718191a1b1c1d1e', - '588c979a61c663d2f066d0c2c0f989806d5f6b61dac384', - '17e8d12cfdf926e0', - 'c0c1c2c3c4c5c6c7c8c9cacbcccdcecf', - '00000003020100a0a1a2a3a4a5'), - ( - '0001020304050607', - '08090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f', - '72c91a36e135f8cf291ca894085c87e3cc15c439c9e43a3b', - 'a091d56e10400916', - 'c0c1c2c3c4c5c6c7c8c9cacbcccdcecf', - '00000004030201a0a1a2a3a4a5'), - ( '0001020304050607', - '08090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20', - '51b1e5f44a197d1da46b0f8e2d282ae871e838bb64da859657', - '4adaa76fbd9fb0c5', - 'c0c1c2c3c4c5c6c7c8c9cacbcccdcecf', - '00000005040302A0A1A2A3A4A5'), - ( '000102030405060708090a0b', - '0c0d0e0f101112131415161718191a1b1c1d1e', - 'a28c6865939a9a79faaa5c4c2a9d4a91cdac8c', - '96c861b9c9e61ef1', - 'c0c1c2c3c4c5c6c7c8c9cacbcccdcecf', - '00000006050403a0a1a2a3a4a5'), - ( '000102030405060708090a0b', - '0c0d0e0f101112131415161718191a1b1c1d1e1f', - 'dcf1fb7b5d9e23fb9d4e131253658ad86ebdca3e', - '51e83f077d9c2d93', - 'c0c1c2c3c4c5c6c7c8c9cacbcccdcecf', - '00000007060504a0a1a2a3a4a5'), - ( '000102030405060708090a0b', - '0c0d0e0f101112131415161718191a1b1c1d1e1f20', - '6fc1b011f006568b5171a42d953d469b2570a4bd87', - '405a0443ac91cb94', - 'c0c1c2c3c4c5c6c7c8c9cacbcccdcecf', - '00000008070605a0a1a2a3a4a5'), - ( '0001020304050607', - '08090a0b0c0d0e0f101112131415161718191a1b1c1d1e', - '0135d1b2c95f41d5d1d4fec185d166b8094e999dfed96c', - '048c56602c97acbb7490', - 'c0c1c2c3c4c5c6c7c8c9cacbcccdcecf', - '00000009080706a0a1a2a3a4a5'), - ( '0001020304050607', - '08090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f', - '7b75399ac0831dd2f0bbd75879a2fd8f6cae6b6cd9b7db24', - 'c17b4433f434963f34b4', - 'c0c1c2c3c4c5c6c7c8c9cacbcccdcecf', - '0000000a090807a0a1a2a3a4a5'), - ( '0001020304050607', - '08090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20', - '82531a60cc24945a4b8279181ab5c84df21ce7f9b73f42e197', - 'ea9c07e56b5eb17e5f4e', - 'c0c1c2c3c4c5c6c7c8c9cacbcccdcecf', - '0000000b0a0908a0a1a2a3a4a5'), - ( '000102030405060708090a0b', - '0c0d0e0f101112131415161718191a1b1c1d1e', - '07342594157785152b074098330abb141b947b', - '566aa9406b4d999988dd', - 'c0c1c2c3c4c5c6c7c8c9cacbcccdcecf', - '0000000c0b0a09a0a1a2a3a4a5'), - ( '000102030405060708090a0b', - '0c0d0e0f101112131415161718191a1b1c1d1e1f', - '676bb20380b0e301e8ab79590a396da78b834934', - 'f53aa2e9107a8b6c022c', - 'c0c1c2c3c4c5c6c7c8c9cacbcccdcecf', - '0000000d0c0b0aa0a1a2a3a4a5'), - ( '000102030405060708090a0b', - '0c0d0e0f101112131415161718191a1b1c1d1e1f20', - 'c0ffa0d6f05bdb67f24d43a4338d2aa4bed7b20e43', - 'cd1aa31662e7ad65d6db', - 'c0c1c2c3c4c5c6c7c8c9cacbcccdcecf', - '0000000e0d0c0ba0a1a2a3a4a5'), - ( '0be1a88bace018b1', - '08e8cf97d820ea258460e96ad9cf5289054d895ceac47c', - '4cb97f86a2a4689a877947ab8091ef5386a6ffbdd080f8', - 'e78cf7cb0cddd7b3', - 'd7828d13b2b0bdc325a76236df93cc6b', - '00412b4ea9cdbe3c9696766cfa'), - ( '63018f76dc8a1bcb', - '9020ea6f91bdd85afa0039ba4baff9bfb79c7028949cd0ec', - '4ccb1e7ca981befaa0726c55d378061298c85c92814abc33', - 'c52ee81d7d77c08a', - 'd7828d13b2b0bdc325a76236df93cc6b', - '0033568ef7b2633c9696766cfa'), - ( 'aa6cfa36cae86b40', - 'b916e0eacc1c00d7dcec68ec0b3bbb1a02de8a2d1aa346132e', - 'b1d23a2220ddc0ac900d9aa03c61fcf4a559a4417767089708', - 'a776796edb723506', - 'd7828d13b2b0bdc325a76236df93cc6b', - '00103fe41336713c9696766cfa'), - ( 'd0d0735c531e1becf049c244', - '12daac5630efa5396f770ce1a66b21f7b2101c', - '14d253c3967b70609b7cbb7c49916028324526', - '9a6f49975bcadeaf', - 'd7828d13b2b0bdc325a76236df93cc6b', - '00764c63b8058e3c9696766cfa'), - ( '77b60f011c03e1525899bcae', - 'e88b6a46c78d63e52eb8c546efb5de6f75e9cc0d', - '5545ff1a085ee2efbf52b2e04bee1e2336c73e3f', - '762c0c7744fe7e3c', - 'd7828d13b2b0bdc325a76236df93cc6b', - '00f8b678094e3b3c9696766cfa'), - ( 'cd9044d2b71fdb8120ea60c0', - '6435acbafb11a82e2f071d7ca4a5ebd93a803ba87f', - '009769ecabdf48625594c59251e6035722675e04c8', - '47099e5ae0704551', - 'd7828d13b2b0bdc325a76236df93cc6b', - '00d560912d3f703c9696766cfa'), - ( 'd85bc7e69f944fb8', - '8a19b950bcf71a018e5e6701c91787659809d67dbedd18', - 'bc218daa947427b6db386a99ac1aef23ade0b52939cb6a', - '637cf9bec2408897c6ba', - 'd7828d13b2b0bdc325a76236df93cc6b', - '0042fff8f1951c3c9696766cfa'), - ( '74a0ebc9069f5b37', - '1761433c37c5a35fc1f39f406302eb907c6163be38c98437', - '5810e6fd25874022e80361a478e3e9cf484ab04f447efff6', - 'f0a477cc2fc9bf548944', - 'd7828d13b2b0bdc325a76236df93cc6b', - '00920f40e56cdc3c9696766cfa'), - ( '44a3aa3aae6475ca', - 'a434a8e58500c6e41530538862d686ea9e81301b5ae4226bfa', - 'f2beed7bc5098e83feb5b31608f8e29c38819a89c8e776f154', - '4d4151a4ed3a8b87b9ce', - 'd7828d13b2b0bdc325a76236df93cc6b', - '0027ca0c7120bc3c9696766cfa'), - ( 'ec46bb63b02520c33c49fd70', - 'b96b49e21d621741632875db7f6c9243d2d7c2', - '31d750a09da3ed7fddd49a2032aabf17ec8ebf', - '7d22c8088c666be5c197', - 'd7828d13b2b0bdc325a76236df93cc6b', - '005b8ccbcd9af83c9696766cfa'), - ( '47a65ac78b3d594227e85e71', - 'e2fcfbb880442c731bf95167c8ffd7895e337076', - 'e882f1dbd38ce3eda7c23f04dd65071eb41342ac', - 'df7e00dccec7ae52987d', - 'd7828d13b2b0bdc325a76236df93cc6b', - '003ebe94044b9a3c9696766cfa'), - ( '6e37a6ef546d955d34ab6059', - 'abf21c0b02feb88f856df4a37381bce3cc128517d4', - 'f32905b88a641b04b9c9ffb58cc390900f3da12ab1', - '6dce9e82efa16da62059', - 'd7828d13b2b0bdc325a76236df93cc6b', - '008d493b30ae8b3c9696766cfa'), - ] - - test_vectors = [[unhexlify(x) 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: - # Encrypt - cipher = AES.new(key, AES.MODE_CCM, nonce, mac_len=len(mac)) - cipher.update(assoc_data) - ct2, mac2 = cipher.encrypt_and_digest(pt) - self.assertEqual(ct, ct2) - self.assertEqual(mac, mac2) - - # Decrypt - cipher = AES.new(key, AES.MODE_CCM, nonce, mac_len=len(mac)) - cipher.update(assoc_data) - pt2 = cipher.decrypt_and_verify(ct, mac) - self.assertEqual(pt, pt2) - - -class TestVectorsWycheproof(unittest.TestCase): - - def __init__(self, wycheproof_warnings, **extra_params): - unittest.TestCase.__init__(self) - self._wycheproof_warnings = wycheproof_warnings - self._extra_params = extra_params - self._id = "None" - - def setUp(self): - - def filter_tag(group): - return group['tagSize'] // 8 - - self.tv = load_test_vectors_wycheproof(("Cipher", "wycheproof"), - "aes_ccm_test.json", - "Wycheproof AES CCM", - group_tag={'tag_size': filter_tag}) - - def shortDescription(self): - return self._id - - def warn(self, tv): - if tv.warning and self._wycheproof_warnings: - import warnings - warnings.warn("Wycheproof warning: %s (%s)" % (self._id, tv.comment)) - - def test_encrypt(self, tv): - self._id = "Wycheproof Encrypt CCM Test #" + str(tv.id) - - try: - cipher = AES.new(tv.key, AES.MODE_CCM, tv.iv, mac_len=tv.tag_size, - **self._extra_params) - except ValueError as e: - if len(tv.iv) not in range(7, 13 + 1, 2) and "Length of parameter 'nonce'" in str(e): - assert not tv.valid - return - if tv.tag_size not in range(4, 16 + 1, 2) and "Parameter 'mac_len'" in str(e): - assert not tv.valid - return - raise e - - cipher.update(tv.aad) - ct, tag = cipher.encrypt_and_digest(tv.msg) - if tv.valid: - self.assertEqual(ct, tv.ct) - self.assertEqual(tag, tv.tag) - self.warn(tv) - - def test_decrypt(self, tv): - self._id = "Wycheproof Decrypt CCM Test #" + str(tv.id) - - try: - cipher = AES.new(tv.key, AES.MODE_CCM, tv.iv, mac_len=tv.tag_size, - **self._extra_params) - except ValueError as e: - if len(tv.iv) not in range(7, 13 + 1, 2) and "Length of parameter 'nonce'" in str(e): - assert not tv.valid - return - if tv.tag_size not in range(4, 16 + 1, 2) and "Parameter 'mac_len'" in str(e): - assert not tv.valid - return - raise e - - cipher.update(tv.aad) - try: - pt = cipher.decrypt_and_verify(tv.ct, tv.tag) - except ValueError: - assert not tv.valid - else: - assert tv.valid - self.assertEqual(pt, tv.msg) - self.warn(tv) - - def test_corrupt_decrypt(self, tv): - self._id = "Wycheproof Corrupt Decrypt CCM Test #" + str(tv.id) - if len(tv.iv) not in range(7, 13 + 1, 2) or len(tv.ct) == 0: - return - cipher = AES.new(tv.key, AES.MODE_CCM, tv.iv, mac_len=tv.tag_size, - **self._extra_params) - cipher.update(tv.aad) - ct_corrupt = strxor(tv.ct, b"\x00" * (len(tv.ct) - 1) + b"\x01") - self.assertRaises(ValueError, cipher.decrypt_and_verify, ct_corrupt, tv.tag) - - def runTest(self): - - for tv in self.tv: - self.test_encrypt(tv) - self.test_decrypt(tv) - self.test_corrupt_decrypt(tv) - - -def get_tests(config={}): - wycheproof_warnings = config.get('wycheproof_warnings') - - tests = [] - tests += list_test_cases(CcmTests) - tests += list_test_cases(CcmFSMTests) - tests += [TestVectors()] - tests += [TestVectorsWycheproof(wycheproof_warnings)] - - return tests - - -if __name__ == '__main__': - def suite(): - unittest.TestSuite(get_tests()) - unittest.main(defaultTest='suite') diff --git a/Crypto/SelfTest/Cipher/test_CFB.py b/Crypto/SelfTest/Cipher/test_CFB.py deleted file mode 100644 index cb0c352..0000000 --- a/Crypto/SelfTest/Cipher/test_CFB.py +++ /dev/null @@ -1,411 +0,0 @@ -# =================================================================== -# -# Copyright (c) 2014, Legrandin -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# =================================================================== - -import unittest -from binascii import unhexlify - -from Crypto.SelfTest.loader import load_test_vectors -from Crypto.SelfTest.st_common import list_test_cases -from Crypto.Util.py3compat import tobytes, is_string -from Crypto.Cipher import AES, DES3, DES -from Crypto.Hash import SHAKE128 - -from Crypto.SelfTest.Cipher.test_CBC import BlockChainingTests - - -def get_tag_random(tag, length): - return SHAKE128.new(data=tobytes(tag)).read(length) - - -class CfbTests(BlockChainingTests): - - aes_mode = AES.MODE_CFB - des3_mode = DES3.MODE_CFB - - # Redefine test_unaligned_data_128/64 - - def test_unaligned_data_128(self): - plaintexts = [ b"7777777" ] * 100 - - cipher = AES.new(self.key_128, AES.MODE_CFB, self.iv_128, segment_size=8) - ciphertexts = [ cipher.encrypt(x) for x in plaintexts ] - cipher = AES.new(self.key_128, AES.MODE_CFB, self.iv_128, segment_size=8) - self.assertEqual(b"".join(ciphertexts), cipher.encrypt(b"".join(plaintexts))) - - cipher = AES.new(self.key_128, AES.MODE_CFB, self.iv_128, segment_size=128) - ciphertexts = [ cipher.encrypt(x) for x in plaintexts ] - cipher = AES.new(self.key_128, AES.MODE_CFB, self.iv_128, segment_size=128) - self.assertEqual(b"".join(ciphertexts), cipher.encrypt(b"".join(plaintexts))) - - def test_unaligned_data_64(self): - plaintexts = [ b"7777777" ] * 100 - cipher = DES3.new(self.key_192, DES3.MODE_CFB, self.iv_64, segment_size=8) - ciphertexts = [ cipher.encrypt(x) for x in plaintexts ] - cipher = DES3.new(self.key_192, DES3.MODE_CFB, self.iv_64, segment_size=8) - self.assertEqual(b"".join(ciphertexts), cipher.encrypt(b"".join(plaintexts))) - - cipher = DES3.new(self.key_192, DES3.MODE_CFB, self.iv_64, segment_size=64) - ciphertexts = [ cipher.encrypt(x) for x in plaintexts ] - cipher = DES3.new(self.key_192, DES3.MODE_CFB, self.iv_64, segment_size=64) - self.assertEqual(b"".join(ciphertexts), cipher.encrypt(b"".join(plaintexts))) - - # Extra - - def test_segment_size_128(self): - for bits in range(8, 129, 8): - cipher = AES.new(self.key_128, AES.MODE_CFB, self.iv_128, - segment_size=bits) - - for bits in 0, 7, 9, 127, 129: - self.assertRaises(ValueError, AES.new, self.key_128, AES.MODE_CFB, - self.iv_128, - segment_size=bits) - - def test_segment_size_64(self): - for bits in range(8, 65, 8): - cipher = DES3.new(self.key_192, DES3.MODE_CFB, self.iv_64, - segment_size=bits) - - for bits in 0, 7, 9, 63, 65: - self.assertRaises(ValueError, DES3.new, self.key_192, AES.MODE_CFB, - self.iv_64, - segment_size=bits) - - -class NistCfbVectors(unittest.TestCase): - - def _do_kat_aes_test(self, file_name, segment_size): - - test_vectors = load_test_vectors(("Cipher", "AES"), - file_name, - "AES CFB%d KAT" % segment_size, - { "count" : lambda x: int(x) } ) - if test_vectors is None: - return - - direction = None - for tv in test_vectors: - - # The test vector file contains some directive lines - if is_string(tv): - direction = tv - continue - - self.description = tv.desc - cipher = AES.new(tv.key, AES.MODE_CFB, tv.iv, - segment_size=segment_size) - if direction == "[ENCRYPT]": - self.assertEqual(cipher.encrypt(tv.plaintext), tv.ciphertext) - elif direction == "[DECRYPT]": - self.assertEqual(cipher.decrypt(tv.ciphertext), tv.plaintext) - else: - assert False - - # See Section 6.4.5 in AESAVS - def _do_mct_aes_test(self, file_name, segment_size): - - test_vectors = load_test_vectors(("Cipher", "AES"), - file_name, - "AES CFB%d Montecarlo" % segment_size, - { "count" : lambda x: int(x) } ) - if test_vectors is None: - return - - assert(segment_size in (8, 128)) - - direction = None - for tv in test_vectors: - - # The test vector file contains some directive lines - if is_string(tv): - direction = tv - continue - - self.description = tv.desc - cipher = AES.new(tv.key, AES.MODE_CFB, tv.iv, - segment_size=segment_size) - - def get_input(input_text, output_seq, j): - # CFB128 - if segment_size == 128: - if j >= 2: - return output_seq[-2] - return [input_text, tv.iv][j] - # CFB8 - if j == 0: - return input_text - elif j <= 16: - return tv.iv[j - 1:j] - return output_seq[j - 17] - - if direction == '[ENCRYPT]': - cts = [] - for j in range(1000): - plaintext = get_input(tv.plaintext, cts, j) - cts.append(cipher.encrypt(plaintext)) - self.assertEqual(cts[-1], tv.ciphertext) - elif direction == '[DECRYPT]': - pts = [] - for j in range(1000): - ciphertext = get_input(tv.ciphertext, pts, j) - pts.append(cipher.decrypt(ciphertext)) - self.assertEqual(pts[-1], tv.plaintext) - else: - assert False - - def _do_tdes_test(self, file_name, segment_size): - - test_vectors = load_test_vectors(("Cipher", "TDES"), - file_name, - "TDES CFB%d KAT" % segment_size, - { "count" : lambda x: int(x) } ) - if test_vectors is None: - return - - direction = None - for tv in test_vectors: - - # The test vector file contains some directive lines - if is_string(tv): - direction = tv - continue - - self.description = tv.desc - if hasattr(tv, "keys"): - cipher = DES.new(tv.keys, DES.MODE_CFB, tv.iv, - segment_size=segment_size) - else: - if tv.key1 != tv.key3: - key = tv.key1 + tv.key2 + tv.key3 # Option 3 - else: - key = tv.key1 + tv.key2 # Option 2 - cipher = DES3.new(key, DES3.MODE_CFB, tv.iv, - segment_size=segment_size) - if direction == "[ENCRYPT]": - self.assertEqual(cipher.encrypt(tv.plaintext), tv.ciphertext) - elif direction == "[DECRYPT]": - self.assertEqual(cipher.decrypt(tv.ciphertext), tv.plaintext) - else: - assert False - - -# Create one test method per file -nist_aes_kat_mmt_files = ( - # KAT - "CFB?GFSbox128.rsp", - "CFB?GFSbox192.rsp", - "CFB?GFSbox256.rsp", - "CFB?KeySbox128.rsp", - "CFB?KeySbox192.rsp", - "CFB?KeySbox256.rsp", - "CFB?VarKey128.rsp", - "CFB?VarKey192.rsp", - "CFB?VarKey256.rsp", - "CFB?VarTxt128.rsp", - "CFB?VarTxt192.rsp", - "CFB?VarTxt256.rsp", - # MMT - "CFB?MMT128.rsp", - "CFB?MMT192.rsp", - "CFB?MMT256.rsp", - ) -nist_aes_mct_files = ( - "CFB?MCT128.rsp", - "CFB?MCT192.rsp", - "CFB?MCT256.rsp", - ) - -for file_gen_name in nist_aes_kat_mmt_files: - for bits in "8", "128": - file_name = file_gen_name.replace("?", bits) - def new_func(self, file_name=file_name, bits=bits): - self._do_kat_aes_test(file_name, int(bits)) - setattr(NistCfbVectors, "test_AES_" + file_name, new_func) - -for file_gen_name in nist_aes_mct_files: - for bits in "8", "128": - file_name = file_gen_name.replace("?", bits) - def new_func(self, file_name=file_name, bits=bits): - self._do_mct_aes_test(file_name, int(bits)) - setattr(NistCfbVectors, "test_AES_" + file_name, new_func) -del file_name, new_func - -nist_tdes_files = ( - "TCFB?MMT2.rsp", # 2TDES - "TCFB?MMT3.rsp", # 3TDES - "TCFB?invperm.rsp", # Single DES - "TCFB?permop.rsp", - "TCFB?subtab.rsp", - "TCFB?varkey.rsp", - "TCFB?vartext.rsp", - ) - -for file_gen_name in nist_tdes_files: - for bits in "8", "64": - file_name = file_gen_name.replace("?", bits) - def new_func(self, file_name=file_name, bits=bits): - self._do_tdes_test(file_name, int(bits)) - setattr(NistCfbVectors, "test_TDES_" + file_name, new_func) - -# END OF NIST CBC TEST VECTORS - - -class SP800TestVectors(unittest.TestCase): - """Class exercising the CFB test vectors found in Section F.3 - of NIST SP 800-3A""" - - def test_aes_128_cfb8(self): - plaintext = '6bc1bee22e409f96e93d7e117393172aae2d' - ciphertext = '3b79424c9c0dd436bace9e0ed4586a4f32b9' - key = '2b7e151628aed2a6abf7158809cf4f3c' - iv = '000102030405060708090a0b0c0d0e0f' - - key = unhexlify(key) - iv = unhexlify(iv) - plaintext = unhexlify(plaintext) - ciphertext = unhexlify(ciphertext) - - cipher = AES.new(key, AES.MODE_CFB, iv, segment_size=8) - self.assertEqual(cipher.encrypt(plaintext), ciphertext) - cipher = AES.new(key, AES.MODE_CFB, iv, segment_size=8) - self.assertEqual(cipher.decrypt(ciphertext), plaintext) - - def test_aes_192_cfb8(self): - plaintext = '6bc1bee22e409f96e93d7e117393172aae2d' - ciphertext = 'cda2521ef0a905ca44cd057cbf0d47a0678a' - key = '8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b' - iv = '000102030405060708090a0b0c0d0e0f' - - key = unhexlify(key) - iv = unhexlify(iv) - plaintext = unhexlify(plaintext) - ciphertext = unhexlify(ciphertext) - - cipher = AES.new(key, AES.MODE_CFB, iv, segment_size=8) - self.assertEqual(cipher.encrypt(plaintext), ciphertext) - cipher = AES.new(key, AES.MODE_CFB, iv, segment_size=8) - self.assertEqual(cipher.decrypt(ciphertext), plaintext) - - def test_aes_256_cfb8(self): - plaintext = '6bc1bee22e409f96e93d7e117393172aae2d' - ciphertext = 'dc1f1a8520a64db55fcc8ac554844e889700' - key = '603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4' - iv = '000102030405060708090a0b0c0d0e0f' - - key = unhexlify(key) - iv = unhexlify(iv) - plaintext = unhexlify(plaintext) - ciphertext = unhexlify(ciphertext) - - cipher = AES.new(key, AES.MODE_CFB, iv, segment_size=8) - self.assertEqual(cipher.encrypt(plaintext), ciphertext) - cipher = AES.new(key, AES.MODE_CFB, iv, segment_size=8) - self.assertEqual(cipher.decrypt(ciphertext), plaintext) - - def test_aes_128_cfb128(self): - plaintext = '6bc1bee22e409f96e93d7e117393172a' +\ - 'ae2d8a571e03ac9c9eb76fac45af8e51' +\ - '30c81c46a35ce411e5fbc1191a0a52ef' +\ - 'f69f2445df4f9b17ad2b417be66c3710' - ciphertext = '3b3fd92eb72dad20333449f8e83cfb4a' +\ - 'c8a64537a0b3a93fcde3cdad9f1ce58b' +\ - '26751f67a3cbb140b1808cf187a4f4df' +\ - 'c04b05357c5d1c0eeac4c66f9ff7f2e6' - key = '2b7e151628aed2a6abf7158809cf4f3c' - iv = '000102030405060708090a0b0c0d0e0f' - - key = unhexlify(key) - iv = unhexlify(iv) - plaintext = unhexlify(plaintext) - ciphertext = unhexlify(ciphertext) - - cipher = AES.new(key, AES.MODE_CFB, iv, segment_size=128) - self.assertEqual(cipher.encrypt(plaintext), ciphertext) - cipher = AES.new(key, AES.MODE_CFB, iv, segment_size=128) - self.assertEqual(cipher.decrypt(ciphertext), plaintext) - - def test_aes_192_cfb128(self): - plaintext = '6bc1bee22e409f96e93d7e117393172a' +\ - 'ae2d8a571e03ac9c9eb76fac45af8e51' +\ - '30c81c46a35ce411e5fbc1191a0a52ef' +\ - 'f69f2445df4f9b17ad2b417be66c3710' - ciphertext = 'cdc80d6fddf18cab34c25909c99a4174' +\ - '67ce7f7f81173621961a2b70171d3d7a' +\ - '2e1e8a1dd59b88b1c8e60fed1efac4c9' +\ - 'c05f9f9ca9834fa042ae8fba584b09ff' - key = '8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b' - iv = '000102030405060708090a0b0c0d0e0f' - - key = unhexlify(key) - iv = unhexlify(iv) - plaintext = unhexlify(plaintext) - ciphertext = unhexlify(ciphertext) - - cipher = AES.new(key, AES.MODE_CFB, iv, segment_size=128) - self.assertEqual(cipher.encrypt(plaintext), ciphertext) - cipher = AES.new(key, AES.MODE_CFB, iv, segment_size=128) - self.assertEqual(cipher.decrypt(ciphertext), plaintext) - - def test_aes_256_cfb128(self): - plaintext = '6bc1bee22e409f96e93d7e117393172a' +\ - 'ae2d8a571e03ac9c9eb76fac45af8e51' +\ - '30c81c46a35ce411e5fbc1191a0a52ef' +\ - 'f69f2445df4f9b17ad2b417be66c3710' - - ciphertext = 'dc7e84bfda79164b7ecd8486985d3860' +\ - '39ffed143b28b1c832113c6331e5407b' +\ - 'df10132415e54b92a13ed0a8267ae2f9' +\ - '75a385741ab9cef82031623d55b1e471' - key = '603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4' - iv = '000102030405060708090a0b0c0d0e0f' - - key = unhexlify(key) - iv = unhexlify(iv) - plaintext = unhexlify(plaintext) - ciphertext = unhexlify(ciphertext) - - cipher = AES.new(key, AES.MODE_CFB, iv, segment_size=128) - self.assertEqual(cipher.encrypt(plaintext), ciphertext) - cipher = AES.new(key, AES.MODE_CFB, iv, segment_size=128) - self.assertEqual(cipher.decrypt(ciphertext), plaintext) - - -def get_tests(config={}): - tests = [] - tests += list_test_cases(CfbTests) - if config.get('slow_tests'): - tests += list_test_cases(NistCfbVectors) - tests += list_test_cases(SP800TestVectors) - return tests - - -if __name__ == '__main__': - suite = lambda: unittest.TestSuite(get_tests()) - unittest.main(defaultTest='suite') diff --git a/Crypto/SelfTest/Cipher/test_CTR.py b/Crypto/SelfTest/Cipher/test_CTR.py deleted file mode 100644 index ed367f8..0000000 --- a/Crypto/SelfTest/Cipher/test_CTR.py +++ /dev/null @@ -1,471 +0,0 @@ -# =================================================================== -# -# Copyright (c) 2015, Legrandin -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# =================================================================== - -import unittest -from binascii import hexlify, unhexlify - -from Crypto.SelfTest.st_common import list_test_cases -from Crypto.Util.py3compat import tobytes, bchr -from Crypto.Cipher import AES, DES3 -from Crypto.Hash import SHAKE128, SHA256 -from Crypto.Util import Counter - -def get_tag_random(tag, length): - return SHAKE128.new(data=tobytes(tag)).read(length) - -class CtrTests(unittest.TestCase): - - key_128 = get_tag_random("key_128", 16) - key_192 = get_tag_random("key_192", 24) - nonce_32 = get_tag_random("nonce_32", 4) - nonce_64 = get_tag_random("nonce_64", 8) - ctr_64 = Counter.new(32, prefix=nonce_32) - ctr_128 = Counter.new(64, prefix=nonce_64) - - def test_loopback_128(self): - cipher = AES.new(self.key_128, AES.MODE_CTR, counter=self.ctr_128) - pt = get_tag_random("plaintext", 16 * 100) - ct = cipher.encrypt(pt) - - cipher = AES.new(self.key_128, AES.MODE_CTR, counter=self.ctr_128) - pt2 = cipher.decrypt(ct) - self.assertEqual(pt, pt2) - - def test_loopback_64(self): - cipher = DES3.new(self.key_192, DES3.MODE_CTR, counter=self.ctr_64) - pt = get_tag_random("plaintext", 8 * 100) - ct = cipher.encrypt(pt) - - cipher = DES3.new(self.key_192, DES3.MODE_CTR, counter=self.ctr_64) - pt2 = cipher.decrypt(ct) - self.assertEqual(pt, pt2) - - def test_invalid_counter_parameter(self): - # Counter object is required for ciphers with short block size - self.assertRaises(TypeError, DES3.new, self.key_192, AES.MODE_CTR) - # Positional arguments are not allowed (Counter must be passed as - # keyword) - self.assertRaises(TypeError, AES.new, self.key_128, AES.MODE_CTR, self.ctr_128) - - def test_nonce_attribute(self): - # Nonce attribute is the prefix passed to Counter (DES3) - cipher = DES3.new(self.key_192, DES3.MODE_CTR, counter=self.ctr_64) - self.assertEqual(cipher.nonce, self.nonce_32) - - # Nonce attribute is the prefix passed to Counter (AES) - cipher = AES.new(self.key_128, AES.MODE_CTR, counter=self.ctr_128) - self.assertEqual(cipher.nonce, self.nonce_64) - - # Nonce attribute is not defined if suffix is used in Counter - counter = Counter.new(64, prefix=self.nonce_32, suffix=self.nonce_32) - cipher = AES.new(self.key_128, AES.MODE_CTR, counter=counter) - self.failIf(hasattr(cipher, "nonce")) - - def test_nonce_parameter(self): - # Nonce parameter becomes nonce attribute - cipher1 = AES.new(self.key_128, AES.MODE_CTR, nonce=self.nonce_64) - self.assertEqual(cipher1.nonce, self.nonce_64) - - counter = Counter.new(64, prefix=self.nonce_64, initial_value=0) - cipher2 = AES.new(self.key_128, AES.MODE_CTR, counter=counter) - self.assertEqual(cipher1.nonce, cipher2.nonce) - - pt = get_tag_random("plaintext", 65536) - self.assertEqual(cipher1.encrypt(pt), cipher2.encrypt(pt)) - - # Nonce is implicitly created (for AES) when no parameters are passed - nonce1 = AES.new(self.key_128, AES.MODE_CTR).nonce - nonce2 = AES.new(self.key_128, AES.MODE_CTR).nonce - self.assertNotEqual(nonce1, nonce2) - self.assertEqual(len(nonce1), 8) - - # Nonce can be zero-length - cipher = AES.new(self.key_128, AES.MODE_CTR, nonce=b"") - self.assertEqual(b"", cipher.nonce) - cipher.encrypt(b'0'*300) - - # Nonce and Counter are mutually exclusive - self.assertRaises(TypeError, AES.new, self.key_128, AES.MODE_CTR, - counter=self.ctr_128, nonce=self.nonce_64) - - def test_initial_value_parameter(self): - # Test with nonce parameter - cipher1 = AES.new(self.key_128, AES.MODE_CTR, - nonce=self.nonce_64, initial_value=0xFFFF) - counter = Counter.new(64, prefix=self.nonce_64, initial_value=0xFFFF) - cipher2 = AES.new(self.key_128, AES.MODE_CTR, counter=counter) - pt = get_tag_random("plaintext", 65536) - self.assertEqual(cipher1.encrypt(pt), cipher2.encrypt(pt)) - - # Test without nonce parameter - cipher1 = AES.new(self.key_128, AES.MODE_CTR, - initial_value=0xFFFF) - counter = Counter.new(64, prefix=cipher1.nonce, initial_value=0xFFFF) - cipher2 = AES.new(self.key_128, AES.MODE_CTR, counter=counter) - pt = get_tag_random("plaintext", 65536) - self.assertEqual(cipher1.encrypt(pt), cipher2.encrypt(pt)) - - # Initial_value and Counter are mutually exclusive - self.assertRaises(TypeError, AES.new, self.key_128, AES.MODE_CTR, - counter=self.ctr_128, initial_value=0) - - def test_initial_value_bytes_parameter(self): - # Same result as when passing an integer - cipher1 = AES.new(self.key_128, AES.MODE_CTR, - nonce=self.nonce_64, - initial_value=b"\x00"*6+b"\xFF\xFF") - cipher2 = AES.new(self.key_128, AES.MODE_CTR, - nonce=self.nonce_64, initial_value=0xFFFF) - pt = get_tag_random("plaintext", 65536) - self.assertEqual(cipher1.encrypt(pt), cipher2.encrypt(pt)) - - # Fail if the iv is too large - self.assertRaises(ValueError, AES.new, self.key_128, AES.MODE_CTR, - initial_value=b"5"*17) - self.assertRaises(ValueError, AES.new, self.key_128, AES.MODE_CTR, - nonce=self.nonce_64, initial_value=b"5"*9) - - # Fail if the iv is too short - self.assertRaises(ValueError, AES.new, self.key_128, AES.MODE_CTR, - initial_value=b"5"*15) - self.assertRaises(ValueError, AES.new, self.key_128, AES.MODE_CTR, - nonce=self.nonce_64, initial_value=b"5"*7) - - def test_iv_with_matching_length(self): - self.assertRaises(ValueError, AES.new, self.key_128, AES.MODE_CTR, - counter=Counter.new(120)) - self.assertRaises(ValueError, AES.new, self.key_128, AES.MODE_CTR, - counter=Counter.new(136)) - - def test_block_size_128(self): - cipher = AES.new(self.key_128, AES.MODE_CTR, counter=self.ctr_128) - self.assertEqual(cipher.block_size, AES.block_size) - - def test_block_size_64(self): - cipher = DES3.new(self.key_192, DES3.MODE_CTR, counter=self.ctr_64) - self.assertEqual(cipher.block_size, DES3.block_size) - - def test_unaligned_data_128(self): - plaintexts = [ b"7777777" ] * 100 - - cipher = AES.new(self.key_128, AES.MODE_CTR, counter=self.ctr_128) - ciphertexts = [ cipher.encrypt(x) for x in plaintexts ] - cipher = AES.new(self.key_128, AES.MODE_CTR, counter=self.ctr_128) - self.assertEqual(b"".join(ciphertexts), cipher.encrypt(b"".join(plaintexts))) - - cipher = AES.new(self.key_128, AES.MODE_CTR, counter=self.ctr_128) - ciphertexts = [ cipher.encrypt(x) for x in plaintexts ] - cipher = AES.new(self.key_128, AES.MODE_CTR, counter=self.ctr_128) - self.assertEqual(b"".join(ciphertexts), cipher.encrypt(b"".join(plaintexts))) - - def test_unaligned_data_64(self): - plaintexts = [ b"7777777" ] * 100 - cipher = DES3.new(self.key_192, AES.MODE_CTR, counter=self.ctr_64) - ciphertexts = [ cipher.encrypt(x) for x in plaintexts ] - cipher = DES3.new(self.key_192, AES.MODE_CTR, counter=self.ctr_64) - self.assertEqual(b"".join(ciphertexts), cipher.encrypt(b"".join(plaintexts))) - - cipher = DES3.new(self.key_192, AES.MODE_CTR, counter=self.ctr_64) - ciphertexts = [ cipher.encrypt(x) for x in plaintexts ] - cipher = DES3.new(self.key_192, AES.MODE_CTR, counter=self.ctr_64) - self.assertEqual(b"".join(ciphertexts), cipher.encrypt(b"".join(plaintexts))) - - def test_unknown_parameters(self): - self.assertRaises(TypeError, AES.new, self.key_128, AES.MODE_CTR, - 7, counter=self.ctr_128) - self.assertRaises(TypeError, AES.new, self.key_128, AES.MODE_CTR, - counter=self.ctr_128, unknown=7) - # But some are only known by the base cipher (e.g. use_aesni consumed by the AES module) - AES.new(self.key_128, AES.MODE_CTR, counter=self.ctr_128, use_aesni=False) - - def test_null_encryption_decryption(self): - for func in "encrypt", "decrypt": - cipher = AES.new(self.key_128, AES.MODE_CTR, counter=self.ctr_128) - result = getattr(cipher, func)(b"") - self.assertEqual(result, b"") - - def test_either_encrypt_or_decrypt(self): - cipher = AES.new(self.key_128, AES.MODE_CTR, counter=self.ctr_128) - cipher.encrypt(b"") - self.assertRaises(TypeError, cipher.decrypt, b"") - - cipher = AES.new(self.key_128, AES.MODE_CTR, counter=self.ctr_128) - cipher.decrypt(b"") - self.assertRaises(TypeError, cipher.encrypt, b"") - - def test_wrap_around(self): - # Counter is only 8 bits, so we can only encrypt/decrypt 256 blocks (=4096 bytes) - counter = Counter.new(8, prefix=bchr(9) * 15) - max_bytes = 4096 - - cipher = AES.new(self.key_128, AES.MODE_CTR, counter=counter) - cipher.encrypt(b'9' * max_bytes) - self.assertRaises(OverflowError, cipher.encrypt, b'9') - - cipher = AES.new(self.key_128, AES.MODE_CTR, counter=counter) - self.assertRaises(OverflowError, cipher.encrypt, b'9' * (max_bytes + 1)) - - cipher = AES.new(self.key_128, AES.MODE_CTR, counter=counter) - cipher.decrypt(b'9' * max_bytes) - self.assertRaises(OverflowError, cipher.decrypt, b'9') - - cipher = AES.new(self.key_128, AES.MODE_CTR, counter=counter) - self.assertRaises(OverflowError, cipher.decrypt, b'9' * (max_bytes + 1)) - - def test_bytearray(self): - data = b"1" * 16 - iv = b"\x00" * 6 + b"\xFF\xFF" - - # Encrypt - cipher1 = AES.new(self.key_128, AES.MODE_CTR, - nonce=self.nonce_64, - initial_value=iv) - ref1 = cipher1.encrypt(data) - - cipher2 = AES.new(self.key_128, AES.MODE_CTR, - nonce=bytearray(self.nonce_64), - initial_value=bytearray(iv)) - ref2 = cipher2.encrypt(bytearray(data)) - - self.assertEqual(ref1, ref2) - self.assertEqual(cipher1.nonce, cipher2.nonce) - - # Decrypt - cipher3 = AES.new(self.key_128, AES.MODE_CTR, - nonce=self.nonce_64, - initial_value=iv) - ref3 = cipher3.decrypt(data) - - cipher4 = AES.new(self.key_128, AES.MODE_CTR, - nonce=bytearray(self.nonce_64), - initial_value=bytearray(iv)) - ref4 = cipher4.decrypt(bytearray(data)) - - self.assertEqual(ref3, ref4) - - def test_very_long_data(self): - cipher = AES.new(b'A' * 32, AES.MODE_CTR, nonce=b'') - ct = cipher.encrypt(b'B' * 1000000) - digest = SHA256.new(ct).hexdigest() - self.assertEqual(digest, "96204fc470476561a3a8f3b6fe6d24be85c87510b638142d1d0fb90989f8a6a6") - - def test_output_param(self): - - pt = b'5' * 16 - cipher = AES.new(b'4'*16, AES.MODE_CTR, nonce=self.nonce_64) - ct = cipher.encrypt(pt) - - output = bytearray(16) - cipher = AES.new(b'4'*16, AES.MODE_CTR, nonce=self.nonce_64) - res = cipher.encrypt(pt, output=output) - self.assertEqual(ct, output) - self.assertEqual(res, None) - - cipher = AES.new(b'4'*16, AES.MODE_CTR, nonce=self.nonce_64) - res = cipher.decrypt(ct, output=output) - self.assertEqual(pt, output) - self.assertEqual(res, None) - - def test_output_param_memoryview(self): - - pt = b'5' * 16 - cipher = AES.new(b'4'*16, AES.MODE_CTR, nonce=self.nonce_64) - ct = cipher.encrypt(pt) - - output = memoryview(bytearray(16)) - cipher = AES.new(b'4'*16, AES.MODE_CTR, nonce=self.nonce_64) - cipher.encrypt(pt, output=output) - self.assertEqual(ct, output) - - cipher = AES.new(b'4'*16, AES.MODE_CTR, nonce=self.nonce_64) - cipher.decrypt(ct, output=output) - self.assertEqual(pt, output) - - def test_output_param_neg(self): - - pt = b'5' * 16 - cipher = AES.new(b'4'*16, AES.MODE_CTR, nonce=self.nonce_64) - ct = cipher.encrypt(pt) - - cipher = AES.new(b'4'*16, AES.MODE_CTR, nonce=self.nonce_64) - self.assertRaises(TypeError, cipher.encrypt, pt, output=b'0'*16) - - cipher = AES.new(b'4'*16, AES.MODE_CTR, nonce=self.nonce_64) - self.assertRaises(TypeError, cipher.decrypt, ct, output=b'0'*16) - - shorter_output = bytearray(15) - cipher = AES.new(b'4'*16, AES.MODE_CTR, nonce=self.nonce_64) - self.assertRaises(ValueError, cipher.encrypt, pt, output=shorter_output) - cipher = AES.new(b'4'*16, AES.MODE_CTR, nonce=self.nonce_64) - self.assertRaises(ValueError, cipher.decrypt, ct, output=shorter_output) - - -class SP800TestVectors(unittest.TestCase): - """Class exercising the CTR test vectors found in Section F.5 - of NIST SP 800-38A""" - - def test_aes_128(self): - plaintext = '6bc1bee22e409f96e93d7e117393172a' +\ - 'ae2d8a571e03ac9c9eb76fac45af8e51' +\ - '30c81c46a35ce411e5fbc1191a0a52ef' +\ - 'f69f2445df4f9b17ad2b417be66c3710' - ciphertext = '874d6191b620e3261bef6864990db6ce' +\ - '9806f66b7970fdff8617187bb9fffdff' +\ - '5ae4df3edbd5d35e5b4f09020db03eab' +\ - '1e031dda2fbe03d1792170a0f3009cee' - key = '2b7e151628aed2a6abf7158809cf4f3c' - counter = Counter.new(nbits=16, - prefix=unhexlify('f0f1f2f3f4f5f6f7f8f9fafbfcfd'), - initial_value=0xfeff) - - key = unhexlify(key) - plaintext = unhexlify(plaintext) - ciphertext = unhexlify(ciphertext) - - cipher = AES.new(key, AES.MODE_CTR, counter=counter) - self.assertEqual(cipher.encrypt(plaintext), ciphertext) - cipher = AES.new(key, AES.MODE_CTR, counter=counter) - self.assertEqual(cipher.decrypt(ciphertext), plaintext) - - def test_aes_192(self): - plaintext = '6bc1bee22e409f96e93d7e117393172a' +\ - 'ae2d8a571e03ac9c9eb76fac45af8e51' +\ - '30c81c46a35ce411e5fbc1191a0a52ef' +\ - 'f69f2445df4f9b17ad2b417be66c3710' - ciphertext = '1abc932417521ca24f2b0459fe7e6e0b' +\ - '090339ec0aa6faefd5ccc2c6f4ce8e94' +\ - '1e36b26bd1ebc670d1bd1d665620abf7' +\ - '4f78a7f6d29809585a97daec58c6b050' - key = '8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b' - counter = Counter.new(nbits=16, - prefix=unhexlify('f0f1f2f3f4f5f6f7f8f9fafbfcfd'), - initial_value=0xfeff) - - key = unhexlify(key) - plaintext = unhexlify(plaintext) - ciphertext = unhexlify(ciphertext) - - cipher = AES.new(key, AES.MODE_CTR, counter=counter) - self.assertEqual(cipher.encrypt(plaintext), ciphertext) - cipher = AES.new(key, AES.MODE_CTR, counter=counter) - self.assertEqual(cipher.decrypt(ciphertext), plaintext) - - def test_aes_256(self): - plaintext = '6bc1bee22e409f96e93d7e117393172a' +\ - 'ae2d8a571e03ac9c9eb76fac45af8e51' +\ - '30c81c46a35ce411e5fbc1191a0a52ef' +\ - 'f69f2445df4f9b17ad2b417be66c3710' - ciphertext = '601ec313775789a5b7a7f504bbf3d228' +\ - 'f443e3ca4d62b59aca84e990cacaf5c5' +\ - '2b0930daa23de94ce87017ba2d84988d' +\ - 'dfc9c58db67aada613c2dd08457941a6' - key = '603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4' - counter = Counter.new(nbits=16, - prefix=unhexlify('f0f1f2f3f4f5f6f7f8f9fafbfcfd'), - initial_value=0xfeff) - key = unhexlify(key) - plaintext = unhexlify(plaintext) - ciphertext = unhexlify(ciphertext) - - cipher = AES.new(key, AES.MODE_CTR, counter=counter) - self.assertEqual(cipher.encrypt(plaintext), ciphertext) - cipher = AES.new(key, AES.MODE_CTR, counter=counter) - self.assertEqual(cipher.decrypt(ciphertext), plaintext) - - -class RFC3686TestVectors(unittest.TestCase): - - # Each item is a test vector with: - # - plaintext - # - ciphertext - # - key (AES 128, 192 or 256 bits) - # - counter prefix (4 byte nonce + 8 byte nonce) - data = ( - ('53696e676c6520626c6f636b206d7367', - 'e4095d4fb7a7b3792d6175a3261311b8', - 'ae6852f8121067cc4bf7a5765577f39e', - '000000300000000000000000'), - ('000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f', - '5104a106168a72d9790d41ee8edad388eb2e1efc46da57c8fce630df9141be28', - '7e24067817fae0d743d6ce1f32539163', - '006cb6dbc0543b59da48d90b'), - ('000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20212223', - 'c1cf48a89f2ffdd9cf4652e9efdb72d74540a42bde6d7836d59a5ceaaef3105325b2072f', - '7691be035e5020a8ac6e618529f9a0dc', - '00e0017b27777f3f4a1786f0'), - ('53696e676c6520626c6f636b206d7367', - '4b55384fe259c9c84e7935a003cbe928', - '16af5b145fc9f579c175f93e3bfb0eed863d06ccfdb78515', - '0000004836733c147d6d93cb'), - ('000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f', - '453243fc609b23327edfaafa7131cd9f8490701c5ad4a79cfc1fe0ff42f4fb00', - '7c5cb2401b3dc33c19e7340819e0f69c678c3db8e6f6a91a', - '0096b03b020c6eadc2cb500d'), - ('000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20212223', - '96893fc55e5c722f540b7dd1ddf7e758d288bc95c69165884536c811662f2188abee0935', - '02bf391ee8ecb159b959617b0965279bf59b60a786d3e0fe', - '0007bdfd5cbd60278dcc0912'), - ('53696e676c6520626c6f636b206d7367', - '145ad01dbf824ec7560863dc71e3e0c0', - '776beff2851db06f4c8a0542c8696f6c6a81af1eec96b4d37fc1d689e6c1c104', - '00000060db5672c97aa8f0b2'), - ('000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f', - 'f05e231b3894612c49ee000b804eb2a9b8306b508f839d6a5530831d9344af1c', - 'f6d66d6bd52d59bb0796365879eff886c66dd51a5b6a99744b50590c87a23884', - '00faac24c1585ef15a43d875'), - ('000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20212223', - 'eb6c52821d0bbbf7ce7594462aca4faab407df866569fd07f48cc0b583d6071f1ec0e6b8', - 'ff7a617ce69148e4f1726e2f43581de2aa62d9f805532edff1eed687fb54153d', - '001cc5b751a51d70a1c11148') - ) - - bindata = [] - for tv in data: - bindata.append([unhexlify(x) for x in tv]) - - def runTest(self): - for pt, ct, key, prefix in self.bindata: - counter = Counter.new(32, prefix=prefix) - cipher = AES.new(key, AES.MODE_CTR, counter=counter) - result = cipher.encrypt(pt) - self.assertEqual(hexlify(ct), hexlify(result)) - - -def get_tests(config={}): - tests = [] - tests += list_test_cases(CtrTests) - tests += list_test_cases(SP800TestVectors) - tests += [ RFC3686TestVectors() ] - return tests - - -if __name__ == '__main__': - suite = lambda: unittest.TestSuite(get_tests()) - unittest.main(defaultTest='suite') diff --git a/Crypto/SelfTest/Cipher/test_ChaCha20.py b/Crypto/SelfTest/Cipher/test_ChaCha20.py deleted file mode 100644 index 2b8de20..0000000 --- a/Crypto/SelfTest/Cipher/test_ChaCha20.py +++ /dev/null @@ -1,529 +0,0 @@ -# =================================================================== -# -# Copyright (c) 2014, Legrandin -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# =================================================================== - -import os -import re -import unittest -from binascii import hexlify, unhexlify - -from Crypto.Util.py3compat import b, tobytes, bchr -from Crypto.Util.strxor import strxor_c -from Crypto.SelfTest.st_common import list_test_cases - -from Crypto.Cipher import ChaCha20 - - -class ChaCha20Test(unittest.TestCase): - - def test_new_positive(self): - cipher = ChaCha20.new(key=b("0")*32, nonce=b"0"*8) - self.assertEqual(cipher.nonce, b"0" * 8) - cipher = ChaCha20.new(key=b("0")*32, nonce=b"0"*12) - self.assertEqual(cipher.nonce, b"0" * 12) - - def test_new_negative(self): - new = ChaCha20.new - self.assertRaises(TypeError, new) - self.assertRaises(TypeError, new, nonce=b("0")) - self.assertRaises(ValueError, new, nonce=b("0")*8, key=b("0")) - self.assertRaises(ValueError, new, nonce=b("0"), key=b("0")*32) - - def test_default_nonce(self): - cipher1 = ChaCha20.new(key=bchr(1) * 32) - cipher2 = ChaCha20.new(key=bchr(1) * 32) - self.assertEquals(len(cipher1.nonce), 8) - self.assertNotEqual(cipher1.nonce, cipher2.nonce) - - def test_nonce(self): - key = b'A' * 32 - - nonce1 = b'P' * 8 - cipher1 = ChaCha20.new(key=key, nonce=nonce1) - self.assertEqual(nonce1, cipher1.nonce) - - nonce2 = b'Q' * 12 - cipher2 = ChaCha20.new(key=key, nonce=nonce2) - self.assertEqual(nonce2, cipher2.nonce) - - def test_eiter_encrypt_or_decrypt(self): - """Verify that a cipher cannot be used for both decrypting and encrypting""" - - c1 = ChaCha20.new(key=b("5") * 32, nonce=b("6") * 8) - c1.encrypt(b("8")) - self.assertRaises(TypeError, c1.decrypt, b("9")) - - c2 = ChaCha20.new(key=b("5") * 32, nonce=b("6") * 8) - c2.decrypt(b("8")) - self.assertRaises(TypeError, c2.encrypt, b("9")) - - def test_round_trip(self): - pt = b("A") * 1024 - c1 = ChaCha20.new(key=b("5") * 32, nonce=b("6") * 8) - c2 = ChaCha20.new(key=b("5") * 32, nonce=b("6") * 8) - ct = c1.encrypt(pt) - self.assertEqual(c2.decrypt(ct), pt) - - self.assertEqual(c1.encrypt(b("")), b("")) - self.assertEqual(c2.decrypt(b("")), b("")) - - def test_streaming(self): - """Verify that an arbitrary number of bytes can be encrypted/decrypted""" - from Crypto.Hash import SHA1 - - segments = (1, 3, 5, 7, 11, 17, 23) - total = sum(segments) - - pt = b("") - while len(pt) < total: - pt += SHA1.new(pt).digest() - - cipher1 = ChaCha20.new(key=b("7") * 32, nonce=b("t") * 8) - ct = cipher1.encrypt(pt) - - cipher2 = ChaCha20.new(key=b("7") * 32, nonce=b("t") * 8) - cipher3 = ChaCha20.new(key=b("7") * 32, nonce=b("t") * 8) - idx = 0 - for segment in segments: - self.assertEqual(cipher2.decrypt(ct[idx:idx+segment]), pt[idx:idx+segment]) - self.assertEqual(cipher3.encrypt(pt[idx:idx+segment]), ct[idx:idx+segment]) - idx += segment - - def test_seek(self): - cipher1 = ChaCha20.new(key=b("9") * 32, nonce=b("e") * 8) - - offset = 64 * 900 + 7 - pt = b("1") * 64 - - cipher1.encrypt(b("0") * offset) - ct1 = cipher1.encrypt(pt) - - cipher2 = ChaCha20.new(key=b("9") * 32, nonce=b("e") * 8) - cipher2.seek(offset) - ct2 = cipher2.encrypt(pt) - - self.assertEquals(ct1, ct2) - - def test_seek_tv(self): - # Test Vector #4, A.1 from - # http://tools.ietf.org/html/draft-nir-cfrg-chacha20-poly1305-04 - key = bchr(0) + bchr(255) + bchr(0) * 30 - nonce = bchr(0) * 8 - cipher = ChaCha20.new(key=key, nonce=nonce) - cipher.seek(64 * 2) - expected_key_stream = unhexlify(b( - "72d54dfbf12ec44b362692df94137f32" - "8fea8da73990265ec1bbbea1ae9af0ca" - "13b25aa26cb4a648cb9b9d1be65b2c09" - "24a66c54d545ec1b7374f4872e99f096" - )) - ct = cipher.encrypt(bchr(0) * len(expected_key_stream)) - self.assertEqual(expected_key_stream, ct) - - def test_rfc7539(self): - # from https://tools.ietf.org/html/rfc7539 Annex A.1 - # Each item is: key, nonce, block #, plaintext, ciphertext - tvs = [ - # Test Vector #1 - ( - "00"*32, - "00"*12, - 0, - "00"*16*4, - "76b8e0ada0f13d90405d6ae55386bd28" - "bdd219b8a08ded1aa836efcc8b770dc7" - "da41597c5157488d7724e03fb8d84a37" - "6a43b8f41518a11cc387b669b2ee6586" - ), - # Test Vector #2 - ( - "00"*31 + "01", - "00"*11 + "02", - 1, - "416e79207375626d697373696f6e2074" - "6f20746865204945544620696e74656e" - "6465642062792074686520436f6e7472" - "696275746f7220666f72207075626c69" - "636174696f6e20617320616c6c206f72" - "2070617274206f6620616e2049455446" - "20496e7465726e65742d447261667420" - "6f722052464320616e6420616e792073" - "746174656d656e74206d616465207769" - "7468696e2074686520636f6e74657874" - "206f6620616e20494554462061637469" - "7669747920697320636f6e7369646572" - "656420616e20224945544620436f6e74" - "7269627574696f6e222e205375636820" - "73746174656d656e747320696e636c75" - "6465206f72616c2073746174656d656e" - "747320696e2049455446207365737369" - "6f6e732c2061732077656c6c20617320" - "7772697474656e20616e6420656c6563" - "74726f6e696320636f6d6d756e696361" - "74696f6e73206d61646520617420616e" - "792074696d65206f7220706c6163652c" - "20776869636820617265206164647265" - "7373656420746f", - "a3fbf07df3fa2fde4f376ca23e827370" - "41605d9f4f4f57bd8cff2c1d4b7955ec" - "2a97948bd3722915c8f3d337f7d37005" - "0e9e96d647b7c39f56e031ca5eb6250d" - "4042e02785ececfa4b4bb5e8ead0440e" - "20b6e8db09d881a7c6132f420e527950" - "42bdfa7773d8a9051447b3291ce1411c" - "680465552aa6c405b7764d5e87bea85a" - "d00f8449ed8f72d0d662ab052691ca66" - "424bc86d2df80ea41f43abf937d3259d" - "c4b2d0dfb48a6c9139ddd7f76966e928" - "e635553ba76c5c879d7b35d49eb2e62b" - "0871cdac638939e25e8a1e0ef9d5280f" - "a8ca328b351c3c765989cbcf3daa8b6c" - "cc3aaf9f3979c92b3720fc88dc95ed84" - "a1be059c6499b9fda236e7e818b04b0b" - "c39c1e876b193bfe5569753f88128cc0" - "8aaa9b63d1a16f80ef2554d7189c411f" - "5869ca52c5b83fa36ff216b9c1d30062" - "bebcfd2dc5bce0911934fda79a86f6e6" - "98ced759c3ff9b6477338f3da4f9cd85" - "14ea9982ccafb341b2384dd902f3d1ab" - "7ac61dd29c6f21ba5b862f3730e37cfd" - "c4fd806c22f221" - ), - # Test Vector #3 - ( - "1c9240a5eb55d38af333888604f6b5f0" - "473917c1402b80099dca5cbc207075c0", - "00"*11 + "02", - 42, - "2754776173206272696c6c69672c2061" - "6e642074686520736c6974687920746f" - "7665730a446964206779726520616e64" - "2067696d626c6520696e207468652077" - "6162653a0a416c6c206d696d73792077" - "6572652074686520626f726f676f7665" - "732c0a416e6420746865206d6f6d6520" - "7261746873206f757467726162652e", - "62e6347f95ed87a45ffae7426f27a1df" - "5fb69110044c0d73118effa95b01e5cf" - "166d3df2d721caf9b21e5fb14c616871" - "fd84c54f9d65b283196c7fe4f60553eb" - "f39c6402c42234e32a356b3e764312a6" - "1a5532055716ead6962568f87d3f3f77" - "04c6a8d1bcd1bf4d50d6154b6da731b1" - "87b58dfd728afa36757a797ac188d1" - ) - ] - - for tv in tvs: - key = unhexlify(tv[0]) - nonce = unhexlify(tv[1]) - offset = tv[2] * 64 - pt = unhexlify(tv[3]) - ct_expect = unhexlify(tv[4]) - - cipher = ChaCha20.new(key=key, nonce=nonce) - if offset != 0: - cipher.seek(offset) - ct = cipher.encrypt(pt) - assert(ct == ct_expect) - - -class XChaCha20Test(unittest.TestCase): - - # From https://tools.ietf.org/html/draft-arciszewski-xchacha-03 - - def test_hchacha20(self): - # Section 2.2.1 - - from Crypto.Cipher.ChaCha20 import _HChaCha20 - - key = b"00:01:02:03:04:05:06:07:08:09:0a:0b:0c:0d:0e:0f:10:11:12:13:14:15:16:17:18:19:1a:1b:1c:1d:1e:1f" - key = unhexlify(key.replace(b":", b"")) - - nonce = b"00:00:00:09:00:00:00:4a:00:00:00:00:31:41:59:27" - nonce = unhexlify(nonce.replace(b":", b"")) - - subkey = _HChaCha20(key, nonce) - - expected = b"82413b42 27b27bfe d30e4250 8a877d73 a0f9e4d5 8a74a853 c12ec413 26d3ecdc" - expected = unhexlify(expected.replace(b" ", b"")) - - self.assertEqual(subkey, expected) - - def test_nonce(self): - key = b'A' * 32 - nonce = b'P' * 24 - cipher = ChaCha20.new(key=key, nonce=nonce) - self.assertEqual(nonce, cipher.nonce) - - def test_encrypt(self): - # Section A.3.2 - - pt = b""" - 5468652064686f6c65202870726f6e6f756e6365642022646f6c652229206973 - 20616c736f206b6e6f776e2061732074686520417369617469632077696c6420 - 646f672c2072656420646f672c20616e642077686973746c696e6720646f672e - 2049742069732061626f7574207468652073697a65206f662061204765726d61 - 6e20736865706865726420627574206c6f6f6b73206d6f7265206c696b652061 - 206c6f6e672d6c656767656420666f782e205468697320686967686c7920656c - 757369766520616e6420736b696c6c6564206a756d70657220697320636c6173 - 736966696564207769746820776f6c7665732c20636f796f7465732c206a6163 - 6b616c732c20616e6420666f78657320696e20746865207461786f6e6f6d6963 - 2066616d696c792043616e696461652e""" - pt = unhexlify(pt.replace(b"\n", b"").replace(b" ", b"")) - - key = unhexlify(b"808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9f") - iv = unhexlify(b"404142434445464748494a4b4c4d4e4f5051525354555658") - - ct = b""" - 7d0a2e6b7f7c65a236542630294e063b7ab9b555a5d5149aa21e4ae1e4fbce87 - ecc8e08a8b5e350abe622b2ffa617b202cfad72032a3037e76ffdcdc4376ee05 - 3a190d7e46ca1de04144850381b9cb29f051915386b8a710b8ac4d027b8b050f - 7cba5854e028d564e453b8a968824173fc16488b8970cac828f11ae53cabd201 - 12f87107df24ee6183d2274fe4c8b1485534ef2c5fbc1ec24bfc3663efaa08bc - 047d29d25043532db8391a8a3d776bf4372a6955827ccb0cdd4af403a7ce4c63 - d595c75a43e045f0cce1f29c8b93bd65afc5974922f214a40b7c402cdb91ae73 - c0b63615cdad0480680f16515a7ace9d39236464328a37743ffc28f4ddb324f4 - d0f5bbdc270c65b1749a6efff1fbaa09536175ccd29fb9e6057b307320d31683 - 8a9c71f70b5b5907a66f7ea49aadc409""" - ct = unhexlify(ct.replace(b"\n", b"").replace(b" ", b"")) - - cipher = ChaCha20.new(key=key, nonce=iv) - cipher.seek(64) # Counter = 1 - ct_test = cipher.encrypt(pt) - self.assertEqual(ct, ct_test) - - -class ByteArrayTest(unittest.TestCase): - """Verify we can encrypt or decrypt bytearrays""" - - def runTest(self): - - data = b"0123" - key = b"9" * 32 - nonce = b"t" * 8 - - # Encryption - data_ba = bytearray(data) - key_ba = bytearray(key) - nonce_ba = bytearray(nonce) - - cipher1 = ChaCha20.new(key=key, nonce=nonce) - ct = cipher1.encrypt(data) - - cipher2 = ChaCha20.new(key=key_ba, nonce=nonce_ba) - key_ba[:1] = b'\xFF' - nonce_ba[:1] = b'\xFF' - ct_test = cipher2.encrypt(data_ba) - - self.assertEqual(ct, ct_test) - self.assertEqual(cipher1.nonce, cipher2.nonce) - - # Decryption - key_ba = bytearray(key) - nonce_ba = bytearray(nonce) - ct_ba = bytearray(ct) - - cipher3 = ChaCha20.new(key=key_ba, nonce=nonce_ba) - key_ba[:1] = b'\xFF' - nonce_ba[:1] = b'\xFF' - pt_test = cipher3.decrypt(ct_ba) - - self.assertEqual(data, pt_test) - - -class MemoryviewTest(unittest.TestCase): - """Verify we can encrypt or decrypt bytearrays""" - - def runTest(self): - - data = b"0123" - key = b"9" * 32 - nonce = b"t" * 8 - - # Encryption - data_mv = memoryview(bytearray(data)) - key_mv = memoryview(bytearray(key)) - nonce_mv = memoryview(bytearray(nonce)) - - cipher1 = ChaCha20.new(key=key, nonce=nonce) - ct = cipher1.encrypt(data) - - cipher2 = ChaCha20.new(key=key_mv, nonce=nonce_mv) - key_mv[:1] = b'\xFF' - nonce_mv[:1] = b'\xFF' - ct_test = cipher2.encrypt(data_mv) - - self.assertEqual(ct, ct_test) - self.assertEqual(cipher1.nonce, cipher2.nonce) - - # Decryption - key_mv = memoryview(bytearray(key)) - nonce_mv = memoryview(bytearray(nonce)) - ct_mv = memoryview(bytearray(ct)) - - cipher3 = ChaCha20.new(key=key_mv, nonce=nonce_mv) - key_mv[:1] = b'\xFF' - nonce_mv[:1] = b'\xFF' - pt_test = cipher3.decrypt(ct_mv) - - self.assertEqual(data, pt_test) - - -class ChaCha20_AGL_NIR(unittest.TestCase): - - # From http://tools.ietf.org/html/draft-agl-tls-chacha20poly1305-04 - # and http://tools.ietf.org/html/draft-nir-cfrg-chacha20-poly1305-04 - tv = [ - ( "00" * 32, - "00" * 8, - "76b8e0ada0f13d90405d6ae55386bd28bdd219b8a08ded1aa836efcc" - "8b770dc7da41597c5157488d7724e03fb8d84a376a43b8f41518a11c" - "c387b669b2ee6586" - "9f07e7be5551387a98ba977c732d080d" - "cb0f29a048e3656912c6533e32ee7aed" - "29b721769ce64e43d57133b074d839d5" - "31ed1f28510afb45ace10a1f4b794d6f" - ), - ( "00" * 31 + "01", - "00" * 8, - "4540f05a9f1fb296d7736e7b208e3c96eb4fe1834688d2604f450952" - "ed432d41bbe2a0b6ea7566d2a5d1e7e20d42af2c53d792b1c43fea81" - "7e9ad275ae546963" - "3aeb5224ecf849929b9d828db1ced4dd" - "832025e8018b8160b82284f3c949aa5a" - "8eca00bbb4a73bdad192b5c42f73f2fd" - "4e273644c8b36125a64addeb006c13a0" - ), - ( "00" * 32, - "00" * 7 + "01", - "de9cba7bf3d69ef5e786dc63973f653a0b49e015adbff7134fcb7df1" - "37821031e85a050278a7084527214f73efc7fa5b5277062eb7a0433e" - "445f41e3" - ), - ( "00" * 32, - "01" + "00" * 7, - "ef3fdfd6c61578fbf5cf35bd3dd33b8009631634d21e42ac33960bd1" - "38e50d32111e4caf237ee53ca8ad6426194a88545ddc497a0b466e7d" - "6bbdb0041b2f586b" - ), - ( "000102030405060708090a0b0c0d0e0f101112131415161718191a1b" - "1c1d1e1f", - "0001020304050607", - "f798a189f195e66982105ffb640bb7757f579da31602fc93ec01ac56" - "f85ac3c134a4547b733b46413042c9440049176905d3be59ea1c53f1" - "5916155c2be8241a38008b9a26bc35941e2444177c8ade6689de9526" - "4986d95889fb60e84629c9bd9a5acb1cc118be563eb9b3a4a472f82e" - "09a7e778492b562ef7130e88dfe031c79db9d4f7c7a899151b9a4750" - "32b63fc385245fe054e3dd5a97a5f576fe064025d3ce042c566ab2c5" - "07b138db853e3d6959660996546cc9c4a6eafdc777c040d70eaf46f7" - "6dad3979e5c5360c3317166a1c894c94a371876a94df7628fe4eaaf2" - "ccb27d5aaae0ad7ad0f9d4b6ad3b54098746d4524d38407a6deb3ab7" - "8fab78c9" - ), - ( "00" * 32, - "00" * 7 + "02", - "c2c64d378cd536374ae204b9ef933fcd" - "1a8b2288b3dfa49672ab765b54ee27c7" - "8a970e0e955c14f3a88e741b97c286f7" - "5f8fc299e8148362fa198a39531bed6d" - ), - ] - - def runTest(self): - for (key, nonce, stream) in self.tv: - c = ChaCha20.new(key=unhexlify(b(key)), nonce=unhexlify(b(nonce))) - ct = unhexlify(b(stream)) - pt = b("\x00") * len(ct) - self.assertEqual(c.encrypt(pt), ct) - - -class TestOutput(unittest.TestCase): - - def runTest(self): - # Encrypt/Decrypt data and test output parameter - - key = b'4' * 32 - nonce = b'5' * 8 - cipher = ChaCha20.new(key=key, nonce=nonce) - - pt = b'5' * 16 - ct = cipher.encrypt(pt) - - output = bytearray(16) - cipher = ChaCha20.new(key=key, nonce=nonce) - res = cipher.encrypt(pt, output=output) - self.assertEqual(ct, output) - self.assertEqual(res, None) - - cipher = ChaCha20.new(key=key, nonce=nonce) - res = cipher.decrypt(ct, output=output) - self.assertEqual(pt, output) - self.assertEqual(res, None) - - output = memoryview(bytearray(16)) - cipher = ChaCha20.new(key=key, nonce=nonce) - cipher.encrypt(pt, output=output) - self.assertEqual(ct, output) - - cipher = ChaCha20.new(key=key, nonce=nonce) - cipher.decrypt(ct, output=output) - self.assertEqual(pt, output) - - cipher = ChaCha20.new(key=key, nonce=nonce) - self.assertRaises(TypeError, cipher.encrypt, pt, output=b'0'*16) - - cipher = ChaCha20.new(key=key, nonce=nonce) - self.assertRaises(TypeError, cipher.decrypt, ct, output=b'0'*16) - - shorter_output = bytearray(7) - - cipher = ChaCha20.new(key=key, nonce=nonce) - self.assertRaises(ValueError, cipher.encrypt, pt, output=shorter_output) - - cipher = ChaCha20.new(key=key, nonce=nonce) - self.assertRaises(ValueError, cipher.decrypt, ct, output=shorter_output) - - -def get_tests(config={}): - tests = [] - tests += list_test_cases(ChaCha20Test) - tests += list_test_cases(XChaCha20Test) - tests.append(ChaCha20_AGL_NIR()) - tests.append(ByteArrayTest()) - tests.append(MemoryviewTest()) - tests.append(TestOutput()) - - return tests - - -if __name__ == '__main__': - import unittest - suite = lambda: unittest.TestSuite(get_tests()) - unittest.main(defaultTest='suite') diff --git a/Crypto/SelfTest/Cipher/test_ChaCha20_Poly1305.py b/Crypto/SelfTest/Cipher/test_ChaCha20_Poly1305.py deleted file mode 100644 index f7baad5..0000000 --- a/Crypto/SelfTest/Cipher/test_ChaCha20_Poly1305.py +++ /dev/null @@ -1,770 +0,0 @@ -# =================================================================== -# -# Copyright (c) 2018, Helder Eijs -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# =================================================================== - -import unittest -from binascii import unhexlify - -from Crypto.SelfTest.st_common import list_test_cases -from Crypto.SelfTest.loader import load_test_vectors_wycheproof -from Crypto.Util.py3compat import tobytes -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 - - -def get_tag_random(tag, length): - return SHAKE128.new(data=tobytes(tag)).read(length) - - -class ChaCha20Poly1305Tests(unittest.TestCase): - - key_256 = get_tag_random("key_256", 32) - nonce_96 = get_tag_random("nonce_96", 12) - data_128 = get_tag_random("data_128", 16) - - def test_loopback(self): - cipher = ChaCha20_Poly1305.new(key=self.key_256, - nonce=self.nonce_96) - pt = get_tag_random("plaintext", 16 * 100) - ct = cipher.encrypt(pt) - - cipher = ChaCha20_Poly1305.new(key=self.key_256, - nonce=self.nonce_96) - pt2 = cipher.decrypt(ct) - self.assertEqual(pt, pt2) - - def test_nonce(self): - # Nonce can only be 8 or 12 bytes - cipher = ChaCha20_Poly1305.new(key=self.key_256, - nonce=b'H' * 8) - self.assertEqual(len(cipher.nonce), 8) - cipher = ChaCha20_Poly1305.new(key=self.key_256, - nonce=b'H' * 12) - self.assertEqual(len(cipher.nonce), 12) - - # If not passed, the nonce is created randomly - cipher = ChaCha20_Poly1305.new(key=self.key_256) - nonce1 = cipher.nonce - cipher = ChaCha20_Poly1305.new(key=self.key_256) - nonce2 = cipher.nonce - self.assertEqual(len(nonce1), 12) - self.assertNotEqual(nonce1, nonce2) - - cipher = ChaCha20_Poly1305.new(key=self.key_256, - nonce=self.nonce_96) - ct = cipher.encrypt(self.data_128) - - cipher = ChaCha20_Poly1305.new(key=self.key_256, - nonce=self.nonce_96) - self.assertEquals(ct, cipher.encrypt(self.data_128)) - - def test_nonce_must_be_bytes(self): - self.assertRaises(TypeError, - ChaCha20_Poly1305.new, - key=self.key_256, - nonce=u'test12345678') - - def test_nonce_length(self): - # nonce can only be 8 or 12 bytes long - self.assertRaises(ValueError, - ChaCha20_Poly1305.new, - key=self.key_256, - nonce=b'0' * 7) - self.assertRaises(ValueError, - ChaCha20_Poly1305.new, - key=self.key_256, - nonce=b'') - - def test_block_size(self): - # Not based on block ciphers - cipher = ChaCha20_Poly1305.new(key=self.key_256, - nonce=self.nonce_96) - self.failIf(hasattr(cipher, 'block_size')) - - def test_nonce_attribute(self): - cipher = ChaCha20_Poly1305.new(key=self.key_256, - nonce=self.nonce_96) - self.assertEqual(cipher.nonce, self.nonce_96) - - # By default, a 12 bytes long nonce is randomly generated - nonce1 = ChaCha20_Poly1305.new(key=self.key_256).nonce - nonce2 = ChaCha20_Poly1305.new(key=self.key_256).nonce - self.assertEqual(len(nonce1), 12) - self.assertNotEqual(nonce1, nonce2) - - def test_unknown_parameters(self): - self.assertRaises(TypeError, - ChaCha20_Poly1305.new, - key=self.key_256, - param=9) - - def test_null_encryption_decryption(self): - for func in "encrypt", "decrypt": - cipher = ChaCha20_Poly1305.new(key=self.key_256, - nonce=self.nonce_96) - result = getattr(cipher, func)(b"") - self.assertEqual(result, b"") - - def test_either_encrypt_or_decrypt(self): - cipher = ChaCha20_Poly1305.new(key=self.key_256, - nonce=self.nonce_96) - cipher.encrypt(b"") - self.assertRaises(TypeError, cipher.decrypt, b"") - - cipher = ChaCha20_Poly1305.new(key=self.key_256, - nonce=self.nonce_96) - cipher.decrypt(b"") - self.assertRaises(TypeError, cipher.encrypt, b"") - - def test_data_must_be_bytes(self): - cipher = ChaCha20_Poly1305.new(key=self.key_256, - nonce=self.nonce_96) - self.assertRaises(TypeError, cipher.encrypt, u'test1234567890-*') - - cipher = ChaCha20_Poly1305.new(key=self.key_256, - nonce=self.nonce_96) - self.assertRaises(TypeError, cipher.decrypt, u'test1234567890-*') - - def test_mac_len(self): - cipher = ChaCha20_Poly1305.new(key=self.key_256, - nonce=self.nonce_96) - _, mac = cipher.encrypt_and_digest(self.data_128) - self.assertEqual(len(mac), 16) - - def test_invalid_mac(self): - from Crypto.Util.strxor import strxor_c - cipher = ChaCha20_Poly1305.new(key=self.key_256, - nonce=self.nonce_96) - ct, mac = cipher.encrypt_and_digest(self.data_128) - - invalid_mac = strxor_c(mac, 0x01) - - cipher = ChaCha20_Poly1305.new(key=self.key_256, - nonce=self.nonce_96) - self.assertRaises(ValueError, cipher.decrypt_and_verify, ct, - invalid_mac) - - def test_hex_mac(self): - cipher = ChaCha20_Poly1305.new(key=self.key_256, - nonce=self.nonce_96) - mac_hex = cipher.hexdigest() - self.assertEqual(cipher.digest(), unhexlify(mac_hex)) - - cipher = ChaCha20_Poly1305.new(key=self.key_256, - nonce=self.nonce_96) - cipher.hexverify(mac_hex) - - def test_message_chunks(self): - # Validate that both associated data and plaintext/ciphertext - # can be broken up in chunks of arbitrary length - - auth_data = get_tag_random("authenticated data", 127) - plaintext = get_tag_random("plaintext", 127) - - cipher = ChaCha20_Poly1305.new(key=self.key_256, - nonce=self.nonce_96) - cipher.update(auth_data) - ciphertext, ref_mac = cipher.encrypt_and_digest(plaintext) - - def break_up(data, chunk_length): - return [data[i:i+chunk_length] for i in range(0, len(data), - chunk_length)] - - # Encryption - for chunk_length in 1, 2, 3, 7, 10, 13, 16, 40, 80, 128: - - cipher = ChaCha20_Poly1305.new(key=self.key_256, - nonce=self.nonce_96) - - for chunk in break_up(auth_data, chunk_length): - cipher.update(chunk) - pt2 = b"" - for chunk in break_up(ciphertext, chunk_length): - pt2 += cipher.decrypt(chunk) - self.assertEqual(plaintext, pt2) - cipher.verify(ref_mac) - - # Decryption - for chunk_length in 1, 2, 3, 7, 10, 13, 16, 40, 80, 128: - - cipher = ChaCha20_Poly1305.new(key=self.key_256, - nonce=self.nonce_96) - - for chunk in break_up(auth_data, chunk_length): - cipher.update(chunk) - ct2 = b"" - for chunk in break_up(plaintext, chunk_length): - ct2 += cipher.encrypt(chunk) - self.assertEqual(ciphertext, ct2) - self.assertEquals(cipher.digest(), ref_mac) - - def test_bytearray(self): - - # Encrypt - key_ba = bytearray(self.key_256) - nonce_ba = bytearray(self.nonce_96) - header_ba = bytearray(self.data_128) - data_ba = bytearray(self.data_128) - - cipher1 = ChaCha20_Poly1305.new(key=self.key_256, - nonce=self.nonce_96) - cipher1.update(self.data_128) - ct = cipher1.encrypt(self.data_128) - tag = cipher1.digest() - - cipher2 = ChaCha20_Poly1305.new(key=self.key_256, - nonce=self.nonce_96) - key_ba[:3] = b'\xFF\xFF\xFF' - nonce_ba[:3] = b'\xFF\xFF\xFF' - cipher2.update(header_ba) - header_ba[:3] = b'\xFF\xFF\xFF' - ct_test = cipher2.encrypt(data_ba) - data_ba[:3] = b'\x99\x99\x99' - tag_test = cipher2.digest() - - self.assertEqual(ct, ct_test) - self.assertEqual(tag, tag_test) - self.assertEqual(cipher1.nonce, cipher2.nonce) - - # Decrypt - key_ba = bytearray(self.key_256) - nonce_ba = bytearray(self.nonce_96) - header_ba = bytearray(self.data_128) - ct_ba = bytearray(ct) - tag_ba = bytearray(tag) - del data_ba - - cipher3 = ChaCha20_Poly1305.new(key=self.key_256, - nonce=self.nonce_96) - key_ba[:3] = b'\xFF\xFF\xFF' - nonce_ba[:3] = b'\xFF\xFF\xFF' - cipher3.update(header_ba) - header_ba[:3] = b'\xFF\xFF\xFF' - pt_test = cipher3.decrypt(ct_ba) - ct_ba[:3] = b'\xFF\xFF\xFF' - cipher3.verify(tag_ba) - - self.assertEqual(pt_test, self.data_128) - - def test_memoryview(self): - - # Encrypt - key_mv = memoryview(bytearray(self.key_256)) - nonce_mv = memoryview(bytearray(self.nonce_96)) - header_mv = memoryview(bytearray(self.data_128)) - data_mv = memoryview(bytearray(self.data_128)) - - cipher1 = ChaCha20_Poly1305.new(key=self.key_256, - nonce=self.nonce_96) - cipher1.update(self.data_128) - ct = cipher1.encrypt(self.data_128) - tag = cipher1.digest() - - cipher2 = ChaCha20_Poly1305.new(key=self.key_256, - nonce=self.nonce_96) - key_mv[:3] = b'\xFF\xFF\xFF' - nonce_mv[:3] = b'\xFF\xFF\xFF' - cipher2.update(header_mv) - header_mv[:3] = b'\xFF\xFF\xFF' - ct_test = cipher2.encrypt(data_mv) - data_mv[:3] = b'\x99\x99\x99' - tag_test = cipher2.digest() - - self.assertEqual(ct, ct_test) - self.assertEqual(tag, tag_test) - self.assertEqual(cipher1.nonce, cipher2.nonce) - - # Decrypt - key_mv = memoryview(bytearray(self.key_256)) - nonce_mv = memoryview(bytearray(self.nonce_96)) - header_mv = memoryview(bytearray(self.data_128)) - ct_mv = memoryview(bytearray(ct)) - tag_mv = memoryview(bytearray(tag)) - del data_mv - - cipher3 = ChaCha20_Poly1305.new(key=self.key_256, - nonce=self.nonce_96) - key_mv[:3] = b'\xFF\xFF\xFF' - nonce_mv[:3] = b'\xFF\xFF\xFF' - cipher3.update(header_mv) - header_mv[:3] = b'\xFF\xFF\xFF' - pt_test = cipher3.decrypt(ct_mv) - ct_mv[:3] = b'\x99\x99\x99' - cipher3.verify(tag_mv) - - self.assertEqual(pt_test, self.data_128) - - -class XChaCha20Poly1305Tests(unittest.TestCase): - - def test_encrypt(self): - # From https://tools.ietf.org/html/draft-arciszewski-xchacha-03 - # Section A.3.1 - - pt = b""" - 4c616469657320616e642047656e746c656d656e206f662074686520636c6173 - 73206f66202739393a204966204920636f756c64206f6666657220796f75206f - 6e6c79206f6e652074697020666f7220746865206675747572652c2073756e73 - 637265656e20776f756c642062652069742e""" - pt = unhexlify(pt.replace(b"\n", b"").replace(b" ", b"")) - - aad = unhexlify(b"50515253c0c1c2c3c4c5c6c7") - key = unhexlify(b"808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9f") - iv = unhexlify(b"404142434445464748494a4b4c4d4e4f5051525354555657") - - ct = b""" - bd6d179d3e83d43b9576579493c0e939572a1700252bfaccbed2902c21396cbb - 731c7f1b0b4aa6440bf3a82f4eda7e39ae64c6708c54c216cb96b72e1213b452 - 2f8c9ba40db5d945b11b69b982c1bb9e3f3fac2bc369488f76b2383565d3fff9 - 21f9664c97637da9768812f615c68b13b52e""" - ct = unhexlify(ct.replace(b"\n", b"").replace(b" ", b"")) - - tag = unhexlify(b"c0875924c1c7987947deafd8780acf49") - - cipher = ChaCha20_Poly1305.new(key=key, nonce=iv) - cipher.update(aad) - ct_test, tag_test = cipher.encrypt_and_digest(pt) - - self.assertEqual(ct, ct_test) - self.assertEqual(tag, tag_test) - - cipher = ChaCha20_Poly1305.new(key=key, nonce=iv) - cipher.update(aad) - cipher.decrypt_and_verify(ct, tag) - - -class ChaCha20Poly1305FSMTests(unittest.TestCase): - - key_256 = get_tag_random("key_256", 32) - nonce_96 = get_tag_random("nonce_96", 12) - data_128 = get_tag_random("data_128", 16) - - def test_valid_init_encrypt_decrypt_digest_verify(self): - # No authenticated data, fixed plaintext - # Verify path INIT->ENCRYPT->DIGEST - cipher = ChaCha20_Poly1305.new(key=self.key_256, - nonce=self.nonce_96) - ct = cipher.encrypt(self.data_128) - mac = cipher.digest() - - # Verify path INIT->DECRYPT->VERIFY - cipher = ChaCha20_Poly1305.new(key=self.key_256, - nonce=self.nonce_96) - cipher.decrypt(ct) - cipher.verify(mac) - - def test_valid_init_update_digest_verify(self): - # No plaintext, fixed authenticated data - # Verify path INIT->UPDATE->DIGEST - cipher = ChaCha20_Poly1305.new(key=self.key_256, - nonce=self.nonce_96) - cipher.update(self.data_128) - mac = cipher.digest() - - # Verify path INIT->UPDATE->VERIFY - cipher = ChaCha20_Poly1305.new(key=self.key_256, - nonce=self.nonce_96) - cipher.update(self.data_128) - cipher.verify(mac) - - def test_valid_full_path(self): - # Fixed authenticated data, fixed plaintext - # Verify path INIT->UPDATE->ENCRYPT->DIGEST - cipher = ChaCha20_Poly1305.new(key=self.key_256, - nonce=self.nonce_96) - cipher.update(self.data_128) - ct = cipher.encrypt(self.data_128) - mac = cipher.digest() - - # Verify path INIT->UPDATE->DECRYPT->VERIFY - cipher = ChaCha20_Poly1305.new(key=self.key_256, - nonce=self.nonce_96) - cipher.update(self.data_128) - cipher.decrypt(ct) - cipher.verify(mac) - - def test_valid_init_digest(self): - # Verify path INIT->DIGEST - cipher = ChaCha20_Poly1305.new(key=self.key_256, - nonce=self.nonce_96) - cipher.digest() - - def test_valid_init_verify(self): - # Verify path INIT->VERIFY - cipher = ChaCha20_Poly1305.new(key=self.key_256, - nonce=self.nonce_96) - mac = cipher.digest() - - cipher = ChaCha20_Poly1305.new(key=self.key_256, - nonce=self.nonce_96) - cipher.verify(mac) - - def test_valid_multiple_encrypt_or_decrypt(self): - for method_name in "encrypt", "decrypt": - for auth_data in (None, b"333", self.data_128, - self.data_128 + b"3"): - cipher = ChaCha20_Poly1305.new(key=self.key_256, - nonce=self.nonce_96) - if auth_data is not None: - cipher.update(auth_data) - method = getattr(cipher, method_name) - method(self.data_128) - method(self.data_128) - method(self.data_128) - method(self.data_128) - - def test_valid_multiple_digest_or_verify(self): - # Multiple calls to digest - cipher = ChaCha20_Poly1305.new(key=self.key_256, - nonce=self.nonce_96) - cipher.update(self.data_128) - first_mac = cipher.digest() - for x in range(4): - self.assertEqual(first_mac, cipher.digest()) - - # Multiple calls to verify - cipher = ChaCha20_Poly1305.new(key=self.key_256, - nonce=self.nonce_96) - cipher.update(self.data_128) - for x in range(5): - cipher.verify(first_mac) - - def test_valid_encrypt_and_digest_decrypt_and_verify(self): - # encrypt_and_digest - cipher = ChaCha20_Poly1305.new(key=self.key_256, - nonce=self.nonce_96) - cipher.update(self.data_128) - ct, mac = cipher.encrypt_and_digest(self.data_128) - - # decrypt_and_verify - cipher = ChaCha20_Poly1305.new(key=self.key_256, - nonce=self.nonce_96) - cipher.update(self.data_128) - pt = cipher.decrypt_and_verify(ct, mac) - self.assertEqual(self.data_128, pt) - - def test_invalid_mixing_encrypt_decrypt(self): - # Once per method, with or without assoc. data - for method1_name, method2_name in (("encrypt", "decrypt"), - ("decrypt", "encrypt")): - for assoc_data_present in (True, False): - cipher = ChaCha20_Poly1305.new(key=self.key_256, - nonce=self.nonce_96) - if assoc_data_present: - cipher.update(self.data_128) - getattr(cipher, method1_name)(self.data_128) - self.assertRaises(TypeError, getattr(cipher, method2_name), - self.data_128) - - def test_invalid_encrypt_or_update_after_digest(self): - for method_name in "encrypt", "update": - cipher = ChaCha20_Poly1305.new(key=self.key_256, - nonce=self.nonce_96) - cipher.encrypt(self.data_128) - cipher.digest() - self.assertRaises(TypeError, getattr(cipher, method_name), - self.data_128) - - cipher = ChaCha20_Poly1305.new(key=self.key_256, - nonce=self.nonce_96) - cipher.encrypt_and_digest(self.data_128) - - def test_invalid_decrypt_or_update_after_verify(self): - cipher = ChaCha20_Poly1305.new(key=self.key_256, - nonce=self.nonce_96) - ct = cipher.encrypt(self.data_128) - mac = cipher.digest() - - for method_name in "decrypt", "update": - cipher = ChaCha20_Poly1305.new(key=self.key_256, - nonce=self.nonce_96) - cipher.decrypt(ct) - cipher.verify(mac) - self.assertRaises(TypeError, getattr(cipher, method_name), - self.data_128) - - cipher = ChaCha20_Poly1305.new(key=self.key_256, - nonce=self.nonce_96) - cipher.decrypt(ct) - cipher.verify(mac) - self.assertRaises(TypeError, getattr(cipher, method_name), - self.data_128) - - cipher = ChaCha20_Poly1305.new(key=self.key_256, - nonce=self.nonce_96) - cipher.decrypt_and_verify(ct, mac) - self.assertRaises(TypeError, getattr(cipher, method_name), - self.data_128) - - -def compact(x): - return unhexlify(x.replace(" ", "").replace(":", "")) - - -class TestVectorsRFC(unittest.TestCase): - """Test cases from RFC7539""" - - # AAD, PT, CT, MAC, KEY, NONCE - test_vectors_hex = [ - ( '50 51 52 53 c0 c1 c2 c3 c4 c5 c6 c7', - '4c 61 64 69 65 73 20 61 6e 64 20 47 65 6e 74 6c' - '65 6d 65 6e 20 6f 66 20 74 68 65 20 63 6c 61 73' - '73 20 6f 66 20 27 39 39 3a 20 49 66 20 49 20 63' - '6f 75 6c 64 20 6f 66 66 65 72 20 79 6f 75 20 6f' - '6e 6c 79 20 6f 6e 65 20 74 69 70 20 66 6f 72 20' - '74 68 65 20 66 75 74 75 72 65 2c 20 73 75 6e 73' - '63 72 65 65 6e 20 77 6f 75 6c 64 20 62 65 20 69' - '74 2e', - 'd3 1a 8d 34 64 8e 60 db 7b 86 af bc 53 ef 7e c2' - 'a4 ad ed 51 29 6e 08 fe a9 e2 b5 a7 36 ee 62 d6' - '3d be a4 5e 8c a9 67 12 82 fa fb 69 da 92 72 8b' - '1a 71 de 0a 9e 06 0b 29 05 d6 a5 b6 7e cd 3b 36' - '92 dd bd 7f 2d 77 8b 8c 98 03 ae e3 28 09 1b 58' - 'fa b3 24 e4 fa d6 75 94 55 85 80 8b 48 31 d7 bc' - '3f f4 de f0 8e 4b 7a 9d e5 76 d2 65 86 ce c6 4b' - '61 16', - '1a:e1:0b:59:4f:09:e2:6a:7e:90:2e:cb:d0:60:06:91', - '80 81 82 83 84 85 86 87 88 89 8a 8b 8c 8d 8e 8f' - '90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d 9e 9f', - '07 00 00 00' + '40 41 42 43 44 45 46 47', - ), - ( 'f3 33 88 86 00 00 00 00 00 00 4e 91', - '49 6e 74 65 72 6e 65 74 2d 44 72 61 66 74 73 20' - '61 72 65 20 64 72 61 66 74 20 64 6f 63 75 6d 65' - '6e 74 73 20 76 61 6c 69 64 20 66 6f 72 20 61 20' - '6d 61 78 69 6d 75 6d 20 6f 66 20 73 69 78 20 6d' - '6f 6e 74 68 73 20 61 6e 64 20 6d 61 79 20 62 65' - '20 75 70 64 61 74 65 64 2c 20 72 65 70 6c 61 63' - '65 64 2c 20 6f 72 20 6f 62 73 6f 6c 65 74 65 64' - '20 62 79 20 6f 74 68 65 72 20 64 6f 63 75 6d 65' - '6e 74 73 20 61 74 20 61 6e 79 20 74 69 6d 65 2e' - '20 49 74 20 69 73 20 69 6e 61 70 70 72 6f 70 72' - '69 61 74 65 20 74 6f 20 75 73 65 20 49 6e 74 65' - '72 6e 65 74 2d 44 72 61 66 74 73 20 61 73 20 72' - '65 66 65 72 65 6e 63 65 20 6d 61 74 65 72 69 61' - '6c 20 6f 72 20 74 6f 20 63 69 74 65 20 74 68 65' - '6d 20 6f 74 68 65 72 20 74 68 61 6e 20 61 73 20' - '2f e2 80 9c 77 6f 72 6b 20 69 6e 20 70 72 6f 67' - '72 65 73 73 2e 2f e2 80 9d', - '64 a0 86 15 75 86 1a f4 60 f0 62 c7 9b e6 43 bd' - '5e 80 5c fd 34 5c f3 89 f1 08 67 0a c7 6c 8c b2' - '4c 6c fc 18 75 5d 43 ee a0 9e e9 4e 38 2d 26 b0' - 'bd b7 b7 3c 32 1b 01 00 d4 f0 3b 7f 35 58 94 cf' - '33 2f 83 0e 71 0b 97 ce 98 c8 a8 4a bd 0b 94 81' - '14 ad 17 6e 00 8d 33 bd 60 f9 82 b1 ff 37 c8 55' - '97 97 a0 6e f4 f0 ef 61 c1 86 32 4e 2b 35 06 38' - '36 06 90 7b 6a 7c 02 b0 f9 f6 15 7b 53 c8 67 e4' - 'b9 16 6c 76 7b 80 4d 46 a5 9b 52 16 cd e7 a4 e9' - '90 40 c5 a4 04 33 22 5e e2 82 a1 b0 a0 6c 52 3e' - 'af 45 34 d7 f8 3f a1 15 5b 00 47 71 8c bc 54 6a' - '0d 07 2b 04 b3 56 4e ea 1b 42 22 73 f5 48 27 1a' - '0b b2 31 60 53 fa 76 99 19 55 eb d6 31 59 43 4e' - 'ce bb 4e 46 6d ae 5a 10 73 a6 72 76 27 09 7a 10' - '49 e6 17 d9 1d 36 10 94 fa 68 f0 ff 77 98 71 30' - '30 5b ea ba 2e da 04 df 99 7b 71 4d 6c 6f 2c 29' - 'a6 ad 5c b4 02 2b 02 70 9b', - 'ee ad 9d 67 89 0c bb 22 39 23 36 fe a1 85 1f 38', - '1c 92 40 a5 eb 55 d3 8a f3 33 88 86 04 f6 b5 f0' - '47 39 17 c1 40 2b 80 09 9d ca 5c bc 20 70 75 c0', - '00 00 00 00 01 02 03 04 05 06 07 08', - ) - ] - - 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: - # Encrypt - cipher = ChaCha20_Poly1305.new(key=key, nonce=nonce) - cipher.update(assoc_data) - ct2, mac2 = cipher.encrypt_and_digest(pt) - self.assertEqual(ct, ct2) - self.assertEqual(mac, mac2) - - # Decrypt - cipher = ChaCha20_Poly1305.new(key=key, nonce=nonce) - cipher.update(assoc_data) - pt2 = cipher.decrypt_and_verify(ct, mac) - self.assertEqual(pt, pt2) - - -class TestVectorsWycheproof(unittest.TestCase): - - def __init__(self, wycheproof_warnings): - unittest.TestCase.__init__(self) - self._wycheproof_warnings = wycheproof_warnings - self._id = "None" - - def load_tests(self, filename): - - def filter_tag(group): - return group['tagSize'] // 8 - - def filter_algo(root): - return root['algorithm'] - - result = load_test_vectors_wycheproof(("Cipher", "wycheproof"), - filename, - "Wycheproof ChaCha20-Poly1305", - root_tag={'algo': filter_algo}, - group_tag={'tag_size': filter_tag}) - return result - - def setUp(self): - self.tv = [] - self.tv.extend(self.load_tests("chacha20_poly1305_test.json")) - self.tv.extend(self.load_tests("xchacha20_poly1305_test.json")) - - def shortDescription(self): - return self._id - - def warn(self, tv): - if tv.warning and self._wycheproof_warnings: - import warnings - warnings.warn("Wycheproof warning: %s (%s)" % (self._id, tv.comment)) - - def test_encrypt(self, tv): - self._id = "Wycheproof Encrypt %s Test #%s" % (tv.algo, tv.id) - - try: - cipher = ChaCha20_Poly1305.new(key=tv.key, nonce=tv.iv) - except ValueError as e: - assert len(tv.iv) not in (8, 12) and "Nonce must be" in str(e) - return - - cipher.update(tv.aad) - ct, tag = cipher.encrypt_and_digest(tv.msg) - if tv.valid: - self.assertEqual(ct, tv.ct) - self.assertEqual(tag, tv.tag) - self.warn(tv) - - def test_decrypt(self, tv): - self._id = "Wycheproof Decrypt %s Test #%s" % (tv.algo, tv.id) - - try: - cipher = ChaCha20_Poly1305.new(key=tv.key, nonce=tv.iv) - except ValueError as e: - assert len(tv.iv) not in (8, 12) and "Nonce must be" in str(e) - return - - cipher.update(tv.aad) - try: - pt = cipher.decrypt_and_verify(tv.ct, tv.tag) - except ValueError: - assert not tv.valid - else: - assert tv.valid - self.assertEqual(pt, tv.msg) - self.warn(tv) - - def test_corrupt_decrypt(self, tv): - self._id = "Wycheproof Corrupt Decrypt ChaCha20-Poly1305 Test #" + str(tv.id) - if len(tv.iv) == 0 or len(tv.ct) < 1: - return - cipher = ChaCha20_Poly1305.new(key=tv.key, nonce=tv.iv) - cipher.update(tv.aad) - ct_corrupt = strxor(tv.ct, b"\x00" * (len(tv.ct) - 1) + b"\x01") - self.assertRaises(ValueError, cipher.decrypt_and_verify, ct_corrupt, tv.tag) - - def runTest(self): - - for tv in self.tv: - self.test_encrypt(tv) - self.test_decrypt(tv) - self.test_corrupt_decrypt(tv) - - -class TestOutput(unittest.TestCase): - - def runTest(self): - # Encrypt/Decrypt data and test output parameter - - key = b'4' * 32 - nonce = b'5' * 12 - cipher = ChaCha20_Poly1305.new(key=key, nonce=nonce) - - pt = b'5' * 16 - ct = cipher.encrypt(pt) - - output = bytearray(16) - cipher = ChaCha20_Poly1305.new(key=key, nonce=nonce) - res = cipher.encrypt(pt, output=output) - self.assertEqual(ct, output) - self.assertEqual(res, None) - - cipher = ChaCha20_Poly1305.new(key=key, nonce=nonce) - res = cipher.decrypt(ct, output=output) - self.assertEqual(pt, output) - self.assertEqual(res, None) - - output = memoryview(bytearray(16)) - cipher = ChaCha20_Poly1305.new(key=key, nonce=nonce) - cipher.encrypt(pt, output=output) - self.assertEqual(ct, output) - - cipher = ChaCha20_Poly1305.new(key=key, nonce=nonce) - cipher.decrypt(ct, output=output) - self.assertEqual(pt, output) - - cipher = ChaCha20_Poly1305.new(key=key, nonce=nonce) - self.assertRaises(TypeError, cipher.encrypt, pt, output=b'0'*16) - - cipher = ChaCha20_Poly1305.new(key=key, nonce=nonce) - self.assertRaises(TypeError, cipher.decrypt, ct, output=b'0'*16) - - shorter_output = bytearray(7) - - cipher = ChaCha20_Poly1305.new(key=key, nonce=nonce) - self.assertRaises(ValueError, cipher.encrypt, pt, output=shorter_output) - - cipher = ChaCha20_Poly1305.new(key=key, nonce=nonce) - self.assertRaises(ValueError, cipher.decrypt, ct, output=shorter_output) - - -def get_tests(config={}): - wycheproof_warnings = config.get('wycheproof_warnings') - - tests = [] - tests += list_test_cases(ChaCha20Poly1305Tests) - tests += list_test_cases(XChaCha20Poly1305Tests) - tests += list_test_cases(ChaCha20Poly1305FSMTests) - tests += [TestVectorsRFC()] - tests += [TestVectorsWycheproof(wycheproof_warnings)] - tests += [TestOutput()] - return tests - - -if __name__ == '__main__': - def suite(): - unittest.TestSuite(get_tests()) - unittest.main(defaultTest='suite') diff --git a/Crypto/SelfTest/Cipher/test_DES.py b/Crypto/SelfTest/Cipher/test_DES.py deleted file mode 100644 index ee261bc..0000000 --- a/Crypto/SelfTest/Cipher/test_DES.py +++ /dev/null @@ -1,374 +0,0 @@ -# -*- coding: utf-8 -*- -# -# SelfTest/Cipher/DES.py: Self-test for the (Single) DES cipher -# -# Written in 2008 by Dwayne C. Litzenberger -# -# =================================================================== -# The contents of this file are dedicated to the public domain. To -# the extent that dedication to the public domain is not available, -# everyone is granted a worldwide, perpetual, royalty-free, -# non-exclusive license to exercise all rights associated with the -# contents of this file for any purpose whatsoever. -# No rights are reserved. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS -# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN -# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# =================================================================== - -"""Self-test suite for Crypto.Cipher.DES""" - -import unittest - -from Crypto.Cipher import DES - -# This is a list of (plaintext, ciphertext, key, description) tuples. -SP800_17_B1_KEY = '01' * 8 -SP800_17_B2_PT = '00' * 8 -test_data = [ - # Test vectors from Appendix A of NIST SP 800-17 - # "Modes of Operation Validation System (MOVS): Requirements and Procedures" - # http://csrc.nist.gov/publications/nistpubs/800-17/800-17.pdf - - # Appendix A - "Sample Round Outputs for the DES" - ('0000000000000000', '82dcbafbdeab6602', '10316e028c8f3b4a', - "NIST SP800-17 A"), - - # Table B.1 - Variable Plaintext Known Answer Test - ('8000000000000000', '95f8a5e5dd31d900', SP800_17_B1_KEY, - 'NIST SP800-17 B.1 #0'), - ('4000000000000000', 'dd7f121ca5015619', SP800_17_B1_KEY, - 'NIST SP800-17 B.1 #1'), - ('2000000000000000', '2e8653104f3834ea', SP800_17_B1_KEY, - 'NIST SP800-17 B.1 #2'), - ('1000000000000000', '4bd388ff6cd81d4f', SP800_17_B1_KEY, - 'NIST SP800-17 B.1 #3'), - ('0800000000000000', '20b9e767b2fb1456', SP800_17_B1_KEY, - 'NIST SP800-17 B.1 #4'), - ('0400000000000000', '55579380d77138ef', SP800_17_B1_KEY, - 'NIST SP800-17 B.1 #5'), - ('0200000000000000', '6cc5defaaf04512f', SP800_17_B1_KEY, - 'NIST SP800-17 B.1 #6'), - ('0100000000000000', '0d9f279ba5d87260', SP800_17_B1_KEY, - 'NIST SP800-17 B.1 #7'), - ('0080000000000000', 'd9031b0271bd5a0a', SP800_17_B1_KEY, - 'NIST SP800-17 B.1 #8'), - ('0040000000000000', '424250b37c3dd951', SP800_17_B1_KEY, - 'NIST SP800-17 B.1 #9'), - ('0020000000000000', 'b8061b7ecd9a21e5', SP800_17_B1_KEY, - 'NIST SP800-17 B.1 #10'), - ('0010000000000000', 'f15d0f286b65bd28', SP800_17_B1_KEY, - 'NIST SP800-17 B.1 #11'), - ('0008000000000000', 'add0cc8d6e5deba1', SP800_17_B1_KEY, - 'NIST SP800-17 B.1 #12'), - ('0004000000000000', 'e6d5f82752ad63d1', SP800_17_B1_KEY, - 'NIST SP800-17 B.1 #13'), - ('0002000000000000', 'ecbfe3bd3f591a5e', SP800_17_B1_KEY, - 'NIST SP800-17 B.1 #14'), - ('0001000000000000', 'f356834379d165cd', SP800_17_B1_KEY, - 'NIST SP800-17 B.1 #15'), - ('0000800000000000', '2b9f982f20037fa9', SP800_17_B1_KEY, - 'NIST SP800-17 B.1 #16'), - ('0000400000000000', '889de068a16f0be6', SP800_17_B1_KEY, - 'NIST SP800-17 B.1 #17'), - ('0000200000000000', 'e19e275d846a1298', SP800_17_B1_KEY, - 'NIST SP800-17 B.1 #18'), - ('0000100000000000', '329a8ed523d71aec', SP800_17_B1_KEY, - 'NIST SP800-17 B.1 #19'), - ('0000080000000000', 'e7fce22557d23c97', SP800_17_B1_KEY, - 'NIST SP800-17 B.1 #20'), - ('0000040000000000', '12a9f5817ff2d65d', SP800_17_B1_KEY, - 'NIST SP800-17 B.1 #21'), - ('0000020000000000', 'a484c3ad38dc9c19', SP800_17_B1_KEY, - 'NIST SP800-17 B.1 #22'), - ('0000010000000000', 'fbe00a8a1ef8ad72', SP800_17_B1_KEY, - 'NIST SP800-17 B.1 #23'), - ('0000008000000000', '750d079407521363', SP800_17_B1_KEY, - 'NIST SP800-17 B.1 #24'), - ('0000004000000000', '64feed9c724c2faf', SP800_17_B1_KEY, - 'NIST SP800-17 B.1 #25'), - ('0000002000000000', 'f02b263b328e2b60', SP800_17_B1_KEY, - 'NIST SP800-17 B.1 #26'), - ('0000001000000000', '9d64555a9a10b852', SP800_17_B1_KEY, - 'NIST SP800-17 B.1 #27'), - ('0000000800000000', 'd106ff0bed5255d7', SP800_17_B1_KEY, - 'NIST SP800-17 B.1 #28'), - ('0000000400000000', 'e1652c6b138c64a5', SP800_17_B1_KEY, - 'NIST SP800-17 B.1 #29'), - ('0000000200000000', 'e428581186ec8f46', SP800_17_B1_KEY, - 'NIST SP800-17 B.1 #30'), - ('0000000100000000', 'aeb5f5ede22d1a36', SP800_17_B1_KEY, - 'NIST SP800-17 B.1 #31'), - ('0000000080000000', 'e943d7568aec0c5c', SP800_17_B1_KEY, - 'NIST SP800-17 B.1 #32'), - ('0000000040000000', 'df98c8276f54b04b', SP800_17_B1_KEY, - 'NIST SP800-17 B.1 #33'), - ('0000000020000000', 'b160e4680f6c696f', SP800_17_B1_KEY, - 'NIST SP800-17 B.1 #34'), - ('0000000010000000', 'fa0752b07d9c4ab8', SP800_17_B1_KEY, - 'NIST SP800-17 B.1 #35'), - ('0000000008000000', 'ca3a2b036dbc8502', SP800_17_B1_KEY, - 'NIST SP800-17 B.1 #36'), - ('0000000004000000', '5e0905517bb59bcf', SP800_17_B1_KEY, - 'NIST SP800-17 B.1 #37'), - ('0000000002000000', '814eeb3b91d90726', SP800_17_B1_KEY, - 'NIST SP800-17 B.1 #38'), - ('0000000001000000', '4d49db1532919c9f', SP800_17_B1_KEY, - 'NIST SP800-17 B.1 #39'), - ('0000000000800000', '25eb5fc3f8cf0621', SP800_17_B1_KEY, - 'NIST SP800-17 B.1 #40'), - ('0000000000400000', 'ab6a20c0620d1c6f', SP800_17_B1_KEY, - 'NIST SP800-17 B.1 #41'), - ('0000000000200000', '79e90dbc98f92cca', SP800_17_B1_KEY, - 'NIST SP800-17 B.1 #42'), - ('0000000000100000', '866ecedd8072bb0e', SP800_17_B1_KEY, - 'NIST SP800-17 B.1 #43'), - ('0000000000080000', '8b54536f2f3e64a8', SP800_17_B1_KEY, - 'NIST SP800-17 B.1 #44'), - ('0000000000040000', 'ea51d3975595b86b', SP800_17_B1_KEY, - 'NIST SP800-17 B.1 #45'), - ('0000000000020000', 'caffc6ac4542de31', SP800_17_B1_KEY, - 'NIST SP800-17 B.1 #46'), - ('0000000000010000', '8dd45a2ddf90796c', SP800_17_B1_KEY, - 'NIST SP800-17 B.1 #47'), - ('0000000000008000', '1029d55e880ec2d0', SP800_17_B1_KEY, - 'NIST SP800-17 B.1 #48'), - ('0000000000004000', '5d86cb23639dbea9', SP800_17_B1_KEY, - 'NIST SP800-17 B.1 #49'), - ('0000000000002000', '1d1ca853ae7c0c5f', SP800_17_B1_KEY, - 'NIST SP800-17 B.1 #50'), - ('0000000000001000', 'ce332329248f3228', SP800_17_B1_KEY, - 'NIST SP800-17 B.1 #51'), - ('0000000000000800', '8405d1abe24fb942', SP800_17_B1_KEY, - 'NIST SP800-17 B.1 #52'), - ('0000000000000400', 'e643d78090ca4207', SP800_17_B1_KEY, - 'NIST SP800-17 B.1 #53'), - ('0000000000000200', '48221b9937748a23', SP800_17_B1_KEY, - 'NIST SP800-17 B.1 #54'), - ('0000000000000100', 'dd7c0bbd61fafd54', SP800_17_B1_KEY, - 'NIST SP800-17 B.1 #55'), - ('0000000000000080', '2fbc291a570db5c4', SP800_17_B1_KEY, - 'NIST SP800-17 B.1 #56'), - ('0000000000000040', 'e07c30d7e4e26e12', SP800_17_B1_KEY, - 'NIST SP800-17 B.1 #57'), - ('0000000000000020', '0953e2258e8e90a1', SP800_17_B1_KEY, - 'NIST SP800-17 B.1 #58'), - ('0000000000000010', '5b711bc4ceebf2ee', SP800_17_B1_KEY, - 'NIST SP800-17 B.1 #59'), - ('0000000000000008', 'cc083f1e6d9e85f6', SP800_17_B1_KEY, - 'NIST SP800-17 B.1 #60'), - ('0000000000000004', 'd2fd8867d50d2dfe', SP800_17_B1_KEY, - 'NIST SP800-17 B.1 #61'), - ('0000000000000002', '06e7ea22ce92708f', SP800_17_B1_KEY, - 'NIST SP800-17 B.1 #62'), - ('0000000000000001', '166b40b44aba4bd6', SP800_17_B1_KEY, - 'NIST SP800-17 B.1 #63'), - - # Table B.2 - Variable Key Known Answer Test - (SP800_17_B2_PT, '95a8d72813daa94d', '8001010101010101', - 'NIST SP800-17 B.2 #0'), - (SP800_17_B2_PT, '0eec1487dd8c26d5', '4001010101010101', - 'NIST SP800-17 B.2 #1'), - (SP800_17_B2_PT, '7ad16ffb79c45926', '2001010101010101', - 'NIST SP800-17 B.2 #2'), - (SP800_17_B2_PT, 'd3746294ca6a6cf3', '1001010101010101', - 'NIST SP800-17 B.2 #3'), - (SP800_17_B2_PT, '809f5f873c1fd761', '0801010101010101', - 'NIST SP800-17 B.2 #4'), - (SP800_17_B2_PT, 'c02faffec989d1fc', '0401010101010101', - 'NIST SP800-17 B.2 #5'), - (SP800_17_B2_PT, '4615aa1d33e72f10', '0201010101010101', - 'NIST SP800-17 B.2 #6'), - (SP800_17_B2_PT, '2055123350c00858', '0180010101010101', - 'NIST SP800-17 B.2 #7'), - (SP800_17_B2_PT, 'df3b99d6577397c8', '0140010101010101', - 'NIST SP800-17 B.2 #8'), - (SP800_17_B2_PT, '31fe17369b5288c9', '0120010101010101', - 'NIST SP800-17 B.2 #9'), - (SP800_17_B2_PT, 'dfdd3cc64dae1642', '0110010101010101', - 'NIST SP800-17 B.2 #10'), - (SP800_17_B2_PT, '178c83ce2b399d94', '0108010101010101', - 'NIST SP800-17 B.2 #11'), - (SP800_17_B2_PT, '50f636324a9b7f80', '0104010101010101', - 'NIST SP800-17 B.2 #12'), - (SP800_17_B2_PT, 'a8468ee3bc18f06d', '0102010101010101', - 'NIST SP800-17 B.2 #13'), - (SP800_17_B2_PT, 'a2dc9e92fd3cde92', '0101800101010101', - 'NIST SP800-17 B.2 #14'), - (SP800_17_B2_PT, 'cac09f797d031287', '0101400101010101', - 'NIST SP800-17 B.2 #15'), - (SP800_17_B2_PT, '90ba680b22aeb525', '0101200101010101', - 'NIST SP800-17 B.2 #16'), - (SP800_17_B2_PT, 'ce7a24f350e280b6', '0101100101010101', - 'NIST SP800-17 B.2 #17'), - (SP800_17_B2_PT, '882bff0aa01a0b87', '0101080101010101', - 'NIST SP800-17 B.2 #18'), - (SP800_17_B2_PT, '25610288924511c2', '0101040101010101', - 'NIST SP800-17 B.2 #19'), - (SP800_17_B2_PT, 'c71516c29c75d170', '0101020101010101', - 'NIST SP800-17 B.2 #20'), - (SP800_17_B2_PT, '5199c29a52c9f059', '0101018001010101', - 'NIST SP800-17 B.2 #21'), - (SP800_17_B2_PT, 'c22f0a294a71f29f', '0101014001010101', - 'NIST SP800-17 B.2 #22'), - (SP800_17_B2_PT, 'ee371483714c02ea', '0101012001010101', - 'NIST SP800-17 B.2 #23'), - (SP800_17_B2_PT, 'a81fbd448f9e522f', '0101011001010101', - 'NIST SP800-17 B.2 #24'), - (SP800_17_B2_PT, '4f644c92e192dfed', '0101010801010101', - 'NIST SP800-17 B.2 #25'), - (SP800_17_B2_PT, '1afa9a66a6df92ae', '0101010401010101', - 'NIST SP800-17 B.2 #26'), - (SP800_17_B2_PT, 'b3c1cc715cb879d8', '0101010201010101', - 'NIST SP800-17 B.2 #27'), - (SP800_17_B2_PT, '19d032e64ab0bd8b', '0101010180010101', - 'NIST SP800-17 B.2 #28'), - (SP800_17_B2_PT, '3cfaa7a7dc8720dc', '0101010140010101', - 'NIST SP800-17 B.2 #29'), - (SP800_17_B2_PT, 'b7265f7f447ac6f3', '0101010120010101', - 'NIST SP800-17 B.2 #30'), - (SP800_17_B2_PT, '9db73b3c0d163f54', '0101010110010101', - 'NIST SP800-17 B.2 #31'), - (SP800_17_B2_PT, '8181b65babf4a975', '0101010108010101', - 'NIST SP800-17 B.2 #32'), - (SP800_17_B2_PT, '93c9b64042eaa240', '0101010104010101', - 'NIST SP800-17 B.2 #33'), - (SP800_17_B2_PT, '5570530829705592', '0101010102010101', - 'NIST SP800-17 B.2 #34'), - (SP800_17_B2_PT, '8638809e878787a0', '0101010101800101', - 'NIST SP800-17 B.2 #35'), - (SP800_17_B2_PT, '41b9a79af79ac208', '0101010101400101', - 'NIST SP800-17 B.2 #36'), - (SP800_17_B2_PT, '7a9be42f2009a892', '0101010101200101', - 'NIST SP800-17 B.2 #37'), - (SP800_17_B2_PT, '29038d56ba6d2745', '0101010101100101', - 'NIST SP800-17 B.2 #38'), - (SP800_17_B2_PT, '5495c6abf1e5df51', '0101010101080101', - 'NIST SP800-17 B.2 #39'), - (SP800_17_B2_PT, 'ae13dbd561488933', '0101010101040101', - 'NIST SP800-17 B.2 #40'), - (SP800_17_B2_PT, '024d1ffa8904e389', '0101010101020101', - 'NIST SP800-17 B.2 #41'), - (SP800_17_B2_PT, 'd1399712f99bf02e', '0101010101018001', - 'NIST SP800-17 B.2 #42'), - (SP800_17_B2_PT, '14c1d7c1cffec79e', '0101010101014001', - 'NIST SP800-17 B.2 #43'), - (SP800_17_B2_PT, '1de5279dae3bed6f', '0101010101012001', - 'NIST SP800-17 B.2 #44'), - (SP800_17_B2_PT, 'e941a33f85501303', '0101010101011001', - 'NIST SP800-17 B.2 #45'), - (SP800_17_B2_PT, 'da99dbbc9a03f379', '0101010101010801', - 'NIST SP800-17 B.2 #46'), - (SP800_17_B2_PT, 'b7fc92f91d8e92e9', '0101010101010401', - 'NIST SP800-17 B.2 #47'), - (SP800_17_B2_PT, 'ae8e5caa3ca04e85', '0101010101010201', - 'NIST SP800-17 B.2 #48'), - (SP800_17_B2_PT, '9cc62df43b6eed74', '0101010101010180', - 'NIST SP800-17 B.2 #49'), - (SP800_17_B2_PT, 'd863dbb5c59a91a0', '0101010101010140', - 'NIST SP800-17 B.2 #50'), - (SP800_17_B2_PT, 'a1ab2190545b91d7', '0101010101010120', - 'NIST SP800-17 B.2 #51'), - (SP800_17_B2_PT, '0875041e64c570f7', '0101010101010110', - 'NIST SP800-17 B.2 #52'), - (SP800_17_B2_PT, '5a594528bebef1cc', '0101010101010108', - 'NIST SP800-17 B.2 #53'), - (SP800_17_B2_PT, 'fcdb3291de21f0c0', '0101010101010104', - 'NIST SP800-17 B.2 #54'), - (SP800_17_B2_PT, '869efd7f9f265a09', '0101010101010102', - 'NIST SP800-17 B.2 #55'), -] - -class RonRivestTest(unittest.TestCase): - """ Ronald L. Rivest's DES test, see - http://people.csail.mit.edu/rivest/Destest.txt - ABSTRACT - -------- - - We present a simple way to test the correctness of a DES implementation: - Use the recurrence relation: - - X0 = 9474B8E8C73BCA7D (hexadecimal) - - X(i+1) = IF (i is even) THEN E(Xi,Xi) ELSE D(Xi,Xi) - - to compute a sequence of 64-bit values: X0, X1, X2, ..., X16. Here - E(X,K) denotes the DES encryption of X using key K, and D(X,K) denotes - the DES decryption of X using key K. If you obtain - - X16 = 1B1A2DDB4C642438 - - your implementation does not have any of the 36,568 possible single-fault - errors described herein. - """ - def runTest(self): - from binascii import b2a_hex - - X = [] - X[0:] = [b'\x94\x74\xB8\xE8\xC7\x3B\xCA\x7D'] - - for i in range(16): - c = DES.new(X[i],DES.MODE_ECB) - if not (i&1): # (num&1) returns 1 for odd numbers - X[i+1:] = [c.encrypt(X[i])] # even - else: - X[i+1:] = [c.decrypt(X[i])] # odd - - self.assertEqual(b2a_hex(X[16]), - b2a_hex(b'\x1B\x1A\x2D\xDB\x4C\x64\x24\x38')) - - -class TestOutput(unittest.TestCase): - - def runTest(self): - # Encrypt/Decrypt data and test output parameter - - cipher = DES.new(b'4'*8, DES.MODE_ECB) - - pt = b'5' * 8 - ct = cipher.encrypt(pt) - - output = bytearray(8) - res = cipher.encrypt(pt, output=output) - self.assertEqual(ct, output) - self.assertEqual(res, None) - - res = cipher.decrypt(ct, output=output) - self.assertEqual(pt, output) - self.assertEqual(res, None) - - output = memoryview(bytearray(8)) - cipher.encrypt(pt, output=output) - self.assertEqual(ct, output) - - cipher.decrypt(ct, output=output) - self.assertEqual(pt, output) - - self.assertRaises(TypeError, cipher.encrypt, pt, output=b'0'*8) - self.assertRaises(TypeError, cipher.decrypt, ct, output=b'0'*8) - - shorter_output = bytearray(7) - self.assertRaises(ValueError, cipher.encrypt, pt, output=shorter_output) - self.assertRaises(ValueError, cipher.decrypt, ct, output=shorter_output) - - -def get_tests(config={}): - from .common import make_block_tests - tests = make_block_tests(DES, "DES", test_data) - tests += [RonRivestTest()] - tests += [TestOutput()] - return tests - - -if __name__ == '__main__': - import unittest - suite = lambda: unittest.TestSuite(get_tests()) - unittest.main(defaultTest='suite') - -# vim:set ts=4 sw=4 sts=4 expandtab: diff --git a/Crypto/SelfTest/Cipher/test_DES3.py b/Crypto/SelfTest/Cipher/test_DES3.py deleted file mode 100644 index 8d6a648..0000000 --- a/Crypto/SelfTest/Cipher/test_DES3.py +++ /dev/null @@ -1,195 +0,0 @@ -# -*- coding: utf-8 -*- -# -# SelfTest/Cipher/DES3.py: Self-test for the Triple-DES cipher -# -# Written in 2008 by Dwayne C. Litzenberger -# -# =================================================================== -# The contents of this file are dedicated to the public domain. To -# the extent that dedication to the public domain is not available, -# everyone is granted a worldwide, perpetual, royalty-free, -# non-exclusive license to exercise all rights associated with the -# contents of this file for any purpose whatsoever. -# No rights are reserved. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS -# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN -# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# =================================================================== - -"""Self-test suite for Crypto.Cipher.DES3""" - -import unittest -from binascii import hexlify, unhexlify - -from Crypto.Cipher import DES3 - -from Crypto.Util.strxor import strxor_c -from Crypto.Util.py3compat import bchr, tostr -from Crypto.SelfTest.loader import load_test_vectors -from Crypto.SelfTest.st_common import list_test_cases - -# This is a list of (plaintext, ciphertext, key, description) tuples. -test_data = [ - # Test vector from Appendix B of NIST SP 800-67 - # "Recommendation for the Triple Data Encryption Algorithm (TDEA) Block - # Cipher" - # http://csrc.nist.gov/publications/nistpubs/800-67/SP800-67.pdf - ('54686520717566636b2062726f776e20666f78206a756d70', - 'a826fd8ce53b855fcce21c8112256fe668d5c05dd9b6b900', - '0123456789abcdef23456789abcdef01456789abcdef0123', - 'NIST SP800-67 B.1'), - - # This test is designed to test the DES3 API, not the correctness of the - # output. - ('21e81b7ade88a259', '5c577d4d9b20c0f8', - '9b397ebf81b1181e282f4bb8adbadc6b', 'Two-key 3DES'), -] - -# NIST CAVP test vectors - -nist_tdes_mmt_files = ("TECBMMT2.rsp", "TECBMMT3.rsp") - -for tdes_file in nist_tdes_mmt_files: - - test_vectors = load_test_vectors( - ("Cipher", "TDES"), - tdes_file, - "TDES ECB (%s)" % tdes_file, - {"count": lambda x: int(x)}) or [] - - for index, tv in enumerate(test_vectors): - - # The test vector file contains some directive lines - if isinstance(tv, str): - continue - - key = tv.key1 + tv.key2 + tv.key3 - test_data_item = (tostr(hexlify(tv.plaintext)), - tostr(hexlify(tv.ciphertext)), - tostr(hexlify(key)), - "%s (%s)" % (tdes_file, index)) - test_data.append(test_data_item) - - -class CheckParity(unittest.TestCase): - - def test_parity_option2(self): - before_2k = unhexlify("CABF326FA56734324FFCCABCDEFACABF") - after_2k = DES3.adjust_key_parity(before_2k) - self.assertEqual(after_2k, - unhexlify("CBBF326EA46734324FFDCBBCDFFBCBBF")) - - def test_parity_option3(self): - before_3k = unhexlify("AAAAAAAAAAAAAAAABBBBBBBBBBBBBBBBCCCCCCCCCCCCCCCC") - after_3k = DES3.adjust_key_parity(before_3k) - self.assertEqual(after_3k, - unhexlify("ABABABABABABABABBABABABABABABABACDCDCDCDCDCDCDCD")) - - def test_degradation(self): - sub_key1 = bchr(1) * 8 - sub_key2 = bchr(255) * 8 - - # K1 == K2 - self.assertRaises(ValueError, DES3.adjust_key_parity, - sub_key1 * 2 + sub_key2) - - # K2 == K3 - self.assertRaises(ValueError, DES3.adjust_key_parity, - sub_key1 + sub_key2 * 2) - - # K1 == K2 == K3 - self.assertRaises(ValueError, DES3.adjust_key_parity, - sub_key1 * 3) - - # K1 == K2 (with different parity) - self.assertRaises(ValueError, DES3.adjust_key_parity, - sub_key1 + strxor_c(sub_key1, 1) + sub_key2) - - -class DegenerateToDESTest(unittest.TestCase): - - def runTest(self): - sub_key1 = bchr(1) * 8 - sub_key2 = bchr(255) * 8 - - # K1 == K2 - self.assertRaises(ValueError, DES3.new, - sub_key1 * 2 + sub_key2, - DES3.MODE_ECB) - - # K2 == K3 - self.assertRaises(ValueError, DES3.new, - sub_key1 + sub_key2 * 2, - DES3.MODE_ECB) - - # K1 == K2 == K3 - self.assertRaises(ValueError, DES3.new, - sub_key1 * 3, - DES3.MODE_ECB) - - # K2 == K3 (parity is ignored) - self.assertRaises(ValueError, DES3.new, - sub_key1 + sub_key2 + strxor_c(sub_key2, 0x1), - DES3.MODE_ECB) - - -class TestOutput(unittest.TestCase): - - def runTest(self): - # Encrypt/Decrypt data and test output parameter - - cipher = DES3.new(b'4'*8 + b'G'*8 + b'T'*8, DES3.MODE_ECB) - - pt = b'5' * 16 - ct = cipher.encrypt(pt) - - output = bytearray(16) - res = cipher.encrypt(pt, output=output) - self.assertEqual(ct, output) - self.assertEqual(res, None) - - res = cipher.decrypt(ct, output=output) - self.assertEqual(pt, output) - self.assertEqual(res, None) - - output = memoryview(bytearray(16)) - cipher.encrypt(pt, output=output) - self.assertEqual(ct, output) - - cipher.decrypt(ct, output=output) - self.assertEqual(pt, output) - - self.assertRaises(TypeError, cipher.encrypt, pt, output=b'0'*16) - self.assertRaises(TypeError, cipher.decrypt, ct, output=b'0'*16) - - shorter_output = bytearray(7) - self.assertRaises(ValueError, cipher.encrypt, pt, output=shorter_output) - self.assertRaises(ValueError, cipher.decrypt, ct, output=shorter_output) - - -def get_tests(config={}): - from .common import make_block_tests - - tests = [] - tests = make_block_tests(DES3, "DES3", test_data) - tests.append(DegenerateToDESTest()) - tests += list_test_cases(CheckParity) - tests += [TestOutput()] - return tests - - -if __name__ == '__main__': - import unittest - - def suite(): - unittest.TestSuite(get_tests()) - - unittest.main(defaultTest='suite') - -# vim:set ts=4 sw=4 sts=4 expandtab: diff --git a/Crypto/SelfTest/Cipher/test_EAX.py b/Crypto/SelfTest/Cipher/test_EAX.py deleted file mode 100644 index ad88262..0000000 --- a/Crypto/SelfTest/Cipher/test_EAX.py +++ /dev/null @@ -1,772 +0,0 @@ -# =================================================================== -# -# Copyright (c) 2015, Legrandin -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# =================================================================== - -import unittest -from binascii import unhexlify - -from Crypto.SelfTest.st_common import list_test_cases -from Crypto.SelfTest.loader import load_test_vectors_wycheproof -from Crypto.Util.py3compat import tobytes, bchr -from Crypto.Cipher import AES, DES3 -from Crypto.Hash import SHAKE128 - -from Crypto.Util.strxor import strxor - - -def get_tag_random(tag, length): - return SHAKE128.new(data=tobytes(tag)).read(length) - - -class EaxTests(unittest.TestCase): - - key_128 = get_tag_random("key_128", 16) - key_192 = get_tag_random("key_192", 16) - nonce_96 = get_tag_random("nonce_128", 12) - data_128 = get_tag_random("data_128", 16) - - def test_loopback_128(self): - cipher = AES.new(self.key_128, AES.MODE_EAX, nonce=self.nonce_96) - pt = get_tag_random("plaintext", 16 * 100) - ct = cipher.encrypt(pt) - - cipher = AES.new(self.key_128, AES.MODE_EAX, nonce=self.nonce_96) - pt2 = cipher.decrypt(ct) - self.assertEqual(pt, pt2) - - def test_loopback_64(self): - cipher = DES3.new(self.key_192, DES3.MODE_EAX, nonce=self.nonce_96) - pt = get_tag_random("plaintext", 8 * 100) - ct = cipher.encrypt(pt) - - cipher = DES3.new(self.key_192, DES3.MODE_EAX, nonce=self.nonce_96) - pt2 = cipher.decrypt(ct) - self.assertEqual(pt, pt2) - - def test_nonce(self): - # If not passed, the nonce is created randomly - cipher = AES.new(self.key_128, AES.MODE_EAX) - nonce1 = cipher.nonce - cipher = AES.new(self.key_128, AES.MODE_EAX) - nonce2 = cipher.nonce - self.assertEqual(len(nonce1), 16) - self.assertNotEqual(nonce1, nonce2) - - cipher = AES.new(self.key_128, AES.MODE_EAX, self.nonce_96) - ct = cipher.encrypt(self.data_128) - - cipher = AES.new(self.key_128, AES.MODE_EAX, nonce=self.nonce_96) - self.assertEquals(ct, cipher.encrypt(self.data_128)) - - def test_nonce_must_be_bytes(self): - self.assertRaises(TypeError, AES.new, self.key_128, AES.MODE_EAX, - nonce=u'test12345678') - - def test_nonce_length(self): - # nonce can be of any length (but not empty) - self.assertRaises(ValueError, AES.new, self.key_128, AES.MODE_EAX, - nonce=b"") - - for x in range(1, 128): - cipher = AES.new(self.key_128, AES.MODE_EAX, nonce=bchr(1) * x) - cipher.encrypt(bchr(1)) - - def test_block_size_128(self): - cipher = AES.new(self.key_128, AES.MODE_EAX, nonce=self.nonce_96) - self.assertEqual(cipher.block_size, AES.block_size) - - def test_block_size_64(self): - cipher = DES3.new(self.key_192, AES.MODE_EAX, nonce=self.nonce_96) - self.assertEqual(cipher.block_size, DES3.block_size) - - def test_nonce_attribute(self): - cipher = AES.new(self.key_128, AES.MODE_EAX, nonce=self.nonce_96) - self.assertEqual(cipher.nonce, self.nonce_96) - - # By default, a 16 bytes long nonce is randomly generated - nonce1 = AES.new(self.key_128, AES.MODE_EAX).nonce - nonce2 = AES.new(self.key_128, AES.MODE_EAX).nonce - self.assertEqual(len(nonce1), 16) - self.assertNotEqual(nonce1, nonce2) - - def test_unknown_parameters(self): - self.assertRaises(TypeError, AES.new, self.key_128, AES.MODE_EAX, - self.nonce_96, 7) - self.assertRaises(TypeError, AES.new, self.key_128, AES.MODE_EAX, - nonce=self.nonce_96, unknown=7) - - # But some are only known by the base cipher - # (e.g. use_aesni consumed by the AES module) - AES.new(self.key_128, AES.MODE_EAX, nonce=self.nonce_96, - use_aesni=False) - - def test_null_encryption_decryption(self): - for func in "encrypt", "decrypt": - cipher = AES.new(self.key_128, AES.MODE_EAX, nonce=self.nonce_96) - result = getattr(cipher, func)(b"") - self.assertEqual(result, b"") - - def test_either_encrypt_or_decrypt(self): - cipher = AES.new(self.key_128, AES.MODE_EAX, nonce=self.nonce_96) - cipher.encrypt(b"") - self.assertRaises(TypeError, cipher.decrypt, b"") - - cipher = AES.new(self.key_128, AES.MODE_EAX, nonce=self.nonce_96) - cipher.decrypt(b"") - self.assertRaises(TypeError, cipher.encrypt, b"") - - def test_data_must_be_bytes(self): - cipher = AES.new(self.key_128, AES.MODE_EAX, nonce=self.nonce_96) - self.assertRaises(TypeError, cipher.encrypt, u'test1234567890-*') - - cipher = AES.new(self.key_128, AES.MODE_EAX, nonce=self.nonce_96) - self.assertRaises(TypeError, cipher.decrypt, u'test1234567890-*') - - def test_mac_len(self): - # Invalid MAC length - self.assertRaises(ValueError, AES.new, self.key_128, AES.MODE_EAX, - nonce=self.nonce_96, mac_len=3) - self.assertRaises(ValueError, AES.new, self.key_128, AES.MODE_EAX, - nonce=self.nonce_96, mac_len=16+1) - - # Valid MAC length - for mac_len in range(5, 16 + 1): - cipher = AES.new(self.key_128, AES.MODE_EAX, nonce=self.nonce_96, - mac_len=mac_len) - _, mac = cipher.encrypt_and_digest(self.data_128) - self.assertEqual(len(mac), mac_len) - - # Default MAC length - cipher = AES.new(self.key_128, AES.MODE_EAX, nonce=self.nonce_96) - _, mac = cipher.encrypt_and_digest(self.data_128) - self.assertEqual(len(mac), 16) - - def test_invalid_mac(self): - from Crypto.Util.strxor import strxor_c - cipher = AES.new(self.key_128, AES.MODE_EAX, nonce=self.nonce_96) - ct, mac = cipher.encrypt_and_digest(self.data_128) - - invalid_mac = strxor_c(mac, 0x01) - - cipher = AES.new(self.key_128, AES.MODE_EAX, nonce=self.nonce_96) - self.assertRaises(ValueError, cipher.decrypt_and_verify, ct, - invalid_mac) - - def test_hex_mac(self): - cipher = AES.new(self.key_128, AES.MODE_EAX, nonce=self.nonce_96) - mac_hex = cipher.hexdigest() - self.assertEqual(cipher.digest(), unhexlify(mac_hex)) - - cipher = AES.new(self.key_128, AES.MODE_EAX, nonce=self.nonce_96) - cipher.hexverify(mac_hex) - - def test_message_chunks(self): - # Validate that both associated data and plaintext/ciphertext - # can be broken up in chunks of arbitrary length - - auth_data = get_tag_random("authenticated data", 127) - plaintext = get_tag_random("plaintext", 127) - - cipher = AES.new(self.key_128, AES.MODE_EAX, nonce=self.nonce_96) - cipher.update(auth_data) - ciphertext, ref_mac = cipher.encrypt_and_digest(plaintext) - - def break_up(data, chunk_length): - return [data[i:i+chunk_length] for i in range(0, len(data), - chunk_length)] - - # Encryption - for chunk_length in 1, 2, 3, 7, 10, 13, 16, 40, 80, 128: - - cipher = AES.new(self.key_128, AES.MODE_EAX, nonce=self.nonce_96) - - for chunk in break_up(auth_data, chunk_length): - cipher.update(chunk) - pt2 = b"" - for chunk in break_up(ciphertext, chunk_length): - pt2 += cipher.decrypt(chunk) - self.assertEqual(plaintext, pt2) - cipher.verify(ref_mac) - - # Decryption - for chunk_length in 1, 2, 3, 7, 10, 13, 16, 40, 80, 128: - - cipher = AES.new(self.key_128, AES.MODE_EAX, nonce=self.nonce_96) - - for chunk in break_up(auth_data, chunk_length): - cipher.update(chunk) - ct2 = b"" - for chunk in break_up(plaintext, chunk_length): - ct2 += cipher.encrypt(chunk) - self.assertEqual(ciphertext, ct2) - self.assertEquals(cipher.digest(), ref_mac) - - def test_bytearray(self): - - # Encrypt - key_ba = bytearray(self.key_128) - nonce_ba = bytearray(self.nonce_96) - header_ba = bytearray(self.data_128) - data_ba = bytearray(self.data_128) - - cipher1 = AES.new(self.key_128, - AES.MODE_EAX, - nonce=self.nonce_96) - cipher1.update(self.data_128) - ct = cipher1.encrypt(self.data_128) - tag = cipher1.digest() - - cipher2 = AES.new(key_ba, - AES.MODE_EAX, - nonce=nonce_ba) - key_ba[:3] = b'\xFF\xFF\xFF' - nonce_ba[:3] = b'\xFF\xFF\xFF' - cipher2.update(header_ba) - header_ba[:3] = b'\xFF\xFF\xFF' - ct_test = cipher2.encrypt(data_ba) - data_ba[:3] = b'\x99\x99\x99' - tag_test = cipher2.digest() - - self.assertEqual(ct, ct_test) - self.assertEqual(tag, tag_test) - self.assertEqual(cipher1.nonce, cipher2.nonce) - - # Decrypt - key_ba = bytearray(self.key_128) - nonce_ba = bytearray(self.nonce_96) - header_ba = bytearray(self.data_128) - ct_ba = bytearray(ct) - tag_ba = bytearray(tag) - del data_ba - - cipher3 = AES.new(key_ba, - AES.MODE_EAX, - nonce=nonce_ba) - key_ba[:3] = b'\xFF\xFF\xFF' - nonce_ba[:3] = b'\xFF\xFF\xFF' - cipher3.update(header_ba) - header_ba[:3] = b'\xFF\xFF\xFF' - pt_test = cipher3.decrypt(ct_ba) - ct_ba[:3] = b'\xFF\xFF\xFF' - cipher3.verify(tag_ba) - - self.assertEqual(pt_test, self.data_128) - - def test_memoryview(self): - - # Encrypt - key_mv = memoryview(bytearray(self.key_128)) - nonce_mv = memoryview(bytearray(self.nonce_96)) - header_mv = memoryview(bytearray(self.data_128)) - data_mv = memoryview(bytearray(self.data_128)) - - cipher1 = AES.new(self.key_128, - AES.MODE_EAX, - nonce=self.nonce_96) - cipher1.update(self.data_128) - ct = cipher1.encrypt(self.data_128) - tag = cipher1.digest() - - cipher2 = AES.new(key_mv, - AES.MODE_EAX, - nonce=nonce_mv) - key_mv[:3] = b'\xFF\xFF\xFF' - nonce_mv[:3] = b'\xFF\xFF\xFF' - cipher2.update(header_mv) - header_mv[:3] = b'\xFF\xFF\xFF' - ct_test = cipher2.encrypt(data_mv) - data_mv[:3] = b'\x99\x99\x99' - tag_test = cipher2.digest() - - self.assertEqual(ct, ct_test) - self.assertEqual(tag, tag_test) - self.assertEqual(cipher1.nonce, cipher2.nonce) - - # Decrypt - key_mv = memoryview(bytearray(self.key_128)) - nonce_mv = memoryview(bytearray(self.nonce_96)) - header_mv = memoryview(bytearray(self.data_128)) - ct_mv = memoryview(bytearray(ct)) - tag_mv = memoryview(bytearray(tag)) - del data_mv - - cipher3 = AES.new(key_mv, - AES.MODE_EAX, - nonce=nonce_mv) - key_mv[:3] = b'\xFF\xFF\xFF' - nonce_mv[:3] = b'\xFF\xFF\xFF' - cipher3.update(header_mv) - header_mv[:3] = b'\xFF\xFF\xFF' - pt_test = cipher3.decrypt(ct_mv) - ct_mv[:3] = b'\x99\x99\x99' - cipher3.verify(tag_mv) - - self.assertEqual(pt_test, self.data_128) - - def test_output_param(self): - - pt = b'5' * 16 - cipher = AES.new(self.key_128, AES.MODE_EAX, nonce=self.nonce_96) - ct = cipher.encrypt(pt) - tag = cipher.digest() - - output = bytearray(16) - cipher = AES.new(self.key_128, AES.MODE_EAX, nonce=self.nonce_96) - res = cipher.encrypt(pt, output=output) - self.assertEqual(ct, output) - self.assertEqual(res, None) - - cipher = AES.new(self.key_128, AES.MODE_EAX, nonce=self.nonce_96) - res = cipher.decrypt(ct, output=output) - self.assertEqual(pt, output) - self.assertEqual(res, None) - - cipher = AES.new(self.key_128, AES.MODE_EAX, nonce=self.nonce_96) - res, tag_out = cipher.encrypt_and_digest(pt, output=output) - self.assertEqual(ct, output) - self.assertEqual(res, None) - self.assertEqual(tag, tag_out) - - cipher = AES.new(self.key_128, AES.MODE_EAX, nonce=self.nonce_96) - res = cipher.decrypt_and_verify(ct, tag, output=output) - self.assertEqual(pt, output) - self.assertEqual(res, None) - - def test_output_param_memoryview(self): - - pt = b'5' * 16 - cipher = AES.new(self.key_128, AES.MODE_EAX, nonce=self.nonce_96) - ct = cipher.encrypt(pt) - - output = memoryview(bytearray(16)) - cipher = AES.new(self.key_128, AES.MODE_EAX, nonce=self.nonce_96) - cipher.encrypt(pt, output=output) - self.assertEqual(ct, output) - - cipher = AES.new(self.key_128, AES.MODE_EAX, nonce=self.nonce_96) - cipher.decrypt(ct, output=output) - self.assertEqual(pt, output) - - def test_output_param_neg(self): - - pt = b'5' * 16 - cipher = AES.new(self.key_128, AES.MODE_EAX, nonce=self.nonce_96) - ct = cipher.encrypt(pt) - - cipher = AES.new(self.key_128, AES.MODE_EAX, nonce=self.nonce_96) - self.assertRaises(TypeError, cipher.encrypt, pt, output=b'0'*16) - - cipher = AES.new(self.key_128, AES.MODE_EAX, nonce=self.nonce_96) - self.assertRaises(TypeError, cipher.decrypt, ct, output=b'0'*16) - - shorter_output = bytearray(15) - cipher = AES.new(self.key_128, AES.MODE_EAX, nonce=self.nonce_96) - self.assertRaises(ValueError, cipher.encrypt, pt, output=shorter_output) - cipher = AES.new(self.key_128, AES.MODE_EAX, nonce=self.nonce_96) - self.assertRaises(ValueError, cipher.decrypt, ct, output=shorter_output) - - -class EaxFSMTests(unittest.TestCase): - - key_128 = get_tag_random("key_128", 16) - nonce_96 = get_tag_random("nonce_128", 12) - data_128 = get_tag_random("data_128", 16) - - def test_valid_init_encrypt_decrypt_digest_verify(self): - # No authenticated data, fixed plaintext - # Verify path INIT->ENCRYPT->DIGEST - cipher = AES.new(self.key_128, AES.MODE_EAX, - nonce=self.nonce_96) - ct = cipher.encrypt(self.data_128) - mac = cipher.digest() - - # Verify path INIT->DECRYPT->VERIFY - cipher = AES.new(self.key_128, AES.MODE_EAX, - nonce=self.nonce_96) - cipher.decrypt(ct) - cipher.verify(mac) - - def test_valid_init_update_digest_verify(self): - # No plaintext, fixed authenticated data - # Verify path INIT->UPDATE->DIGEST - cipher = AES.new(self.key_128, AES.MODE_EAX, - nonce=self.nonce_96) - cipher.update(self.data_128) - mac = cipher.digest() - - # Verify path INIT->UPDATE->VERIFY - cipher = AES.new(self.key_128, AES.MODE_EAX, - nonce=self.nonce_96) - cipher.update(self.data_128) - cipher.verify(mac) - - def test_valid_full_path(self): - # Fixed authenticated data, fixed plaintext - # Verify path INIT->UPDATE->ENCRYPT->DIGEST - cipher = AES.new(self.key_128, AES.MODE_EAX, - nonce=self.nonce_96) - cipher.update(self.data_128) - ct = cipher.encrypt(self.data_128) - mac = cipher.digest() - - # Verify path INIT->UPDATE->DECRYPT->VERIFY - cipher = AES.new(self.key_128, AES.MODE_EAX, - nonce=self.nonce_96) - cipher.update(self.data_128) - cipher.decrypt(ct) - cipher.verify(mac) - - def test_valid_init_digest(self): - # Verify path INIT->DIGEST - cipher = AES.new(self.key_128, AES.MODE_EAX, nonce=self.nonce_96) - cipher.digest() - - def test_valid_init_verify(self): - # Verify path INIT->VERIFY - cipher = AES.new(self.key_128, AES.MODE_EAX, nonce=self.nonce_96) - mac = cipher.digest() - - cipher = AES.new(self.key_128, AES.MODE_EAX, nonce=self.nonce_96) - cipher.verify(mac) - - def test_valid_multiple_encrypt_or_decrypt(self): - for method_name in "encrypt", "decrypt": - for auth_data in (None, b"333", self.data_128, - self.data_128 + b"3"): - if auth_data is None: - assoc_len = None - else: - assoc_len = len(auth_data) - cipher = AES.new(self.key_128, AES.MODE_EAX, - nonce=self.nonce_96) - if auth_data is not None: - cipher.update(auth_data) - method = getattr(cipher, method_name) - method(self.data_128) - method(self.data_128) - method(self.data_128) - method(self.data_128) - - def test_valid_multiple_digest_or_verify(self): - # Multiple calls to digest - cipher = AES.new(self.key_128, AES.MODE_EAX, nonce=self.nonce_96) - cipher.update(self.data_128) - first_mac = cipher.digest() - for x in range(4): - self.assertEqual(first_mac, cipher.digest()) - - # Multiple calls to verify - cipher = AES.new(self.key_128, AES.MODE_EAX, nonce=self.nonce_96) - cipher.update(self.data_128) - for x in range(5): - cipher.verify(first_mac) - - def test_valid_encrypt_and_digest_decrypt_and_verify(self): - # encrypt_and_digest - cipher = AES.new(self.key_128, AES.MODE_EAX, nonce=self.nonce_96) - cipher.update(self.data_128) - ct, mac = cipher.encrypt_and_digest(self.data_128) - - # decrypt_and_verify - cipher = AES.new(self.key_128, AES.MODE_EAX, nonce=self.nonce_96) - cipher.update(self.data_128) - pt = cipher.decrypt_and_verify(ct, mac) - self.assertEqual(self.data_128, pt) - - def test_invalid_mixing_encrypt_decrypt(self): - # Once per method, with or without assoc. data - for method1_name, method2_name in (("encrypt", "decrypt"), - ("decrypt", "encrypt")): - for assoc_data_present in (True, False): - cipher = AES.new(self.key_128, AES.MODE_EAX, - nonce=self.nonce_96) - if assoc_data_present: - cipher.update(self.data_128) - getattr(cipher, method1_name)(self.data_128) - self.assertRaises(TypeError, getattr(cipher, method2_name), - self.data_128) - - def test_invalid_encrypt_or_update_after_digest(self): - for method_name in "encrypt", "update": - cipher = AES.new(self.key_128, AES.MODE_EAX, nonce=self.nonce_96) - cipher.encrypt(self.data_128) - cipher.digest() - self.assertRaises(TypeError, getattr(cipher, method_name), - self.data_128) - - cipher = AES.new(self.key_128, AES.MODE_EAX, nonce=self.nonce_96) - cipher.encrypt_and_digest(self.data_128) - - def test_invalid_decrypt_or_update_after_verify(self): - cipher = AES.new(self.key_128, AES.MODE_EAX, nonce=self.nonce_96) - ct = cipher.encrypt(self.data_128) - mac = cipher.digest() - - for method_name in "decrypt", "update": - cipher = AES.new(self.key_128, AES.MODE_EAX, nonce=self.nonce_96) - cipher.decrypt(ct) - cipher.verify(mac) - self.assertRaises(TypeError, getattr(cipher, method_name), - self.data_128) - - cipher = AES.new(self.key_128, AES.MODE_EAX, nonce=self.nonce_96) - cipher.decrypt_and_verify(ct, mac) - self.assertRaises(TypeError, getattr(cipher, method_name), - self.data_128) - - -class TestVectorsPaper(unittest.TestCase): - """Class exercising the EAX test vectors found in - http://www.cs.ucdavis.edu/~rogaway/papers/eax.pdf""" - - test_vectors_hex = [ - ( '6bfb914fd07eae6b', - '', - '', - 'e037830e8389f27b025a2d6527e79d01', - '233952dee4d5ed5f9b9c6d6ff80ff478', - '62EC67F9C3A4A407FCB2A8C49031A8B3' - ), - ( - 'fa3bfd4806eb53fa', - 'f7fb', - '19dd', - '5c4c9331049d0bdab0277408f67967e5', - '91945d3f4dcbee0bf45ef52255f095a4', - 'BECAF043B0A23D843194BA972C66DEBD' - ), - ( '234a3463c1264ac6', - '1a47cb4933', - 'd851d5bae0', - '3a59f238a23e39199dc9266626c40f80', - '01f74ad64077f2e704c0f60ada3dd523', - '70C3DB4F0D26368400A10ED05D2BFF5E' - ), - ( - '33cce2eabff5a79d', - '481c9e39b1', - '632a9d131a', - 'd4c168a4225d8e1ff755939974a7bede', - 'd07cf6cbb7f313bdde66b727afd3c5e8', - '8408DFFF3C1A2B1292DC199E46B7D617' - ), - ( - 'aeb96eaebe2970e9', - '40d0c07da5e4', - '071dfe16c675', - 'cb0677e536f73afe6a14b74ee49844dd', - '35b6d0580005bbc12b0587124557d2c2', - 'FDB6B06676EEDC5C61D74276E1F8E816' - ), - ( - 'd4482d1ca78dce0f', - '4de3b35c3fc039245bd1fb7d', - '835bb4f15d743e350e728414', - 'abb8644fd6ccb86947c5e10590210a4f', - 'bd8e6e11475e60b268784c38c62feb22', - '6EAC5C93072D8E8513F750935E46DA1B' - ), - ( - '65d2017990d62528', - '8b0a79306c9ce7ed99dae4f87f8dd61636', - '02083e3979da014812f59f11d52630da30', - '137327d10649b0aa6e1c181db617d7f2', - '7c77d6e813bed5ac98baa417477a2e7d', - '1A8C98DCD73D38393B2BF1569DEEFC19' - ), - ( - '54b9f04e6a09189a', - '1bda122bce8a8dbaf1877d962b8592dd2d56', - '2ec47b2c4954a489afc7ba4897edcdae8cc3', - '3b60450599bd02c96382902aef7f832a', - '5fff20cafab119ca2fc73549e20f5b0d', - 'DDE59B97D722156D4D9AFF2BC7559826' - ), - ( - '899a175897561d7e', - '6cf36720872b8513f6eab1a8a44438d5ef11', - '0de18fd0fdd91e7af19f1d8ee8733938b1e8', - 'e7f6d2231618102fdb7fe55ff1991700', - 'a4a4782bcffd3ec5e7ef6d8c34a56123', - 'B781FCF2F75FA5A8DE97A9CA48E522EC' - ), - ( - '126735fcc320d25a', - 'ca40d7446e545ffaed3bd12a740a659ffbbb3ceab7', - 'cb8920f87a6c75cff39627b56e3ed197c552d295a7', - 'cfc46afc253b4652b1af3795b124ab6e', - '8395fcf1e95bebd697bd010bc766aac3', - '22E7ADD93CFC6393C57EC0B3C17D6B44' - ), - ] - - test_vectors = [[unhexlify(x) 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: - # Encrypt - cipher = AES.new(key, AES.MODE_EAX, nonce, mac_len=len(mac)) - cipher.update(assoc_data) - ct2, mac2 = cipher.encrypt_and_digest(pt) - self.assertEqual(ct, ct2) - self.assertEqual(mac, mac2) - - # Decrypt - cipher = AES.new(key, AES.MODE_EAX, nonce, mac_len=len(mac)) - cipher.update(assoc_data) - pt2 = cipher.decrypt_and_verify(ct, mac) - self.assertEqual(pt, pt2) - - -class TestVectorsWycheproof(unittest.TestCase): - - def __init__(self, wycheproof_warnings): - unittest.TestCase.__init__(self) - self._wycheproof_warnings = wycheproof_warnings - self._id = "None" - - def setUp(self): - - def filter_tag(group): - return group['tagSize'] // 8 - - self.tv = load_test_vectors_wycheproof(("Cipher", "wycheproof"), - "aes_eax_test.json", - "Wycheproof EAX", - group_tag={'tag_size': filter_tag}) - - def shortDescription(self): - return self._id - - def warn(self, tv): - if tv.warning and self._wycheproof_warnings: - import warnings - warnings.warn("Wycheproof warning: %s (%s)" % (self._id, tv.comment)) - - def test_encrypt(self, tv): - self._id = "Wycheproof Encrypt EAX Test #" + str(tv.id) - - try: - cipher = AES.new(tv.key, AES.MODE_EAX, tv.iv, mac_len=tv.tag_size) - except ValueError as e: - assert len(tv.iv) == 0 and "Nonce cannot be empty" in str(e) - return - - cipher.update(tv.aad) - ct, tag = cipher.encrypt_and_digest(tv.msg) - if tv.valid: - self.assertEqual(ct, tv.ct) - self.assertEqual(tag, tv.tag) - self.warn(tv) - - def test_decrypt(self, tv): - self._id = "Wycheproof Decrypt EAX Test #" + str(tv.id) - - try: - cipher = AES.new(tv.key, AES.MODE_EAX, tv.iv, mac_len=tv.tag_size) - except ValueError as e: - assert len(tv.iv) == 0 and "Nonce cannot be empty" in str(e) - return - - cipher.update(tv.aad) - try: - pt = cipher.decrypt_and_verify(tv.ct, tv.tag) - except ValueError: - assert not tv.valid - else: - assert tv.valid - self.assertEqual(pt, tv.msg) - self.warn(tv) - - def test_corrupt_decrypt(self, tv): - self._id = "Wycheproof Corrupt Decrypt EAX Test #" + str(tv.id) - if len(tv.iv) == 0 or len(tv.ct) < 1: - return - cipher = AES.new(tv.key, AES.MODE_EAX, tv.iv, mac_len=tv.tag_size) - cipher.update(tv.aad) - ct_corrupt = strxor(tv.ct, b"\x00" * (len(tv.ct) - 1) + b"\x01") - self.assertRaises(ValueError, cipher.decrypt_and_verify, ct_corrupt, tv.tag) - - def runTest(self): - - for tv in self.tv: - self.test_encrypt(tv) - self.test_decrypt(tv) - self.test_corrupt_decrypt(tv) - - -class TestOtherCiphers(unittest.TestCase): - - @classmethod - def create_test(cls, name, factory, key_size): - - def test_template(self, factory=factory, key_size=key_size): - cipher = factory.new(get_tag_random("cipher", key_size), - factory.MODE_EAX, - nonce=b"nonce") - ct, mac = cipher.encrypt_and_digest(b"plaintext") - - cipher = factory.new(get_tag_random("cipher", key_size), - factory.MODE_EAX, - nonce=b"nonce") - pt2 = cipher.decrypt_and_verify(ct, mac) - - self.assertEqual(b"plaintext", pt2) - - setattr(cls, "test_" + name, test_template) - - -from Crypto.Cipher import DES, DES3, ARC2, CAST, Blowfish - -TestOtherCiphers.create_test("DES_" + str(DES.key_size), DES, DES.key_size) -for ks in DES3.key_size: - TestOtherCiphers.create_test("DES3_" + str(ks), DES3, ks) -for ks in ARC2.key_size: - TestOtherCiphers.create_test("ARC2_" + str(ks), ARC2, ks) -for ks in CAST.key_size: - TestOtherCiphers.create_test("CAST_" + str(ks), CAST, ks) -for ks in Blowfish.key_size: - TestOtherCiphers.create_test("Blowfish_" + str(ks), Blowfish, ks) - - -def get_tests(config={}): - wycheproof_warnings = config.get('wycheproof_warnings') - - tests = [] - tests += list_test_cases(EaxTests) - tests += list_test_cases(EaxFSMTests) - tests += [ TestVectorsPaper() ] - tests += [ TestVectorsWycheproof(wycheproof_warnings) ] - tests += list_test_cases(TestOtherCiphers) - return tests - - -if __name__ == '__main__': - suite = lambda: unittest.TestSuite(get_tests()) - unittest.main(defaultTest='suite') diff --git a/Crypto/SelfTest/Cipher/test_GCM.py b/Crypto/SelfTest/Cipher/test_GCM.py deleted file mode 100644 index 5e7694f..0000000 --- a/Crypto/SelfTest/Cipher/test_GCM.py +++ /dev/null @@ -1,950 +0,0 @@ -# =================================================================== -# -# Copyright (c) 2015, Legrandin -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# =================================================================== - -from __future__ import print_function - -import unittest -from binascii import unhexlify - -from Crypto.SelfTest.st_common import list_test_cases -from Crypto.SelfTest.loader import load_test_vectors, load_test_vectors_wycheproof - -from Crypto.Util.py3compat import tobytes, bchr -from Crypto.Cipher import AES -from Crypto.Hash import SHAKE128, SHA256 - -from Crypto.Util.strxor import strxor - - -def get_tag_random(tag, length): - return SHAKE128.new(data=tobytes(tag)).read(length) - - -class GcmTests(unittest.TestCase): - - key_128 = get_tag_random("key_128", 16) - nonce_96 = get_tag_random("nonce_128", 12) - data_128 = get_tag_random("data_128", 16) - - def test_loopback_128(self): - cipher = AES.new(self.key_128, AES.MODE_GCM, nonce=self.nonce_96) - pt = get_tag_random("plaintext", 16 * 100) - ct = cipher.encrypt(pt) - - cipher = AES.new(self.key_128, AES.MODE_GCM, nonce=self.nonce_96) - pt2 = cipher.decrypt(ct) - self.assertEqual(pt, pt2) - - def test_nonce(self): - # Nonce is optional (a random one will be created) - AES.new(self.key_128, AES.MODE_GCM) - - cipher = AES.new(self.key_128, AES.MODE_GCM, self.nonce_96) - ct = cipher.encrypt(self.data_128) - - cipher = AES.new(self.key_128, AES.MODE_GCM, nonce=self.nonce_96) - self.assertEquals(ct, cipher.encrypt(self.data_128)) - - def test_nonce_must_be_bytes(self): - self.assertRaises(TypeError, AES.new, self.key_128, AES.MODE_GCM, - nonce=u'test12345678') - - def test_nonce_length(self): - # nonce can be of any length (but not empty) - self.assertRaises(ValueError, AES.new, self.key_128, AES.MODE_GCM, - nonce=b"") - - for x in range(1, 128): - cipher = AES.new(self.key_128, AES.MODE_GCM, nonce=bchr(1) * x) - cipher.encrypt(bchr(1)) - - def test_block_size_128(self): - cipher = AES.new(self.key_128, AES.MODE_GCM, nonce=self.nonce_96) - self.assertEqual(cipher.block_size, AES.block_size) - - def test_nonce_attribute(self): - cipher = AES.new(self.key_128, AES.MODE_GCM, nonce=self.nonce_96) - self.assertEqual(cipher.nonce, self.nonce_96) - - # By default, a 15 bytes long nonce is randomly generated - nonce1 = AES.new(self.key_128, AES.MODE_GCM).nonce - nonce2 = AES.new(self.key_128, AES.MODE_GCM).nonce - self.assertEqual(len(nonce1), 16) - self.assertNotEqual(nonce1, nonce2) - - def test_unknown_parameters(self): - self.assertRaises(TypeError, AES.new, self.key_128, AES.MODE_GCM, - self.nonce_96, 7) - self.assertRaises(TypeError, AES.new, self.key_128, AES.MODE_GCM, - nonce=self.nonce_96, unknown=7) - - # But some are only known by the base cipher - # (e.g. use_aesni consumed by the AES module) - AES.new(self.key_128, AES.MODE_GCM, nonce=self.nonce_96, - use_aesni=False) - - def test_null_encryption_decryption(self): - for func in "encrypt", "decrypt": - cipher = AES.new(self.key_128, AES.MODE_GCM, nonce=self.nonce_96) - result = getattr(cipher, func)(b"") - self.assertEqual(result, b"") - - def test_either_encrypt_or_decrypt(self): - cipher = AES.new(self.key_128, AES.MODE_GCM, nonce=self.nonce_96) - cipher.encrypt(b"") - self.assertRaises(TypeError, cipher.decrypt, b"") - - cipher = AES.new(self.key_128, AES.MODE_GCM, nonce=self.nonce_96) - cipher.decrypt(b"") - self.assertRaises(TypeError, cipher.encrypt, b"") - - def test_data_must_be_bytes(self): - cipher = AES.new(self.key_128, AES.MODE_GCM, nonce=self.nonce_96) - self.assertRaises(TypeError, cipher.encrypt, u'test1234567890-*') - - cipher = AES.new(self.key_128, AES.MODE_GCM, nonce=self.nonce_96) - self.assertRaises(TypeError, cipher.decrypt, u'test1234567890-*') - - def test_mac_len(self): - # Invalid MAC length - self.assertRaises(ValueError, AES.new, self.key_128, AES.MODE_GCM, - nonce=self.nonce_96, mac_len=3) - self.assertRaises(ValueError, AES.new, self.key_128, AES.MODE_GCM, - nonce=self.nonce_96, mac_len=16+1) - - # Valid MAC length - for mac_len in range(5, 16 + 1): - cipher = AES.new(self.key_128, AES.MODE_GCM, nonce=self.nonce_96, - mac_len=mac_len) - _, mac = cipher.encrypt_and_digest(self.data_128) - self.assertEqual(len(mac), mac_len) - - # Default MAC length - cipher = AES.new(self.key_128, AES.MODE_GCM, nonce=self.nonce_96) - _, mac = cipher.encrypt_and_digest(self.data_128) - self.assertEqual(len(mac), 16) - - def test_invalid_mac(self): - from Crypto.Util.strxor import strxor_c - cipher = AES.new(self.key_128, AES.MODE_GCM, nonce=self.nonce_96) - ct, mac = cipher.encrypt_and_digest(self.data_128) - - invalid_mac = strxor_c(mac, 0x01) - - cipher = AES.new(self.key_128, AES.MODE_GCM, nonce=self.nonce_96) - self.assertRaises(ValueError, cipher.decrypt_and_verify, ct, - invalid_mac) - - def test_hex_mac(self): - cipher = AES.new(self.key_128, AES.MODE_GCM, nonce=self.nonce_96) - mac_hex = cipher.hexdigest() - self.assertEqual(cipher.digest(), unhexlify(mac_hex)) - - cipher = AES.new(self.key_128, AES.MODE_GCM, nonce=self.nonce_96) - cipher.hexverify(mac_hex) - - def test_message_chunks(self): - # Validate that both associated data and plaintext/ciphertext - # can be broken up in chunks of arbitrary length - - auth_data = get_tag_random("authenticated data", 127) - plaintext = get_tag_random("plaintext", 127) - - cipher = AES.new(self.key_128, AES.MODE_GCM, nonce=self.nonce_96) - cipher.update(auth_data) - ciphertext, ref_mac = cipher.encrypt_and_digest(plaintext) - - def break_up(data, chunk_length): - return [data[i:i+chunk_length] for i in range(0, len(data), - chunk_length)] - - # Encryption - for chunk_length in 1, 2, 3, 7, 10, 13, 16, 40, 80, 128: - - cipher = AES.new(self.key_128, AES.MODE_GCM, nonce=self.nonce_96) - - for chunk in break_up(auth_data, chunk_length): - cipher.update(chunk) - pt2 = b"" - for chunk in break_up(ciphertext, chunk_length): - pt2 += cipher.decrypt(chunk) - self.assertEqual(plaintext, pt2) - cipher.verify(ref_mac) - - # Decryption - for chunk_length in 1, 2, 3, 7, 10, 13, 16, 40, 80, 128: - - cipher = AES.new(self.key_128, AES.MODE_GCM, nonce=self.nonce_96) - - for chunk in break_up(auth_data, chunk_length): - cipher.update(chunk) - ct2 = b"" - for chunk in break_up(plaintext, chunk_length): - ct2 += cipher.encrypt(chunk) - self.assertEqual(ciphertext, ct2) - self.assertEquals(cipher.digest(), ref_mac) - - def test_bytearray(self): - - # Encrypt - key_ba = bytearray(self.key_128) - nonce_ba = bytearray(self.nonce_96) - header_ba = bytearray(self.data_128) - data_ba = bytearray(self.data_128) - - cipher1 = AES.new(self.key_128, - AES.MODE_GCM, - nonce=self.nonce_96) - cipher1.update(self.data_128) - ct = cipher1.encrypt(self.data_128) - tag = cipher1.digest() - - cipher2 = AES.new(key_ba, - AES.MODE_GCM, - nonce=nonce_ba) - key_ba[:3] = b"\xFF\xFF\xFF" - nonce_ba[:3] = b"\xFF\xFF\xFF" - cipher2.update(header_ba) - header_ba[:3] = b"\xFF\xFF\xFF" - ct_test = cipher2.encrypt(data_ba) - data_ba[:3] = b"\xFF\xFF\xFF" - tag_test = cipher2.digest() - - self.assertEqual(ct, ct_test) - self.assertEqual(tag, tag_test) - self.assertEqual(cipher1.nonce, cipher2.nonce) - - # Decrypt - key_ba = bytearray(self.key_128) - nonce_ba = bytearray(self.nonce_96) - header_ba = bytearray(self.data_128) - del data_ba - - cipher4 = AES.new(key_ba, - AES.MODE_GCM, - nonce=nonce_ba) - key_ba[:3] = b"\xFF\xFF\xFF" - nonce_ba[:3] = b"\xFF\xFF\xFF" - cipher4.update(header_ba) - header_ba[:3] = b"\xFF\xFF\xFF" - pt_test = cipher4.decrypt_and_verify(bytearray(ct_test), bytearray(tag_test)) - - self.assertEqual(self.data_128, pt_test) - - def test_memoryview(self): - - # Encrypt - key_mv = memoryview(bytearray(self.key_128)) - nonce_mv = memoryview(bytearray(self.nonce_96)) - header_mv = memoryview(bytearray(self.data_128)) - data_mv = memoryview(bytearray(self.data_128)) - - cipher1 = AES.new(self.key_128, - AES.MODE_GCM, - nonce=self.nonce_96) - cipher1.update(self.data_128) - ct = cipher1.encrypt(self.data_128) - tag = cipher1.digest() - - cipher2 = AES.new(key_mv, - AES.MODE_GCM, - nonce=nonce_mv) - key_mv[:3] = b"\xFF\xFF\xFF" - nonce_mv[:3] = b"\xFF\xFF\xFF" - cipher2.update(header_mv) - header_mv[:3] = b"\xFF\xFF\xFF" - ct_test = cipher2.encrypt(data_mv) - data_mv[:3] = b"\xFF\xFF\xFF" - tag_test = cipher2.digest() - - self.assertEqual(ct, ct_test) - self.assertEqual(tag, tag_test) - self.assertEqual(cipher1.nonce, cipher2.nonce) - - # Decrypt - key_mv = memoryview(bytearray(self.key_128)) - nonce_mv = memoryview(bytearray(self.nonce_96)) - header_mv = memoryview(bytearray(self.data_128)) - del data_mv - - cipher4 = AES.new(key_mv, - AES.MODE_GCM, - nonce=nonce_mv) - key_mv[:3] = b"\xFF\xFF\xFF" - nonce_mv[:3] = b"\xFF\xFF\xFF" - cipher4.update(header_mv) - header_mv[:3] = b"\xFF\xFF\xFF" - pt_test = cipher4.decrypt_and_verify(memoryview(ct_test), memoryview(tag_test)) - - self.assertEqual(self.data_128, pt_test) - - def test_output_param(self): - - pt = b'5' * 16 - cipher = AES.new(self.key_128, AES.MODE_GCM, nonce=self.nonce_96) - ct = cipher.encrypt(pt) - tag = cipher.digest() - - output = bytearray(16) - cipher = AES.new(self.key_128, AES.MODE_GCM, nonce=self.nonce_96) - res = cipher.encrypt(pt, output=output) - self.assertEqual(ct, output) - self.assertEqual(res, None) - - cipher = AES.new(self.key_128, AES.MODE_GCM, nonce=self.nonce_96) - res = cipher.decrypt(ct, output=output) - self.assertEqual(pt, output) - self.assertEqual(res, None) - - cipher = AES.new(self.key_128, AES.MODE_GCM, nonce=self.nonce_96) - res, tag_out = cipher.encrypt_and_digest(pt, output=output) - self.assertEqual(ct, output) - self.assertEqual(res, None) - self.assertEqual(tag, tag_out) - - cipher = AES.new(self.key_128, AES.MODE_GCM, nonce=self.nonce_96) - res = cipher.decrypt_and_verify(ct, tag, output=output) - self.assertEqual(pt, output) - self.assertEqual(res, None) - - def test_output_param_memoryview(self): - - pt = b'5' * 16 - cipher = AES.new(self.key_128, AES.MODE_GCM, nonce=self.nonce_96) - ct = cipher.encrypt(pt) - - output = memoryview(bytearray(16)) - cipher = AES.new(self.key_128, AES.MODE_GCM, nonce=self.nonce_96) - cipher.encrypt(pt, output=output) - self.assertEqual(ct, output) - - cipher = AES.new(self.key_128, AES.MODE_GCM, nonce=self.nonce_96) - cipher.decrypt(ct, output=output) - self.assertEqual(pt, output) - - def test_output_param_neg(self): - - pt = b'5' * 16 - cipher = AES.new(self.key_128, AES.MODE_GCM, nonce=self.nonce_96) - ct = cipher.encrypt(pt) - - cipher = AES.new(self.key_128, AES.MODE_GCM, nonce=self.nonce_96) - self.assertRaises(TypeError, cipher.encrypt, pt, output=b'0'*16) - - cipher = AES.new(self.key_128, AES.MODE_GCM, nonce=self.nonce_96) - self.assertRaises(TypeError, cipher.decrypt, ct, output=b'0'*16) - - shorter_output = bytearray(15) - cipher = AES.new(self.key_128, AES.MODE_GCM, nonce=self.nonce_96) - self.assertRaises(ValueError, cipher.encrypt, pt, output=shorter_output) - cipher = AES.new(self.key_128, AES.MODE_GCM, nonce=self.nonce_96) - self.assertRaises(ValueError, cipher.decrypt, ct, output=shorter_output) - - -class GcmFSMTests(unittest.TestCase): - - key_128 = get_tag_random("key_128", 16) - nonce_96 = get_tag_random("nonce_128", 12) - data_128 = get_tag_random("data_128", 16) - - def test_valid_init_encrypt_decrypt_digest_verify(self): - # No authenticated data, fixed plaintext - # Verify path INIT->ENCRYPT->DIGEST - cipher = AES.new(self.key_128, AES.MODE_GCM, - nonce=self.nonce_96) - ct = cipher.encrypt(self.data_128) - mac = cipher.digest() - - # Verify path INIT->DECRYPT->VERIFY - cipher = AES.new(self.key_128, AES.MODE_GCM, - nonce=self.nonce_96) - cipher.decrypt(ct) - cipher.verify(mac) - - def test_valid_init_update_digest_verify(self): - # No plaintext, fixed authenticated data - # Verify path INIT->UPDATE->DIGEST - cipher = AES.new(self.key_128, AES.MODE_GCM, - nonce=self.nonce_96) - cipher.update(self.data_128) - mac = cipher.digest() - - # Verify path INIT->UPDATE->VERIFY - cipher = AES.new(self.key_128, AES.MODE_GCM, - nonce=self.nonce_96) - cipher.update(self.data_128) - cipher.verify(mac) - - def test_valid_full_path(self): - # Fixed authenticated data, fixed plaintext - # Verify path INIT->UPDATE->ENCRYPT->DIGEST - cipher = AES.new(self.key_128, AES.MODE_GCM, - nonce=self.nonce_96) - cipher.update(self.data_128) - ct = cipher.encrypt(self.data_128) - mac = cipher.digest() - - # Verify path INIT->UPDATE->DECRYPT->VERIFY - cipher = AES.new(self.key_128, AES.MODE_GCM, - nonce=self.nonce_96) - cipher.update(self.data_128) - cipher.decrypt(ct) - cipher.verify(mac) - - def test_valid_init_digest(self): - # Verify path INIT->DIGEST - cipher = AES.new(self.key_128, AES.MODE_GCM, nonce=self.nonce_96) - cipher.digest() - - def test_valid_init_verify(self): - # Verify path INIT->VERIFY - cipher = AES.new(self.key_128, AES.MODE_GCM, nonce=self.nonce_96) - mac = cipher.digest() - - cipher = AES.new(self.key_128, AES.MODE_GCM, nonce=self.nonce_96) - cipher.verify(mac) - - def test_valid_multiple_encrypt_or_decrypt(self): - for method_name in "encrypt", "decrypt": - for auth_data in (None, b"333", self.data_128, - self.data_128 + b"3"): - if auth_data is None: - assoc_len = None - else: - assoc_len = len(auth_data) - cipher = AES.new(self.key_128, AES.MODE_GCM, - nonce=self.nonce_96) - if auth_data is not None: - cipher.update(auth_data) - method = getattr(cipher, method_name) - method(self.data_128) - method(self.data_128) - method(self.data_128) - method(self.data_128) - - def test_valid_multiple_digest_or_verify(self): - # Multiple calls to digest - cipher = AES.new(self.key_128, AES.MODE_GCM, nonce=self.nonce_96) - cipher.update(self.data_128) - first_mac = cipher.digest() - for x in range(4): - self.assertEqual(first_mac, cipher.digest()) - - # Multiple calls to verify - cipher = AES.new(self.key_128, AES.MODE_GCM, nonce=self.nonce_96) - cipher.update(self.data_128) - for x in range(5): - cipher.verify(first_mac) - - def test_valid_encrypt_and_digest_decrypt_and_verify(self): - # encrypt_and_digest - cipher = AES.new(self.key_128, AES.MODE_GCM, nonce=self.nonce_96) - cipher.update(self.data_128) - ct, mac = cipher.encrypt_and_digest(self.data_128) - - # decrypt_and_verify - cipher = AES.new(self.key_128, AES.MODE_GCM, nonce=self.nonce_96) - cipher.update(self.data_128) - pt = cipher.decrypt_and_verify(ct, mac) - self.assertEqual(self.data_128, pt) - - def test_invalid_mixing_encrypt_decrypt(self): - # Once per method, with or without assoc. data - for method1_name, method2_name in (("encrypt", "decrypt"), - ("decrypt", "encrypt")): - for assoc_data_present in (True, False): - cipher = AES.new(self.key_128, AES.MODE_GCM, - nonce=self.nonce_96) - if assoc_data_present: - cipher.update(self.data_128) - getattr(cipher, method1_name)(self.data_128) - self.assertRaises(TypeError, getattr(cipher, method2_name), - self.data_128) - - def test_invalid_encrypt_or_update_after_digest(self): - for method_name in "encrypt", "update": - cipher = AES.new(self.key_128, AES.MODE_GCM, nonce=self.nonce_96) - cipher.encrypt(self.data_128) - cipher.digest() - self.assertRaises(TypeError, getattr(cipher, method_name), - self.data_128) - - cipher = AES.new(self.key_128, AES.MODE_GCM, nonce=self.nonce_96) - cipher.encrypt_and_digest(self.data_128) - - def test_invalid_decrypt_or_update_after_verify(self): - cipher = AES.new(self.key_128, AES.MODE_GCM, nonce=self.nonce_96) - ct = cipher.encrypt(self.data_128) - mac = cipher.digest() - - for method_name in "decrypt", "update": - cipher = AES.new(self.key_128, AES.MODE_GCM, nonce=self.nonce_96) - cipher.decrypt(ct) - cipher.verify(mac) - self.assertRaises(TypeError, getattr(cipher, method_name), - self.data_128) - - cipher = AES.new(self.key_128, AES.MODE_GCM, nonce=self.nonce_96) - cipher.decrypt_and_verify(ct, mac) - self.assertRaises(TypeError, getattr(cipher, method_name), - self.data_128) - - -class TestVectors(unittest.TestCase): - """Class exercising the GCM test vectors found in - http://csrc.nist.gov/groups/ST/toolkit/BCM/documents/proposedmodes/gcm/gcm-revised-spec.pdf""" - - # List of test vectors, each made up of: - # - authenticated data - # - plaintext - # - ciphertext - # - MAC - # - AES key - # - nonce - test_vectors_hex = [ - ( - '', - '', - '', - '58e2fccefa7e3061367f1d57a4e7455a', - '00000000000000000000000000000000', - '000000000000000000000000' - ), - ( - '', - '00000000000000000000000000000000', - '0388dace60b6a392f328c2b971b2fe78', - 'ab6e47d42cec13bdf53a67b21257bddf', - '00000000000000000000000000000000', - '000000000000000000000000' - ), - ( - '', - 'd9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a72' + - '1c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b391aafd255', - '42831ec2217774244b7221b784d0d49ce3aa212f2c02a4e035c17e2329aca12e' + - '21d514b25466931c7d8f6a5aac84aa051ba30b396a0aac973d58e091473f5985', - '4d5c2af327cd64a62cf35abd2ba6fab4', - 'feffe9928665731c6d6a8f9467308308', - 'cafebabefacedbaddecaf888' - ), - ( - 'feedfacedeadbeeffeedfacedeadbeefabaddad2', - 'd9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a72' + - '1c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39', - '42831ec2217774244b7221b784d0d49ce3aa212f2c02a4e035c17e2329aca12e' + - '21d514b25466931c7d8f6a5aac84aa051ba30b396a0aac973d58e091', - '5bc94fbc3221a5db94fae95ae7121a47', - 'feffe9928665731c6d6a8f9467308308', - 'cafebabefacedbaddecaf888' - ), - ( - 'feedfacedeadbeeffeedfacedeadbeefabaddad2', - 'd9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a72' + - '1c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39', - '61353b4c2806934a777ff51fa22a4755699b2a714fcdc6f83766e5f97b6c7423' + - '73806900e49f24b22b097544d4896b424989b5e1ebac0f07c23f4598', - '3612d2e79e3b0785561be14aaca2fccb', - 'feffe9928665731c6d6a8f9467308308', - 'cafebabefacedbad' - ), - ( - 'feedfacedeadbeeffeedfacedeadbeefabaddad2', - 'd9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a72' + - '1c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39', - '8ce24998625615b603a033aca13fb894be9112a5c3a211a8ba262a3cca7e2ca7' + - '01e4a9a4fba43c90ccdcb281d48c7c6fd62875d2aca417034c34aee5', - '619cc5aefffe0bfa462af43c1699d050', - 'feffe9928665731c6d6a8f9467308308', - '9313225df88406e555909c5aff5269aa' + - '6a7a9538534f7da1e4c303d2a318a728c3c0c95156809539fcf0e2429a6b5254' + - '16aedbf5a0de6a57a637b39b' - ), - ( - '', - '', - '', - 'cd33b28ac773f74ba00ed1f312572435', - '000000000000000000000000000000000000000000000000', - '000000000000000000000000' - ), - ( - '', - '00000000000000000000000000000000', - '98e7247c07f0fe411c267e4384b0f600', - '2ff58d80033927ab8ef4d4587514f0fb', - '000000000000000000000000000000000000000000000000', - '000000000000000000000000' - ), - ( - '', - 'd9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a72' + - '1c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b391aafd255', - '3980ca0b3c00e841eb06fac4872a2757859e1ceaa6efd984628593b40ca1e19c' + - '7d773d00c144c525ac619d18c84a3f4718e2448b2fe324d9ccda2710acade256', - '9924a7c8587336bfb118024db8674a14', - 'feffe9928665731c6d6a8f9467308308feffe9928665731c', - 'cafebabefacedbaddecaf888' - ), - ( - 'feedfacedeadbeeffeedfacedeadbeefabaddad2', - 'd9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a72' + - '1c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39', - '3980ca0b3c00e841eb06fac4872a2757859e1ceaa6efd984628593b40ca1e19c' + - '7d773d00c144c525ac619d18c84a3f4718e2448b2fe324d9ccda2710', - '2519498e80f1478f37ba55bd6d27618c', - 'feffe9928665731c6d6a8f9467308308feffe9928665731c', - 'cafebabefacedbaddecaf888' - ), - ( - 'feedfacedeadbeeffeedfacedeadbeefabaddad2', - 'd9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a72' + - '1c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39', - '0f10f599ae14a154ed24b36e25324db8c566632ef2bbb34f8347280fc4507057' + - 'fddc29df9a471f75c66541d4d4dad1c9e93a19a58e8b473fa0f062f7', - '65dcc57fcf623a24094fcca40d3533f8', - 'feffe9928665731c6d6a8f9467308308feffe9928665731c', - 'cafebabefacedbad' - ), - ( - 'feedfacedeadbeeffeedfacedeadbeefabaddad2', - 'd9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a72' + - '1c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39', - 'd27e88681ce3243c4830165a8fdcf9ff1de9a1d8e6b447ef6ef7b79828666e45' + - '81e79012af34ddd9e2f037589b292db3e67c036745fa22e7e9b7373b', - 'dcf566ff291c25bbb8568fc3d376a6d9', - 'feffe9928665731c6d6a8f9467308308feffe9928665731c', - '9313225df88406e555909c5aff5269aa' + - '6a7a9538534f7da1e4c303d2a318a728c3c0c95156809539fcf0e2429a6b5254' + - '16aedbf5a0de6a57a637b39b' - ), - ( - '', - '', - '', - '530f8afbc74536b9a963b4f1c4cb738b', - '0000000000000000000000000000000000000000000000000000000000000000', - '000000000000000000000000' - ), - ( - '', - '00000000000000000000000000000000', - 'cea7403d4d606b6e074ec5d3baf39d18', - 'd0d1c8a799996bf0265b98b5d48ab919', - '0000000000000000000000000000000000000000000000000000000000000000', - '000000000000000000000000' - ), - ( '', - 'd9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a72' + - '1c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b391aafd255', - '522dc1f099567d07f47f37a32a84427d643a8cdcbfe5c0c97598a2bd2555d1aa' + - '8cb08e48590dbb3da7b08b1056828838c5f61e6393ba7a0abcc9f662898015ad', - 'b094dac5d93471bdec1a502270e3cc6c', - 'feffe9928665731c6d6a8f9467308308feffe9928665731c6d6a8f9467308308', - 'cafebabefacedbaddecaf888' - ), - ( - 'feedfacedeadbeeffeedfacedeadbeefabaddad2', - 'd9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a72' + - '1c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39', - '522dc1f099567d07f47f37a32a84427d643a8cdcbfe5c0c97598a2bd2555d1aa' + - '8cb08e48590dbb3da7b08b1056828838c5f61e6393ba7a0abcc9f662', - '76fc6ece0f4e1768cddf8853bb2d551b', - 'feffe9928665731c6d6a8f9467308308feffe9928665731c6d6a8f9467308308', - 'cafebabefacedbaddecaf888' - ), - ( - 'feedfacedeadbeeffeedfacedeadbeefabaddad2', - 'd9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a72' + - '1c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39', - 'c3762df1ca787d32ae47c13bf19844cbaf1ae14d0b976afac52ff7d79bba9de0' + - 'feb582d33934a4f0954cc2363bc73f7862ac430e64abe499f47c9b1f', - '3a337dbf46a792c45e454913fe2ea8f2', - 'feffe9928665731c6d6a8f9467308308feffe9928665731c6d6a8f9467308308', - 'cafebabefacedbad' - ), - ( - 'feedfacedeadbeeffeedfacedeadbeefabaddad2', - 'd9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a72' + - '1c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39', - '5a8def2f0c9e53f1f75d7853659e2a20eeb2b22aafde6419a058ab4f6f746bf4' + - '0fc0c3b780f244452da3ebf1c5d82cdea2418997200ef82e44ae7e3f', - 'a44a8266ee1c8eb0c8b5d4cf5ae9f19a', - 'feffe9928665731c6d6a8f9467308308feffe9928665731c6d6a8f9467308308', - '9313225df88406e555909c5aff5269aa' + - '6a7a9538534f7da1e4c303d2a318a728c3c0c95156809539fcf0e2429a6b5254' + - '16aedbf5a0de6a57a637b39b' - ) - ] - - test_vectors = [[unhexlify(x) 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: - - # Encrypt - cipher = AES.new(key, AES.MODE_GCM, nonce, mac_len=len(mac)) - cipher.update(assoc_data) - ct2, mac2 = cipher.encrypt_and_digest(pt) - self.assertEqual(ct, ct2) - self.assertEqual(mac, mac2) - - # Decrypt - cipher = AES.new(key, AES.MODE_GCM, nonce, mac_len=len(mac)) - cipher.update(assoc_data) - pt2 = cipher.decrypt_and_verify(ct, mac) - self.assertEqual(pt, pt2) - - -class TestVectorsGueronKrasnov(unittest.TestCase): - """Class exercising the GCM test vectors found in - 'The fragility of AES-GCM authentication algorithm', Gueron, Krasnov - https://eprint.iacr.org/2013/157.pdf""" - - def test_1(self): - key = unhexlify("3da6c536d6295579c0959a7043efb503") - iv = unhexlify("2b926197d34e091ef722db94") - aad = unhexlify("00000000000000000000000000000000" + - "000102030405060708090a0b0c0d0e0f" + - "101112131415161718191a1b1c1d1e1f" + - "202122232425262728292a2b2c2d2e2f" + - "303132333435363738393a3b3c3d3e3f") - digest = unhexlify("69dd586555ce3fcc89663801a71d957b") - - cipher = AES.new(key, AES.MODE_GCM, iv).update(aad) - self.assertEqual(digest, cipher.digest()) - - def test_2(self): - key = unhexlify("843ffcf5d2b72694d19ed01d01249412") - iv = unhexlify("dbcca32ebf9b804617c3aa9e") - aad = unhexlify("00000000000000000000000000000000" + - "101112131415161718191a1b1c1d1e1f") - pt = unhexlify("000102030405060708090a0b0c0d0e0f" + - "101112131415161718191a1b1c1d1e1f" + - "202122232425262728292a2b2c2d2e2f" + - "303132333435363738393a3b3c3d3e3f" + - "404142434445464748494a4b4c4d4e4f") - ct = unhexlify("6268c6fa2a80b2d137467f092f657ac0" + - "4d89be2beaa623d61b5a868c8f03ff95" + - "d3dcee23ad2f1ab3a6c80eaf4b140eb0" + - "5de3457f0fbc111a6b43d0763aa422a3" + - "013cf1dc37fe417d1fbfc449b75d4cc5") - digest = unhexlify("3b629ccfbc1119b7319e1dce2cd6fd6d") - - cipher = AES.new(key, AES.MODE_GCM, iv).update(aad) - ct2, digest2 = cipher.encrypt_and_digest(pt) - - self.assertEqual(ct, ct2) - self.assertEqual(digest, digest2) - - -class NISTTestVectorsGCM(unittest.TestCase): - - def __init__(self, a): - self.use_clmul = True - unittest.TestCase.__init__(self, a) - - -class NISTTestVectorsGCM_no_clmul(unittest.TestCase): - - def __init__(self, a): - self.use_clmul = False - unittest.TestCase.__init__(self, a) - - -test_vectors_nist = load_test_vectors( - ("Cipher", "AES"), - "gcmDecrypt128.rsp", - "GCM decrypt", - {"count": lambda x: int(x)}) or [] - -test_vectors_nist += load_test_vectors( - ("Cipher", "AES"), - "gcmEncryptExtIV128.rsp", - "GCM encrypt", - {"count": lambda x: int(x)}) or [] - -for idx, tv in enumerate(test_vectors_nist): - - # The test vector file contains some directive lines - if isinstance(tv, str): - continue - - def single_test(self, tv=tv): - - self.description = tv.desc - cipher = AES.new(tv.key, AES.MODE_GCM, nonce=tv.iv, - mac_len=len(tv.tag), use_clmul=self.use_clmul) - cipher.update(tv.aad) - if "FAIL" in tv.others: - self.assertRaises(ValueError, cipher.decrypt_and_verify, - tv.ct, tv.tag) - else: - pt = cipher.decrypt_and_verify(tv.ct, tv.tag) - self.assertEqual(pt, tv.pt) - - setattr(NISTTestVectorsGCM, "test_%d" % idx, single_test) - setattr(NISTTestVectorsGCM_no_clmul, "test_%d" % idx, single_test) - - -class TestVectorsWycheproof(unittest.TestCase): - - def __init__(self, wycheproof_warnings, **extra_params): - unittest.TestCase.__init__(self) - self._wycheproof_warnings = wycheproof_warnings - self._extra_params = extra_params - self._id = "None" - - def setUp(self): - - def filter_tag(group): - return group['tagSize'] // 8 - - self.tv = load_test_vectors_wycheproof(("Cipher", "wycheproof"), - "aes_gcm_test.json", - "Wycheproof GCM", - group_tag={'tag_size': filter_tag}) - - def shortDescription(self): - return self._id - - def warn(self, tv): - if tv.warning and self._wycheproof_warnings: - import warnings - warnings.warn("Wycheproof warning: %s (%s)" % (self._id, tv.comment)) - - def test_encrypt(self, tv): - self._id = "Wycheproof Encrypt GCM Test #" + str(tv.id) - - try: - cipher = AES.new(tv.key, AES.MODE_GCM, tv.iv, mac_len=tv.tag_size, - **self._extra_params) - except ValueError as e: - if len(tv.iv) == 0 and "Nonce cannot be empty" in str(e): - return - raise e - - cipher.update(tv.aad) - ct, tag = cipher.encrypt_and_digest(tv.msg) - if tv.valid: - self.assertEqual(ct, tv.ct) - self.assertEqual(tag, tv.tag) - self.warn(tv) - - def test_decrypt(self, tv): - self._id = "Wycheproof Decrypt GCM Test #" + str(tv.id) - - try: - cipher = AES.new(tv.key, AES.MODE_GCM, tv.iv, mac_len=tv.tag_size, - **self._extra_params) - except ValueError as e: - if len(tv.iv) == 0 and "Nonce cannot be empty" in str(e): - return - raise e - - cipher.update(tv.aad) - try: - pt = cipher.decrypt_and_verify(tv.ct, tv.tag) - except ValueError: - assert not tv.valid - else: - assert tv.valid - self.assertEqual(pt, tv.msg) - self.warn(tv) - - def test_corrupt_decrypt(self, tv): - self._id = "Wycheproof Corrupt Decrypt GCM Test #" + str(tv.id) - if len(tv.iv) == 0 or len(tv.ct) < 1: - return - cipher = AES.new(tv.key, AES.MODE_GCM, tv.iv, mac_len=tv.tag_size, - **self._extra_params) - cipher.update(tv.aad) - ct_corrupt = strxor(tv.ct, b"\x00" * (len(tv.ct) - 1) + b"\x01") - self.assertRaises(ValueError, cipher.decrypt_and_verify, ct_corrupt, tv.tag) - - def runTest(self): - - for tv in self.tv: - self.test_encrypt(tv) - self.test_decrypt(tv) - self.test_corrupt_decrypt(tv) - - -class TestVariableLength(unittest.TestCase): - - def __init__(self, **extra_params): - unittest.TestCase.__init__(self) - self._extra_params = extra_params - - def runTest(self): - key = b'0' * 16 - h = SHA256.new() - - for length in range(160): - nonce = '{0:04d}'.format(length).encode('utf-8') - data = bchr(length) * length - cipher = AES.new(key, AES.MODE_GCM, nonce=nonce, **self._extra_params) - ct, tag = cipher.encrypt_and_digest(data) - h.update(ct) - h.update(tag) - - self.assertEqual(h.hexdigest(), "7b7eb1ffbe67a2e53a912067c0ec8e62ebc7ce4d83490ea7426941349811bdf4") - - -def get_tests(config={}): - from Crypto.Util import _cpu_features - - wycheproof_warnings = config.get('wycheproof_warnings') - - tests = [] - tests += list_test_cases(GcmTests) - tests += list_test_cases(GcmFSMTests) - tests += [TestVectors()] - tests += [TestVectorsWycheproof(wycheproof_warnings)] - tests += list_test_cases(TestVectorsGueronKrasnov) - tests += [TestVariableLength()] - if config.get('slow_tests'): - tests += list_test_cases(NISTTestVectorsGCM) - - if _cpu_features.have_clmul(): - tests += [TestVectorsWycheproof(wycheproof_warnings, use_clmul=False)] - tests += [TestVariableLength(use_clmul=False)] - if config.get('slow_tests'): - tests += list_test_cases(NISTTestVectorsGCM_no_clmul) - else: - print("Skipping test of PCLMULDQD in AES GCM") - - return tests - - -if __name__ == '__main__': - def suite(): - unittest.TestSuite(get_tests()) - unittest.main(defaultTest='suite') diff --git a/Crypto/SelfTest/Cipher/test_OCB.py b/Crypto/SelfTest/Cipher/test_OCB.py deleted file mode 100644 index c1baab3..0000000 --- a/Crypto/SelfTest/Cipher/test_OCB.py +++ /dev/null @@ -1,742 +0,0 @@ -# =================================================================== -# -# Copyright (c) 2014, Legrandin -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# =================================================================== - -import os -import re -import unittest -from binascii import hexlify, unhexlify - -from Crypto.Util.py3compat import b, tobytes, bchr -from Crypto.Util.strxor import strxor_c -from Crypto.Util.number import long_to_bytes -from Crypto.SelfTest.st_common import list_test_cases - -from Crypto.Cipher import AES -from Crypto.Hash import SHAKE128 - - -def get_tag_random(tag, length): - return SHAKE128.new(data=tobytes(tag)).read(length) - - -class OcbTests(unittest.TestCase): - - key_128 = get_tag_random("key_128", 16) - nonce_96 = get_tag_random("nonce_128", 12) - data_128 = get_tag_random("data_128", 16) - - def test_loopback_128(self): - cipher = AES.new(self.key_128, AES.MODE_OCB, nonce=self.nonce_96) - pt = get_tag_random("plaintext", 16 * 100) - ct, mac = cipher.encrypt_and_digest(pt) - - cipher = AES.new(self.key_128, AES.MODE_OCB, nonce=self.nonce_96) - pt2 = cipher.decrypt_and_verify(ct, mac) - self.assertEqual(pt, pt2) - - def test_nonce(self): - # Nonce is optional - AES.new(self.key_128, AES.MODE_OCB) - - cipher = AES.new(self.key_128, AES.MODE_OCB, self.nonce_96) - ct = cipher.encrypt(self.data_128) - - cipher = AES.new(self.key_128, AES.MODE_OCB, nonce=self.nonce_96) - self.assertEquals(ct, cipher.encrypt(self.data_128)) - - def test_nonce_must_be_bytes(self): - self.assertRaises(TypeError, AES.new, self.key_128, AES.MODE_OCB, - nonce=u'test12345678') - - def test_nonce_length(self): - # nonce cannot be empty - self.assertRaises(ValueError, AES.new, self.key_128, AES.MODE_OCB, - nonce=b("")) - - # nonce can be up to 15 bytes long - for length in range(1, 16): - AES.new(self.key_128, AES.MODE_OCB, nonce=self.data_128[:length]) - - self.assertRaises(ValueError, AES.new, self.key_128, AES.MODE_OCB, - nonce=self.data_128) - - def test_block_size_128(self): - cipher = AES.new(self.key_128, AES.MODE_OCB, nonce=self.nonce_96) - self.assertEqual(cipher.block_size, AES.block_size) - - # By default, a 15 bytes long nonce is randomly generated - nonce1 = AES.new(self.key_128, AES.MODE_OCB).nonce - nonce2 = AES.new(self.key_128, AES.MODE_OCB).nonce - self.assertEqual(len(nonce1), 15) - self.assertNotEqual(nonce1, nonce2) - - def test_nonce_attribute(self): - cipher = AES.new(self.key_128, AES.MODE_OCB, nonce=self.nonce_96) - self.assertEqual(cipher.nonce, self.nonce_96) - - # By default, a 15 bytes long nonce is randomly generated - nonce1 = AES.new(self.key_128, AES.MODE_OCB).nonce - nonce2 = AES.new(self.key_128, AES.MODE_OCB).nonce - self.assertEqual(len(nonce1), 15) - self.assertNotEqual(nonce1, nonce2) - - def test_unknown_parameters(self): - self.assertRaises(TypeError, AES.new, self.key_128, AES.MODE_OCB, - self.nonce_96, 7) - self.assertRaises(TypeError, AES.new, self.key_128, AES.MODE_OCB, - nonce=self.nonce_96, unknown=7) - - # But some are only known by the base cipher - # (e.g. use_aesni consumed by the AES module) - AES.new(self.key_128, AES.MODE_OCB, nonce=self.nonce_96, - use_aesni=False) - - def test_null_encryption_decryption(self): - for func in "encrypt", "decrypt": - cipher = AES.new(self.key_128, AES.MODE_OCB, nonce=self.nonce_96) - result = getattr(cipher, func)(b("")) - self.assertEqual(result, b("")) - - def test_either_encrypt_or_decrypt(self): - cipher = AES.new(self.key_128, AES.MODE_OCB, nonce=self.nonce_96) - cipher.encrypt(b("xyz")) - self.assertRaises(TypeError, cipher.decrypt, b("xyz")) - - cipher = AES.new(self.key_128, AES.MODE_OCB, nonce=self.nonce_96) - cipher.decrypt(b("xyz")) - self.assertRaises(TypeError, cipher.encrypt, b("xyz")) - - def test_data_must_be_bytes(self): - cipher = AES.new(self.key_128, AES.MODE_OCB, nonce=self.nonce_96) - self.assertRaises(TypeError, cipher.encrypt, u'test1234567890-*') - - cipher = AES.new(self.key_128, AES.MODE_OCB, nonce=self.nonce_96) - self.assertRaises(TypeError, cipher.decrypt, u'test1234567890-*') - - def test_mac_len(self): - # Invalid MAC length - self.assertRaises(ValueError, AES.new, self.key_128, AES.MODE_OCB, - nonce=self.nonce_96, mac_len=7) - self.assertRaises(ValueError, AES.new, self.key_128, AES.MODE_OCB, - nonce=self.nonce_96, mac_len=16+1) - - # Valid MAC length - for mac_len in range(8, 16 + 1): - cipher = AES.new(self.key_128, AES.MODE_OCB, nonce=self.nonce_96, - mac_len=mac_len) - _, mac = cipher.encrypt_and_digest(self.data_128) - self.assertEqual(len(mac), mac_len) - - # Default MAC length - cipher = AES.new(self.key_128, AES.MODE_OCB, nonce=self.nonce_96) - _, mac = cipher.encrypt_and_digest(self.data_128) - self.assertEqual(len(mac), 16) - - def test_invalid_mac(self): - from Crypto.Util.strxor import strxor_c - cipher = AES.new(self.key_128, AES.MODE_OCB, nonce=self.nonce_96) - ct, mac = cipher.encrypt_and_digest(self.data_128) - - invalid_mac = strxor_c(mac, 0x01) - - cipher = AES.new(self.key_128, AES.MODE_OCB, nonce=self.nonce_96) - self.assertRaises(ValueError, cipher.decrypt_and_verify, ct, - invalid_mac) - - def test_hex_mac(self): - cipher = AES.new(self.key_128, AES.MODE_OCB, nonce=self.nonce_96) - mac_hex = cipher.hexdigest() - self.assertEqual(cipher.digest(), unhexlify(mac_hex)) - - cipher = AES.new(self.key_128, AES.MODE_OCB, nonce=self.nonce_96) - cipher.hexverify(mac_hex) - - def test_message_chunks(self): - # Validate that both associated data and plaintext/ciphertext - # can be broken up in chunks of arbitrary length - - auth_data = get_tag_random("authenticated data", 127) - plaintext = get_tag_random("plaintext", 127) - - cipher = AES.new(self.key_128, AES.MODE_OCB, nonce=self.nonce_96) - cipher.update(auth_data) - ciphertext, ref_mac = cipher.encrypt_and_digest(plaintext) - - def break_up(data, chunk_length): - return [data[i:i+chunk_length] for i in range(0, len(data), - chunk_length)] - - # Encryption - for chunk_length in 1, 2, 3, 7, 10, 13, 16, 40, 80, 128: - - cipher = AES.new(self.key_128, AES.MODE_OCB, nonce=self.nonce_96) - - for chunk in break_up(auth_data, chunk_length): - cipher.update(chunk) - pt2 = b("") - for chunk in break_up(ciphertext, chunk_length): - pt2 += cipher.decrypt(chunk) - pt2 += cipher.decrypt() - self.assertEqual(plaintext, pt2) - cipher.verify(ref_mac) - - # Decryption - for chunk_length in 1, 2, 3, 7, 10, 13, 16, 40, 80, 128: - - cipher = AES.new(self.key_128, AES.MODE_OCB, nonce=self.nonce_96) - - for chunk in break_up(auth_data, chunk_length): - cipher.update(chunk) - ct2 = b("") - for chunk in break_up(plaintext, chunk_length): - ct2 += cipher.encrypt(chunk) - ct2 += cipher.encrypt() - self.assertEqual(ciphertext, ct2) - self.assertEquals(cipher.digest(), ref_mac) - - def test_bytearray(self): - - # Encrypt - key_ba = bytearray(self.key_128) - nonce_ba = bytearray(self.nonce_96) - header_ba = bytearray(self.data_128) - data_ba = bytearray(self.data_128) - - cipher1 = AES.new(self.key_128, - AES.MODE_OCB, - nonce=self.nonce_96) - cipher1.update(self.data_128) - ct = cipher1.encrypt(self.data_128) + cipher1.encrypt() - tag = cipher1.digest() - - cipher2 = AES.new(key_ba, - AES.MODE_OCB, - nonce=nonce_ba) - key_ba[:3] = b"\xFF\xFF\xFF" - nonce_ba[:3] = b"\xFF\xFF\xFF" - cipher2.update(header_ba) - header_ba[:3] = b"\xFF\xFF\xFF" - ct_test = cipher2.encrypt(data_ba) + cipher2.encrypt() - data_ba[:3] = b"\xFF\xFF\xFF" - tag_test = cipher2.digest() - - self.assertEqual(ct, ct_test) - self.assertEqual(tag, tag_test) - self.assertEqual(cipher1.nonce, cipher2.nonce) - - # Decrypt - key_ba = bytearray(self.key_128) - nonce_ba = bytearray(self.nonce_96) - header_ba = bytearray(self.data_128) - del data_ba - - cipher4 = AES.new(key_ba, - AES.MODE_OCB, - nonce=nonce_ba) - key_ba[:3] = b"\xFF\xFF\xFF" - nonce_ba[:3] = b"\xFF\xFF\xFF" - cipher4.update(header_ba) - header_ba[:3] = b"\xFF\xFF\xFF" - pt_test = cipher4.decrypt_and_verify(bytearray(ct_test), bytearray(tag_test)) - - self.assertEqual(self.data_128, pt_test) - - def test_memoryview(self): - - # Encrypt - key_mv = memoryview(bytearray(self.key_128)) - nonce_mv = memoryview(bytearray(self.nonce_96)) - header_mv = memoryview(bytearray(self.data_128)) - data_mv = memoryview(bytearray(self.data_128)) - - cipher1 = AES.new(self.key_128, - AES.MODE_OCB, - nonce=self.nonce_96) - cipher1.update(self.data_128) - ct = cipher1.encrypt(self.data_128) + cipher1.encrypt() - tag = cipher1.digest() - - cipher2 = AES.new(key_mv, - AES.MODE_OCB, - nonce=nonce_mv) - key_mv[:3] = b"\xFF\xFF\xFF" - nonce_mv[:3] = b"\xFF\xFF\xFF" - cipher2.update(header_mv) - header_mv[:3] = b"\xFF\xFF\xFF" - ct_test = cipher2.encrypt(data_mv) + cipher2.encrypt() - data_mv[:3] = b"\xFF\xFF\xFF" - tag_test = cipher2.digest() - - self.assertEqual(ct, ct_test) - self.assertEqual(tag, tag_test) - self.assertEqual(cipher1.nonce, cipher2.nonce) - - # Decrypt - key_mv = memoryview(bytearray(self.key_128)) - nonce_mv = memoryview(bytearray(self.nonce_96)) - header_mv = memoryview(bytearray(self.data_128)) - del data_mv - - cipher4 = AES.new(key_mv, - AES.MODE_OCB, - nonce=nonce_mv) - key_mv[:3] = b"\xFF\xFF\xFF" - nonce_mv[:3] = b"\xFF\xFF\xFF" - cipher4.update(header_mv) - header_mv[:3] = b"\xFF\xFF\xFF" - pt_test = cipher4.decrypt_and_verify(memoryview(ct_test), memoryview(tag_test)) - - self.assertEqual(self.data_128, pt_test) - - -class OcbFSMTests(unittest.TestCase): - - key_128 = get_tag_random("key_128", 16) - nonce_96 = get_tag_random("nonce_128", 12) - data_128 = get_tag_random("data_128", 16) - - def test_valid_init_encrypt_decrypt_digest_verify(self): - # No authenticated data, fixed plaintext - # Verify path INIT->ENCRYPT->ENCRYPT(NONE)->DIGEST - cipher = AES.new(self.key_128, AES.MODE_OCB, - nonce=self.nonce_96) - ct = cipher.encrypt(self.data_128) - ct += cipher.encrypt() - mac = cipher.digest() - - # Verify path INIT->DECRYPT->DECRYPT(NONCE)->VERIFY - cipher = AES.new(self.key_128, AES.MODE_OCB, - nonce=self.nonce_96) - cipher.decrypt(ct) - cipher.decrypt() - cipher.verify(mac) - - def test_invalid_init_encrypt_decrypt_digest_verify(self): - # No authenticated data, fixed plaintext - # Verify path INIT->ENCRYPT->DIGEST - cipher = AES.new(self.key_128, AES.MODE_OCB, - nonce=self.nonce_96) - ct = cipher.encrypt(self.data_128) - self.assertRaises(TypeError, cipher.digest) - - # Verify path INIT->DECRYPT->VERIFY - cipher = AES.new(self.key_128, AES.MODE_OCB, - nonce=self.nonce_96) - cipher.decrypt(ct) - self.assertRaises(TypeError, cipher.verify) - - def test_valid_init_update_digest_verify(self): - # No plaintext, fixed authenticated data - # Verify path INIT->UPDATE->DIGEST - cipher = AES.new(self.key_128, AES.MODE_OCB, - nonce=self.nonce_96) - cipher.update(self.data_128) - mac = cipher.digest() - - # Verify path INIT->UPDATE->VERIFY - cipher = AES.new(self.key_128, AES.MODE_OCB, - nonce=self.nonce_96) - cipher.update(self.data_128) - cipher.verify(mac) - - def test_valid_full_path(self): - # Fixed authenticated data, fixed plaintext - # Verify path INIT->UPDATE->ENCRYPT->ENCRYPT(NONE)->DIGEST - cipher = AES.new(self.key_128, AES.MODE_OCB, - nonce=self.nonce_96) - cipher.update(self.data_128) - ct = cipher.encrypt(self.data_128) - ct += cipher.encrypt() - mac = cipher.digest() - - # Verify path INIT->UPDATE->DECRYPT->DECRYPT(NONE)->VERIFY - cipher = AES.new(self.key_128, AES.MODE_OCB, - nonce=self.nonce_96) - cipher.update(self.data_128) - cipher.decrypt(ct) - cipher.decrypt() - cipher.verify(mac) - - def test_invalid_encrypt_after_final(self): - cipher = AES.new(self.key_128, AES.MODE_OCB, - nonce=self.nonce_96) - cipher.update(self.data_128) - cipher.encrypt(self.data_128) - cipher.encrypt() - self.assertRaises(TypeError, cipher.encrypt, self.data_128) - - def test_invalid_decrypt_after_final(self): - cipher = AES.new(self.key_128, AES.MODE_OCB, - nonce=self.nonce_96) - cipher.update(self.data_128) - cipher.decrypt(self.data_128) - cipher.decrypt() - self.assertRaises(TypeError, cipher.decrypt, self.data_128) - - def test_valid_init_digest(self): - # Verify path INIT->DIGEST - cipher = AES.new(self.key_128, AES.MODE_OCB, nonce=self.nonce_96) - cipher.digest() - - def test_valid_init_verify(self): - # Verify path INIT->VERIFY - cipher = AES.new(self.key_128, AES.MODE_OCB, nonce=self.nonce_96) - mac = cipher.digest() - - cipher = AES.new(self.key_128, AES.MODE_OCB, nonce=self.nonce_96) - cipher.verify(mac) - - def test_valid_multiple_encrypt_or_decrypt(self): - for method_name in "encrypt", "decrypt": - for auth_data in (None, b("333"), self.data_128, - self.data_128 + b("3")): - if auth_data is None: - assoc_len = None - else: - assoc_len = len(auth_data) - cipher = AES.new(self.key_128, AES.MODE_OCB, - nonce=self.nonce_96) - if auth_data is not None: - cipher.update(auth_data) - method = getattr(cipher, method_name) - method(self.data_128) - method(self.data_128) - method(self.data_128) - method(self.data_128) - method() - - def test_valid_multiple_digest_or_verify(self): - # Multiple calls to digest - cipher = AES.new(self.key_128, AES.MODE_OCB, nonce=self.nonce_96) - cipher.update(self.data_128) - first_mac = cipher.digest() - for x in range(4): - self.assertEqual(first_mac, cipher.digest()) - - # Multiple calls to verify - cipher = AES.new(self.key_128, AES.MODE_OCB, nonce=self.nonce_96) - cipher.update(self.data_128) - for x in range(5): - cipher.verify(first_mac) - - def test_valid_encrypt_and_digest_decrypt_and_verify(self): - # encrypt_and_digest - cipher = AES.new(self.key_128, AES.MODE_OCB, nonce=self.nonce_96) - cipher.update(self.data_128) - ct, mac = cipher.encrypt_and_digest(self.data_128) - - # decrypt_and_verify - cipher = AES.new(self.key_128, AES.MODE_OCB, nonce=self.nonce_96) - cipher.update(self.data_128) - pt = cipher.decrypt_and_verify(ct, mac) - self.assertEqual(self.data_128, pt) - - def test_invalid_mixing_encrypt_decrypt(self): - # Once per method, with or without assoc. data - for method1_name, method2_name in (("encrypt", "decrypt"), - ("decrypt", "encrypt")): - for assoc_data_present in (True, False): - cipher = AES.new(self.key_128, AES.MODE_OCB, - nonce=self.nonce_96) - if assoc_data_present: - cipher.update(self.data_128) - getattr(cipher, method1_name)(self.data_128) - self.assertRaises(TypeError, getattr(cipher, method2_name), - self.data_128) - - def test_invalid_encrypt_or_update_after_digest(self): - for method_name in "encrypt", "update": - cipher = AES.new(self.key_128, AES.MODE_OCB, nonce=self.nonce_96) - cipher.encrypt(self.data_128) - cipher.encrypt() - cipher.digest() - self.assertRaises(TypeError, getattr(cipher, method_name), - self.data_128) - - cipher = AES.new(self.key_128, AES.MODE_OCB, nonce=self.nonce_96) - cipher.encrypt_and_digest(self.data_128) - - def test_invalid_decrypt_or_update_after_verify(self): - cipher = AES.new(self.key_128, AES.MODE_OCB, nonce=self.nonce_96) - ct = cipher.encrypt(self.data_128) - ct += cipher.encrypt() - mac = cipher.digest() - - for method_name in "decrypt", "update": - cipher = AES.new(self.key_128, AES.MODE_OCB, nonce=self.nonce_96) - cipher.decrypt(ct) - cipher.decrypt() - cipher.verify(mac) - self.assertRaises(TypeError, getattr(cipher, method_name), - self.data_128) - - cipher = AES.new(self.key_128, AES.MODE_OCB, nonce=self.nonce_96) - cipher.decrypt_and_verify(ct, mac) - self.assertRaises(TypeError, getattr(cipher, method_name), - self.data_128) - - -class OcbRfc7253Test(unittest.TestCase): - - # Tuple with - # - nonce - # - authenticated data - # - plaintext - # - ciphertext and 16 byte MAC tag - tv1_key = "000102030405060708090A0B0C0D0E0F" - tv1 = ( - ( - "BBAA99887766554433221100", - "", - "", - "785407BFFFC8AD9EDCC5520AC9111EE6" - ), - ( - "BBAA99887766554433221101", - "0001020304050607", - "0001020304050607", - "6820B3657B6F615A5725BDA0D3B4EB3A257C9AF1F8F03009" - ), - ( - "BBAA99887766554433221102", - "0001020304050607", - "", - "81017F8203F081277152FADE694A0A00" - ), - ( - "BBAA99887766554433221103", - "", - "0001020304050607", - "45DD69F8F5AAE72414054CD1F35D82760B2CD00D2F99BFA9" - ), - ( - "BBAA99887766554433221104", - "000102030405060708090A0B0C0D0E0F", - "000102030405060708090A0B0C0D0E0F", - "571D535B60B277188BE5147170A9A22C3AD7A4FF3835B8C5" - "701C1CCEC8FC3358" - ), - ( - "BBAA99887766554433221105", - "000102030405060708090A0B0C0D0E0F", - "", - "8CF761B6902EF764462AD86498CA6B97" - ), - ( - "BBAA99887766554433221106", - "", - "000102030405060708090A0B0C0D0E0F", - "5CE88EC2E0692706A915C00AEB8B2396F40E1C743F52436B" - "DF06D8FA1ECA343D" - ), - ( - "BBAA99887766554433221107", - "000102030405060708090A0B0C0D0E0F1011121314151617", - "000102030405060708090A0B0C0D0E0F1011121314151617", - "1CA2207308C87C010756104D8840CE1952F09673A448A122" - "C92C62241051F57356D7F3C90BB0E07F" - ), - ( - "BBAA99887766554433221108", - "000102030405060708090A0B0C0D0E0F1011121314151617", - "", - "6DC225A071FC1B9F7C69F93B0F1E10DE" - ), - ( - "BBAA99887766554433221109", - "", - "000102030405060708090A0B0C0D0E0F1011121314151617", - "221BD0DE7FA6FE993ECCD769460A0AF2D6CDED0C395B1C3C" - "E725F32494B9F914D85C0B1EB38357FF" - ), - ( - "BBAA9988776655443322110A", - "000102030405060708090A0B0C0D0E0F1011121314151617" - "18191A1B1C1D1E1F", - "000102030405060708090A0B0C0D0E0F1011121314151617" - "18191A1B1C1D1E1F", - "BD6F6C496201C69296C11EFD138A467ABD3C707924B964DE" - "AFFC40319AF5A48540FBBA186C5553C68AD9F592A79A4240" - ), - ( - "BBAA9988776655443322110B", - "000102030405060708090A0B0C0D0E0F1011121314151617" - "18191A1B1C1D1E1F", - "", - "FE80690BEE8A485D11F32965BC9D2A32" - ), - ( - "BBAA9988776655443322110C", - "", - "000102030405060708090A0B0C0D0E0F1011121314151617" - "18191A1B1C1D1E1F", - "2942BFC773BDA23CABC6ACFD9BFD5835BD300F0973792EF4" - "6040C53F1432BCDFB5E1DDE3BC18A5F840B52E653444D5DF" - ), - ( - "BBAA9988776655443322110D", - "000102030405060708090A0B0C0D0E0F1011121314151617" - "18191A1B1C1D1E1F2021222324252627", - "000102030405060708090A0B0C0D0E0F1011121314151617" - "18191A1B1C1D1E1F2021222324252627", - "D5CA91748410C1751FF8A2F618255B68A0A12E093FF45460" - "6E59F9C1D0DDC54B65E8628E568BAD7AED07BA06A4A69483" - "A7035490C5769E60" - ), - ( - "BBAA9988776655443322110E", - "000102030405060708090A0B0C0D0E0F1011121314151617" - "18191A1B1C1D1E1F2021222324252627", - "", - "C5CD9D1850C141E358649994EE701B68" - ), - ( - "BBAA9988776655443322110F", - "", - "000102030405060708090A0B0C0D0E0F1011121314151617" - "18191A1B1C1D1E1F2021222324252627", - "4412923493C57D5DE0D700F753CCE0D1D2D95060122E9F15" - "A5DDBFC5787E50B5CC55EE507BCB084E479AD363AC366B95" - "A98CA5F3000B1479" - ) - ) - - # Tuple with - # - key - # - nonce - # - authenticated data - # - plaintext - # - ciphertext and 12 byte MAC tag - tv2 = ( - "0F0E0D0C0B0A09080706050403020100", - "BBAA9988776655443322110D", - "000102030405060708090A0B0C0D0E0F1011121314151617" - "18191A1B1C1D1E1F2021222324252627", - "000102030405060708090A0B0C0D0E0F1011121314151617" - "18191A1B1C1D1E1F2021222324252627", - "1792A4E31E0755FB03E31B22116E6C2DDF9EFD6E33D536F1" - "A0124B0A55BAE884ED93481529C76B6AD0C515F4D1CDD4FD" - "AC4F02AA" - ) - - # Tuple with - # - key length - # - MAC tag length - # - Expected output - tv3 = ( - (128, 128, "67E944D23256C5E0B6C61FA22FDF1EA2"), - (192, 128, "F673F2C3E7174AAE7BAE986CA9F29E17"), - (256, 128, "D90EB8E9C977C88B79DD793D7FFA161C"), - (128, 96, "77A3D8E73589158D25D01209"), - (192, 96, "05D56EAD2752C86BE6932C5E"), - (256, 96, "5458359AC23B0CBA9E6330DD"), - (128, 64, "192C9B7BD90BA06A"), - (192, 64, "0066BC6E0EF34E24"), - (256, 64, "7D4EA5D445501CBE"), - ) - - def test1(self): - key = unhexlify(b(self.tv1_key)) - for tv in self.tv1: - nonce, aad, pt, ct = [ unhexlify(b(x)) for x in tv ] - ct, mac_tag = ct[:-16], ct[-16:] - - cipher = AES.new(key, AES.MODE_OCB, nonce=nonce) - cipher.update(aad) - ct2 = cipher.encrypt(pt) + cipher.encrypt() - self.assertEquals(ct, ct2) - self.assertEquals(mac_tag, cipher.digest()) - - cipher = AES.new(key, AES.MODE_OCB, nonce=nonce) - cipher.update(aad) - pt2 = cipher.decrypt(ct) + cipher.decrypt() - self.assertEquals(pt, pt2) - cipher.verify(mac_tag) - - def test2(self): - - key, nonce, aad, pt, ct = [ unhexlify(b(x)) for x in self.tv2 ] - ct, mac_tag = ct[:-12], ct[-12:] - - cipher = AES.new(key, AES.MODE_OCB, nonce=nonce, mac_len=12) - cipher.update(aad) - ct2 = cipher.encrypt(pt) + cipher.encrypt() - self.assertEquals(ct, ct2) - self.assertEquals(mac_tag, cipher.digest()) - - cipher = AES.new(key, AES.MODE_OCB, nonce=nonce, mac_len=12) - cipher.update(aad) - pt2 = cipher.decrypt(ct) + cipher.decrypt() - self.assertEquals(pt, pt2) - cipher.verify(mac_tag) - - def test3(self): - - for keylen, taglen, result in self.tv3: - - key = bchr(0) * (keylen // 8 - 1) + bchr(taglen) - C = b("") - - for i in range(128): - S = bchr(0) * i - - N = long_to_bytes(3 * i + 1, 12) - cipher = AES.new(key, AES.MODE_OCB, nonce=N, mac_len=taglen // 8) - cipher.update(S) - C += cipher.encrypt(S) + cipher.encrypt() + cipher.digest() - - N = long_to_bytes(3 * i + 2, 12) - cipher = AES.new(key, AES.MODE_OCB, nonce=N, mac_len=taglen // 8) - C += cipher.encrypt(S) + cipher.encrypt() + cipher.digest() - - N = long_to_bytes(3 * i + 3, 12) - cipher = AES.new(key, AES.MODE_OCB, nonce=N, mac_len=taglen // 8) - cipher.update(S) - C += cipher.encrypt() + cipher.digest() - - N = long_to_bytes(385, 12) - cipher = AES.new(key, AES.MODE_OCB, nonce=N, mac_len=taglen // 8) - cipher.update(C) - result2 = cipher.encrypt() + cipher.digest() - self.assertEquals(unhexlify(b(result)), result2) - - -def get_tests(config={}): - tests = [] - tests += list_test_cases(OcbTests) - tests += list_test_cases(OcbFSMTests) - tests += list_test_cases(OcbRfc7253Test) - return tests - - -if __name__ == '__main__': - import unittest - suite = lambda: unittest.TestSuite(get_tests()) - unittest.main(defaultTest='suite') diff --git a/Crypto/SelfTest/Cipher/test_OFB.py b/Crypto/SelfTest/Cipher/test_OFB.py deleted file mode 100644 index ec145ad..0000000 --- a/Crypto/SelfTest/Cipher/test_OFB.py +++ /dev/null @@ -1,238 +0,0 @@ -# =================================================================== -# -# Copyright (c) 2015, Legrandin -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# =================================================================== - -import unittest -from binascii import unhexlify - -from Crypto.SelfTest.st_common import list_test_cases -from Crypto.Util.py3compat import tobytes -from Crypto.Cipher import AES, DES3, DES -from Crypto.Hash import SHAKE128 -from Crypto.SelfTest.loader import load_test_vectors_wycheproof - -def get_tag_random(tag, length): - return SHAKE128.new(data=tobytes(tag)).read(length) - -from Crypto.SelfTest.Cipher.test_CBC import BlockChainingTests - -class OfbTests(BlockChainingTests): - - aes_mode = AES.MODE_OFB - des3_mode = DES3.MODE_OFB - - # Redefine test_unaligned_data_128/64 - - def test_unaligned_data_128(self): - plaintexts = [ b"7777777" ] * 100 - - cipher = AES.new(self.key_128, AES.MODE_CFB, self.iv_128, segment_size=8) - ciphertexts = [ cipher.encrypt(x) for x in plaintexts ] - cipher = AES.new(self.key_128, AES.MODE_CFB, self.iv_128, segment_size=8) - self.assertEqual(b"".join(ciphertexts), cipher.encrypt(b"".join(plaintexts))) - - cipher = AES.new(self.key_128, AES.MODE_CFB, self.iv_128, segment_size=128) - ciphertexts = [ cipher.encrypt(x) for x in plaintexts ] - cipher = AES.new(self.key_128, AES.MODE_CFB, self.iv_128, segment_size=128) - self.assertEqual(b"".join(ciphertexts), cipher.encrypt(b"".join(plaintexts))) - - def test_unaligned_data_64(self): - plaintexts = [ b"7777777" ] * 100 - cipher = DES3.new(self.key_192, DES3.MODE_CFB, self.iv_64, segment_size=8) - ciphertexts = [ cipher.encrypt(x) for x in plaintexts ] - cipher = DES3.new(self.key_192, DES3.MODE_CFB, self.iv_64, segment_size=8) - self.assertEqual(b"".join(ciphertexts), cipher.encrypt(b"".join(plaintexts))) - - cipher = DES3.new(self.key_192, DES3.MODE_CFB, self.iv_64, segment_size=64) - ciphertexts = [ cipher.encrypt(x) for x in plaintexts ] - cipher = DES3.new(self.key_192, DES3.MODE_CFB, self.iv_64, segment_size=64) - self.assertEqual(b"".join(ciphertexts), cipher.encrypt(b"".join(plaintexts))) - - -from Crypto.SelfTest.Cipher.test_CBC import NistBlockChainingVectors - -class NistOfbVectors(NistBlockChainingVectors): - aes_mode = AES.MODE_OFB - des_mode = DES.MODE_OFB - des3_mode = DES3.MODE_OFB - - -# Create one test method per file -nist_aes_kat_mmt_files = ( - # KAT - "OFBGFSbox128.rsp", - "OFBGFSbox192.rsp", - "OFBGFSbox256.rsp", - "OFBKeySbox128.rsp", - "OFBKeySbox192.rsp", - "OFBKeySbox256.rsp", - "OFBVarKey128.rsp", - "OFBVarKey192.rsp", - "OFBVarKey256.rsp", - "OFBVarTxt128.rsp", - "OFBVarTxt192.rsp", - "OFBVarTxt256.rsp", - # MMT - "OFBMMT128.rsp", - "OFBMMT192.rsp", - "OFBMMT256.rsp", - ) -nist_aes_mct_files = ( - "OFBMCT128.rsp", - "OFBMCT192.rsp", - "OFBMCT256.rsp", - ) - -for file_name in nist_aes_kat_mmt_files: - def new_func(self, file_name=file_name): - self._do_kat_aes_test(file_name) - setattr(NistOfbVectors, "test_AES_" + file_name, new_func) - -for file_name in nist_aes_mct_files: - def new_func(self, file_name=file_name): - self._do_mct_aes_test(file_name) - setattr(NistOfbVectors, "test_AES_" + file_name, new_func) -del file_name, new_func - -nist_tdes_files = ( - "TOFBMMT2.rsp", # 2TDES - "TOFBMMT3.rsp", # 3TDES - "TOFBinvperm.rsp", # Single DES - "TOFBpermop.rsp", - "TOFBsubtab.rsp", - "TOFBvarkey.rsp", - "TOFBvartext.rsp", - ) - -for file_name in nist_tdes_files: - def new_func(self, file_name=file_name): - self._do_tdes_test(file_name) - setattr(NistOfbVectors, "test_TDES_" + file_name, new_func) - -# END OF NIST OFB TEST VECTORS - - -class SP800TestVectors(unittest.TestCase): - """Class exercising the OFB test vectors found in Section F.4 - of NIST SP 800-3A""" - - def test_aes_128(self): - plaintext = '6bc1bee22e409f96e93d7e117393172a' +\ - 'ae2d8a571e03ac9c9eb76fac45af8e51' +\ - '30c81c46a35ce411e5fbc1191a0a52ef' +\ - 'f69f2445df4f9b17ad2b417be66c3710' - ciphertext = '3b3fd92eb72dad20333449f8e83cfb4a' +\ - '7789508d16918f03f53c52dac54ed825' +\ - '9740051e9c5fecf64344f7a82260edcc' +\ - '304c6528f659c77866a510d9c1d6ae5e' - key = '2b7e151628aed2a6abf7158809cf4f3c' - iv = '000102030405060708090a0b0c0d0e0f' - - key = unhexlify(key) - iv = unhexlify(iv) - plaintext = unhexlify(plaintext) - ciphertext = unhexlify(ciphertext) - - cipher = AES.new(key, AES.MODE_OFB, iv) - self.assertEqual(cipher.encrypt(plaintext), ciphertext) - cipher = AES.new(key, AES.MODE_OFB, iv) - self.assertEqual(cipher.decrypt(ciphertext), plaintext) - - cipher = AES.new(key, AES.MODE_OFB, iv) - self.assertEqual(cipher.encrypt(plaintext[:-8]), ciphertext[:-8]) - cipher = AES.new(key, AES.MODE_OFB, iv) - self.assertEqual(cipher.decrypt(ciphertext[:-8]), plaintext[:-8]) - - def test_aes_192(self): - plaintext = '6bc1bee22e409f96e93d7e117393172a' +\ - 'ae2d8a571e03ac9c9eb76fac45af8e51' +\ - '30c81c46a35ce411e5fbc1191a0a52ef' +\ - 'f69f2445df4f9b17ad2b417be66c3710' - ciphertext = 'cdc80d6fddf18cab34c25909c99a4174' +\ - 'fcc28b8d4c63837c09e81700c1100401' +\ - '8d9a9aeac0f6596f559c6d4daf59a5f2' +\ - '6d9f200857ca6c3e9cac524bd9acc92a' - key = '8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b' - iv = '000102030405060708090a0b0c0d0e0f' - - key = unhexlify(key) - iv = unhexlify(iv) - plaintext = unhexlify(plaintext) - ciphertext = unhexlify(ciphertext) - - cipher = AES.new(key, AES.MODE_OFB, iv) - self.assertEqual(cipher.encrypt(plaintext), ciphertext) - cipher = AES.new(key, AES.MODE_OFB, iv) - self.assertEqual(cipher.decrypt(ciphertext), plaintext) - - cipher = AES.new(key, AES.MODE_OFB, iv) - self.assertEqual(cipher.encrypt(plaintext[:-8]), ciphertext[:-8]) - cipher = AES.new(key, AES.MODE_OFB, iv) - self.assertEqual(cipher.decrypt(ciphertext[:-8]), plaintext[:-8]) - - def test_aes_256(self): - plaintext = '6bc1bee22e409f96e93d7e117393172a' +\ - 'ae2d8a571e03ac9c9eb76fac45af8e51' +\ - '30c81c46a35ce411e5fbc1191a0a52ef' +\ - 'f69f2445df4f9b17ad2b417be66c3710' - ciphertext = 'dc7e84bfda79164b7ecd8486985d3860' +\ - '4febdc6740d20b3ac88f6ad82a4fb08d' +\ - '71ab47a086e86eedf39d1c5bba97c408' +\ - '0126141d67f37be8538f5a8be740e484' - key = '603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4' - iv = '000102030405060708090a0b0c0d0e0f' - - key = unhexlify(key) - iv = unhexlify(iv) - plaintext = unhexlify(plaintext) - ciphertext = unhexlify(ciphertext) - - cipher = AES.new(key, AES.MODE_OFB, iv) - self.assertEqual(cipher.encrypt(plaintext), ciphertext) - cipher = AES.new(key, AES.MODE_OFB, iv) - self.assertEqual(cipher.decrypt(ciphertext), plaintext) - - cipher = AES.new(key, AES.MODE_OFB, iv) - self.assertEqual(cipher.encrypt(plaintext[:-8]), ciphertext[:-8]) - cipher = AES.new(key, AES.MODE_OFB, iv) - self.assertEqual(cipher.decrypt(ciphertext[:-8]), plaintext[:-8]) - - -def get_tests(config={}): - tests = [] - tests += list_test_cases(OfbTests) - if config.get('slow_tests'): - tests += list_test_cases(NistOfbVectors) - tests += list_test_cases(SP800TestVectors) - return tests - - -if __name__ == '__main__': - suite = lambda: unittest.TestSuite(get_tests()) - unittest.main(defaultTest='suite') diff --git a/Crypto/SelfTest/Cipher/test_OpenPGP.py b/Crypto/SelfTest/Cipher/test_OpenPGP.py deleted file mode 100644 index e6cae67..0000000 --- a/Crypto/SelfTest/Cipher/test_OpenPGP.py +++ /dev/null @@ -1,218 +0,0 @@ -# =================================================================== -# -# Copyright (c) 2015, Legrandin -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# =================================================================== - -import unittest -from binascii import unhexlify - -from Crypto.SelfTest.st_common import list_test_cases -from Crypto.Util.py3compat import tobytes -from Crypto.Cipher import AES, DES3, DES -from Crypto.Hash import SHAKE128 - -def get_tag_random(tag, length): - return SHAKE128.new(data=tobytes(tag)).read(length) - - -from Crypto.SelfTest.Cipher.test_CBC import BlockChainingTests - -class OpenPGPTests(BlockChainingTests): - - aes_mode = AES.MODE_OPENPGP - des3_mode = DES3.MODE_OPENPGP - - # Redefine test_unaligned_data_128/64 - - key_128 = get_tag_random("key_128", 16) - key_192 = get_tag_random("key_192", 24) - iv_128 = get_tag_random("iv_128", 16) - iv_64 = get_tag_random("iv_64", 8) - data_128 = get_tag_random("data_128", 16) - - def test_loopback_128(self): - cipher = AES.new(self.key_128, AES.MODE_OPENPGP, self.iv_128) - pt = get_tag_random("plaintext", 16 * 100) - ct = cipher.encrypt(pt) - - eiv, ct = ct[:18], ct[18:] - - cipher = AES.new(self.key_128, AES.MODE_OPENPGP, eiv) - pt2 = cipher.decrypt(ct) - self.assertEqual(pt, pt2) - - def test_loopback_64(self): - cipher = DES3.new(self.key_192, DES3.MODE_OPENPGP, self.iv_64) - pt = get_tag_random("plaintext", 8 * 100) - ct = cipher.encrypt(pt) - - eiv, ct = ct[:10], ct[10:] - - cipher = DES3.new(self.key_192, DES3.MODE_OPENPGP, eiv) - pt2 = cipher.decrypt(ct) - self.assertEqual(pt, pt2) - - def test_IV_iv_attributes(self): - cipher = AES.new(self.key_128, AES.MODE_OPENPGP, self.iv_128) - eiv = cipher.encrypt(b"") - self.assertEqual(cipher.iv, self.iv_128) - - cipher = AES.new(self.key_128, AES.MODE_OPENPGP, eiv) - self.assertEqual(cipher.iv, self.iv_128) - - def test_null_encryption_decryption(self): - cipher = AES.new(self.key_128, AES.MODE_OPENPGP, self.iv_128) - eiv = cipher.encrypt(b"") - - cipher = AES.new(self.key_128, AES.MODE_OPENPGP, eiv) - self.assertEqual(cipher.decrypt(b""), b"") - - def test_either_encrypt_or_decrypt(self): - cipher = AES.new(self.key_128, AES.MODE_OPENPGP, self.iv_128) - eiv = cipher.encrypt(b"") - self.assertRaises(TypeError, cipher.decrypt, b"") - - cipher = AES.new(self.key_128, AES.MODE_OPENPGP, eiv) - cipher.decrypt(b"") - self.assertRaises(TypeError, cipher.encrypt, b"") - - def test_unaligned_data_128(self): - plaintexts = [ b"7777777" ] * 100 - - cipher = AES.new(self.key_128, AES.MODE_OPENPGP, self.iv_128) - ciphertexts = [ cipher.encrypt(x) for x in plaintexts ] - cipher = AES.new(self.key_128, AES.MODE_OPENPGP, self.iv_128) - self.assertEqual(b"".join(ciphertexts), cipher.encrypt(b"".join(plaintexts))) - - def test_unaligned_data_64(self): - plaintexts = [ b"7777777" ] * 100 - - cipher = DES3.new(self.key_192, DES3.MODE_OPENPGP, self.iv_64) - ciphertexts = [ cipher.encrypt(x) for x in plaintexts ] - cipher = DES3.new(self.key_192, DES3.MODE_OPENPGP, self.iv_64) - self.assertEqual(b"".join(ciphertexts), cipher.encrypt(b"".join(plaintexts))) - - def test_output_param(self): - pass - - def test_output_param_same_buffer(self): - pass - - def test_output_param_memoryview(self): - pass - - def test_output_param_neg(self): - pass - - -class TestVectors(unittest.TestCase): - - def test_aes(self): - # The following test vectors have been generated with gpg v1.4.0. - # The command line used was: - # - # gpg -c -z 0 --cipher-algo AES --passphrase secret_passphrase \ - # --disable-mdc --s2k-mode 0 --output ct pt - # - # As result, the content of the file 'pt' is encrypted with a key derived - # from 'secret_passphrase' and written to file 'ct'. - # Test vectors must be extracted from 'ct', which is a collection of - # TLVs (see RFC4880 for all details): - # - the encrypted data (with the encrypted IV as prefix) is the payload - # of the TLV with tag 9 (Symmetrical Encrypted Data Packet). - # This is the ciphertext in the test vector. - # - inside the encrypted part, there is a further layer of TLVs. One must - # look for tag 11 (Literal Data Packet); in its payload, after a short - # but time dependent header, there is the content of file 'pt'. - # In the test vector, the plaintext is the complete set of TLVs that gets - # encrypted. It is not just the content of 'pt'. - # - the key is the leftmost 16 bytes of the SHA1 digest of the password. - # The test vector contains such shortened digest. - # - # Note that encryption uses a clear IV, and decryption an encrypted IV - - plaintext = 'ac18620270744fb4f647426c61636b4361745768697465436174' - ciphertext = 'dc6b9e1f095de609765c59983db5956ae4f63aea7405389d2ebb' - key = '5baa61e4c9b93f3f0682250b6cf8331b' - iv = '3d7d3e62282add7eb203eeba5c800733' - encrypted_iv='fd934601ef49cb58b6d9aebca6056bdb96ef' - - plaintext = unhexlify(plaintext) - ciphertext = unhexlify(ciphertext) - key = unhexlify(key) - iv = unhexlify(iv) - encrypted_iv = unhexlify(encrypted_iv) - - cipher = AES.new(key, AES.MODE_OPENPGP, iv) - ct = cipher.encrypt(plaintext) - self.assertEqual(ct[:18], encrypted_iv) - self.assertEqual(ct[18:], ciphertext) - - cipher = AES.new(key, AES.MODE_OPENPGP, encrypted_iv) - pt = cipher.decrypt(ciphertext) - self.assertEqual(pt, plaintext) - - def test_des3(self): - # The following test vectors have been generated with gpg v1.4.0. - # The command line used was: - # gpg -c -z 0 --cipher-algo 3DES --passphrase secret_passphrase \ - # --disable-mdc --s2k-mode 0 --output ct pt - # For an explanation, see test_AES.py . - - plaintext = 'ac1762037074324fb53ba3596f73656d69746556616c6c6579' - ciphertext = '9979238528357b90e2e0be549cb0b2d5999b9a4a447e5c5c7d' - key = '7ade65b460f5ea9be35f9e14aa883a2048e3824aa616c0b2' - iv='cd47e2afb8b7e4b0' - encrypted_iv='6a7eef0b58050e8b904a' - - plaintext = unhexlify(plaintext) - ciphertext = unhexlify(ciphertext) - key = unhexlify(key) - iv = unhexlify(iv) - encrypted_iv = unhexlify(encrypted_iv) - - cipher = DES3.new(key, DES3.MODE_OPENPGP, iv) - ct = cipher.encrypt(plaintext) - self.assertEqual(ct[:10], encrypted_iv) - self.assertEqual(ct[10:], ciphertext) - - cipher = DES3.new(key, DES3.MODE_OPENPGP, encrypted_iv) - pt = cipher.decrypt(ciphertext) - self.assertEqual(pt, plaintext) - - -def get_tests(config={}): - tests = [] - tests += list_test_cases(OpenPGPTests) - tests += list_test_cases(TestVectors) - return tests - - -if __name__ == '__main__': - suite = lambda: unittest.TestSuite(get_tests()) - unittest.main(defaultTest='suite') diff --git a/Crypto/SelfTest/Cipher/test_SIV.py b/Crypto/SelfTest/Cipher/test_SIV.py deleted file mode 100644 index 421c9eb..0000000 --- a/Crypto/SelfTest/Cipher/test_SIV.py +++ /dev/null @@ -1,551 +0,0 @@ -# =================================================================== -# -# Copyright (c) 2015, Legrandin -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# =================================================================== - -import json -import unittest -from binascii import unhexlify - -from Crypto.SelfTest.st_common import list_test_cases -from Crypto.SelfTest.loader import load_test_vectors_wycheproof - -from Crypto.Util.py3compat import tobytes, bchr -from Crypto.Cipher import AES -from Crypto.Hash import SHAKE128 - -from Crypto.Util.strxor import strxor - - -def get_tag_random(tag, length): - return SHAKE128.new(data=tobytes(tag)).read(length) - - -class SivTests(unittest.TestCase): - - key_256 = get_tag_random("key_256", 32) - key_384 = get_tag_random("key_384", 48) - key_512 = get_tag_random("key_512", 64) - nonce_96 = get_tag_random("nonce_128", 12) - data_128 = get_tag_random("data_128", 16) - - def test_loopback_128(self): - for key in self.key_256, self.key_384, self.key_512: - cipher = AES.new(key, AES.MODE_SIV, nonce=self.nonce_96) - pt = get_tag_random("plaintext", 16 * 100) - ct, mac = cipher.encrypt_and_digest(pt) - - cipher = AES.new(key, AES.MODE_SIV, nonce=self.nonce_96) - pt2 = cipher.decrypt_and_verify(ct, mac) - self.assertEqual(pt, pt2) - - def test_nonce(self): - # Deterministic encryption - AES.new(self.key_256, AES.MODE_SIV) - - cipher = AES.new(self.key_256, AES.MODE_SIV, self.nonce_96) - ct1, tag1 = cipher.encrypt_and_digest(self.data_128) - - cipher = AES.new(self.key_256, AES.MODE_SIV, nonce=self.nonce_96) - ct2, tag2 = cipher.encrypt_and_digest(self.data_128) - self.assertEquals(ct1 + tag1, ct2 + tag2) - - def test_nonce_must_be_bytes(self): - self.assertRaises(TypeError, AES.new, self.key_256, AES.MODE_SIV, - nonce=u'test12345678') - - def test_nonce_length(self): - # nonce can be of any length (but not empty) - self.assertRaises(ValueError, AES.new, self.key_256, AES.MODE_SIV, - nonce=b"") - - for x in range(1, 128): - cipher = AES.new(self.key_256, AES.MODE_SIV, nonce=bchr(1) * x) - cipher.encrypt_and_digest(b'\x01') - - def test_block_size_128(self): - cipher = AES.new(self.key_256, AES.MODE_SIV, nonce=self.nonce_96) - self.assertEqual(cipher.block_size, AES.block_size) - - def test_nonce_attribute(self): - cipher = AES.new(self.key_256, AES.MODE_SIV, nonce=self.nonce_96) - self.assertEqual(cipher.nonce, self.nonce_96) - - # By default, no nonce is randomly generated - self.failIf(hasattr(AES.new(self.key_256, AES.MODE_SIV), "nonce")) - - def test_unknown_parameters(self): - self.assertRaises(TypeError, AES.new, self.key_256, AES.MODE_SIV, - self.nonce_96, 7) - self.assertRaises(TypeError, AES.new, self.key_256, AES.MODE_SIV, - nonce=self.nonce_96, unknown=7) - - # But some are only known by the base cipher - # (e.g. use_aesni consumed by the AES module) - AES.new(self.key_256, AES.MODE_SIV, nonce=self.nonce_96, - use_aesni=False) - - def test_encrypt_excludes_decrypt(self): - cipher = AES.new(self.key_256, AES.MODE_SIV, nonce=self.nonce_96) - cipher.encrypt_and_digest(self.data_128) - self.assertRaises(TypeError, cipher.decrypt, self.data_128) - - cipher = AES.new(self.key_256, AES.MODE_SIV, nonce=self.nonce_96) - cipher.encrypt_and_digest(self.data_128) - self.assertRaises(TypeError, cipher.decrypt_and_verify, - self.data_128, self.data_128) - - def test_data_must_be_bytes(self): - cipher = AES.new(self.key_256, AES.MODE_SIV, nonce=self.nonce_96) - self.assertRaises(TypeError, cipher.encrypt, u'test1234567890-*') - - cipher = AES.new(self.key_256, AES.MODE_SIV, nonce=self.nonce_96) - self.assertRaises(TypeError, cipher.decrypt_and_verify, - u'test1234567890-*', b"xxxx") - - def test_mac_len(self): - cipher = AES.new(self.key_256, AES.MODE_SIV, nonce=self.nonce_96) - _, mac = cipher.encrypt_and_digest(self.data_128) - self.assertEqual(len(mac), 16) - - def test_invalid_mac(self): - from Crypto.Util.strxor import strxor_c - cipher = AES.new(self.key_256, AES.MODE_SIV, nonce=self.nonce_96) - ct, mac = cipher.encrypt_and_digest(self.data_128) - - invalid_mac = strxor_c(mac, 0x01) - - cipher = AES.new(self.key_256, AES.MODE_SIV, nonce=self.nonce_96) - self.assertRaises(ValueError, cipher.decrypt_and_verify, ct, - invalid_mac) - - def test_hex_mac(self): - cipher = AES.new(self.key_256, AES.MODE_SIV, nonce=self.nonce_96) - mac_hex = cipher.hexdigest() - self.assertEqual(cipher.digest(), unhexlify(mac_hex)) - - cipher = AES.new(self.key_256, AES.MODE_SIV, nonce=self.nonce_96) - cipher.hexverify(mac_hex) - - def test_bytearray(self): - - # Encrypt - key = bytearray(self.key_256) - nonce = bytearray(self.nonce_96) - data = bytearray(self.data_128) - header = bytearray(self.data_128) - - cipher1 = AES.new(self.key_256, - AES.MODE_SIV, - nonce=self.nonce_96) - cipher1.update(self.data_128) - ct, tag = cipher1.encrypt_and_digest(self.data_128) - - cipher2 = AES.new(key, - AES.MODE_SIV, - nonce=nonce) - key[:3] = b'\xFF\xFF\xFF' - nonce[:3] = b'\xFF\xFF\xFF' - cipher2.update(header) - header[:3] = b'\xFF\xFF\xFF' - ct_test, tag_test = cipher2.encrypt_and_digest(data) - - self.assertEqual(ct, ct_test) - self.assertEqual(tag, tag_test) - self.assertEqual(cipher1.nonce, cipher2.nonce) - - # Decrypt - key = bytearray(self.key_256) - nonce = bytearray(self.nonce_96) - header = bytearray(self.data_128) - ct_ba = bytearray(ct) - tag_ba = bytearray(tag) - - cipher3 = AES.new(key, - AES.MODE_SIV, - nonce=nonce) - key[:3] = b'\xFF\xFF\xFF' - nonce[:3] = b'\xFF\xFF\xFF' - cipher3.update(header) - header[:3] = b'\xFF\xFF\xFF' - pt_test = cipher3.decrypt_and_verify(ct_ba, tag_ba) - - self.assertEqual(self.data_128, pt_test) - - def test_memoryview(self): - - # Encrypt - key = memoryview(bytearray(self.key_256)) - nonce = memoryview(bytearray(self.nonce_96)) - data = memoryview(bytearray(self.data_128)) - header = memoryview(bytearray(self.data_128)) - - cipher1 = AES.new(self.key_256, - AES.MODE_SIV, - nonce=self.nonce_96) - cipher1.update(self.data_128) - ct, tag = cipher1.encrypt_and_digest(self.data_128) - - cipher2 = AES.new(key, - AES.MODE_SIV, - nonce=nonce) - key[:3] = b'\xFF\xFF\xFF' - nonce[:3] = b'\xFF\xFF\xFF' - cipher2.update(header) - header[:3] = b'\xFF\xFF\xFF' - ct_test, tag_test= cipher2.encrypt_and_digest(data) - - self.assertEqual(ct, ct_test) - self.assertEqual(tag, tag_test) - self.assertEqual(cipher1.nonce, cipher2.nonce) - - # Decrypt - key = memoryview(bytearray(self.key_256)) - nonce = memoryview(bytearray(self.nonce_96)) - header = memoryview(bytearray(self.data_128)) - ct_ba = memoryview(bytearray(ct)) - tag_ba = memoryview(bytearray(tag)) - - cipher3 = AES.new(key, - AES.MODE_SIV, - nonce=nonce) - key[:3] = b'\xFF\xFF\xFF' - nonce[:3] = b'\xFF\xFF\xFF' - cipher3.update(header) - header[:3] = b'\xFF\xFF\xFF' - pt_test = cipher3.decrypt_and_verify(ct_ba, tag_ba) - - self.assertEqual(self.data_128, pt_test) - - def test_output_param(self): - - pt = b'5' * 16 - cipher = AES.new(self.key_256, AES.MODE_SIV, nonce=self.nonce_96) - ct, tag = cipher.encrypt_and_digest(pt) - - output = bytearray(16) - cipher = AES.new(self.key_256, AES.MODE_SIV, nonce=self.nonce_96) - res, tag_out = cipher.encrypt_and_digest(pt, output=output) - self.assertEqual(ct, output) - self.assertEqual(res, None) - self.assertEqual(tag, tag_out) - - cipher = AES.new(self.key_256, AES.MODE_SIV, nonce=self.nonce_96) - res = cipher.decrypt_and_verify(ct, tag, output=output) - self.assertEqual(pt, output) - self.assertEqual(res, None) - - def test_output_param_memoryview(self): - - pt = b'5' * 16 - cipher = AES.new(self.key_256, AES.MODE_SIV, nonce=self.nonce_96) - ct, tag = cipher.encrypt_and_digest(pt) - - output = memoryview(bytearray(16)) - cipher = AES.new(self.key_256, AES.MODE_SIV, nonce=self.nonce_96) - cipher.encrypt_and_digest(pt, output=output) - self.assertEqual(ct, output) - - cipher = AES.new(self.key_256, AES.MODE_SIV, nonce=self.nonce_96) - cipher.decrypt_and_verify(ct, tag, output=output) - self.assertEqual(pt, output) - - def test_output_param_neg(self): - - pt = b'5' * 16 - cipher = AES.new(self.key_256, AES.MODE_SIV, nonce=self.nonce_96) - ct, tag = cipher.encrypt_and_digest(pt) - - cipher = AES.new(self.key_256, AES.MODE_SIV, nonce=self.nonce_96) - self.assertRaises(TypeError, cipher.encrypt_and_digest, pt, output=b'0'*16) - - cipher = AES.new(self.key_256, AES.MODE_SIV, nonce=self.nonce_96) - self.assertRaises(TypeError, cipher.decrypt_and_verify, ct, tag, output=b'0'*16) - - shorter_output = bytearray(15) - cipher = AES.new(self.key_256, AES.MODE_SIV, nonce=self.nonce_96) - self.assertRaises(ValueError, cipher.encrypt_and_digest, pt, output=shorter_output) - cipher = AES.new(self.key_256, AES.MODE_SIV, nonce=self.nonce_96) - self.assertRaises(ValueError, cipher.decrypt_and_verify, ct, tag, output=shorter_output) - - -class SivFSMTests(unittest.TestCase): - - key_256 = get_tag_random("key_256", 32) - nonce_96 = get_tag_random("nonce_96", 12) - data_128 = get_tag_random("data_128", 16) - - def test_invalid_init_encrypt(self): - # Path INIT->ENCRYPT fails - cipher = AES.new(self.key_256, AES.MODE_SIV, - nonce=self.nonce_96) - self.assertRaises(TypeError, cipher.encrypt, b"xxx") - - def test_invalid_init_decrypt(self): - # Path INIT->DECRYPT fails - cipher = AES.new(self.key_256, AES.MODE_SIV, - nonce=self.nonce_96) - self.assertRaises(TypeError, cipher.decrypt, b"xxx") - - def test_valid_init_update_digest_verify(self): - # No plaintext, fixed authenticated data - # Verify path INIT->UPDATE->DIGEST - cipher = AES.new(self.key_256, AES.MODE_SIV, - nonce=self.nonce_96) - cipher.update(self.data_128) - mac = cipher.digest() - - # Verify path INIT->UPDATE->VERIFY - cipher = AES.new(self.key_256, AES.MODE_SIV, - nonce=self.nonce_96) - cipher.update(self.data_128) - cipher.verify(mac) - - def test_valid_init_digest(self): - # Verify path INIT->DIGEST - cipher = AES.new(self.key_256, AES.MODE_SIV, nonce=self.nonce_96) - cipher.digest() - - def test_valid_init_verify(self): - # Verify path INIT->VERIFY - cipher = AES.new(self.key_256, AES.MODE_SIV, nonce=self.nonce_96) - mac = cipher.digest() - - cipher = AES.new(self.key_256, AES.MODE_SIV, nonce=self.nonce_96) - cipher.verify(mac) - - def test_valid_multiple_digest_or_verify(self): - # Multiple calls to digest - cipher = AES.new(self.key_256, AES.MODE_SIV, nonce=self.nonce_96) - cipher.update(self.data_128) - first_mac = cipher.digest() - for x in range(4): - self.assertEqual(first_mac, cipher.digest()) - - # Multiple calls to verify - cipher = AES.new(self.key_256, AES.MODE_SIV, nonce=self.nonce_96) - cipher.update(self.data_128) - for x in range(5): - cipher.verify(first_mac) - - def test_valid_encrypt_and_digest_decrypt_and_verify(self): - # encrypt_and_digest - cipher = AES.new(self.key_256, AES.MODE_SIV, nonce=self.nonce_96) - cipher.update(self.data_128) - ct, mac = cipher.encrypt_and_digest(self.data_128) - - # decrypt_and_verify - cipher = AES.new(self.key_256, AES.MODE_SIV, nonce=self.nonce_96) - cipher.update(self.data_128) - pt = cipher.decrypt_and_verify(ct, mac) - self.assertEqual(self.data_128, pt) - - def test_invalid_multiple_encrypt_and_digest(self): - cipher = AES.new(self.key_256, AES.MODE_SIV, nonce=self.nonce_96) - ct, tag = cipher.encrypt_and_digest(self.data_128) - self.assertRaises(TypeError, cipher.encrypt_and_digest, b'') - - def test_invalid_multiple_decrypt_and_verify(self): - cipher = AES.new(self.key_256, AES.MODE_SIV, nonce=self.nonce_96) - ct, tag = cipher.encrypt_and_digest(self.data_128) - - cipher = AES.new(self.key_256, AES.MODE_SIV, nonce=self.nonce_96) - cipher.decrypt_and_verify(ct, tag) - self.assertRaises(TypeError, cipher.decrypt_and_verify, ct, tag) - - -def transform(tv): - new_tv = [[unhexlify(x) for x in tv[0].split("-")]] - new_tv += [ unhexlify(x) for x in tv[1:5]] - if tv[5]: - nonce = unhexlify(tv[5]) - else: - nonce = None - new_tv += [ nonce ] - return new_tv - - -class TestVectors(unittest.TestCase): - """Class exercising the SIV test vectors found in RFC5297""" - - # This is a list of tuples with 5 items: - # - # 1. Header + '|' + plaintext - # 2. Header + '|' + ciphertext + '|' + MAC - # 3. AES-128 key - # 4. Description - # 5. Dictionary of parameters to be passed to AES.new(). - # It must include the nonce. - # - # A "Header" is a dash ('-') separated sequece of components. - # - test_vectors_hex = [ - ( - '101112131415161718191a1b1c1d1e1f2021222324252627', - '112233445566778899aabbccddee', - '40c02b9690c4dc04daef7f6afe5c', - '85632d07c6e8f37f950acd320a2ecc93', - 'fffefdfcfbfaf9f8f7f6f5f4f3f2f1f0f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff', - None - ), - ( - '00112233445566778899aabbccddeeffdeaddadadeaddadaffeeddccbbaa9988' + - '7766554433221100-102030405060708090a0', - '7468697320697320736f6d6520706c61696e7465787420746f20656e63727970' + - '74207573696e67205349562d414553', - 'cb900f2fddbe404326601965c889bf17dba77ceb094fa663b7a3f748ba8af829' + - 'ea64ad544a272e9c485b62a3fd5c0d', - '7bdb6e3b432667eb06f4d14bff2fbd0f', - '7f7e7d7c7b7a79787776757473727170404142434445464748494a4b4c4d4e4f', - '09f911029d74e35bd84156c5635688c0' - ), - ] - - test_vectors = [ transform(tv) for tv in test_vectors_hex ] - - def runTest(self): - for assoc_data, pt, ct, mac, key, nonce in self.test_vectors: - - # Encrypt - cipher = AES.new(key, AES.MODE_SIV, nonce=nonce) - for x in assoc_data: - cipher.update(x) - ct2, mac2 = cipher.encrypt_and_digest(pt) - self.assertEqual(ct, ct2) - self.assertEqual(mac, mac2) - - # Decrypt - cipher = AES.new(key, AES.MODE_SIV, nonce=nonce) - for x in assoc_data: - cipher.update(x) - pt2 = cipher.decrypt_and_verify(ct, mac) - self.assertEqual(pt, pt2) - - -class TestVectorsWycheproof(unittest.TestCase): - - def __init__(self): - unittest.TestCase.__init__(self) - self._id = "None" - - def setUp(self): - self.tv = load_test_vectors_wycheproof(("Cipher", "wycheproof"), - "aes_siv_cmac_test.json", - "Wycheproof AES SIV") - - def shortDescription(self): - return self._id - - def test_encrypt(self, tv): - self._id = "Wycheproof Encrypt AES-SIV Test #" + str(tv.id) - - cipher = AES.new(tv.key, AES.MODE_SIV) - cipher.update(tv.aad) - ct, tag = cipher.encrypt_and_digest(tv.msg) - if tv.valid: - self.assertEqual(tag + ct, tv.ct) - - def test_decrypt(self, tv): - self._id = "Wycheproof Decrypt AES_SIV Test #" + str(tv.id) - - cipher = AES.new(tv.key, AES.MODE_SIV) - cipher.update(tv.aad) - try: - pt = cipher.decrypt_and_verify(tv.ct[16:], tv.ct[:16]) - except ValueError: - assert not tv.valid - else: - assert tv.valid - self.assertEqual(pt, tv.msg) - - def runTest(self): - - for tv in self.tv: - self.test_encrypt(tv) - self.test_decrypt(tv) - - -class TestVectorsWycheproof2(unittest.TestCase): - - def __init__(self): - unittest.TestCase.__init__(self) - self._id = "None" - - def setUp(self): - self.tv = load_test_vectors_wycheproof(("Cipher", "wycheproof"), - "aead_aes_siv_cmac_test.json", - "Wycheproof AEAD SIV") - - def shortDescription(self): - return self._id - - def test_encrypt(self, tv): - self._id = "Wycheproof Encrypt AEAD-AES-SIV Test #" + str(tv.id) - - cipher = AES.new(tv.key, AES.MODE_SIV, nonce=tv.iv) - cipher.update(tv.aad) - ct, tag = cipher.encrypt_and_digest(tv.msg) - if tv.valid: - self.assertEqual(ct, tv.ct) - self.assertEqual(tag, tv.tag) - - def test_decrypt(self, tv): - self._id = "Wycheproof Decrypt AEAD-AES-SIV Test #" + str(tv.id) - - cipher = AES.new(tv.key, AES.MODE_SIV, nonce=tv.iv) - cipher.update(tv.aad) - try: - pt = cipher.decrypt_and_verify(tv.ct, tv.tag) - except ValueError: - assert not tv.valid - else: - assert tv.valid - self.assertEqual(pt, tv.msg) - - def runTest(self): - - for tv in self.tv: - self.test_encrypt(tv) - self.test_decrypt(tv) - - -def get_tests(config={}): - wycheproof_warnings = config.get('wycheproof_warnings') - - tests = [] - tests += list_test_cases(SivTests) - tests += list_test_cases(SivFSMTests) - tests += [ TestVectors() ] - tests += [ TestVectorsWycheproof() ] - tests += [ TestVectorsWycheproof2() ] - return tests - - -if __name__ == '__main__': - suite = lambda: unittest.TestSuite(get_tests()) - unittest.main(defaultTest='suite') diff --git a/Crypto/SelfTest/Cipher/test_Salsa20.py b/Crypto/SelfTest/Cipher/test_Salsa20.py deleted file mode 100644 index fdcb072..0000000 --- a/Crypto/SelfTest/Cipher/test_Salsa20.py +++ /dev/null @@ -1,367 +0,0 @@ -# -*- coding: utf-8 -*- -# -# SelfTest/Cipher/Salsa20.py: Self-test for the Salsa20 stream cipher -# -# Written in 2013 by Fabrizio Tarizzo -# -# =================================================================== -# The contents of this file are dedicated to the public domain. To -# the extent that dedication to the public domain is not available, -# everyone is granted a worldwide, perpetual, royalty-free, -# non-exclusive license to exercise all rights associated with the -# contents of this file for any purpose whatsoever. -# No rights are reserved. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS -# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN -# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# =================================================================== - -"""Self-test suite for Crypto.Cipher.Salsa20""" - -import unittest - -from Crypto.Util.py3compat import bchr - -from Crypto.SelfTest.st_common import list_test_cases - -from Crypto.Cipher import Salsa20 - -from .common import make_stream_tests - -# This is a list of (plaintext, ciphertext, key[, description[, params]]) -# tuples. -test_data = [ - # Test vectors are taken from - # http://www.ecrypt.eu.org/stream/svn/viewcvs.cgi/ecrypt/trunk/submissions/salsa20/full/verified.test-vectors - ( '00' * 512, - '4dfa5e481da23ea09a31022050859936da52fcee218005164f267cb65f5cfd7f' - + '2b4f97e0ff16924a52df269515110a07f9e460bc65ef95da58f740b7d1dbb0aa' - + 'd64cec189c7eb8c6bbf3d7376c80a481d43e628701f6a27afb9fe23919f24114' - + '8db44f70d7063efcc3dd55a0893a613c3c6fe1c127bd6f59910589293bb6ef9e' - + 'e24819066dee1a64f49b0bbad5988635272b169af861f85df881939f29ada6fd' - + '0241410e8d332ae4798d929434a2630de451ec4e0169694cbaa7ebb121ea6a2b' - + 'da9c1581f429e0a00f7d67e23b730676783b262e8eb43a25f55fb90b3e753aef' - + '8c6713ec66c51881111593ccb3e8cb8f8de124080501eeeb389c4bcb6977cf95' - + '7d5789631eb4554400e1e025935dfa7b3e9039d61bdc58a8697d36815bf1985c' - + 'efdf7ae112e5bb81e37ecf0616ce7147fc08a93a367e08631f23c03b00a8da2f' - + 'aa5024e5c8d30aca43fc2d5082067b21b234bc741d68fb292c6012c3764ccee3' - + '1e364a5403e00cfee338a21a01e7d3cefd5a770ca0ab48c435ea6116435f7ad8' - + '30b217b49f978a68e207ed9f462af7fb195b2115fe8f24f152e4ddc32202d6f2' - + 'b52fafbcfbc202d8a259a611e901d3f62d065eb13f09bbc45cd45119b843efaa' - + 'b375703739daced4dd4059fd71c3c47fc2f9939670fad4a46066adcc6a564578' - + '3308b90ffb72be04a6b147cbe38cc0c3b9267c296a92a7c69873f9f263be9703', - '80000000000000000000000000000000', - '128 bits key, set 1, vector 0', - dict (iv='00'*8)), - - ( '00' * 512, - 'e3be8fdd8beca2e3ea8ef9475b29a6e7003951e1097a5c38d23b7a5fad9f6844' - + 'b22c97559e2723c7cbbd3fe4fc8d9a0744652a83e72a9c461876af4d7ef1a117' - + '8da2b74eef1b6283e7e20166abcae538e9716e4669e2816b6b20c5c356802001' - + 'cc1403a9a117d12a2669f456366d6ebb0f1246f1265150f793cdb4b253e348ae' - + '203d89bc025e802a7e0e00621d70aa36b7e07cb1e7d5b38d5e222b8b0e4b8407' - + '0142b1e29504767d76824850320b5368129fdd74e861b498e3be8d16f2d7d169' - + '57be81f47b17d9ae7c4ff15429a73e10acf250ed3a90a93c711308a74c6216a9' - + 'ed84cd126da7f28e8abf8bb63517e1ca98e712f4fb2e1a6aed9fdc73291faa17' - + '958211c4ba2ebd5838c635edb81f513a91a294e194f1c039aeec657dce40aa7e' - + '7c0af57cacefa40c9f14b71a4b3456a63e162ec7d8d10b8ffb1810d71001b618' - + '2f9f73da53b85405c11f7b2d890fa8ae0c7f2e926d8a98c7ec4e91b65120e988' - + '349631a700c6facec3471cb0413656e75e309456584084d7e12c5b43a41c43ed' - + '9a048abd9b880da65f6a665a20fe7b77cd292fe62cae644b7f7df69f32bdb331' - + '903e6505ce44fdc293920c6a9ec7057e23df7dad298f82ddf4efb7fdc7bfc622' - + '696afcfd0cddcc83c7e77f11a649d79acdc3354e9635ff137e929933a0bd6f53' - + '77efa105a3a4266b7c0d089d08f1e855cc32b15b93784a36e56a76cc64bc8477', - '8000000000000000000000000000000000000000000000000000000000000000', - '256 bits key, set 1, vector 0', - dict (iv='00'*8)), - - ( '00' * 512, - '169060ccb42bea7bee4d8012a02f3635eb7bca12859fa159cd559094b3507db8' - + '01735d1a1300102a9c9415546829cbd2021ba217b39b81d89c55b13d0c603359' - + '3f84159a3c84f4b4f4a0edcd9d38ff261a737909e0b66d68b5cac496f3a5be99' - + 'cb12c321ab711afaab36cc0947955e1a9bb952ed54425e7711279fbc81bb83f5' - + '6e55cea44e6daddb05858a153ea6213b3350c12aa1a83ef2726f09485fa71790' - + 'f9b9f922c7dda1113b1f9d56658ed3402803f511bc1f122601d5e7f0ff036e23' - + '23ef24bb24195b9fd574823cd8a40c29d86bd35c191e2038779ff696c712b6d8' - + '2e7014dbe1ac5d527af076c088c4a8d44317958189f6ef54933a7e0816b5b916' - + 'd8f12ed8afe9422b85e5cc9b8adec9d6cfabe8dbc1082bccc02f5a7266aa074c' - + 'a284e583a35837798cc0e69d4ce937653b8cdd65ce414b89138615ccb165ad19' - + '3c6b9c3d05eef4be921a10ea811fe61d11c6867600188e065daff90b509ec56b' - + 'd41e7e8968c478c78d590c2d2ee24ea009c8f49bc3d81672cfc47895a9e21c9a' - + '471ebf8e294bee5d2de436ac8d052bf31111b345f1da23c3a4d13b9fc5f0900a' - + 'a298f98f538973b8fad40d4d159777de2cfe2a3dead1645ddb49794827dba040' - + 'f70a0ff4ecd155e0f033604693a51e2363880e2ecf98699e7174af7c2c6b0fc6' - + '59ae329599a3949272a37b9b2183a0910922a3f325ae124dcbdd735364055ceb', - '09090909090909090909090909090909', - '128 bits key, set 2, vector 9', - dict (iv='00'*8)), - - ( '00' * 512, - '7041e747ceb22ed7812985465f50333124f971da1c5d6efe5ca201b886f31046' - + 'e757e5c3ec914f60ed1f6bce2819b6810953f12b8ba1199bf82d746a8b8a88f1' - + '142002978ec4c35b95dc2c82990f9e847a0ab45f2ca72625f5190c820f29f3aa' - + 'f5f0b5572b06b70a144f2a240c3b3098d4831fa1ce1459f8d1df226a6a79b0ab' - + '41e91799ef31b5ff3d756c19126b19025858ee70fbd69f2be955cb011c005e31' - + '32b271b378f39b0cb594e95c99ce6ff17735a541891845bbf0450afcb4a850b9' - + '4ee90afb713ae7e01295c74381180a3816d7020d5a396c0d97aaa783eaabb6ec' - + '44d5111157f2212d1b1b8fca7893e8b520cd482418c272ab119b569a2b9598eb' - + '355624d12e79adab81153b58cd22eaf1b2a32395dedc4a1c66f4d274070b9800' - + 'ea95766f0245a8295f8aadb36ddbbdfa936417c8dbc6235d19494036964d3e70' - + 'b125b0f800c3d53881d9d11e7970f827c2f9556935cd29e927b0aceb8cae5fd4' - + '0fd88a8854010a33db94c96c98735858f1c5df6844f864feaca8f41539313e7f' - + '3c0610214912cd5e6362197646207e2d64cd5b26c9dfe0822629dcbeb16662e8' - + '9ff5bf5cf2e499138a5e27bd5027329d0e68ddf53103e9e409523662e27f61f6' - + '5cf38c1232023e6a6ef66c315bcb2a4328642faabb7ca1e889e039e7c444b34b' - + 'b3443f596ac730f3df3dfcdb343c307c80f76e43e8898c5e8f43dc3bb280add0', - '0909090909090909090909090909090909090909090909090909090909090909', - '256 bits key, set 2, vector 9', - dict (iv='00'*8)), - - ( '00' * 1024, - '71daee5142d0728b41b6597933ebf467e43279e30978677078941602629cbf68' - + 'b73d6bd2c95f118d2b3e6ec955dabb6dc61c4143bc9a9b32b99dbe6866166dc0' - + '8631b7d6553050303d7252c264d3a90d26c853634813e09ad7545a6ce7e84a5d' - + 'fc75ec43431207d5319970b0faadb0e1510625bb54372c8515e28e2accf0a993' - + '0ad15f431874923d2a59e20d9f2a5367dba6051564f150287debb1db536ff9b0' - + '9ad981f25e5010d85d76ee0c305f755b25e6f09341e0812f95c94f42eead346e' - + '81f39c58c5faa2c88953dc0cac90469db2063cb5cdb22c9eae22afbf0506fca4' - + '1dc710b846fbdfe3c46883dd118f3a5e8b11b6afd9e71680d8666557301a2daa' - + 'fb9496c559784d35a035360885f9b17bd7191977deea932b981ebdb29057ae3c' - + '92cfeff5e6c5d0cb62f209ce342d4e35c69646ccd14e53350e488bb310a32f8b' - + '0248e70acc5b473df537ced3f81a014d4083932bedd62ed0e447b6766cd2604b' - + '706e9b346c4468beb46a34ecf1610ebd38331d52bf33346afec15eefb2a7699e' - + '8759db5a1f636a48a039688e39de34d995df9f27ed9edc8dd795e39e53d9d925' - + 'b278010565ff665269042f05096d94da3433d957ec13d2fd82a0066283d0d1ee' - + 'b81bf0ef133b7fd90248b8ffb499b2414cd4fa003093ff0864575a43749bf596' - + '02f26c717fa96b1d057697db08ebc3fa664a016a67dcef8807577cc3a09385d3' - + 'f4dc79b34364bb3b166ce65fe1dd28e3950fe6fa81063f7b16ce1c0e6daac1f8' - + '188455b77752045e863c9b256ad92bc6e2d08314c5bba191c274f42dfbb3d652' - + 'bb771956555e880f84cd8b827a4c5a52f3a099fa0259bd4aac3efd541f191170' - + '4412d6e85fbcc628b335875b9fef24807f6e1bc66c3186159e1e7f5a13913e02' - + 'd241ce2efdbcaa275039fb14eac5923d17ffbc7f1abd3b45e92127575bfbabf9' - + '3a257ebef0aa1437b326e41b585af572f7239c33b32981a1577a4f629b027e1e' - + 'b49d58cc497e944d79cef44357c2bf25442ab779651e991147bf79d6fd3a8868' - + '0cd3b1748e07fd10d78aceef6db8a5e563570d40127f754146c34a440f2a991a' - + '23fa39d365141f255041f2135c5cba4373452c114da1801bacca38610e3a6524' - + '2b822d32de4ab5a7d3cf9b61b37493c863bd12e2cae10530cddcda2cb7a5436b' - + 'ef8988d4d24e8cdc31b2d2a3586340bc5141f8f6632d0dd543bfed81eb471ba1' - + 'f3dc2225a15ffddcc03eb48f44e27e2aa390598adf83f15c6608a5f18d4dfcf0' - + 'f547d467a4d70b281c83a595d7660d0b62de78b9cca023cca89d7b1f83484638' - + '0e228c25f049184a612ef5bb3d37454e6cfa5b10dceda619d898a699b3c8981a' - + '173407844bb89b4287bf57dd6600c79e352c681d74b03fa7ea0d7bf6ad69f8a6' - + '8ecb001963bd2dd8a2baa0083ec09751cd9742402ad716be16d5c052304cfca1', - '0F62B5085BAE0154A7FA4DA0F34699EC', - '128 bits key, Set 6, vector# 3', - dict (iv='288FF65DC42B92F9')), - - ( '00' * 1024, - '5e5e71f90199340304abb22a37b6625bf883fb89ce3b21f54a10b81066ef87da' - + '30b77699aa7379da595c77dd59542da208e5954f89e40eb7aa80a84a6176663f' - + 'd910cde567cf1ff60f7040548d8f376bfd1f44c4774aac37410ede7d5c3463fc' - + '4508a603201d8495ad257894e5eb1914b53e8da5e4bf2bc83ac87ce55cc67df7' - + '093d9853d2a83a9c8be969175df7c807a17156df768445dd0874a9271c6537f5' - + 'ce0466473582375f067fa4fcdaf65dbc0139cd75e8c21a482f28c0fb8c3d9f94' - + '22606cc8e88fe28fe73ec3cb10ff0e8cc5f2a49e540f007265c65b7130bfdb98' - + '795b1df9522da46e48b30e55d9f0d787955ece720205b29c85f3ad9be33b4459' - + '7d21b54d06c9a60b04b8e640c64e566e51566730e86cf128ab14174f91bd8981' - + 'a6fb00fe587bbd6c38b5a1dfdb04ea7e61536fd229f957aa9b070ca931358e85' - + '11b92c53c523cb54828fb1513c5636fa9a0645b4a3c922c0db94986d92f314ff' - + '7852c03b231e4dceea5dd8cced621869cff818daf3c270ff3c8be2e5c74be767' - + 'a4e1fdf3327a934fe31e46df5a74ae2021cee021d958c4f615263d99a5ddae7f' - + 'eab45e6eccbafefe4761c57750847b7e75ee2e2f14333c0779ce4678f47b1e1b' - + '760a03a5f17d6e91d4b42313b3f1077ee270e432fe04917ed1fc8babebf7c941' - + '42b80dfb44a28a2a3e59093027606f6860bfb8c2e5897078cfccda7314c70035' - + 'f137de6f05daa035891d5f6f76e1df0fce1112a2ff0ac2bd3534b5d1bf4c7165' - + 'fb40a1b6eacb7f295711c4907ae457514a7010f3a342b4427593d61ba993bc59' - + '8bd09c56b9ee53aac5dd861fa4b4bb53888952a4aa9d8ca8671582de716270e1' - + '97375b3ee49e51fa2bf4ef32015dd9a764d966aa2ae541592d0aa650849e99ca' - + '5c6c39beebf516457cc32fe4c105bff314a12f1ec94bdf4d626f5d9b1cbbde42' - + 'e5733f0885765ba29e2e82c829d312f5fc7e180679ac84826c08d0a644b326d0' - + '44da0fdcc75fa53cfe4ced0437fa4df5a7ecbca8b4cb7c4a9ecf9a60d00a56eb' - + '81da52adc21f508dbb60a9503a3cc94a896616d86020d5b0e5c637329b6d396a' - + '41a21ba2c4a9493cf33fa2d4f10f77d5b12fdad7e478ccfe79b74851fc96a7ca' - + '6320c5efd561a222c0ab0fb44bbda0e42149611d2262bb7d1719150fa798718a' - + '0eec63ee297cad459869c8b0f06c4e2b56cbac03cd2605b2a924efedf85ec8f1' - + '9b0b6c90e7cbd933223ffeb1b3a3f9677657905829294c4c70acdb8b0891b47d' - + '0875d0cd6c0f4efe2917fc44b581ef0d1e4280197065d07da34ab33283364552' - + 'efad0bd9257b059acdd0a6f246812feb69e7e76065f27dbc2eee94da9cc41835' - + 'bf826e36e5cebe5d4d6a37a6a666246290ce51a0c082718ab0ec855668db1add' - + 'a658e5f257e0db39384d02e6145c4c00eaa079098f6d820d872de711b6ed08cf', - '0F62B5085BAE0154A7FA4DA0F34699EC3F92E5388BDE3184D72A7DD02376C91C', - '256 bits key, Set 6, vector# 3', - dict (iv='288FF65DC42B92F9')), - -] - - -class KeyLength(unittest.TestCase): - - def runTest(self): - - nonce = bchr(0) * 8 - for key_length in (15, 30, 33): - key = bchr(1) * key_length - self.assertRaises(ValueError, Salsa20.new, key, nonce) - - -class NonceTests(unittest.TestCase): - - def test_invalid_nonce_length(self): - key = bchr(1) * 16 - self.assertRaises(ValueError, Salsa20.new, key, bchr(0) * 7) - self.assertRaises(ValueError, Salsa20.new, key, bchr(0) * 9) - - def test_default_nonce(self): - - cipher1 = Salsa20.new(bchr(1) * 16) - cipher2 = Salsa20.new(bchr(1) * 16) - self.assertEqual(len(cipher1.nonce), 8) - self.assertNotEqual(cipher1.nonce, cipher2.nonce) - - -class ByteArrayTest(unittest.TestCase): - """Verify we can encrypt or decrypt bytearrays""" - - def runTest(self): - - data = b"0123" - key = b"9" * 32 - nonce = b"t" * 8 - - # Encryption - data_ba = bytearray(data) - key_ba = bytearray(key) - nonce_ba = bytearray(nonce) - - cipher1 = Salsa20.new(key=key, nonce=nonce) - ct = cipher1.encrypt(data) - - cipher2 = Salsa20.new(key=key_ba, nonce=nonce_ba) - key_ba[:1] = b'\xFF' - nonce_ba[:1] = b'\xFF' - ct_test = cipher2.encrypt(data_ba) - - self.assertEqual(ct, ct_test) - self.assertEqual(cipher1.nonce, cipher2.nonce) - - # Decryption - key_ba = bytearray(key) - nonce_ba = bytearray(nonce) - ct_ba = bytearray(ct) - - cipher3 = Salsa20.new(key=key_ba, nonce=nonce_ba) - key_ba[:1] = b'\xFF' - nonce_ba[:1] = b'\xFF' - pt_test = cipher3.decrypt(ct_ba) - - self.assertEqual(data, pt_test) - - -class MemoryviewTest(unittest.TestCase): - """Verify we can encrypt or decrypt bytearrays""" - - def runTest(self): - - data = b"0123" - key = b"9" * 32 - nonce = b"t" * 8 - - # Encryption - data_mv = memoryview(bytearray(data)) - key_mv = memoryview(bytearray(key)) - nonce_mv = memoryview(bytearray(nonce)) - - cipher1 = Salsa20.new(key=key, nonce=nonce) - ct = cipher1.encrypt(data) - - cipher2 = Salsa20.new(key=key_mv, nonce=nonce_mv) - key_mv[:1] = b'\xFF' - nonce_mv[:1] = b'\xFF' - ct_test = cipher2.encrypt(data_mv) - - self.assertEqual(ct, ct_test) - self.assertEqual(cipher1.nonce, cipher2.nonce) - - # Decryption - key_mv = memoryview(bytearray(key)) - nonce_mv = memoryview(bytearray(nonce)) - ct_mv = memoryview(bytearray(ct)) - - cipher3 = Salsa20.new(key=key_mv, nonce=nonce_mv) - key_mv[:1] = b'\xFF' - nonce_mv[:1] = b'\xFF' - pt_test = cipher3.decrypt(ct_mv) - - self.assertEqual(data, pt_test) - - -class TestOutput(unittest.TestCase): - - def runTest(self): - # Encrypt/Decrypt data and test output parameter - - key = b'4' * 32 - nonce = b'5' * 8 - cipher = Salsa20.new(key=key, nonce=nonce) - - pt = b'5' * 16 - ct = cipher.encrypt(pt) - - output = bytearray(16) - cipher = Salsa20.new(key=key, nonce=nonce) - res = cipher.encrypt(pt, output=output) - self.assertEqual(ct, output) - self.assertEqual(res, None) - - cipher = Salsa20.new(key=key, nonce=nonce) - res = cipher.decrypt(ct, output=output) - self.assertEqual(pt, output) - self.assertEqual(res, None) - - output = memoryview(bytearray(16)) - cipher = Salsa20.new(key=key, nonce=nonce) - cipher.encrypt(pt, output=output) - self.assertEqual(ct, output) - - cipher = Salsa20.new(key=key, nonce=nonce) - cipher.decrypt(ct, output=output) - self.assertEqual(pt, output) - - cipher = Salsa20.new(key=key, nonce=nonce) - self.assertRaises(TypeError, cipher.encrypt, pt, output=b'0'*16) - - cipher = Salsa20.new(key=key, nonce=nonce) - self.assertRaises(TypeError, cipher.decrypt, ct, output=b'0'*16) - - shorter_output = bytearray(7) - - cipher = Salsa20.new(key=key, nonce=nonce) - self.assertRaises(ValueError, cipher.encrypt, pt, output=shorter_output) - - cipher = Salsa20.new(key=key, nonce=nonce) - self.assertRaises(ValueError, cipher.decrypt, ct, output=shorter_output) - - -def get_tests(config={}): - tests = make_stream_tests(Salsa20, "Salsa20", test_data) - tests.append(KeyLength()) - tests += list_test_cases(NonceTests) - tests.append(ByteArrayTest()) - tests.append(MemoryviewTest()) - tests.append(TestOutput()) - - return tests - - -if __name__ == '__main__': - import unittest - suite = lambda: unittest.TestSuite(get_tests()) - unittest.main(defaultTest='suite') - -# vim:set ts=4 sw=4 sts=4 expandtab: diff --git a/Crypto/SelfTest/Cipher/test_pkcs1_15.py b/Crypto/SelfTest/Cipher/test_pkcs1_15.py deleted file mode 100644 index e122971..0000000 --- a/Crypto/SelfTest/Cipher/test_pkcs1_15.py +++ /dev/null @@ -1,252 +0,0 @@ -# -*- coding: utf-8 -*- -# -# SelfTest/Cipher/test_pkcs1_15.py: Self-test for PKCS#1 v1.5 encryption -# -# =================================================================== -# The contents of this file are dedicated to the public domain. To -# the extent that dedication to the public domain is not available, -# everyone is granted a worldwide, perpetual, royalty-free, -# non-exclusive license to exercise all rights associated with the -# contents of this file for any purpose whatsoever. -# No rights are reserved. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS -# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN -# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# =================================================================== - -from __future__ import print_function - -import json -import unittest -from binascii import unhexlify - -from Crypto.PublicKey import RSA -from Crypto.SelfTest.st_common import list_test_cases, a2b_hex, b2a_hex -from Crypto import Random -from Crypto.Cipher import PKCS1_v1_5 as PKCS -from Crypto.Util.py3compat import b -from Crypto.Util.number import bytes_to_long, long_to_bytes -from Crypto.SelfTest.loader import load_test_vectors_wycheproof - - -def rws(t): - """Remove white spaces, tabs, and new lines from a string""" - for c in ['\n', '\t', ' ']: - t = t.replace(c,'') - return t - -def t2b(t): - """Convert a text string with bytes in hex form to a byte string""" - clean = b(rws(t)) - if len(clean)%2 == 1: - raise ValueError("Even number of characters expected") - return a2b_hex(clean) - -class PKCS1_15_Tests(unittest.TestCase): - - def setUp(self): - self.rng = Random.new().read - self.key1024 = RSA.generate(1024, self.rng) - - # List of tuples with test data for PKCS#1 v1.5. - # Each tuple is made up by: - # Item #0: dictionary with RSA key component, or key to import - # Item #1: plaintext - # Item #2: ciphertext - # Item #3: random data - - _testData = ( - - # - # Generated with openssl 0.9.8o - # - ( - # Private key - '''-----BEGIN RSA PRIVATE KEY----- -MIICXAIBAAKBgQDAiAnvIAOvqVwJTaYzsKnefZftgtXGE2hPJppGsWl78yz9jeXY -W/FxX/gTPURArNhdnhP6n3p2ZaDIBrO2zizbgIXs0IsljTTcr4vnI8fMXzyNUOjA -zP3nzMqZDZK6757XQAobOssMkBFqRWwilT/3DsBhRpl3iMUhF+wvpTSHewIDAQAB -AoGAC4HV/inOrpgTvSab8Wj0riyZgQOZ3U3ZpSlsfR8ra9Ib9Uee3jCYnKscu6Gk -y6zI/cdt8EPJ4PuwAWSNJzbpbVaDvUq25OD+CX8/uRT08yBS4J8TzBitZJTD4lS7 -atdTnKT0Wmwk+u8tDbhvMKwnUHdJLcuIsycts9rwJVapUtkCQQDvDpx2JMun0YKG -uUttjmL8oJ3U0m3ZvMdVwBecA0eebZb1l2J5PvI3EJD97eKe91Nsw8T3lwpoN40k -IocSVDklAkEAzi1HLHE6EzVPOe5+Y0kGvrIYRRhncOb72vCvBZvD6wLZpQgqo6c4 -d3XHFBBQWA6xcvQb5w+VVEJZzw64y25sHwJBAMYReRl6SzL0qA0wIYrYWrOt8JeQ -8mthulcWHXmqTgC6FEXP9Es5GD7/fuKl4wqLKZgIbH4nqvvGay7xXLCXD/ECQH9a -1JYNMtRen5unSAbIOxRcKkWz92F0LKpm9ZW/S9vFHO+mBcClMGoKJHiuQxLBsLbT -NtEZfSJZAeS2sUtn3/0CQDb2M2zNBTF8LlM0nxmh0k9VGm5TVIyBEMcipmvOgqIs -HKukWBcq9f/UOmS0oEhai/6g+Uf7VHJdWaeO5LzuvwU= ------END RSA PRIVATE KEY-----''', - # Plaintext - '''THIS IS PLAINTEXT\x0A''', - # Ciphertext - '''3f dc fd 3c cd 5c 9b 12 af 65 32 e3 f7 d0 da 36 - 8f 8f d9 e3 13 1c 7f c8 b3 f9 c1 08 e4 eb 79 9c - 91 89 1f 96 3b 94 77 61 99 a4 b1 ee 5d e6 17 c9 - 5d 0a b5 63 52 0a eb 00 45 38 2a fb b0 71 3d 11 - f7 a1 9e a7 69 b3 af 61 c0 bb 04 5b 5d 4b 27 44 - 1f 5b 97 89 ba 6a 08 95 ee 4f a2 eb 56 64 e5 0f - da 7c f9 9a 61 61 06 62 ed a0 bc 5f aa 6c 31 78 - 70 28 1a bb 98 3c e3 6a 60 3c d1 0b 0f 5a f4 75''', - # Random data - '''eb d7 7d 86 a4 35 23 a3 54 7e 02 0b 42 1d - 61 6c af 67 b8 4e 17 56 80 66 36 04 64 34 26 8a - 47 dd 44 b3 1a b2 17 60 f4 91 2e e2 b5 95 64 cc - f9 da c8 70 94 54 86 4c ef 5b 08 7d 18 c4 ab 8d - 04 06 33 8f ca 15 5f 52 60 8a a1 0c f5 08 b5 4c - bb 99 b8 94 25 04 9c e6 01 75 e6 f9 63 7a 65 61 - 13 8a a7 47 77 81 ae 0d b8 2c 4d 50 a5''' - ), - ) - - def testEncrypt1(self): - for test in self._testData: - # Build the key - key = RSA.importKey(test[0]) - # RNG that takes its random numbers from a pool given - # at initialization - class randGen: - def __init__(self, data): - self.data = data - self.idx = 0 - def __call__(self, N): - r = self.data[self.idx:self.idx+N] - self.idx += N - return r - # The real test - cipher = PKCS.new(key, randfunc=randGen(t2b(test[3]))) - ct = cipher.encrypt(b(test[1])) - self.assertEqual(ct, t2b(test[2])) - - def testEncrypt2(self): - # Verify that encryption fail if plaintext is too long - pt = '\x00'*(128-11+1) - cipher = PKCS.new(self.key1024) - self.assertRaises(ValueError, cipher.encrypt, pt) - - def testVerify1(self): - for test in self._testData: - # Build the key - key = RSA.importKey(test[0]) - # The real test - cipher = PKCS.new(key) - pt = cipher.decrypt(t2b(test[2]), "---") - self.assertEqual(pt, b(test[1])) - - def testVerify2(self): - # Verify that decryption fails if ciphertext is not as long as - # RSA modulus - cipher = PKCS.new(self.key1024) - self.assertRaises(ValueError, cipher.decrypt, '\x00'*127, "---") - self.assertRaises(ValueError, cipher.decrypt, '\x00'*129, "---") - - # Verify that decryption fails if there are less then 8 non-zero padding - # bytes - pt = b('\x00\x02' + '\xFF'*7 + '\x00' + '\x45'*118) - pt_int = bytes_to_long(pt) - ct_int = self.key1024._encrypt(pt_int) - ct = long_to_bytes(ct_int, 128) - self.assertEqual("---", cipher.decrypt(ct, "---")) - - def testEncryptVerify1(self): - # Encrypt/Verify messages of length [0..RSAlen-11] - # and therefore padding [8..117] - for pt_len in range(0,128-11+1): - pt = self.rng(pt_len) - cipher = PKCS.new(self.key1024) - ct = cipher.encrypt(pt) - pt2 = cipher.decrypt(ct, "---") - self.assertEqual(pt,pt2) - - def testByteArray(self): - pt = b"XER" - cipher = PKCS.new(self.key1024) - ct = cipher.encrypt(bytearray(pt)) - pt2 = cipher.decrypt(bytearray(ct), "---") - self.assertEqual(pt, pt2) - - def testMemoryview(self): - pt = b"XER" - cipher = PKCS.new(self.key1024) - ct = cipher.encrypt(memoryview(bytearray(pt))) - pt2 = cipher.decrypt(memoryview(bytearray(ct)), "---") - self.assertEqual(pt, pt2) - - -class TestVectorsWycheproof(unittest.TestCase): - - def __init__(self, wycheproof_warnings, skip_slow_tests): - unittest.TestCase.__init__(self) - self._wycheproof_warnings = wycheproof_warnings - self._skip_slow_tests = skip_slow_tests - self._id = "None" - - def load_tests(self, filename): - - def filter_rsa(group): - return RSA.import_key(group['privateKeyPem']) - - result = load_test_vectors_wycheproof(("Cipher", "wycheproof"), - filename, - "Wycheproof PKCS#1v1.5 (%s)" % filename, - group_tag={'rsa_key': filter_rsa} - ) - return result - - def setUp(self): - self.tv = [] - self.tv.extend(self.load_tests("rsa_pkcs1_2048_test.json")) - if not self._skip_slow_tests: - self.tv.extend(self.load_tests("rsa_pkcs1_3072_test.json")) - self.tv.extend(self.load_tests("rsa_pkcs1_4096_test.json")) - - def shortDescription(self): - return self._id - - def warn(self, tv): - if tv.warning and self._wycheproof_warnings: - import warnings - warnings.warn("Wycheproof warning: %s (%s)" % (self._id, tv.comment)) - - def test_decrypt(self, tv): - self._id = "Wycheproof Decrypt PKCS#1v1.5 Test #%s" % tv.id - - cipher = PKCS.new(tv.rsa_key) - try: - pt = cipher.decrypt(tv.ct, sentinel=b'---') - except ValueError: - assert not tv.valid - else: - if pt == b'---': - assert not tv.valid - else: - assert tv.valid - self.assertEqual(pt, tv.msg) - self.warn(tv) - - def runTest(self): - - for tv in self.tv: - self.test_decrypt(tv) - - -def get_tests(config={}): - skip_slow_tests = not config.get('slow_tests') - wycheproof_warnings = config.get('wycheproof_warnings') - - tests = [] - tests += list_test_cases(PKCS1_15_Tests) - tests += [TestVectorsWycheproof(wycheproof_warnings, skip_slow_tests)] - return tests - -if __name__ == '__main__': - suite = lambda: unittest.TestSuite(get_tests()) - unittest.main(defaultTest='suite') - -# vim:set ts=4 sw=4 sts=4 expandtab: diff --git a/Crypto/SelfTest/Cipher/test_pkcs1_oaep.py b/Crypto/SelfTest/Cipher/test_pkcs1_oaep.py deleted file mode 100644 index 1711581..0000000 --- a/Crypto/SelfTest/Cipher/test_pkcs1_oaep.py +++ /dev/null @@ -1,506 +0,0 @@ -# -*- coding: utf-8 -*- -# -# SelfTest/Cipher/test_pkcs1_oaep.py: Self-test for PKCS#1 OAEP encryption -# -# =================================================================== -# The contents of this file are dedicated to the public domain. To -# the extent that dedication to the public domain is not available, -# everyone is granted a worldwide, perpetual, royalty-free, -# non-exclusive license to exercise all rights associated with the -# contents of this file for any purpose whatsoever. -# No rights are reserved. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS -# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN -# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# =================================================================== - -import unittest - -from Crypto.SelfTest.st_common import list_test_cases, a2b_hex -from Crypto.SelfTest.loader import load_test_vectors_wycheproof - -from Crypto.PublicKey import RSA -from Crypto.Cipher import PKCS1_OAEP as PKCS -from Crypto.Hash import MD2, MD5, SHA1, SHA256, RIPEMD160, SHA224, SHA384, SHA512 -from Crypto import Random -from Crypto.Signature.pss import MGF1 - -from Crypto.Util.py3compat import b, bchr - - -def rws(t): - """Remove white spaces, tabs, and new lines from a string""" - for c in ['\n', '\t', ' ']: - t = t.replace(c, '') - return t - - -def t2b(t): - """Convert a text string with bytes in hex form to a byte string""" - clean = rws(t) - if len(clean) % 2 == 1: - raise ValueError("Even number of characters expected") - return a2b_hex(clean) - - -class PKCS1_OAEP_Tests(unittest.TestCase): - - def setUp(self): - self.rng = Random.new().read - self.key1024 = RSA.generate(1024, self.rng) - - # List of tuples with test data for PKCS#1 OAEP - # Each tuple is made up by: - # Item #0: dictionary with RSA key component - # Item #1: plaintext - # Item #2: ciphertext - # Item #3: random data (=seed) - # Item #4: hash object - - _testData = ( - - # - # From in oaep-int.txt to be found in - # ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-1/pkcs-1v2-1-vec.zip - # - ( - # Private key - { - 'n':'''bb f8 2f 09 06 82 ce 9c 23 38 ac 2b 9d a8 71 f7 - 36 8d 07 ee d4 10 43 a4 40 d6 b6 f0 74 54 f5 1f - b8 df ba af 03 5c 02 ab 61 ea 48 ce eb 6f cd 48 - 76 ed 52 0d 60 e1 ec 46 19 71 9d 8a 5b 8b 80 7f - af b8 e0 a3 df c7 37 72 3e e6 b4 b7 d9 3a 25 84 - ee 6a 64 9d 06 09 53 74 88 34 b2 45 45 98 39 4e - e0 aa b1 2d 7b 61 a5 1f 52 7a 9a 41 f6 c1 68 7f - e2 53 72 98 ca 2a 8f 59 46 f8 e5 fd 09 1d bd cb''', - # Public key - 'e':'11', - # In the test vector, only p and q were given... - # d is computed offline as e^{-1} mod (p-1)(q-1) - 'd':'''a5dafc5341faf289c4b988db30c1cdf83f31251e0 - 668b42784813801579641b29410b3c7998d6bc465745e5c3 - 92669d6870da2c082a939e37fdcb82ec93edac97ff3ad595 - 0accfbc111c76f1a9529444e56aaf68c56c092cd38dc3bef - 5d20a939926ed4f74a13eddfbe1a1cecc4894af9428c2b7b - 8883fe4463a4bc85b1cb3c1''' - } - , - # Plaintext - '''d4 36 e9 95 69 fd 32 a7 c8 a0 5b bc 90 d3 2c 49''', - # Ciphertext - '''12 53 e0 4d c0 a5 39 7b b4 4a 7a b8 7e 9b f2 a0 - 39 a3 3d 1e 99 6f c8 2a 94 cc d3 00 74 c9 5d f7 - 63 72 20 17 06 9e 52 68 da 5d 1c 0b 4f 87 2c f6 - 53 c1 1d f8 23 14 a6 79 68 df ea e2 8d ef 04 bb - 6d 84 b1 c3 1d 65 4a 19 70 e5 78 3b d6 eb 96 a0 - 24 c2 ca 2f 4a 90 fe 9f 2e f5 c9 c1 40 e5 bb 48 - da 95 36 ad 87 00 c8 4f c9 13 0a de a7 4e 55 8d - 51 a7 4d df 85 d8 b5 0d e9 68 38 d6 06 3e 09 55''', - # Random - '''aa fd 12 f6 59 ca e6 34 89 b4 79 e5 07 6d de c2 - f0 6c b5 8f''', - # Hash - SHA1, - ), - - # - # From in oaep-vect.txt to be found in Example 1.1 - # ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-1/pkcs-1v2-1-vec.zip - # - ( - # Private key - { - 'n':'''a8 b3 b2 84 af 8e b5 0b 38 70 34 a8 60 f1 46 c4 - 91 9f 31 87 63 cd 6c 55 98 c8 ae 48 11 a1 e0 ab - c4 c7 e0 b0 82 d6 93 a5 e7 fc ed 67 5c f4 66 85 - 12 77 2c 0c bc 64 a7 42 c6 c6 30 f5 33 c8 cc 72 - f6 2a e8 33 c4 0b f2 58 42 e9 84 bb 78 bd bf 97 - c0 10 7d 55 bd b6 62 f5 c4 e0 fa b9 84 5c b5 14 - 8e f7 39 2d d3 aa ff 93 ae 1e 6b 66 7b b3 d4 24 - 76 16 d4 f5 ba 10 d4 cf d2 26 de 88 d3 9f 16 fb''', - 'e':'''01 00 01''', - 'd':'''53 33 9c fd b7 9f c8 46 6a 65 5c 73 16 ac a8 5c - 55 fd 8f 6d d8 98 fd af 11 95 17 ef 4f 52 e8 fd - 8e 25 8d f9 3f ee 18 0f a0 e4 ab 29 69 3c d8 3b - 15 2a 55 3d 4a c4 d1 81 2b 8b 9f a5 af 0e 7f 55 - fe 73 04 df 41 57 09 26 f3 31 1f 15 c4 d6 5a 73 - 2c 48 31 16 ee 3d 3d 2d 0a f3 54 9a d9 bf 7c bf - b7 8a d8 84 f8 4d 5b eb 04 72 4d c7 36 9b 31 de - f3 7d 0c f5 39 e9 cf cd d3 de 65 37 29 ea d5 d1 ''' - } - , - # Plaintext - '''66 28 19 4e 12 07 3d b0 3b a9 4c da 9e f9 53 23 - 97 d5 0d ba 79 b9 87 00 4a fe fe 34''', - # Ciphertext - '''35 4f e6 7b 4a 12 6d 5d 35 fe 36 c7 77 79 1a 3f - 7b a1 3d ef 48 4e 2d 39 08 af f7 22 fa d4 68 fb - 21 69 6d e9 5d 0b e9 11 c2 d3 17 4f 8a fc c2 01 - 03 5f 7b 6d 8e 69 40 2d e5 45 16 18 c2 1a 53 5f - a9 d7 bf c5 b8 dd 9f c2 43 f8 cf 92 7d b3 13 22 - d6 e8 81 ea a9 1a 99 61 70 e6 57 a0 5a 26 64 26 - d9 8c 88 00 3f 84 77 c1 22 70 94 a0 d9 fa 1e 8c - 40 24 30 9c e1 ec cc b5 21 00 35 d4 7a c7 2e 8a''', - # Random - '''18 b7 76 ea 21 06 9d 69 77 6a 33 e9 6b ad 48 e1 - dd a0 a5 ef''', - SHA1 - ), - - # - # From in oaep-vect.txt to be found in Example 2.1 - # ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-1/pkcs-1v2-1-vec.zip - # - ( - # Private key - { - 'n':'''01 94 7c 7f ce 90 42 5f 47 27 9e 70 85 1f 25 d5 - e6 23 16 fe 8a 1d f1 93 71 e3 e6 28 e2 60 54 3e - 49 01 ef 60 81 f6 8c 0b 81 41 19 0d 2a e8 da ba - 7d 12 50 ec 6d b6 36 e9 44 ec 37 22 87 7c 7c 1d - 0a 67 f1 4b 16 94 c5 f0 37 94 51 a4 3e 49 a3 2d - de 83 67 0b 73 da 91 a1 c9 9b c2 3b 43 6a 60 05 - 5c 61 0f 0b af 99 c1 a0 79 56 5b 95 a3 f1 52 66 - 32 d1 d4 da 60 f2 0e da 25 e6 53 c4 f0 02 76 6f - 45''', - 'e':'''01 00 01''', - 'd':'''08 23 f2 0f ad b5 da 89 08 8a 9d 00 89 3e 21 fa - 4a 1b 11 fb c9 3c 64 a3 be 0b aa ea 97 fb 3b 93 - c3 ff 71 37 04 c1 9c 96 3c 1d 10 7a ae 99 05 47 - 39 f7 9e 02 e1 86 de 86 f8 7a 6d de fe a6 d8 cc - d1 d3 c8 1a 47 bf a7 25 5b e2 06 01 a4 a4 b2 f0 - 8a 16 7b 5e 27 9d 71 5b 1b 45 5b dd 7e ab 24 59 - 41 d9 76 8b 9a ce fb 3c cd a5 95 2d a3 ce e7 25 - 25 b4 50 16 63 a8 ee 15 c9 e9 92 d9 24 62 fe 39''' - }, - # Plaintext - '''8f f0 0c aa 60 5c 70 28 30 63 4d 9a 6c 3d 42 c6 - 52 b5 8c f1 d9 2f ec 57 0b ee e7''', - # Ciphertext - '''01 81 af 89 22 b9 fc b4 d7 9d 92 eb e1 98 15 99 - 2f c0 c1 43 9d 8b cd 49 13 98 a0 f4 ad 3a 32 9a - 5b d9 38 55 60 db 53 26 83 c8 b7 da 04 e4 b1 2a - ed 6a ac df 47 1c 34 c9 cd a8 91 ad dc c2 df 34 - 56 65 3a a6 38 2e 9a e5 9b 54 45 52 57 eb 09 9d - 56 2b be 10 45 3f 2b 6d 13 c5 9c 02 e1 0f 1f 8a - bb 5d a0 d0 57 09 32 da cf 2d 09 01 db 72 9d 0f - ef cc 05 4e 70 96 8e a5 40 c8 1b 04 bc ae fe 72 - 0e''', - # Random - '''8c 40 7b 5e c2 89 9e 50 99 c5 3e 8c e7 93 bf 94 - e7 1b 17 82''', - SHA1 - ), - - # - # From in oaep-vect.txt to be found in Example 10.1 - # ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-1/pkcs-1v2-1-vec.zip - # - ( - # Private key - { - 'n':'''ae 45 ed 56 01 ce c6 b8 cc 05 f8 03 93 5c 67 4d - db e0 d7 5c 4c 09 fd 79 51 fc 6b 0c ae c3 13 a8 - df 39 97 0c 51 8b ff ba 5e d6 8f 3f 0d 7f 22 a4 - 02 9d 41 3f 1a e0 7e 4e be 9e 41 77 ce 23 e7 f5 - 40 4b 56 9e 4e e1 bd cf 3c 1f b0 3e f1 13 80 2d - 4f 85 5e b9 b5 13 4b 5a 7c 80 85 ad ca e6 fa 2f - a1 41 7e c3 76 3b e1 71 b0 c6 2b 76 0e de 23 c1 - 2a d9 2b 98 08 84 c6 41 f5 a8 fa c2 6b da d4 a0 - 33 81 a2 2f e1 b7 54 88 50 94 c8 25 06 d4 01 9a - 53 5a 28 6a fe b2 71 bb 9b a5 92 de 18 dc f6 00 - c2 ae ea e5 6e 02 f7 cf 79 fc 14 cf 3b dc 7c d8 - 4f eb bb f9 50 ca 90 30 4b 22 19 a7 aa 06 3a ef - a2 c3 c1 98 0e 56 0c d6 4a fe 77 95 85 b6 10 76 - 57 b9 57 85 7e fd e6 01 09 88 ab 7d e4 17 fc 88 - d8 f3 84 c4 e6 e7 2c 3f 94 3e 0c 31 c0 c4 a5 cc - 36 f8 79 d8 a3 ac 9d 7d 59 86 0e aa da 6b 83 bb''', - 'e':'''01 00 01''', - 'd':'''05 6b 04 21 6f e5 f3 54 ac 77 25 0a 4b 6b 0c 85 - 25 a8 5c 59 b0 bd 80 c5 64 50 a2 2d 5f 43 8e 59 - 6a 33 3a a8 75 e2 91 dd 43 f4 8c b8 8b 9d 5f c0 - d4 99 f9 fc d1 c3 97 f9 af c0 70 cd 9e 39 8c 8d - 19 e6 1d b7 c7 41 0a 6b 26 75 df bf 5d 34 5b 80 - 4d 20 1a dd 50 2d 5c e2 df cb 09 1c e9 99 7b be - be 57 30 6f 38 3e 4d 58 81 03 f0 36 f7 e8 5d 19 - 34 d1 52 a3 23 e4 a8 db 45 1d 6f 4a 5b 1b 0f 10 - 2c c1 50 e0 2f ee e2 b8 8d ea 4a d4 c1 ba cc b2 - 4d 84 07 2d 14 e1 d2 4a 67 71 f7 40 8e e3 05 64 - fb 86 d4 39 3a 34 bc f0 b7 88 50 1d 19 33 03 f1 - 3a 22 84 b0 01 f0 f6 49 ea f7 93 28 d4 ac 5c 43 - 0a b4 41 49 20 a9 46 0e d1 b7 bc 40 ec 65 3e 87 - 6d 09 ab c5 09 ae 45 b5 25 19 01 16 a0 c2 61 01 - 84 82 98 50 9c 1c 3b f3 a4 83 e7 27 40 54 e1 5e - 97 07 50 36 e9 89 f6 09 32 80 7b 52 57 75 1e 79''' - }, - # Plaintext - '''8b ba 6b f8 2a 6c 0f 86 d5 f1 75 6e 97 95 68 70 - b0 89 53 b0 6b 4e b2 05 bc 16 94 ee''', - # Ciphertext - '''53 ea 5d c0 8c d2 60 fb 3b 85 85 67 28 7f a9 15 - 52 c3 0b 2f eb fb a2 13 f0 ae 87 70 2d 06 8d 19 - ba b0 7f e5 74 52 3d fb 42 13 9d 68 c3 c5 af ee - e0 bf e4 cb 79 69 cb f3 82 b8 04 d6 e6 13 96 14 - 4e 2d 0e 60 74 1f 89 93 c3 01 4b 58 b9 b1 95 7a - 8b ab cd 23 af 85 4f 4c 35 6f b1 66 2a a7 2b fc - c7 e5 86 55 9d c4 28 0d 16 0c 12 67 85 a7 23 eb - ee be ff 71 f1 15 94 44 0a ae f8 7d 10 79 3a 87 - 74 a2 39 d4 a0 4c 87 fe 14 67 b9 da f8 52 08 ec - 6c 72 55 79 4a 96 cc 29 14 2f 9a 8b d4 18 e3 c1 - fd 67 34 4b 0c d0 82 9d f3 b2 be c6 02 53 19 62 - 93 c6 b3 4d 3f 75 d3 2f 21 3d d4 5c 62 73 d5 05 - ad f4 cc ed 10 57 cb 75 8f c2 6a ee fa 44 12 55 - ed 4e 64 c1 99 ee 07 5e 7f 16 64 61 82 fd b4 64 - 73 9b 68 ab 5d af f0 e6 3e 95 52 01 68 24 f0 54 - bf 4d 3c 8c 90 a9 7b b6 b6 55 32 84 eb 42 9f cc''', - # Random - '''47 e1 ab 71 19 fe e5 6c 95 ee 5e aa d8 6f 40 d0 - aa 63 bd 33''', - SHA1 - ), - ) - - def testEncrypt1(self): - # Verify encryption using all test vectors - for test in self._testData: - # Build the key - comps = [int(rws(test[0][x]), 16) for x in ('n', 'e')] - key = RSA.construct(comps) - - # RNG that takes its random numbers from a pool given - # at initialization - class randGen: - - def __init__(self, data): - self.data = data - self.idx = 0 - - def __call__(self, N): - r = self.data[self.idx:N] - self.idx += N - return r - - # The real test - cipher = PKCS.new(key, test[4], randfunc=randGen(t2b(test[3]))) - ct = cipher.encrypt(t2b(test[1])) - self.assertEqual(ct, t2b(test[2])) - - def testEncrypt2(self): - # Verify that encryption fails if plaintext is too long - pt = '\x00'*(128-2*20-2+1) - cipher = PKCS.new(self.key1024) - self.assertRaises(ValueError, cipher.encrypt, pt) - - def testDecrypt1(self): - # Verify decryption using all test vectors - for test in self._testData: - # Build the key - comps = [int(rws(test[0][x]),16) for x in ('n', 'e', 'd')] - key = RSA.construct(comps) - # The real test - cipher = PKCS.new(key, test[4]) - pt = cipher.decrypt(t2b(test[2])) - self.assertEqual(pt, t2b(test[1])) - - def testDecrypt2(self): - # Simplest possible negative tests - for ct_size in (127, 128, 129): - cipher = PKCS.new(self.key1024) - self.assertRaises(ValueError, cipher.decrypt, bchr(0x00)*ct_size) - - def testEncryptDecrypt1(self): - # Encrypt/Decrypt messages of length [0..128-2*20-2] - for pt_len in range(0, 128-2*20-2): - pt = self.rng(pt_len) - cipher = PKCS.new(self.key1024) - ct = cipher.encrypt(pt) - pt2 = cipher.decrypt(ct) - self.assertEqual(pt, pt2) - - def testEncryptDecrypt2(self): - # Helper function to monitor what's requested from RNG - global asked - - def localRng(N): - global asked - asked += N - return self.rng(N) - - # Verify that OAEP is friendly to all hashes - for hashmod in (MD2, MD5, SHA1, SHA256, RIPEMD160): - # Verify that encrypt() asks for as many random bytes - # as the hash output size - asked = 0 - pt = self.rng(40) - cipher = PKCS.new(self.key1024, hashmod, randfunc=localRng) - ct = cipher.encrypt(pt) - self.assertEqual(cipher.decrypt(ct), pt) - self.assertEqual(asked, hashmod.digest_size) - - def testEncryptDecrypt3(self): - # Verify that OAEP supports labels - pt = self.rng(35) - xlabel = self.rng(22) - cipher = PKCS.new(self.key1024, label=xlabel) - ct = cipher.encrypt(pt) - self.assertEqual(cipher.decrypt(ct), pt) - - def testEncryptDecrypt4(self): - # Verify that encrypt() uses the custom MGF - global mgfcalls - # Helper function to monitor what's requested from MGF - - def newMGF(seed, maskLen): - global mgfcalls - mgfcalls += 1 - return b'\x00' * maskLen - - mgfcalls = 0 - pt = self.rng(32) - cipher = PKCS.new(self.key1024, mgfunc=newMGF) - ct = cipher.encrypt(pt) - self.assertEqual(mgfcalls, 2) - self.assertEqual(cipher.decrypt(ct), pt) - - def testByteArray(self): - pt = b("XER") - cipher = PKCS.new(self.key1024) - ct = cipher.encrypt(bytearray(pt)) - pt2 = cipher.decrypt(bytearray(ct)) - self.assertEqual(pt, pt2) - - def testMemoryview(self): - pt = b("XER") - cipher = PKCS.new(self.key1024) - ct = cipher.encrypt(memoryview(bytearray(pt))) - pt2 = cipher.decrypt(memoryview(bytearray(ct))) - self.assertEqual(pt, pt2) - - -class TestVectorsWycheproof(unittest.TestCase): - - def __init__(self, wycheproof_warnings, skip_slow_tests): - unittest.TestCase.__init__(self) - self._wycheproof_warnings = wycheproof_warnings - self._skip_slow_tests = skip_slow_tests - self._id = "None" - - def load_tests(self, filename): - - def filter_rsa(group): - return RSA.import_key(group['privateKeyPem']) - - def filter_sha(group): - if group['sha'] == "SHA-1": - return SHA1 - elif group['sha'] == "SHA-224": - return SHA224 - elif group['sha'] == "SHA-256": - return SHA256 - elif group['sha'] == "SHA-384": - return SHA384 - elif group['sha'] == "SHA-512": - return SHA512 - else: - raise ValueError("Unknown sha " + group['sha']) - - def filter_mgf(group): - if group['mgfSha'] == "SHA-1": - return lambda x, y: MGF1(x, y, SHA1) - elif group['mgfSha'] == "SHA-224": - return lambda x, y: MGF1(x, y, SHA224) - elif group['mgfSha'] == "SHA-256": - return lambda x, y: MGF1(x, y, SHA256) - elif group['mgfSha'] == "SHA-384": - return lambda x, y: MGF1(x, y, SHA384) - elif group['mgfSha'] == "SHA-512": - return lambda x, y: MGF1(x, y, SHA512) - else: - raise ValueError("Unknown mgf/sha " + group['mgfSha']) - - def filter_algo(group): - return "%s with MGF1/%s" % (group['sha'], group['mgfSha']) - - result = load_test_vectors_wycheproof(("Cipher", "wycheproof"), - filename, - "Wycheproof PKCS#1 OAEP (%s)" % filename, - group_tag={'rsa_key': filter_rsa, - 'hash_mod': filter_sha, - 'mgf': filter_mgf, - 'algo': filter_algo} - ) - return result - - def setUp(self): - self.tv = [] - self.tv.extend(self.load_tests("rsa_oaep_2048_sha1_mgf1sha1_test.json")) - self.tv.extend(self.load_tests("rsa_oaep_2048_sha224_mgf1sha1_test.json")) - self.tv.extend(self.load_tests("rsa_oaep_2048_sha224_mgf1sha224_test.json")) - self.tv.extend(self.load_tests("rsa_oaep_2048_sha256_mgf1sha1_test.json")) - self.tv.extend(self.load_tests("rsa_oaep_2048_sha256_mgf1sha256_test.json")) - self.tv.extend(self.load_tests("rsa_oaep_2048_sha384_mgf1sha1_test.json")) - self.tv.extend(self.load_tests("rsa_oaep_2048_sha384_mgf1sha384_test.json")) - self.tv.extend(self.load_tests("rsa_oaep_2048_sha512_mgf1sha1_test.json")) - self.tv.extend(self.load_tests("rsa_oaep_2048_sha512_mgf1sha512_test.json")) - if not self._skip_slow_tests: - self.tv.extend(self.load_tests("rsa_oaep_3072_sha256_mgf1sha1_test.json")) - self.tv.extend(self.load_tests("rsa_oaep_3072_sha256_mgf1sha256_test.json")) - self.tv.extend(self.load_tests("rsa_oaep_3072_sha512_mgf1sha1_test.json")) - self.tv.extend(self.load_tests("rsa_oaep_3072_sha512_mgf1sha512_test.json")) - self.tv.extend(self.load_tests("rsa_oaep_4096_sha256_mgf1sha1_test.json")) - self.tv.extend(self.load_tests("rsa_oaep_4096_sha256_mgf1sha256_test.json")) - self.tv.extend(self.load_tests("rsa_oaep_4096_sha512_mgf1sha1_test.json")) - self.tv.extend(self.load_tests("rsa_oaep_4096_sha512_mgf1sha512_test.json")) - self.tv.extend(self.load_tests("rsa_oaep_4096_sha512_mgf1sha512_test.json")) - self.tv.extend(self.load_tests("rsa_oaep_misc_test.json")) - - def shortDescription(self): - return self._id - - def warn(self, tv): - if tv.warning and self._wycheproof_warnings: - import warnings - warnings.warn("Wycheproof warning: %s (%s)" % (self._id, tv.comment)) - - def test_decrypt(self, tv): - self._id = "Wycheproof Decrypt %s Test #%s" % (tv.algo, tv.id) - - cipher = PKCS.new(tv.rsa_key, hashAlgo=tv.hash_mod, mgfunc=tv.mgf, label=tv.label) - try: - pt = cipher.decrypt(tv.ct) - except ValueError: - assert not tv.valid - else: - assert tv.valid - self.assertEqual(pt, tv.msg) - self.warn(tv) - - def runTest(self): - - for tv in self.tv: - self.test_decrypt(tv) - - -def get_tests(config={}): - skip_slow_tests = not config.get('slow_tests') - wycheproof_warnings = config.get('wycheproof_warnings') - - tests = [] - tests += list_test_cases(PKCS1_OAEP_Tests) - tests += [TestVectorsWycheproof(wycheproof_warnings, skip_slow_tests)] - return tests - - -if __name__ == '__main__': - def suite(): - unittest.TestSuite(get_tests()) - unittest.main(defaultTest='suite') - -# vim:set ts=4 sw=4 sts=4 expandtab: diff --git a/Crypto/SelfTest/Hash/__init__.py b/Crypto/SelfTest/Hash/__init__.py deleted file mode 100644 index 1933f2a..0000000 --- a/Crypto/SelfTest/Hash/__init__.py +++ /dev/null @@ -1,61 +0,0 @@ -# -*- coding: utf-8 -*- -# -# SelfTest/Hash/__init__.py: Self-test for hash modules -# -# Written in 2008 by Dwayne C. Litzenberger -# -# =================================================================== -# The contents of this file are dedicated to the public domain. To -# the extent that dedication to the public domain is not available, -# everyone is granted a worldwide, perpetual, royalty-free, -# non-exclusive license to exercise all rights associated with the -# contents of this file for any purpose whatsoever. -# No rights are reserved. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS -# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN -# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# =================================================================== - -"""Self-test for hash modules""" - -__revision__ = "$Id$" - -def get_tests(config={}): - tests = [] - from Crypto.SelfTest.Hash import test_HMAC; tests += test_HMAC.get_tests(config=config) - from Crypto.SelfTest.Hash import test_CMAC; tests += test_CMAC.get_tests(config=config) - from Crypto.SelfTest.Hash import test_MD2; tests += test_MD2.get_tests(config=config) - from Crypto.SelfTest.Hash import test_MD4; tests += test_MD4.get_tests(config=config) - from Crypto.SelfTest.Hash import test_MD5; tests += test_MD5.get_tests(config=config) - from Crypto.SelfTest.Hash import test_RIPEMD160; tests += test_RIPEMD160.get_tests(config=config) - from Crypto.SelfTest.Hash import test_SHA1; tests += test_SHA1.get_tests(config=config) - from Crypto.SelfTest.Hash import test_SHA256; tests += test_SHA256.get_tests(config=config) - from Crypto.SelfTest.Hash import test_SHA3_224; tests += test_SHA3_224.get_tests(config=config) - from Crypto.SelfTest.Hash import test_SHA3_256; tests += test_SHA3_256.get_tests(config=config) - from Crypto.SelfTest.Hash import test_SHA3_384; tests += test_SHA3_384.get_tests(config=config) - from Crypto.SelfTest.Hash import test_SHA3_512; tests += test_SHA3_512.get_tests(config=config) - from Crypto.SelfTest.Hash import test_keccak; tests += test_keccak.get_tests(config=config) - from Crypto.SelfTest.Hash import test_SHAKE; tests += test_SHAKE.get_tests(config=config) - try: - from Crypto.SelfTest.Hash import test_SHA224; tests += test_SHA224.get_tests(config=config) - from Crypto.SelfTest.Hash import test_SHA384; tests += test_SHA384.get_tests(config=config) - from Crypto.SelfTest.Hash import test_SHA512; tests += test_SHA512.get_tests(config=config) - except ImportError: - import sys - sys.stderr.write("SelfTest: warning: not testing SHA224/SHA384/SHA512 modules (not available)\n") - from Crypto.SelfTest.Hash import test_BLAKE2; tests += test_BLAKE2.get_tests(config=config) - from Crypto.SelfTest.Hash import test_Poly1305; tests += test_Poly1305.get_tests(config=config) - return tests - -if __name__ == '__main__': - import unittest - suite = lambda: unittest.TestSuite(get_tests()) - unittest.main(defaultTest='suite') - -# vim:set ts=4 sw=4 sts=4 expandtab: diff --git a/Crypto/SelfTest/Hash/__pycache__/__init__.cpython-36.pyc b/Crypto/SelfTest/Hash/__pycache__/__init__.cpython-36.pyc deleted file mode 100644 index 603e3fb51a59d31c01be0e8bca92868cca399f0f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1855 zcmb`I%Wm676ozLglA@^l%}IJeRltj?K+M>Roxli!IF11uv5g=OP)8er)=)AfiWG*l z0~wk{;A{i*HTp{2X4O~dD(8$Uf#9+zh50#WzTtlkhvcYNE}PFjZaSaKgnT2ZBM1Fg z(4rS0jPwbked>`RWeUrEp?$^8F?FKw=S*X|ul7}zXT}%O*Iae1vjQ`}Qc9S9LAu4e zA1+*f_&9c>xHAlS=h}&`JJXQe_-=HkZl18s0fi)ZY(OhPJA@XUDuj%PpbT>QWJ-lX z$$~DFv9cg6_mw_dG8I@(A*ChNv3639+)n4$@B~}faOJAvV4XW zfEmJ&%*ZekSV0sdD`Z#^m?=!j%nU05D~h6I#SAM0D~Xb1r3|Y8D~qyZm?5ine6!G+R)36Ca%a4eu4{ z(xiYdqkVjKa0r1u2!o+FS`QyChYdOB?9C2!i;Lrf zZ3v1IL$I^E2Vr>?_UxSbRI~X_<2+ft{+oLtaeA0fMe(ALi z!RhW4zsV1<3j3W;4iCIwwBHHBxPyKWbe1L-oZw)8>|N;3w|h@^yN~*}rW8R3X5OWPhN6DiY zCRX`nPglH$p97V`Lr^N=UGXdWec6f>9eMEk_O*ySyp z+6L)vaNP0|ZCMBw_J3EyAEN0x<6ngT1Oxw^Tel9kd?y%Lvw3_S20hF7u2%i6Ju8Aj zAJ3e@#2LAfwOmJQwT>39qh;G(;KjDRHJfwXLw|-AU4js*(h{ltr>3N?YS9`sXk$Gh zvm}OXPaQ9?ZH^oG`2Z8H4qQRGjpMV5$(Y8Nr3*j&5^DB<2cpIst_+a?InV0`mFCW2Bg!iH?uK)l5 diff --git a/Crypto/SelfTest/Hash/__pycache__/common.cpython-36.pyc b/Crypto/SelfTest/Hash/__pycache__/common.cpython-36.pyc deleted file mode 100644 index 4099ba9b9110a75082e31e819143b32518016a95..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 7206 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 diff --git a/Crypto/SelfTest/Hash/__pycache__/test_BLAKE2.cpython-36.pyc b/Crypto/SelfTest/Hash/__pycache__/test_BLAKE2.cpython-36.pyc deleted file mode 100644 index 258d1f4522e988ad1f3cc4e918da13fd8d9983a4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 12558 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 D;PFb$ diff --git a/Crypto/SelfTest/Hash/__pycache__/test_CMAC.cpython-36.pyc b/Crypto/SelfTest/Hash/__pycache__/test_CMAC.cpython-36.pyc deleted file mode 100644 index c9e345332efeaf6683001447786406584be25fab..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 9188 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 a=Kr;hQ84s{D+?DF-dMOceVSlysQ(K<5*Duj diff --git a/Crypto/SelfTest/Hash/__pycache__/test_HMAC.cpython-36.pyc b/Crypto/SelfTest/Hash/__pycache__/test_HMAC.cpython-36.pyc deleted file mode 100644 index 56db0dc37117d5a1080ba923de76c5fcfd90bca4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 9411 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 diff --git a/Crypto/SelfTest/Hash/__pycache__/test_MD5.cpython-36.pyc b/Crypto/SelfTest/Hash/__pycache__/test_MD5.cpython-36.pyc deleted file mode 100644 index 0140b85465d958a017b6fd659f4af0783fcbcf1c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2306 zcmaJ?$#UC95XAuCB9U4wJKnM(@*>lgNbF0MOJ$0S?Iczf*>Q|i3N^$GC`ceF1CVT~ zq!V4a`5SW1C5L=VPPpczU(hK%pk%A!a)6pfqo=!PreAlDHZwDAy|{`0u5#Qz+_|R$ z`~w)tUqA@was&}RLQmOOi1>lv3W)JyBn}F0A?FKG(Jg|k7?lQPw+ynodmH{>LEwIB8zW0vPg?t(__J{gj|5g z4RZ4ha;tQP+}h^jKVg;0YPZSK8_t~t-8piH)ZQXkwXng}UnW zMzPe2_jl4!{Si(!>rdLoF&vJop$y#xB7gusQ@g`W`Z@}O{dM@8i^3%Jm>18-2~9GI z=nAoY;@E*K_f%P@jxEcMV^cq{b=9I7cXDBANxDM^JL$fZq;WXx*D^`=eZ?|*jxPsF z&&0N-_?qKT)pRUNHBBW$IFlS%Rt(v(HJ_+@(36Sjm|9>F)uxISSZXHVo}Wp9WA?y~ zSbooPG@BTzfz?1$Fb)(`A@a%WfF=p-~ch0k0guxfM&tJ;x@hWf3PZuwg2Suli1) zD-H;<)#h5O-RVAj^!V#b(52)v5)1EgNk==;#RnKFmoy^3y!E?U%bL1A2T?TTWEz7d1 z%;*2_5{3n`1S3xv8yJ>l5jQ|b&|eQx$`c_Kh)4>g__lDw1K1)djZv&0@@Zkr^^pY$ zb;twc<@IBhg{+ef@HX`}Aq06lO>(s2t1x-6pw!j6t;=;q(G1;zAEU-+l?hf}5+2Y@ z7=^^0P5|eLH9%MNM}xs=7~caI6X>V%*b8$Rg43gQSiZbF z3{$qMJH@cxV3$$u?%XC=cEt>rtb9MhgC4=FzrbGtgNscjFXWe44Y?I)(-?A;`Kk#q ztL>O!6|>e;-wK-_DmT4xndXV>TiwE|OWFr_j( zNeeF59Ir`ame{NXBokS{KN6`)&aYkry+j8h0$|m=f~rLxpo5p^^1&$k7m+Ab(Y&~@ KP_00n!TT?_a5w(| diff --git a/Crypto/SelfTest/Hash/__pycache__/test_Poly1305.cpython-36.pyc b/Crypto/SelfTest/Hash/__pycache__/test_Poly1305.cpython-36.pyc deleted file mode 100644 index c4b20dfd31d5b0810a28d7deb75aafad0e04d28a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 13401 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 Y8m%w=ymDpf^2LRV=a-fi=dpwKKj*1?-~a#s diff --git a/Crypto/SelfTest/Hash/__pycache__/test_RIPEMD160.cpython-36.pyc b/Crypto/SelfTest/Hash/__pycache__/test_RIPEMD160.cpython-36.pyc deleted file mode 100644 index 1424cf11c7845c257ccbbef8c550f5b950b634ce..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1572 zcmZ`(TXWM!6xK>kV&_7j4J`w0G2s$BO>Es(T1`6{Afbh}q?ClV=*6?Ev+F4Ft&&2U z3_QUrKcs(2uYJm2@Ket^31m7`Y4)4rv%BASZnC$qFdM$S!@IMF@sDxgnMeCRu3RC2 z0iuLs{KgOj1J;_yWFsM`BZ2@YR8t z31qq1tHc$k!>xBlJS8jp)36M;-xGp6J4SQu1htGNDamTth!V$Pl+%RDNF~${9GBTF z3PUNGqCOL@OBr}hX^gL|tkfH_KPryud6A`qZnJFI0+I+^aA_bsDI?%qdVVNmpnOP} zN4Xz_O39M&vcaTqZKgtLQ;1l|BVqeKXEI_*AZ!*YhjLq}q_nt5$_52HV3AZl3MejV z=nBRh;kX`WR4MK{G@{B2#+Ujs&v{qYA??b%C>ttt5;t`0C@qP^5XE-pMM=4k1f7_Ts9n++tl-z&!fan7?Zw@K?X<< z2}Z_&2QH>1N~WnanzzbCrs(>jQw>& z%XrzbS673CphrIzt{GgLxbjs5AYk^4K6#@j+JZ{Y>|1Y4V!SqA6PPM0_>Ig!_5Bpi zdTl$?G&tkisv@7qfs$zJw}4b)p9x+_WQ#@b{#3on&#{PFL=|^I|G$=C&wn+ ze;e5?JT=~Jzv5ZD#|Pc^=&0Bm4!m|R73X#PGr;_a**;Bhn-`3jg ziO`4aTBD<~)|JI+PT!zNuIp=%d3>wHB-w5JRaQHlK2Hao&UT`A&mR+wNuBi{Q(^3r z!hCDIC0I$ajd@fL2Wg@8;+odqImGBDe3NW0z%pJhtKar`UjX0O!e2QqBfF>lQ@Os^ zB=H=6C;YHiXs)J}S^7jp!xTc(%=AoTy7g%5Da&f7woWLU)3%lAK(hr6mrfmv+PSBqHA^` tP2I!nEZ6=J4tsLr2D)+^p*n41wed9#V*Ce9GEFL`#;P?xQ^mei$-hZgi&6jp diff --git a/Crypto/SelfTest/Hash/__pycache__/test_SHA1.cpython-36.pyc b/Crypto/SelfTest/Hash/__pycache__/test_SHA1.cpython-36.pyc deleted file mode 100644 index fda4202f9cfbda52c33bf2d5de938a1ba070aa8a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1550 zcmZuxOK;mo5Z)yziF*1GH$WPo5R$gA0$49nlmw(kjkJJ)qHY5jXv4N(SKO6En-68V za%@4m)b24qq<^44X0JW@+*?karEDXIk~72E3Wf-MK+-k(p;Dx=SCu$KYdYgc^^R&qpkr90-<*db$V%t4|VMf5ornB559z zbk-alAKgMasDWi+#xBEPas}#6m=NlzW!?qzMZ#0LPlm&x#Vp6}x1B-9A!A~(Zm-|z z4|;9C>-a;Tw&`F~EY2_Mo z_ucVNDBd%WD4du093%C-PZOyO5EQzgF7>w`rrqfEHF%Ra%KPOX`wl>|_QjL2G4cJmCwz5`K88+uv z(tH_`XiUlBS1JQww0t^cVzZ~_%P{dtm>z<%vHF02`Bxd;?kUS^r)f1iHi&Ms>ohc3 zrU8T%UK%W!)RTZVG_HCeD@&v1mOnZ!*__P#Nfae9uP7@WgxtyUqeKu7_8KIMRF+af zxJcgxVkT=xLhxX`5bRsd6V7XDjUJ^_nJ4o(iz!$2bhU^|gR<0b6jY3O5=^szSs39smT(@|fYtXi z&4d{f^XJNi>3IAP zsyDbwlRpCS8aRV88_8UDTQ#s-h8uw_LZRFMFov>M7b)m@rK=O$D9eK9(Zu&WX^w-K zq<#==O8WQ?y!&oys*8>B3^o3#a&W)Pm_*F;_!nyKOAyjf`~JUtq5qn3TE>QFRT1JQ~UB~fS)qzO>uWT15}-OGaFP`mOu>AE=p+9EXZ;%z zuqGDVhX>Gw9(;FX!7z8>Av}V|v);rmtlWm%aOaafag+;p7mhxKui>cdOgiul9DlMV zUDY}7!MAYlvu#^&bY_jdzx?q`mHE>~)s0tgibi?)N_(&L#kyJfuSGrg&tCsbDQh_m zgERq3Ll#89DdjPvf+a}?f<{pmQXwFdilH22VVNWVM-+&2!~#(wD#Q}8LaY&Q zC!7XJ%Hk+Wc_32)Jj*gBi4tiN6E0Ym2Vu@=#7W9{MwMbpB?984wZ+vfEcjIq$>rV? z@x(jvNN{ozw;Tu)0p*g4P|!@K3~dE8%P7YRG08}T>VV{&awTFaB$h@onzvTVS(*hL zQxI{aV#Z{ab3p-8ngkgr{4mvokreApKmafr&=`{J%TK>(vAp!o#jNp)%3G|eb*Y-h zd#CgtVy??o-KeGaM*LZLZ#PPNu+ehvy%ZNpFIyh*ln|BVQsy*Gh)5tv@-!qd#gYIC zqnImH3!Y0J=aS?q4Oj?d=XUY`+)5j3XNHT@wDBvP^$8NN!6~iE{$QHWg-+>I?gz)V z-aGGY=r$c}?mi4Ycdr)Vo z7`bL;nHRI|w(as?mcEC(zWh3VC-k@!%h`B+(acxNa9kGIHSfpc8XwlvwU7&e0gQJp z$L8U^LGxqt%*IdYnU$4J_aN&iN$<}UPq5mzhNlf%G|QZ8N89iE=EdhAMCAiY4buVK@Fy7NbG_S z0idPb+RbHk^$*Ek!qun!3%WQx*D_JgH8X&0_easHelHU;fSw z!YlNH91dtp52O)aKNbpO9Q8gjMbJT#T4r0^&ITK|=(M-K64gX)>>S}nlA^A8x;Shc zPjJ-#M7H*q%;*LB*Pxk83fueS!aBzo&#g;(VZV5{=|Ja_{+|5(=0)e+KJJ=%N}hf4 zXL3%Cd(g$XtxIxgQL@(U{U6=GTdx7NjhDZ60`86impNY-j~$bo%J_`o z_cjUz!4oQez{zx+2q{IZV(Gdr<2(qwIMHDs@?3|xOd{7)AR{mKm4KK9%!|E5`w2)H zgb;<%RUb{KW0C8C3rGS#cm0sD1hfi7z?6g_b~OZfta%>iZlpctC0-nO(o;Hexr($1 z)nP%%Z8GS$yKkIcWq_1+ayhM9d#;|h-Ac?Ss_m_oAR5)~in>-+^M_|EQMTJt^#Y0s zMmy-Xof>hmUfy=kRJEvEI&Eq3FH+q`ldrxReJiR_iN;3D(`LGud!w?*U(3UAR3nxi zErmQ0XmGS~X=Jcw5HK>x8kxLin|uzJr|nj?nwyUwp#Ay|GGgt~J!^;Fq&Mx`mf>gj ze*~rB^_oM3SwG9>Vy3dJ-N~}q0#>Dw_p;0cxA{^Tv+DrfU~ic@1H<=m)CSOfx_Q~*LD z(7c>6FXX~YLLNmTk-5*A)*;s}V>}Sh+9H?j*!5!wMaaQrp%>?|3M6yG#AAq^5Md-d zPbxo1LSJi_hmj7IQ~*9tAZMZEZH#6B31O%-(gbOWR3IHAogkG+Go(4v0%?i#EFDXP zeTW+-3HNoLxG@)8M#_zSh;a8v^Oz;VkA;s#!kA)y2wozkj5v2Cu$GFe9nAJs582u7 zL-Ei#a5y_S2-~raG%y|sPhtT`tN_hC?FE4=SnijP)Q+161bx>SZN)`zEQzr9BwiHGvz4kGSXFZBJQk;_nqPOgb;(~{ zce`6NaiX#*7HejTwcdPm%yHavhddm{J{$5OXME@l{UJ^btaf+PL$bO!Q?0!yAl<3U z#q*7YfmPkZ<<)&;C_garJIIRh<6C54SMQk#Q;3ym1E}E``NNI;(8wPdxmOuXY}!*# zE@rdEy!s{1wDv?b>*B>0h9Bm-n55h5MuYuMtQTw)yPJSaGu!k6(+1jYT)uIX<7<6@ z3~woF*=AU@M>{C3WsA_Bjs1!CsYUzPrS`1qkuia7XeNqzmPxbt^<&z~x_#`S(2!%= zSa?ZMEOvT0u-pD>UNpv|bo&VTQ*#rq&Arj5)~>F-?EkhDvmC@{e?w!n*`i{|+V1)W zAJB9c3stPj#@HHcw_8~T3z=or2({9;ukVLHHbsej*TeKJMU(c8@)LpAfo%+$SgN~* inM|}D6Vp#Pv+1>;nPaStlO3y%8M$+J?_>PO-@gGHkvLlb diff --git a/Crypto/SelfTest/Hash/__pycache__/test_SHA384.cpython-36.pyc b/Crypto/SelfTest/Hash/__pycache__/test_SHA384.cpython-36.pyc deleted file mode 100644 index b4a182eaed5a78410c1b5c7e0f34612c5f24f8ba..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1523 zcmYjRPjA~c6qjT>ahi15x~%^XIt(iupf)K|q_ho1*8)QiL$M*f%om5`BON7{?MQOB z1nsH4_6zJA>?`TIQ@%n^d$dy^63EB*hwsmid}Oz8-;#fRul~6e1pfs$zAaoo$5H=| z69nS`?!kTN!4^C?2w=x`;2}Jk_QqimxDdXA{g2@|vK{#PEUJEkZ{W_XJMO}_aPTo0 z_iXoc3%-N9pTaPJJ4eCb@#POkcIKWowr=8jRWvqsiz@shmnK2+P|gh5_rQC)cFdaK-6bSe%}D9g^8KDK}g>Ukl6m z!t0PMugUp_JFnKl^Q!hbB+WHhjgNC6mS!ZERB*`=NK7|l+%ifOSJWV0Jh!pHe%jND9^&~!wDLFh8 z?J>(V5k$$9Dw7L5Ndq}cq}2$bWkMy?fkvz;*Oo|*r$G=w?F4heQc#KHc%a%@DV#{1 z26P08qZ|Y4Jk@Q`9!rYlWK3~m6-z)k5Sf%bPeCWvvXrGfaa=gXxyF;HglMC9<`@$~ zXWSw*j!2T(j1o>APoxo$CNx(`CWMrqfBLmj^UL^DO`EtVTeT@e6fftGNjg6#sQ_Y~y%|qdvq5LWpKT8NT=3(1GqODm(9^ zFnAZe3!&F^vB$Qd|EY(4vh(^1Hw1&Q-P-iSmG_G5eyPsvvnXKD8}HuexwVsa%Ph)rF|YQ~S-a!C zPe3(l(D9nNE2e9+wff(nx{Fqy{}{bh)o7;X)6w#xIa$ovXjbSi>!BFc*x^r?%A6@o zV6+K2@-M&}bU*U_K3WIb6gga8v^!JVY)YdTq4w7-2>0;shf!GFN3QKpCZ#IolS#FQ z>}%sqzI+ib)_{9e6P$)k^da~VBBbGKtfar17mbfN-tie6`4?#IbY0Jl=^k!x`#;ZA zsX;ya5xE*iP(AYU-umSlgyUW8VYQky-q#?i{25g~16=#luevxD&tL3&LEj5@HcDSr zwd>d0?e=5>3xmZRc;S}<=c=?Qd+244acaB1VyWtKl&HAg%|-n{Tntt2zmDXI-+sN{3b(elZ{YOgut9bCBtB1*?gfZTX&&(q z7l&tYN996-av@D%Y?Pfy#;9^{oq$Y_JLu{5VIaH&lB>XC0$Cve!*j!VEpEXXZC&2~ z{_7*yq(i|59|x!ebO0p(0;V8=Q+i1i?XwBE;OsZ{m~iWwUa|@6TT^mrO-SEX4vb1* z!8k#SDWrb325gO;{lJIKoofbONWWZonpjgt$pb%-(0dj(T5tk~FC7MD0gqDZ27v$x zuz94SqXrWd7zZn(A&lcN>Z(|TJn2E44Od`v+QzhLYY_jcOT~=#A}M2`euxsttgakg z4C7ZqT-*j5?2vb3GFFtDVKo} z>RPMRrR#LjS_4|9*2f-f?(|my6y@=+quQgBc6RKL283 zeMx@Vx^yN^-{Mv1zi*YzYg0OLLT6(4OR5YrE{^+XQ|Ve$@cd@`Cjirgsw(#;wyO4P z9J=+|*@Yb^OnGWhD8)hz;r1Z4&wnA7*fD8 z4t*EPj#(}~Mk{PbgMdZ}y$!la&v?@g;!g&if#K|43o2%Wt*eM@(yl)<|U->P{(WL1i?M@0i{5YAbY48rh#m!g582R4fIsbbT+Qdrs@4HAXt2`Wdx z+jwsqclVBky)6vrKLY6x$dpFlNIT}LZ_uE|<8Cxc6}oAx=yDkHyc34vQ?zoAlR+dq zNmAr+ZT45VZG9gv|5%vh2ag|4!Y^P}A Cr`t~e diff --git a/Crypto/SelfTest/Hash/__pycache__/test_SHA3_256.cpython-36.pyc b/Crypto/SelfTest/Hash/__pycache__/test_SHA3_256.cpython-36.pyc deleted file mode 100644 index a9de1e93247b9304e64df8c51e82dc3b9bc4767c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1971 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 aJ?prR+i)GHTB+Txt=HBYwHj2!n*C2}ZcO+9 diff --git a/Crypto/SelfTest/Hash/__pycache__/test_SHAKE.cpython-36.pyc b/Crypto/SelfTest/Hash/__pycache__/test_SHAKE.cpython-36.pyc deleted file mode 100644 index 9c87128cfe4bd1c96674ce1002e7145beb57e3d3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4036 zcmb_fTXWmS6~+P}30`!uEXh)A%k(WV+gOaP#7=LnGp^H2JmGXK$C+Zj{ipA`;Z^dhyI3r%1od17y8uiEChy zKi&xUmMrUE*3?r1{}3(xj#(DBe2X(~$INGVJF(q&e5ddFE~9ZbF7%6j(eQ=1)c1VP z@Wr^?ulSXI)vuaXXdz4*sB7NmW^FY-%}b~%^!h7E5)Uj5)X(Yy8@tjs5;UvB`BhhkqS-+~7C(&2Jg-wzsXut)ox2MclcqM5^lP zexyXbGm!O1@^GjIn_qWv_y}ORJXGOv1t(~fbRpdh_k?y5@fYb~NEi2q_%8hU zFinM2t$}*{Vn2+vD@Dk4H5)ZUfYVK3Vc$I%bnX~>*U+uMS#kw?{reBim!WLNVbX05 z57q7<*=okoPR?)MYo_pu+rzNE7j{M3%v_^MUPH(=$w!*Ts0Pi=;h{cfx;Shw9AI(u zQhW$OX${1(D{P4^+iR@CjxJ8{-+X7q*%mp%4hk8CEU-)*Q0DHk)wPX%SkH!~Y@q9m z7%!|_V`jJ_aX{YgxwO_;>7BV)fq56QnO3im&mK7w>y%n@9w#{dCy`~4=tDS;BW7jcj%={5?d8t7W)Oi#lI zA*;*J4u|5glmls0YuH91c?sLks<1qzLXe1VNRIGZOibxi7CFGinHo$cPgHR*zldg{ z@*$WhRbWSBQ;J4Mxg%Q@RFT_b*m(?U;;p2-5qQkYq`T3QjG5~T1Ylg4nBs$~Ql48}NzZlc<2y>JMrlfO8x-(gQsVqp80BUx}??cv=;iL>fdWmrW6hB1swNXJ{$qQP1`&UfFX!&y2S* zGi-YoQ5=6jJl(~9So|iwK1a*NQ~zx7gjcTpTbe)5ig*joKBM_r`Zlo*MOQA6`r4&J zp8E7X_CAjDWupQB%P?M3uMZ420&fzitK8fzQ%NuuPo-m&h(SN z!Wd=8ei$V|&_-|aOhSNSmmF2$3Y3R|qrLqkQY6tYQ|{QN8@}0Y>HsE$O}?Z+_$!(* zBW|5EyTSY_7o8AJN;{w$e1sYD4#->lOio~jwlIJfA!>l zMSgkQq`wJ5O1cpE>$4y6XQ4gl_XmkV)UQtcDam4s{K8*38U9*DF)p85STYP%R;0~k zjB>xM(o~NWc!a+mrU1;C$X_Iw^1mwqB1)GeRdn^YHr*AVXJS diff --git a/Crypto/SelfTest/Hash/__pycache__/test_keccak.cpython-36.pyc b/Crypto/SelfTest/Hash/__pycache__/test_keccak.cpython-36.pyc deleted file mode 100644 index ac66eb63e89bd06a1f80513f4bb5de88609c05ba..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6582 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 diff --git a/Crypto/SelfTest/Hash/common.py b/Crypto/SelfTest/Hash/common.py deleted file mode 100644 index b89db84..0000000 --- a/Crypto/SelfTest/Hash/common.py +++ /dev/null @@ -1,290 +0,0 @@ -# -*- coding: utf-8 -*- -# -# SelfTest/Hash/common.py: Common code for Crypto.SelfTest.Hash -# -# Written in 2008 by Dwayne C. Litzenberger -# -# =================================================================== -# The contents of this file are dedicated to the public domain. To -# the extent that dedication to the public domain is not available, -# everyone is granted a worldwide, perpetual, royalty-free, -# non-exclusive license to exercise all rights associated with the -# contents of this file for any purpose whatsoever. -# No rights are reserved. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS -# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN -# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# =================================================================== - -"""Self-testing for PyCrypto hash modules""" - -import re -import sys -import unittest -import binascii -import Crypto.Hash -from binascii import hexlify, unhexlify -from Crypto.Util.py3compat import b, tobytes -from Crypto.Util.strxor import strxor_c - -def t2b(hex_string): - shorter = re.sub(br'\s+', b'', tobytes(hex_string)) - return unhexlify(shorter) - - -class HashDigestSizeSelfTest(unittest.TestCase): - - def __init__(self, hashmod, description, expected, extra_params): - unittest.TestCase.__init__(self) - self.hashmod = hashmod - self.expected = expected - self.description = description - self.extra_params = extra_params - - def shortDescription(self): - return self.description - - def runTest(self): - if "truncate" not in self.extra_params: - self.failUnless(hasattr(self.hashmod, "digest_size")) - self.assertEquals(self.hashmod.digest_size, self.expected) - h = self.hashmod.new(**self.extra_params) - self.failUnless(hasattr(h, "digest_size")) - self.assertEquals(h.digest_size, self.expected) - - -class HashSelfTest(unittest.TestCase): - - def __init__(self, hashmod, description, expected, input, extra_params): - unittest.TestCase.__init__(self) - self.hashmod = hashmod - self.expected = expected.lower() - self.input = input - self.description = description - self.extra_params = extra_params - - def shortDescription(self): - return self.description - - def runTest(self): - h = self.hashmod.new(**self.extra_params) - h.update(self.input) - - out1 = binascii.b2a_hex(h.digest()) - out2 = h.hexdigest() - - h = self.hashmod.new(self.input, **self.extra_params) - - out3 = h.hexdigest() - out4 = binascii.b2a_hex(h.digest()) - - # PY3K: hexdigest() should return str(), and digest() bytes - self.assertEqual(self.expected, out1) # h = .new(); h.update(data); h.digest() - if sys.version_info[0] == 2: - self.assertEqual(self.expected, out2) # h = .new(); h.update(data); h.hexdigest() - self.assertEqual(self.expected, out3) # h = .new(data); h.hexdigest() - else: - self.assertEqual(self.expected.decode(), out2) # h = .new(); h.update(data); h.hexdigest() - self.assertEqual(self.expected.decode(), out3) # h = .new(data); h.hexdigest() - self.assertEqual(self.expected, out4) # h = .new(data); h.digest() - - # Verify that the .new() method produces a fresh hash object, except - # for MD5 and SHA1, which are hashlib objects. (But test any .new() - # method that does exist.) - if self.hashmod.__name__ not in ('Crypto.Hash.MD5', 'Crypto.Hash.SHA1') or hasattr(h, 'new'): - h2 = h.new() - h2.update(self.input) - out5 = binascii.b2a_hex(h2.digest()) - self.assertEqual(self.expected, out5) - - -class HashTestOID(unittest.TestCase): - def __init__(self, hashmod, oid, extra_params): - unittest.TestCase.__init__(self) - self.hashmod = hashmod - self.oid = oid - self.extra_params = extra_params - - def runTest(self): - h = self.hashmod.new(**self.extra_params) - self.assertEqual(h.oid, self.oid) - - -class ByteArrayTest(unittest.TestCase): - - def __init__(self, module, extra_params): - unittest.TestCase.__init__(self) - self.module = module - self.extra_params = extra_params - - def runTest(self): - data = b("\x00\x01\x02") - - # Data can be a bytearray (during initialization) - ba = bytearray(data) - - h1 = self.module.new(data, **self.extra_params) - h2 = self.module.new(ba, **self.extra_params) - ba[:1] = b'\xFF' - self.assertEqual(h1.digest(), h2.digest()) - - # Data can be a bytearray (during operation) - ba = bytearray(data) - - h1 = self.module.new(**self.extra_params) - h2 = self.module.new(**self.extra_params) - - h1.update(data) - h2.update(ba) - - ba[:1] = b'\xFF' - self.assertEqual(h1.digest(), h2.digest()) - - -class MemoryViewTest(unittest.TestCase): - - def __init__(self, module, extra_params): - unittest.TestCase.__init__(self) - self.module = module - self.extra_params = extra_params - - def runTest(self): - - data = b"\x00\x01\x02" - - def get_mv_ro(data): - return memoryview(data) - - def get_mv_rw(data): - return memoryview(bytearray(data)) - - for get_mv in get_mv_ro, get_mv_rw: - - # Data can be a memoryview (during initialization) - mv = get_mv(data) - - h1 = self.module.new(data, **self.extra_params) - h2 = self.module.new(mv, **self.extra_params) - if not mv.readonly: - mv[:1] = b'\xFF' - self.assertEqual(h1.digest(), h2.digest()) - - # Data can be a memoryview (during operation) - mv = get_mv(data) - - h1 = self.module.new(**self.extra_params) - h2 = self.module.new(**self.extra_params) - h1.update(data) - h2.update(mv) - if not mv.readonly: - mv[:1] = b'\xFF' - self.assertEqual(h1.digest(), h2.digest()) - - -class MACSelfTest(unittest.TestCase): - - def __init__(self, module, description, result, data, key, params): - unittest.TestCase.__init__(self) - self.module = module - self.result = t2b(result) - self.data = t2b(data) - self.key = t2b(key) - self.params = params - self.description = description - - def shortDescription(self): - return self.description - - def runTest(self): - - result_hex = hexlify(self.result) - - # Verify result - h = self.module.new(self.key, **self.params) - h.update(self.data) - self.assertEqual(self.result, h.digest()) - self.assertEqual(hexlify(self.result).decode('ascii'), h.hexdigest()) - - # Verify that correct MAC does not raise any exception - h.verify(self.result) - h.hexverify(result_hex) - - # Verify that incorrect MAC does raise ValueError exception - wrong_mac = strxor_c(self.result, 255) - self.assertRaises(ValueError, h.verify, wrong_mac) - self.assertRaises(ValueError, h.hexverify, "4556") - - # Verify again, with data passed to new() - h = self.module.new(self.key, self.data, **self.params) - self.assertEqual(self.result, h.digest()) - self.assertEqual(hexlify(self.result).decode('ascii'), h.hexdigest()) - - # Test .copy() - try: - h = self.module.new(self.key, self.data, **self.params) - h2 = h.copy() - h3 = h.copy() - - # Verify that changing the copy does not change the original - h2.update(b"bla") - self.assertEqual(h3.digest(), self.result) - - # Verify that both can reach the same state - h.update(b"bla") - self.assertEqual(h.digest(), h2.digest()) - except NotImplementedError: - pass - - # PY3K: Check that hexdigest() returns str and digest() returns bytes - self.assertTrue(isinstance(h.digest(), type(b""))) - self.assertTrue(isinstance(h.hexdigest(), type(""))) - - # PY3K: Check that .hexverify() accepts bytes or str - h.hexverify(h.hexdigest()) - h.hexverify(h.hexdigest().encode('ascii')) - - -def make_hash_tests(module, module_name, test_data, digest_size, oid=None, - extra_params={}): - tests = [] - for i in range(len(test_data)): - row = test_data[i] - (expected, input) = map(tobytes,row[0:2]) - if len(row) < 3: - description = repr(input) - else: - description = row[2] - name = "%s #%d: %s" % (module_name, i+1, description) - tests.append(HashSelfTest(module, name, expected, input, extra_params)) - - name = "%s #%d: digest_size" % (module_name, len(test_data) + 1) - tests.append(HashDigestSizeSelfTest(module, name, digest_size, extra_params)) - - if oid is not None: - tests.append(HashTestOID(module, oid, extra_params)) - - tests.append(ByteArrayTest(module, extra_params)) - - tests.append(MemoryViewTest(module, extra_params)) - - return tests - - -def make_mac_tests(module, module_name, test_data): - tests = [] - for i, row in enumerate(test_data): - if len(row) == 4: - (key, data, results, description, params) = list(row) + [ {} ] - else: - (key, data, results, description, params) = row - name = "%s #%d: %s" % (module_name, i+1, description) - tests.append(MACSelfTest(module, name, results, data, key, params)) - return tests - -# vim:set ts=4 sw=4 sts=4 expandtab: diff --git a/Crypto/SelfTest/Hash/test_BLAKE2.py b/Crypto/SelfTest/Hash/test_BLAKE2.py deleted file mode 100644 index f32163d..0000000 --- a/Crypto/SelfTest/Hash/test_BLAKE2.py +++ /dev/null @@ -1,482 +0,0 @@ -# =================================================================== -# -# Copyright (c) 2014, Legrandin -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# =================================================================== - -import os -import re -import unittest -import warnings -from binascii import unhexlify, hexlify - -from Crypto.Util.py3compat import tobytes -from Crypto.Util.strxor import strxor_c -from Crypto.SelfTest.st_common import list_test_cases - -from Crypto.Hash import BLAKE2b, BLAKE2s - - -class Blake2Test(unittest.TestCase): - - def test_new_positive(self): - - h = self.BLAKE2.new(digest_bits=self.max_bits) - for new_func in self.BLAKE2.new, h.new: - - for dbits in range(8, self.max_bits + 1, 8): - hobj = new_func(digest_bits=dbits) - self.assertEqual(hobj.digest_size, dbits // 8) - - for dbytes in range(1, self.max_bytes + 1): - hobj = new_func(digest_bytes=dbytes) - self.assertEqual(hobj.digest_size, dbytes) - - digest1 = new_func(data=b"\x90", digest_bytes=self.max_bytes).digest() - digest2 = new_func(digest_bytes=self.max_bytes).update(b"\x90").digest() - self.assertEqual(digest1, digest2) - - new_func(data=b"A", key=b"5", digest_bytes=self.max_bytes) - - hobj = h.new() - self.assertEqual(hobj.digest_size, self.max_bytes) - - def test_new_negative(self): - - h = self.BLAKE2.new(digest_bits=self.max_bits) - for new_func in self.BLAKE2.new, h.new: - self.assertRaises(TypeError, new_func, - digest_bytes=self.max_bytes, - digest_bits=self.max_bits) - self.assertRaises(ValueError, new_func, digest_bytes=0) - self.assertRaises(ValueError, new_func, - digest_bytes=self.max_bytes + 1) - self.assertRaises(ValueError, new_func, digest_bits=7) - self.assertRaises(ValueError, new_func, digest_bits=15) - self.assertRaises(ValueError, new_func, - digest_bits=self.max_bits + 1) - self.assertRaises(TypeError, new_func, - digest_bytes=self.max_bytes, - key=u"string") - self.assertRaises(TypeError, new_func, - digest_bytes=self.max_bytes, - data=u"string") - - def test_default_digest_size(self): - digest = self.BLAKE2.new(data=b'abc').digest() - self.assertEquals(len(digest), self.max_bytes) - - def test_update(self): - pieces = [b"\x0A" * 200, b"\x14" * 300] - h = self.BLAKE2.new(digest_bytes=self.max_bytes) - h.update(pieces[0]).update(pieces[1]) - digest = h.digest() - h = self.BLAKE2.new(digest_bytes=self.max_bytes) - h.update(pieces[0] + pieces[1]) - self.assertEqual(h.digest(), digest) - - def test_update_negative(self): - h = self.BLAKE2.new(digest_bytes=self.max_bytes) - self.assertRaises(TypeError, h.update, u"string") - - def test_digest(self): - h = self.BLAKE2.new(digest_bytes=self.max_bytes) - digest = h.digest() - - # hexdigest does not change the state - self.assertEqual(h.digest(), digest) - # digest returns a byte string - self.failUnless(isinstance(digest, type(b"digest"))) - - def test_update_after_digest(self): - msg = b"rrrrttt" - - # Normally, update() cannot be done after digest() - h = self.BLAKE2.new(digest_bits=256, data=msg[:4]) - dig1 = h.digest() - self.assertRaises(TypeError, h.update, msg[4:]) - dig2 = self.BLAKE2.new(digest_bits=256, data=msg).digest() - - # With the proper flag, it is allowed - h = self.BLAKE2.new(digest_bits=256, data=msg[:4], update_after_digest=True) - self.assertEquals(h.digest(), dig1) - # ... and the subsequent digest applies to the entire message - # up to that point - h.update(msg[4:]) - self.assertEquals(h.digest(), dig2) - - def test_hex_digest(self): - mac = self.BLAKE2.new(digest_bits=self.max_bits) - digest = mac.digest() - hexdigest = mac.hexdigest() - - # hexdigest is equivalent to digest - self.assertEqual(hexlify(digest), tobytes(hexdigest)) - # hexdigest does not change the state - self.assertEqual(mac.hexdigest(), hexdigest) - # hexdigest returns a string - self.failUnless(isinstance(hexdigest, type("digest"))) - - def test_verify(self): - h = self.BLAKE2.new(digest_bytes=self.max_bytes, key=b"4") - mac = h.digest() - h.verify(mac) - wrong_mac = strxor_c(mac, 255) - self.assertRaises(ValueError, h.verify, wrong_mac) - - def test_hexverify(self): - h = self.BLAKE2.new(digest_bytes=self.max_bytes, key=b"4") - mac = h.hexdigest() - h.hexverify(mac) - self.assertRaises(ValueError, h.hexverify, "4556") - - def test_oid(self): - - prefix = "1.3.6.1.4.1.1722.12.2." + self.oid_variant + "." - - for digest_bits in self.digest_bits_oid: - h = self.BLAKE2.new(digest_bits=digest_bits) - self.assertEqual(h.oid, prefix + str(digest_bits // 8)) - - h = self.BLAKE2.new(digest_bits=digest_bits, key=b"secret") - self.assertRaises(AttributeError, lambda: h.oid) - - for digest_bits in (8, self.max_bits): - if digest_bits in self.digest_bits_oid: - continue - self.assertRaises(AttributeError, lambda: h.oid) - - def test_bytearray(self): - - key = b'0' * 16 - data = b"\x00\x01\x02" - - # Data and key can be a bytearray (during initialization) - key_ba = bytearray(key) - data_ba = bytearray(data) - - h1 = self.BLAKE2.new(data=data, key=key) - h2 = self.BLAKE2.new(data=data_ba, key=key_ba) - key_ba[:1] = b'\xFF' - data_ba[:1] = b'\xFF' - - self.assertEqual(h1.digest(), h2.digest()) - - # Data can be a bytearray (during operation) - data_ba = bytearray(data) - - h1 = self.BLAKE2.new() - h2 = self.BLAKE2.new() - h1.update(data) - h2.update(data_ba) - data_ba[:1] = b'\xFF' - - self.assertEqual(h1.digest(), h2.digest()) - - def test_memoryview(self): - - key = b'0' * 16 - data = b"\x00\x01\x02" - - def get_mv_ro(data): - return memoryview(data) - - def get_mv_rw(data): - return memoryview(bytearray(data)) - - for get_mv in (get_mv_ro, get_mv_rw): - - # Data and key can be a memoryview (during initialization) - key_mv = get_mv(key) - data_mv = get_mv(data) - - h1 = self.BLAKE2.new(data=data, key=key) - h2 = self.BLAKE2.new(data=data_mv, key=key_mv) - if not data_mv.readonly: - data_mv[:1] = b'\xFF' - key_mv[:1] = b'\xFF' - - self.assertEqual(h1.digest(), h2.digest()) - - # Data can be a memoryview (during operation) - data_mv = get_mv(data) - - h1 = self.BLAKE2.new() - h2 = self.BLAKE2.new() - h1.update(data) - h2.update(data_mv) - if not data_mv.readonly: - data_mv[:1] = b'\xFF' - - self.assertEqual(h1.digest(), h2.digest()) - - -class Blake2bTest(Blake2Test): - #: Module - BLAKE2 = BLAKE2b - #: Max output size (in bits) - max_bits = 512 - #: Max output size (in bytes) - max_bytes = 64 - #: Bit size of the digests for which an ASN OID exists - digest_bits_oid = (160, 256, 384, 512) - # http://tools.ietf.org/html/draft-saarinen-blake2-02 - oid_variant = "1" - - -class Blake2sTest(Blake2Test): - #: Module - BLAKE2 = BLAKE2s - #: Max output size (in bits) - max_bits = 256 - #: Max output size (in bytes) - max_bytes = 32 - #: Bit size of the digests for which an ASN OID exists - digest_bits_oid = (128, 160, 224, 256) - # http://tools.ietf.org/html/draft-saarinen-blake2-02 - oid_variant = "2" - - -class Blake2OfficialTestVector(unittest.TestCase): - - def _load_tests(self, test_vector_file): - expected = "in" - test_vectors = [] - with open(test_vector_file, "rt") as test_vector_fd: - for line_number, line in enumerate(test_vector_fd): - - if line.strip() == "" or line.startswith("#"): - continue - - res = re.match("%s:\t([0-9A-Fa-f]*)" % expected, line) - if not res: - raise ValueError("Incorrect test vector format (line %d)" - % line_number) - - if res.group(1): - bin_value = unhexlify(tobytes(res.group(1))) - else: - bin_value = b"" - if expected == "in": - input_data = bin_value - expected = "key" - elif expected == "key": - key = bin_value - expected = "hash" - else: - result = bin_value - expected = "in" - test_vectors.append((input_data, key, result)) - return test_vectors - - def setUp(self): - - dir_comps = ("Hash", self.name) - file_name = self.name.lower() + "-test.txt" - self.description = "%s tests" % self.name - - try: - import pycryptodome_test_vectors # type: ignore - except ImportError: - warnings.warn("Warning: skipping extended tests for %s" % self.name, - UserWarning) - self.test_vectors = [] - return - - init_dir = os.path.dirname(pycryptodome_test_vectors.__file__) - full_file_name = os.path.join(os.path.join(init_dir, *dir_comps), file_name) - self.test_vectors = self._load_tests(full_file_name) - - def runTest(self): - for (input_data, key, result) in self.test_vectors: - mac = self.BLAKE2.new(key=key, digest_bytes=self.max_bytes) - mac.update(input_data) - self.assertEqual(mac.digest(), result) - - -class Blake2bOfficialTestVector(Blake2OfficialTestVector): - #: Module - BLAKE2 = BLAKE2b - #: Hash name - name = "BLAKE2b" - #: Max digest size - max_bytes = 64 - - -class Blake2sOfficialTestVector(Blake2OfficialTestVector): - #: Module - BLAKE2 = BLAKE2s - #: Hash name - name = "BLAKE2s" - #: Max digest size - max_bytes = 32 - - -class Blake2TestVector1(unittest.TestCase): - - def _load_tests(self, test_vector_file): - test_vectors = [] - with open(test_vector_file, "rt") as test_vector_fd: - for line_number, line in enumerate(test_vector_fd): - if line.strip() == "" or line.startswith("#"): - continue - res = re.match("digest: ([0-9A-Fa-f]*)", line) - if not res: - raise ValueError("Incorrect test vector format (line %d)" - % line_number) - - test_vectors.append(unhexlify(tobytes(res.group(1)))) - return test_vectors - - def setUp(self): - dir_comps = ("Hash", self.name) - file_name = "tv1.txt" - self.description = "%s tests" % self.name - - try: - import pycryptodome_test_vectors - except ImportError: - warnings.warn("Warning: skipping extended tests for %s" % self.name, - UserWarning) - self.test_vectors = [] - return - - init_dir = os.path.dirname(pycryptodome_test_vectors.__file__) - full_file_name = os.path.join(os.path.join(init_dir, *dir_comps), file_name) - self.test_vectors = self._load_tests(full_file_name) - - def runTest(self): - - for tv in self.test_vectors: - digest_bytes = len(tv) - next_data = b"" - for _ in range(100): - h = self.BLAKE2.new(digest_bytes=digest_bytes) - h.update(next_data) - next_data = h.digest() + next_data - self.assertEqual(h.digest(), tv) - - -class Blake2bTestVector1(Blake2TestVector1): - #: Module - BLAKE2 = BLAKE2b - #: Hash name - name = "BLAKE2b" - - -class Blake2sTestVector1(Blake2TestVector1): - #: Module - BLAKE2 = BLAKE2s - #: Hash name - name = "BLAKE2s" - - -class Blake2TestVector2(unittest.TestCase): - - def _load_tests(self, test_vector_file): - test_vectors = [] - with open(test_vector_file, "rt") as test_vector_fd: - for line_number, line in enumerate(test_vector_fd): - if line.strip() == "" or line.startswith("#"): - continue - res = re.match(r"digest\(([0-9]+)\): ([0-9A-Fa-f]*)", line) - if not res: - raise ValueError("Incorrect test vector format (line %d)" - % line_number) - key_size = int(res.group(1)) - result = unhexlify(tobytes(res.group(2))) - test_vectors.append((key_size, result)) - return test_vectors - - def setUp(self): - dir_comps = ("Hash", self.name) - file_name = "tv2.txt" - self.description = "%s tests" % self.name - - try: - import pycryptodome_test_vectors # type: ignore - except ImportError: - warnings.warn("Warning: skipping extended tests for %s" % self.name, - UserWarning) - self.test_vectors = [] - return - - init_dir = os.path.dirname(pycryptodome_test_vectors.__file__) - full_file_name = os.path.join(os.path.join(init_dir, *dir_comps), file_name) - self.test_vectors = self._load_tests(full_file_name) - - def runTest(self): - - for key_size, result in self.test_vectors: - next_data = b"" - for _ in range(100): - h = self.BLAKE2.new(digest_bytes=self.max_bytes, - key=b"A" * key_size) - h.update(next_data) - next_data = h.digest() + next_data - self.assertEqual(h.digest(), result) - - -class Blake2bTestVector2(Blake2TestVector1): - #: Module - BLAKE2 = BLAKE2b - #: Hash name - name = "BLAKE2b" - #: Max digest size in bytes - max_bytes = 64 - - -class Blake2sTestVector2(Blake2TestVector1): - #: Module - BLAKE2 = BLAKE2s - #: Hash name - name = "BLAKE2s" - #: Max digest size in bytes - max_bytes = 32 - - -def get_tests(config={}): - tests = [] - - tests += list_test_cases(Blake2bTest) - tests.append(Blake2bOfficialTestVector()) - tests.append(Blake2bTestVector1()) - tests.append(Blake2bTestVector2()) - - tests += list_test_cases(Blake2sTest) - tests.append(Blake2sOfficialTestVector()) - tests.append(Blake2sTestVector1()) - tests.append(Blake2sTestVector2()) - - return tests - - -if __name__ == '__main__': - import unittest - def suite(): - return unittest.TestSuite(get_tests()) - unittest.main(defaultTest='suite') diff --git a/Crypto/SelfTest/Hash/test_CMAC.py b/Crypto/SelfTest/Hash/test_CMAC.py deleted file mode 100644 index 8cdbf09..0000000 --- a/Crypto/SelfTest/Hash/test_CMAC.py +++ /dev/null @@ -1,448 +0,0 @@ -# -# SelfTest/Hash/CMAC.py: Self-test for the CMAC module -# -# =================================================================== -# -# Copyright (c) 2014, Legrandin -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# =================================================================== - -"""Self-test suite for Crypto.Hash.CMAC""" - -import json -import unittest -from binascii import unhexlify - -from Crypto.Util.py3compat import tobytes - -from Crypto.Hash import CMAC -from Crypto.Cipher import AES, DES3 -from Crypto.Hash import SHAKE128 - -from Crypto.Util.strxor import strxor - -from Crypto.SelfTest.st_common import list_test_cases -from Crypto.SelfTest.loader import load_test_vectors_wycheproof - -# This is a list of (key, data, result, description, module) tuples. -test_data = [ - - ## Test vectors from RFC 4493 ## - ## The are also in NIST SP 800 38B D.2 ## - ( '2b7e151628aed2a6abf7158809cf4f3c', - '', - 'bb1d6929e95937287fa37d129b756746', - 'RFC 4493 #1', - AES - ), - - ( '2b7e151628aed2a6abf7158809cf4f3c', - '6bc1bee22e409f96e93d7e117393172a', - '070a16b46b4d4144f79bdd9dd04a287c', - 'RFC 4493 #2', - AES - ), - - ( '2b7e151628aed2a6abf7158809cf4f3c', - '6bc1bee22e409f96e93d7e117393172a'+ - 'ae2d8a571e03ac9c9eb76fac45af8e51'+ - '30c81c46a35ce411', - 'dfa66747de9ae63030ca32611497c827', - 'RFC 4493 #3', - AES - ), - - ( '2b7e151628aed2a6abf7158809cf4f3c', - '6bc1bee22e409f96e93d7e117393172a'+ - 'ae2d8a571e03ac9c9eb76fac45af8e51'+ - '30c81c46a35ce411e5fbc1191a0a52ef'+ - 'f69f2445df4f9b17ad2b417be66c3710', - '51f0bebf7e3b9d92fc49741779363cfe', - 'RFC 4493 #4', - AES - ), - - ## The rest of Appendix D of NIST SP 800 38B - ## was not totally correct. - ## Values in Examples 14, 15, 18, and 19 were wrong. - ## The updated test values are published in: - ## http://csrc.nist.gov/publications/nistpubs/800-38B/Updated_CMAC_Examples.pdf - - ( '8e73b0f7da0e6452c810f32b809079e5'+ - '62f8ead2522c6b7b', - '', - 'd17ddf46adaacde531cac483de7a9367', - 'NIST SP 800 38B D.2 Example 5', - AES - ), - - ( '8e73b0f7da0e6452c810f32b809079e5'+ - '62f8ead2522c6b7b', - '6bc1bee22e409f96e93d7e117393172a', - '9e99a7bf31e710900662f65e617c5184', - 'NIST SP 800 38B D.2 Example 6', - AES - ), - - ( '8e73b0f7da0e6452c810f32b809079e5'+ - '62f8ead2522c6b7b', - '6bc1bee22e409f96e93d7e117393172a'+ - 'ae2d8a571e03ac9c9eb76fac45af8e51'+ - '30c81c46a35ce411', - '8a1de5be2eb31aad089a82e6ee908b0e', - 'NIST SP 800 38B D.2 Example 7', - AES - ), - - ( '8e73b0f7da0e6452c810f32b809079e5'+ - '62f8ead2522c6b7b', - '6bc1bee22e409f96e93d7e117393172a'+ - 'ae2d8a571e03ac9c9eb76fac45af8e51'+ - '30c81c46a35ce411e5fbc1191a0a52ef'+ - 'f69f2445df4f9b17ad2b417be66c3710', - 'a1d5df0eed790f794d77589659f39a11', - 'NIST SP 800 38B D.2 Example 8', - AES - ), - - ( '603deb1015ca71be2b73aef0857d7781'+ - '1f352c073b6108d72d9810a30914dff4', - '', - '028962f61b7bf89efc6b551f4667d983', - 'NIST SP 800 38B D.3 Example 9', - AES - ), - - ( '603deb1015ca71be2b73aef0857d7781'+ - '1f352c073b6108d72d9810a30914dff4', - '6bc1bee22e409f96e93d7e117393172a', - '28a7023f452e8f82bd4bf28d8c37c35c', - 'NIST SP 800 38B D.3 Example 10', - AES - ), - - ( '603deb1015ca71be2b73aef0857d7781'+ - '1f352c073b6108d72d9810a30914dff4', - '6bc1bee22e409f96e93d7e117393172a'+ - 'ae2d8a571e03ac9c9eb76fac45af8e51'+ - '30c81c46a35ce411', - 'aaf3d8f1de5640c232f5b169b9c911e6', - 'NIST SP 800 38B D.3 Example 11', - AES - ), - - ( '603deb1015ca71be2b73aef0857d7781'+ - '1f352c073b6108d72d9810a30914dff4', - '6bc1bee22e409f96e93d7e117393172a'+ - 'ae2d8a571e03ac9c9eb76fac45af8e51'+ - '30c81c46a35ce411e5fbc1191a0a52ef'+ - 'f69f2445df4f9b17ad2b417be66c3710', - 'e1992190549f6ed5696a2c056c315410', - 'NIST SP 800 38B D.3 Example 12', - AES - ), - - ( '8aa83bf8cbda1062'+ - '0bc1bf19fbb6cd58'+ - 'bc313d4a371ca8b5', - '', - 'b7a688e122ffaf95', - 'NIST SP 800 38B D.4 Example 13', - DES3 - ), - - ( '8aa83bf8cbda1062'+ - '0bc1bf19fbb6cd58'+ - 'bc313d4a371ca8b5', - '6bc1bee22e409f96', - '8e8f293136283797', - 'NIST SP 800 38B D.4 Example 14', - DES3 - ), - - ( '8aa83bf8cbda1062'+ - '0bc1bf19fbb6cd58'+ - 'bc313d4a371ca8b5', - '6bc1bee22e409f96'+ - 'e93d7e117393172a'+ - 'ae2d8a57', - '743ddbe0ce2dc2ed', - 'NIST SP 800 38B D.4 Example 15', - DES3 - ), - - ( '8aa83bf8cbda1062'+ - '0bc1bf19fbb6cd58'+ - 'bc313d4a371ca8b5', - '6bc1bee22e409f96'+ - 'e93d7e117393172a'+ - 'ae2d8a571e03ac9c'+ - '9eb76fac45af8e51', - '33e6b1092400eae5', - 'NIST SP 800 38B D.4 Example 16', - DES3 - ), - - ( '4cf15134a2850dd5'+ - '8a3d10ba80570d38', - '', - 'bd2ebf9a3ba00361', - 'NIST SP 800 38B D.7 Example 17', - DES3 - ), - - ( '4cf15134a2850dd5'+ - '8a3d10ba80570d38', - '6bc1bee22e409f96', - '4ff2ab813c53ce83', - 'NIST SP 800 38B D.7 Example 18', - DES3 - ), - - ( '4cf15134a2850dd5'+ - '8a3d10ba80570d38', - '6bc1bee22e409f96'+ - 'e93d7e117393172a'+ - 'ae2d8a57', - '62dd1b471902bd4e', - 'NIST SP 800 38B D.7 Example 19', - DES3 - ), - - ( '4cf15134a2850dd5'+ - '8a3d10ba80570d38', - '6bc1bee22e409f96'+ - 'e93d7e117393172a'+ - 'ae2d8a571e03ac9c'+ - '9eb76fac45af8e51', - '31b1e431dabc4eb8', - 'NIST SP 800 38B D.7 Example 20', - DES3 - ), - -] - - -def get_tag_random(tag, length): - return SHAKE128.new(data=tobytes(tag)).read(length) - - -class TestCMAC(unittest.TestCase): - - def test_internal_caching(self): - """Verify that internal caching is implemented correctly""" - - data_to_mac = get_tag_random("data_to_mac", 128) - key = get_tag_random("key", 16) - ref_mac = CMAC.new(key, msg=data_to_mac, ciphermod=AES).digest() - - # Break up in chunks of different length - # The result must always be the same - for chunk_length in 1, 2, 3, 7, 10, 13, 16, 40, 80, 128: - - chunks = [data_to_mac[i:i+chunk_length] for i in - range(0, len(data_to_mac), chunk_length)] - - mac = CMAC.new(key, ciphermod=AES) - for chunk in chunks: - mac.update(chunk) - self.assertEqual(ref_mac, mac.digest()) - - def test_update_after_digest(self): - msg = b"rrrrttt" - key = b"4" * 16 - - # Normally, update() cannot be done after digest() - h = CMAC.new(key, msg[:4], ciphermod=AES) - dig1 = h.digest() - self.assertRaises(TypeError, h.update, msg[4:]) - dig2 = CMAC.new(key, msg, ciphermod=AES).digest() - - # With the proper flag, it is allowed - h2 = CMAC.new(key, msg[:4], ciphermod=AES, update_after_digest=True) - self.assertEquals(h2.digest(), dig1) - # ... and the subsequent digest applies to the entire message - # up to that point - h2.update(msg[4:]) - self.assertEquals(h2.digest(), dig2) - - -class ByteArrayTests(unittest.TestCase): - - def runTest(self): - - key = b"0" * 16 - data = b"\x00\x01\x02" - - # Data and key can be a bytearray (during initialization) - key_ba = bytearray(key) - data_ba = bytearray(data) - - h1 = CMAC.new(key, data, ciphermod=AES) - h2 = CMAC.new(key_ba, data_ba, ciphermod=AES) - key_ba[:1] = b'\xFF' - data_ba[:1] = b'\xFF' - self.assertEqual(h1.digest(), h2.digest()) - - # Data can be a bytearray (during operation) - key_ba = bytearray(key) - data_ba = bytearray(data) - - h1 = CMAC.new(key, ciphermod=AES) - h2 = CMAC.new(key, ciphermod=AES) - h1.update(data) - h2.update(data_ba) - data_ba[:1] = b'\xFF' - self.assertEqual(h1.digest(), h2.digest()) - - -class MemoryViewTests(unittest.TestCase): - - def runTest(self): - - key = b"0" * 16 - data = b"\x00\x01\x02" - - def get_mv_ro(data): - return memoryview(data) - - def get_mv_rw(data): - return memoryview(bytearray(data)) - - for get_mv in (get_mv_ro, get_mv_rw): - - # Data and key can be a memoryview (during initialization) - key_mv = get_mv(key) - data_mv = get_mv(data) - - h1 = CMAC.new(key, data, ciphermod=AES) - h2 = CMAC.new(key_mv, data_mv, ciphermod=AES) - if not data_mv.readonly: - key_mv[:1] = b'\xFF' - data_mv[:1] = b'\xFF' - self.assertEqual(h1.digest(), h2.digest()) - - # Data can be a memoryview (during operation) - data_mv = get_mv(data) - - h1 = CMAC.new(key, ciphermod=AES) - h2 = CMAC.new(key, ciphermod=AES) - h1.update(data) - h2.update(data_mv) - if not data_mv.readonly: - data_mv[:1] = b'\xFF' - self.assertEqual(h1.digest(), h2.digest()) - - -class TestVectorsWycheproof(unittest.TestCase): - - def __init__(self, wycheproof_warnings): - unittest.TestCase.__init__(self) - self._wycheproof_warnings = wycheproof_warnings - self._id = "None" - - def setUp(self): - - def filter_tag(group): - return group['tagSize'] // 8 - - self.tv = load_test_vectors_wycheproof(("Hash", "wycheproof"), - "aes_cmac_test.json", - "Wycheproof CMAC", - group_tag={'tag_size': filter_tag}) - - def shortDescription(self): - return self._id - - def warn(self, tv): - if tv.warning and self._wycheproof_warnings: - import warnings - warnings.warn("Wycheproof warning: %s (%s)" % (self._id, tv.comment)) - - def test_create_mac(self, tv): - self._id = "Wycheproof MAC creation Test #" + str(tv.id) - - try: - tag = CMAC.new(tv.key, tv.msg, ciphermod=AES, mac_len=tv.tag_size).digest() - except ValueError as e: - if len(tv.key) not in (16, 24, 32) and "key length" in str(e): - return - raise e - if tv.valid: - self.assertEqual(tag, tv.tag) - self.warn(tv) - - def test_verify_mac(self, tv): - self._id = "Wycheproof MAC verification Test #" + str(tv.id) - - try: - mac = CMAC.new(tv.key, tv.msg, ciphermod=AES, mac_len=tv.tag_size) - except ValueError as e: - if len(tv.key) not in (16, 24, 32) and "key length" in str(e): - return - raise e - try: - mac.verify(tv.tag) - except ValueError: - assert not tv.valid - else: - assert tv.valid - self.warn(tv) - - def runTest(self): - - for tv in self.tv: - self.test_create_mac(tv) - self.test_verify_mac(tv) - - -def get_tests(config={}): - global test_data - import types - from .common import make_mac_tests - - wycheproof_warnings = config.get('wycheproof_warnings') - - # Add new() parameters to the back of each test vector - params_test_data = [] - for row in test_data: - t = list(row) - t[4] = dict(ciphermod=t[4]) - params_test_data.append(t) - - tests = make_mac_tests(CMAC, "CMAC", params_test_data) - tests.append(ByteArrayTests()) - tests.append(list_test_cases(TestCMAC)) - tests.append(MemoryViewTests()) - tests += [ TestVectorsWycheproof(wycheproof_warnings) ] - return tests - - -if __name__ == '__main__': - import unittest - suite = lambda: unittest.TestSuite(get_tests()) - unittest.main(defaultTest='suite') diff --git a/Crypto/SelfTest/Hash/test_HMAC.py b/Crypto/SelfTest/Hash/test_HMAC.py deleted file mode 100644 index 7be15be..0000000 --- a/Crypto/SelfTest/Hash/test_HMAC.py +++ /dev/null @@ -1,402 +0,0 @@ -# -*- coding: utf-8 -*- -# -# SelfTest/Hash/HMAC.py: Self-test for the HMAC module -# -# Written in 2008 by Dwayne C. Litzenberger -# -# =================================================================== -# The contents of this file are dedicated to the public domain. To -# the extent that dedication to the public domain is not available, -# everyone is granted a worldwide, perpetual, royalty-free, -# non-exclusive license to exercise all rights associated with the -# contents of this file for any purpose whatsoever. -# No rights are reserved. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS -# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN -# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# =================================================================== - -"""Self-test suite for Crypto.Hash.HMAC""" - -import sys -import unittest -from binascii import hexlify -from Crypto.Util.py3compat import tostr, tobytes - -from Crypto.Hash import HMAC, MD5, SHA1, SHA256 -hash_modules = dict(MD5=MD5, SHA1=SHA1, SHA256=SHA256) - -try: - from Crypto.Hash import SHA224, SHA384, SHA512, RIPEMD160 - hash_modules.update(dict(SHA224=SHA224, SHA384=SHA384, SHA512=SHA512, - RIPEMD160=RIPEMD160)) -except ImportError: - sys.stderr.write("SelfTest: warning: not testing HMAC-SHA224/384/512" - " (not available)\n") - -default_hash = None - -def xl(text): - return tostr(hexlify(tobytes(text))) - -# This is a list of (key, data, results, description) tuples. -test_data = [ - ## Test vectors from RFC 2202 ## - # Test that the default hashmod is MD5 - ('0b' * 16, - '4869205468657265', - dict(default_hash='9294727a3638bb1c13f48ef8158bfc9d'), - 'default-is-MD5'), - - # Test case 1 (MD5) - ('0b' * 16, - '4869205468657265', - dict(MD5='9294727a3638bb1c13f48ef8158bfc9d'), - 'RFC 2202 #1-MD5 (HMAC-MD5)'), - - # Test case 1 (SHA1) - ('0b' * 20, - '4869205468657265', - dict(SHA1='b617318655057264e28bc0b6fb378c8ef146be00'), - 'RFC 2202 #1-SHA1 (HMAC-SHA1)'), - - # Test case 2 - ('4a656665', - '7768617420646f2079612077616e7420666f72206e6f7468696e673f', - dict(MD5='750c783e6ab0b503eaa86e310a5db738', - SHA1='effcdf6ae5eb2fa2d27416d5f184df9c259a7c79'), - 'RFC 2202 #2 (HMAC-MD5/SHA1)'), - - # Test case 3 (MD5) - ('aa' * 16, - 'dd' * 50, - dict(MD5='56be34521d144c88dbb8c733f0e8b3f6'), - 'RFC 2202 #3-MD5 (HMAC-MD5)'), - - # Test case 3 (SHA1) - ('aa' * 20, - 'dd' * 50, - dict(SHA1='125d7342b9ac11cd91a39af48aa17b4f63f175d3'), - 'RFC 2202 #3-SHA1 (HMAC-SHA1)'), - - # Test case 4 - ('0102030405060708090a0b0c0d0e0f10111213141516171819', - 'cd' * 50, - dict(MD5='697eaf0aca3a3aea3a75164746ffaa79', - SHA1='4c9007f4026250c6bc8414f9bf50c86c2d7235da'), - 'RFC 2202 #4 (HMAC-MD5/SHA1)'), - - # Test case 5 (MD5) - ('0c' * 16, - '546573742057697468205472756e636174696f6e', - dict(MD5='56461ef2342edc00f9bab995690efd4c'), - 'RFC 2202 #5-MD5 (HMAC-MD5)'), - - # Test case 5 (SHA1) - # NB: We do not implement hash truncation, so we only test the full hash here. - ('0c' * 20, - '546573742057697468205472756e636174696f6e', - dict(SHA1='4c1a03424b55e07fe7f27be1d58bb9324a9a5a04'), - 'RFC 2202 #5-SHA1 (HMAC-SHA1)'), - - # Test case 6 - ('aa' * 80, - '54657374205573696e67204c6172676572205468616e20426c6f636b2d53697a' - + '65204b6579202d2048617368204b6579204669727374', - dict(MD5='6b1ab7fe4bd7bf8f0b62e6ce61b9d0cd', - SHA1='aa4ae5e15272d00e95705637ce8a3b55ed402112'), - 'RFC 2202 #6 (HMAC-MD5/SHA1)'), - - # Test case 7 - ('aa' * 80, - '54657374205573696e67204c6172676572205468616e20426c6f636b2d53697a' - + '65204b657920616e64204c6172676572205468616e204f6e6520426c6f636b2d' - + '53697a652044617461', - dict(MD5='6f630fad67cda0ee1fb1f562db3aa53e', - SHA1='e8e99d0f45237d786d6bbaa7965c7808bbff1a91'), - 'RFC 2202 #7 (HMAC-MD5/SHA1)'), - - ## Test vectors from RFC 4231 ## - # 4.2. Test Case 1 - ('0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b', - '4869205468657265', - dict(SHA256=''' - b0344c61d8db38535ca8afceaf0bf12b - 881dc200c9833da726e9376c2e32cff7 - '''), - 'RFC 4231 #1 (HMAC-SHA256)'), - - # 4.3. Test Case 2 - Test with a key shorter than the length of the HMAC - # output. - ('4a656665', - '7768617420646f2079612077616e7420666f72206e6f7468696e673f', - dict(SHA256=''' - 5bdcc146bf60754e6a042426089575c7 - 5a003f089d2739839dec58b964ec3843 - '''), - 'RFC 4231 #2 (HMAC-SHA256)'), - - # 4.4. Test Case 3 - Test with a combined length of key and data that is - # larger than 64 bytes (= block-size of SHA-224 and SHA-256). - ('aa' * 20, - 'dd' * 50, - dict(SHA256=''' - 773ea91e36800e46854db8ebd09181a7 - 2959098b3ef8c122d9635514ced565fe - '''), - 'RFC 4231 #3 (HMAC-SHA256)'), - - # 4.5. Test Case 4 - Test with a combined length of key and data that is - # larger than 64 bytes (= block-size of SHA-224 and SHA-256). - ('0102030405060708090a0b0c0d0e0f10111213141516171819', - 'cd' * 50, - dict(SHA256=''' - 82558a389a443c0ea4cc819899f2083a - 85f0faa3e578f8077a2e3ff46729665b - '''), - 'RFC 4231 #4 (HMAC-SHA256)'), - - # 4.6. Test Case 5 - Test with a truncation of output to 128 bits. - # - # Not included because we do not implement hash truncation. - # - - # 4.7. Test Case 6 - Test with a key larger than 128 bytes (= block-size of - # SHA-384 and SHA-512). - ('aa' * 131, - '54657374205573696e67204c6172676572205468616e20426c6f636b2d53697a' - + '65204b6579202d2048617368204b6579204669727374', - dict(SHA256=''' - 60e431591ee0b67f0d8a26aacbf5b77f - 8e0bc6213728c5140546040f0ee37f54 - '''), - 'RFC 4231 #6 (HMAC-SHA256)'), - - # 4.8. Test Case 7 - Test with a key and data that is larger than 128 bytes - # (= block-size of SHA-384 and SHA-512). - ('aa' * 131, - '5468697320697320612074657374207573696e672061206c6172676572207468' - + '616e20626c6f636b2d73697a65206b657920616e642061206c61726765722074' - + '68616e20626c6f636b2d73697a6520646174612e20546865206b6579206e6565' - + '647320746f20626520686173686564206265666f7265206265696e6720757365' - + '642062792074686520484d414320616c676f726974686d2e', - dict(SHA256=''' - 9b09ffa71b942fcb27635fbcd5b0e944 - bfdc63644f0713938a7f51535c3a35e2 - '''), - 'RFC 4231 #7 (HMAC-SHA256)'), - - # Test case 8 (SHA224) - ('4a656665', - '7768617420646f2079612077616e74' - + '20666f72206e6f7468696e673f', - dict(SHA224='a30e01098bc6dbbf45690f3a7e9e6d0f8bbea2a39e6148008fd05e44'), - 'RFC 4634 8.4 SHA224 (HMAC-SHA224)'), - - # Test case 9 (SHA384) - ('4a656665', - '7768617420646f2079612077616e74' - + '20666f72206e6f7468696e673f', - dict(SHA384='af45d2e376484031617f78d2b58a6b1b9c7ef464f5a01b47e42ec3736322445e8e2240ca5e69e2c78b3239ecfab21649'), - 'RFC 4634 8.4 SHA384 (HMAC-SHA384)'), - - # Test case 10 (SHA512) - ('4a656665', - '7768617420646f2079612077616e74' - + '20666f72206e6f7468696e673f', - dict(SHA512='164b7a7bfcf819e2e395fbe73b56e0a387bd64222e831fd610270cd7ea2505549758bf75c05a994a6d034f65f8f0e6fdcaeab1a34d4a6b4b636e070a38bce737'), - 'RFC 4634 8.4 SHA512 (HMAC-SHA512)'), - - # Test case 11 (RIPEMD) - ('0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b', - xl("Hi There"), - dict(RIPEMD160='24cb4bd67d20fc1a5d2ed7732dcc39377f0a5668'), - 'RFC 2286 #1 (HMAC-RIPEMD)'), - - # Test case 12 (RIPEMD) - (xl("Jefe"), - xl("what do ya want for nothing?"), - dict(RIPEMD160='dda6c0213a485a9e24f4742064a7f033b43c4069'), - 'RFC 2286 #2 (HMAC-RIPEMD)'), - - # Test case 13 (RIPEMD) - ('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', - 'dd' * 50, - dict(RIPEMD160='b0b105360de759960ab4f35298e116e295d8e7c1'), - 'RFC 2286 #3 (HMAC-RIPEMD)'), - - # Test case 14 (RIPEMD) - ('0102030405060708090a0b0c0d0e0f10111213141516171819', - 'cd' * 50, - dict(RIPEMD160='d5ca862f4d21d5e610e18b4cf1beb97a4365ecf4'), - 'RFC 2286 #4 (HMAC-RIPEMD)'), - - # Test case 15 (RIPEMD) - ('0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c', - xl("Test With Truncation"), - dict(RIPEMD160='7619693978f91d90539ae786500ff3d8e0518e39'), - 'RFC 2286 #5 (HMAC-RIPEMD)'), - - # Test case 16 (RIPEMD) - ('aa' * 80, - xl("Test Using Larger Than Block-Size Key - Hash Key First"), - dict(RIPEMD160='6466ca07ac5eac29e1bd523e5ada7605b791fd8b'), - 'RFC 2286 #6 (HMAC-RIPEMD)'), - - # Test case 17 (RIPEMD) - ('aa' * 80, - xl("Test Using Larger Than Block-Size Key and Larger Than One Block-Size Data"), - dict(RIPEMD160='69ea60798d71616cce5fd0871e23754cd75d5a0a'), - 'RFC 2286 #7 (HMAC-RIPEMD)'), - -] - - -class HMAC_Module_and_Instance_Test(unittest.TestCase): - """Test the HMAC construction and verify that it does not - matter if you initialize it with a hash module or - with an hash instance. - - See https://bugs.launchpad.net/pycrypto/+bug/1209399 - """ - - def __init__(self, hashmods): - """Initialize the test with a dictionary of hash modules - indexed by their names""" - - unittest.TestCase.__init__(self) - self.hashmods = hashmods - self.description = "" - - def shortDescription(self): - return self.description - - def runTest(self): - key = b"\x90\x91\x92\x93" * 4 - payload = b"\x00" * 100 - - for hashname, hashmod in self.hashmods.items(): - if hashmod is None: - continue - self.description = "Test HMAC in combination with " + hashname - one = HMAC.new(key, payload, hashmod).digest() - two = HMAC.new(key, payload, hashmod.new()).digest() - self.assertEqual(one, two) - - -class HMAC_None(unittest.TestCase): - - def runTest(self): - - key = b"\x04" * 20 - one = HMAC.new(key, b"", SHA1).digest() - two = HMAC.new(key, None, SHA1).digest() - self.assertEqual(one, two) - - -class ByteArrayTests(unittest.TestCase): - - def runTest(self): - - key = b"0" * 16 - data = b"\x00\x01\x02" - - # Data and key can be a bytearray (during initialization) - key_ba = bytearray(key) - data_ba = bytearray(data) - - h1 = HMAC.new(key, data) - h2 = HMAC.new(key_ba, data_ba) - key_ba[:1] = b'\xFF' - data_ba[:1] = b'\xFF' - self.assertEqual(h1.digest(), h2.digest()) - - # Data can be a bytearray (during operation) - key_ba = bytearray(key) - data_ba = bytearray(data) - - h1 = HMAC.new(key) - h2 = HMAC.new(key) - h1.update(data) - h2.update(data_ba) - data_ba[:1] = b'\xFF' - self.assertEqual(h1.digest(), h2.digest()) - - -class MemoryViewTests(unittest.TestCase): - - def runTest(self): - - key = b"0" * 16 - data = b"\x00\x01\x02" - - def get_mv_ro(data): - return memoryview(data) - - def get_mv_rw(data): - return memoryview(bytearray(data)) - - for get_mv in (get_mv_ro, get_mv_rw): - - # Data and key can be a memoryview (during initialization) - key_mv = get_mv(key) - data_mv = get_mv(data) - - h1 = HMAC.new(key, data) - h2 = HMAC.new(key_mv, data_mv) - if not data_mv.readonly: - key_mv[:1] = b'\xFF' - data_mv[:1] = b'\xFF' - self.assertEqual(h1.digest(), h2.digest()) - - # Data can be a memoryview (during operation) - data_mv = get_mv(data) - - h1 = HMAC.new(key) - h2 = HMAC.new(key) - h1.update(data) - h2.update(data_mv) - if not data_mv.readonly: - data_mv[:1] = b'\xFF' - self.assertEqual(h1.digest(), h2.digest()) - - -def get_tests(config={}): - global test_data - import types - from .common import make_mac_tests - - # A test vector contains multiple results, each one for a - # different hash algorithm. - # Here we expand each test vector into multiple ones, - # and add the relevant parameters that will be passed to new() - exp_test_data = [] - for row in test_data: - for modname in row[2].keys(): - t = list(row) - t[2] = row[2][modname] - try: - t.append(dict(digestmod=globals()[modname])) - exp_test_data.append(t) - except AttributeError: - sys.stderr.write("SelfTest: warning: not testing HMAC-%s" - " (not available)\n" % modname) - tests = make_mac_tests(HMAC, "HMAC", exp_test_data) - tests.append(HMAC_Module_and_Instance_Test(hash_modules)) - tests.append(HMAC_None()) - - tests.append(ByteArrayTests()) - tests.append(MemoryViewTests()) - - return tests - - -if __name__ == '__main__': - suite = lambda: unittest.TestSuite(get_tests()) - unittest.main(defaultTest='suite') diff --git a/Crypto/SelfTest/Hash/test_MD2.py b/Crypto/SelfTest/Hash/test_MD2.py deleted file mode 100644 index 9375168..0000000 --- a/Crypto/SelfTest/Hash/test_MD2.py +++ /dev/null @@ -1,62 +0,0 @@ -# -*- coding: utf-8 -*- -# -# SelfTest/Hash/MD2.py: Self-test for the MD2 hash function -# -# Written in 2008 by Dwayne C. Litzenberger -# -# =================================================================== -# The contents of this file are dedicated to the public domain. To -# the extent that dedication to the public domain is not available, -# everyone is granted a worldwide, perpetual, royalty-free, -# non-exclusive license to exercise all rights associated with the -# contents of this file for any purpose whatsoever. -# No rights are reserved. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS -# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN -# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# =================================================================== - -"""Self-test suite for Crypto.Hash.MD2""" - -from Crypto.Util.py3compat import * - -# This is a list of (expected_result, input[, description]) tuples. -test_data = [ - # Test vectors from RFC 1319 - ('8350e5a3e24c153df2275c9f80692773', '', "'' (empty string)"), - ('32ec01ec4a6dac72c0ab96fb34c0b5d1', 'a'), - ('da853b0d3f88d99b30283a69e6ded6bb', 'abc'), - ('ab4f496bfb2a530b219ff33031fe06b0', 'message digest'), - - ('4e8ddff3650292ab5a4108c3aa47940b', 'abcdefghijklmnopqrstuvwxyz', - 'a-z'), - - ('da33def2a42df13975352846c30338cd', - 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789', - 'A-Z, a-z, 0-9'), - - ('d5976f79d83d3a0dc9806c3c66f3efd8', - '1234567890123456789012345678901234567890123456' - + '7890123456789012345678901234567890', - "'1234567890' * 8"), -] - -def get_tests(config={}): - from Crypto.Hash import MD2 - from .common import make_hash_tests - return make_hash_tests(MD2, "MD2", test_data, - digest_size=16, - oid="1.2.840.113549.2.2") - -if __name__ == '__main__': - import unittest - suite = lambda: unittest.TestSuite(get_tests()) - unittest.main(defaultTest='suite') - -# vim:set ts=4 sw=4 sts=4 expandtab: diff --git a/Crypto/SelfTest/Hash/test_MD4.py b/Crypto/SelfTest/Hash/test_MD4.py deleted file mode 100644 index 17b48a7..0000000 --- a/Crypto/SelfTest/Hash/test_MD4.py +++ /dev/null @@ -1,64 +0,0 @@ -# -*- coding: utf-8 -*- -# -# SelfTest/Hash/MD4.py: Self-test for the MD4 hash function -# -# Written in 2008 by Dwayne C. Litzenberger -# -# =================================================================== -# The contents of this file are dedicated to the public domain. To -# the extent that dedication to the public domain is not available, -# everyone is granted a worldwide, perpetual, royalty-free, -# non-exclusive license to exercise all rights associated with the -# contents of this file for any purpose whatsoever. -# No rights are reserved. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS -# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN -# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# =================================================================== - -"""Self-test suite for Crypto.Hash.MD4""" - -__revision__ = "$Id$" - -from Crypto.Util.py3compat import * - -# This is a list of (expected_result, input[, description]) tuples. -test_data = [ - # Test vectors from RFC 1320 - ('31d6cfe0d16ae931b73c59d7e0c089c0', '', "'' (empty string)"), - ('bde52cb31de33e46245e05fbdbd6fb24', 'a'), - ('a448017aaf21d8525fc10ae87aa6729d', 'abc'), - ('d9130a8164549fe818874806e1c7014b', 'message digest'), - - ('d79e1c308aa5bbcdeea8ed63df412da9', 'abcdefghijklmnopqrstuvwxyz', - 'a-z'), - - ('043f8582f241db351ce627e153e7f0e4', - 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789', - 'A-Z, a-z, 0-9'), - - ('e33b4ddc9c38f2199c3e7b164fcc0536', - '1234567890123456789012345678901234567890123456' - + '7890123456789012345678901234567890', - "'1234567890' * 8"), -] - -def get_tests(config={}): - from Crypto.Hash import MD4 - from .common import make_hash_tests - return make_hash_tests(MD4, "MD4", test_data, - digest_size=16, - oid="1.2.840.113549.2.4") - -if __name__ == '__main__': - import unittest - suite = lambda: unittest.TestSuite(get_tests()) - unittest.main(defaultTest='suite') - -# vim:set ts=4 sw=4 sts=4 expandtab: diff --git a/Crypto/SelfTest/Hash/test_MD5.py b/Crypto/SelfTest/Hash/test_MD5.py deleted file mode 100644 index 830ace7..0000000 --- a/Crypto/SelfTest/Hash/test_MD5.py +++ /dev/null @@ -1,94 +0,0 @@ -# -*- coding: utf-8 -*- -# -# SelfTest/Hash/MD5.py: Self-test for the MD5 hash function -# -# Written in 2008 by Dwayne C. Litzenberger -# -# =================================================================== -# The contents of this file are dedicated to the public domain. To -# the extent that dedication to the public domain is not available, -# everyone is granted a worldwide, perpetual, royalty-free, -# non-exclusive license to exercise all rights associated with the -# contents of this file for any purpose whatsoever. -# No rights are reserved. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS -# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN -# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# =================================================================== - -"""Self-test suite for Crypto.Hash.MD5""" - -from Crypto.Util.py3compat import * -from Crypto.Hash import MD5 -from binascii import unhexlify -import unittest -from Crypto.SelfTest.st_common import list_test_cases - - -# This is a list of (expected_result, input[, description]) tuples. -test_data = [ - # Test vectors from RFC 1321 - ('d41d8cd98f00b204e9800998ecf8427e', '', "'' (empty string)"), - ('0cc175b9c0f1b6a831c399e269772661', 'a'), - ('900150983cd24fb0d6963f7d28e17f72', 'abc'), - ('f96b697d7cb7938d525a2f31aaf161d0', 'message digest'), - - ('c3fcd3d76192e4007dfb496cca67e13b', 'abcdefghijklmnopqrstuvwxyz', - 'a-z'), - - ('d174ab98d277d9f5a5611c2c9f419d9f', - 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789', - 'A-Z, a-z, 0-9'), - - ('57edf4a22be3c955ac49da2e2107b67a', - '1234567890123456789012345678901234567890123456' - + '7890123456789012345678901234567890', - "'1234567890' * 8"), - - # https://www.cosic.esat.kuleuven.be/nessie/testvectors/hash/md5/Md5-128.unverified.test-vectors - ('57EDF4A22BE3C955AC49DA2E2107B67A', '1234567890' * 8, 'Set 1, vector #7'), - ('7707D6AE4E027C70EEA2A935C2296F21', 'a'*1000000, 'Set 1, vector #8'), -] - - -class Md5IterTest(unittest.TestCase): - - def runTest(self): - message = b("\x00") * 16 - result1 = "4AE71336E44BF9BF79D2752E234818A5".lower() - result2 = "1A83F51285E4D89403D00C46EF8508FE".lower() - - h = MD5.new(message) - message = h.digest() - self.assertEqual(h.hexdigest(), result1) - - for _ in range(99999): - h = MD5.new(message) - message = h.digest() - - self.assertEqual(h.hexdigest(), result2) - - -def get_tests(config={}): - from .common import make_hash_tests - - tests = make_hash_tests(MD5, "MD5", test_data, - digest_size=16, - oid="1.2.840.113549.2.5") - if config.get('slow_tests'): - tests += [ Md5IterTest() ] - return tests - - -if __name__ == '__main__': - import unittest - suite = lambda: unittest.TestSuite(get_tests()) - unittest.main(defaultTest='suite') - -# vim:set ts=4 sw=4 sts=4 expandtab: diff --git a/Crypto/SelfTest/Hash/test_Poly1305.py b/Crypto/SelfTest/Hash/test_Poly1305.py deleted file mode 100644 index 0bbb6bd..0000000 --- a/Crypto/SelfTest/Hash/test_Poly1305.py +++ /dev/null @@ -1,542 +0,0 @@ -# -# SelfTest/Hash/test_Poly1305.py: Self-test for the Poly1305 module -# -# =================================================================== -# -# Copyright (c) 2018, Helder Eijs -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# =================================================================== - -"""Self-test suite for Crypto.Hash._Poly1305""" - -import json -import unittest -from binascii import unhexlify, hexlify - -from .common import make_mac_tests -from Crypto.SelfTest.st_common import list_test_cases - -from Crypto.Hash import Poly1305 -from Crypto.Cipher import AES, ChaCha20 - -from Crypto.Util.py3compat import tobytes -from Crypto.Util.strxor import strxor_c - -# This is a list of (r+s keypair, data, result, description, keywords) tuples. -test_data_basic = [ - ( - "85d6be7857556d337f4452fe42d506a80103808afb0db2fd4abff6af4149f51b", - hexlify(b"Cryptographic Forum Research Group").decode(), - "a8061dc1305136c6c22b8baf0c0127a9", - "RFC7539" - ), - ( - "746869732069732033322d62797465206b657920666f7220506f6c7931333035", - "0000000000000000000000000000000000000000000000000000000000000000", - "49ec78090e481ec6c26b33b91ccc0307", - "https://tools.ietf.org/html/draft-agl-tls-chacha20poly1305-00#section-7 A", - ), - ( - "746869732069732033322d62797465206b657920666f7220506f6c7931333035", - "48656c6c6f20776f726c6421", - "a6f745008f81c916a20dcc74eef2b2f0", - "https://tools.ietf.org/html/draft-agl-tls-chacha20poly1305-00#section-7 B", - ), - ( - "746869732069732033322d62797465206b657920666f7220506f6c7931333035", - "", - "6b657920666f7220506f6c7931333035", - "Generated with pure Python", - ), - ( - "746869732069732033322d62797465206b657920666f7220506f6c7931333035", - "FF", - "f7e4e0ef4c46d106219da3d1bdaeb3ff", - "Generated with pure Python", - ), - ( - "746869732069732033322d62797465206b657920666f7220506f6c7931333035", - "FF00", - "7471eceeb22988fc936da1d6e838b70e", - "Generated with pure Python", - ), - ( - "746869732069732033322d62797465206b657920666f7220506f6c7931333035", - "AA" * 17, - "32590bc07cb2afaccca3f67f122975fe", - "Generated with pure Python", - ), - ( - "00" * 32, - "00" * 64, - "00" * 16, - "RFC7539 A.3 #1", - ), - ( - "0000000000000000000000000000000036e5f6b5c5e06070f0efca96227a863e", - hexlify( - b"Any submission t" - b"o the IETF inten" - b"ded by the Contr" - b"ibutor for publi" - b"cation as all or" - b" part of an IETF" - b" Internet-Draft " - b"or RFC and any s" - b"tatement made wi" - b"thin the context" - b" of an IETF acti" - b"vity is consider" - b"ed an \"IETF Cont" - b"ribution\". Such " - b"statements inclu" - b"de oral statemen" - b"ts in IETF sessi" - b"ons, as well as " - b"written and elec" - b"tronic communica" - b"tions made at an" - b"y time or place," - b" which are addre" - b"ssed to").decode(), - "36e5f6b5c5e06070f0efca96227a863e", - "RFC7539 A.3 #2", - ), - ( - "36e5f6b5c5e06070f0efca96227a863e00000000000000000000000000000000", - hexlify( - b"Any submission t" - b"o the IETF inten" - b"ded by the Contr" - b"ibutor for publi" - b"cation as all or" - b" part of an IETF" - b" Internet-Draft " - b"or RFC and any s" - b"tatement made wi" - b"thin the context" - b" of an IETF acti" - b"vity is consider" - b"ed an \"IETF Cont" - b"ribution\". Such " - b"statements inclu" - b"de oral statemen" - b"ts in IETF sessi" - b"ons, as well as " - b"written and elec" - b"tronic communica" - b"tions made at an" - b"y time or place," - b" which are addre" - b"ssed to").decode(), - "f3477e7cd95417af89a6b8794c310cf0", - "RFC7539 A.3 #3", - ), - ( - "1c9240a5eb55d38af333888604f6b5f0473917c1402b80099dca5cbc207075c0", - "2754776173206272696c6c69672c2061" - "6e642074686520736c6974687920746f" - "7665730a446964206779726520616e64" - "2067696d626c6520696e207468652077" - "6162653a0a416c6c206d696d73792077" - "6572652074686520626f726f676f7665" - "732c0a416e6420746865206d6f6d6520" - "7261746873206f757467726162652e", - "4541669a7eaaee61e708dc7cbcc5eb62", - "RFC7539 A.3 #4", - ), - ( - "02" + "00" * 31, - "FF" * 16, - "03" + "00" * 15, - "RFC7539 A.3 #5", - ), - ( - "02" + "00" * 15 + "FF" * 16, - "02" + "00" * 15, - "03" + "00" * 15, - "RFC7539 A.3 #6", - ), - ( - "01" + "00" * 31, - "FF" * 16 + "F0" + "FF" * 15 + "11" + "00" * 15, - "05" + "00" * 15, - "RFC7539 A.3 #7", - ), - ( - "01" + "00" * 31, - "FF" * 16 + "FB" + "FE" * 15 + "01" * 16, - "00" * 16, - "RFC7539 A.3 #8", - ), - ( - "02" + "00" * 31, - "FD" + "FF" * 15, - "FA" + "FF" * 15, - "RFC7539 A.3 #9", - ), - ( - "01 00 00 00 00 00 00 00 04 00 00 00 00 00 00 00" - "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00", - "E3 35 94 D7 50 5E 43 B9 00 00 00 00 00 00 00 00" - "33 94 D7 50 5E 43 79 CD 01 00 00 00 00 00 00 00" - "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00" - "01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00", - "14 00 00 00 00 00 00 00 55 00 00 00 00 00 00 00", - "RFC7539 A.3 #10", - ), - ( - "01 00 00 00 00 00 00 00 04 00 00 00 00 00 00 00" - "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00", - "E3 35 94 D7 50 5E 43 B9 00 00 00 00 00 00 00 00" - "33 94 D7 50 5E 43 79 CD 01 00 00 00 00 00 00 00" - "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00", - "13" + "00" * 15, - "RFC7539 A.3 #11", - ), -] - -# This is a list of (key(k+r), data, result, description, keywords) tuples. -test_data_aes = [ - ( - "ec074c835580741701425b623235add6851fc40c3467ac0be05cc20404f3f700", - "f3f6", - "f4c633c3044fc145f84f335cb81953de", - "http://cr.yp.to/mac/poly1305-20050329.pdf", - { 'cipher':AES, 'nonce':unhexlify("fb447350c4e868c52ac3275cf9d4327e") } - ), - ( - "75deaa25c09f208e1dc4ce6b5cad3fbfa0f3080000f46400d0c7e9076c834403", - "", - "dd3fab2251f11ac759f0887129cc2ee7", - "http://cr.yp.to/mac/poly1305-20050329.pdf", - { 'cipher':AES, 'nonce':unhexlify("61ee09218d29b0aaed7e154a2c5509cc") } - ), - ( - "6acb5f61a7176dd320c5c1eb2edcdc7448443d0bb0d21109c89a100b5ce2c208", - "663cea190ffb83d89593f3f476b6bc24" - "d7e679107ea26adb8caf6652d0656136", - "0ee1c16bb73f0f4fd19881753c01cdbe", - "http://cr.yp.to/mac/poly1305-20050329.pdf", - { 'cipher':AES, 'nonce':unhexlify("ae212a55399729595dea458bc621ff0e") } - ), - ( - "e1a5668a4d5b66a5f68cc5424ed5982d12976a08c4426d0ce8a82407c4f48207", - "ab0812724a7f1e342742cbed374d94d1" - "36c6b8795d45b3819830f2c04491faf0" - "990c62e48b8018b2c3e4a0fa3134cb67" - "fa83e158c994d961c4cb21095c1bf9", - "5154ad0d2cb26e01274fc51148491f1b", - "http://cr.yp.to/mac/poly1305-20050329.pdf", - { 'cipher':AES, 'nonce':unhexlify("9ae831e743978d3a23527c7128149e3a") } - ), -] - -test_data_chacha20 = [ - ( - "00" * 32, - "FF" * 15, - "13cc5bbadc36b03a5163928f0bcb65aa", - "RFC7539 A.4 #1", - { 'cipher':ChaCha20, 'nonce':unhexlify("00" * 12) } - ), - ( - "00" * 31 + "01", - "FF" * 15, - "0baf33c1d6df211bdd50a6767e98e00a", - "RFC7539 A.4 #2", - { 'cipher':ChaCha20, 'nonce':unhexlify("00" * 11 + "02") } - ), - ( - "1c 92 40 a5 eb 55 d3 8a f3 33 88 86 04 f6 b5 f0" - "47 39 17 c1 40 2b 80 09 9d ca 5c bc 20 70 75 c0", - "FF" * 15, - "e8b4c6db226cd8939e65e02eebf834ce", - "RFC7539 A.4 #3", - { 'cipher':ChaCha20, 'nonce':unhexlify("00" * 11 + "02") } - ), - ( - "1c 92 40 a5 eb 55 d3 8a f3 33 88 86 04 f6 b5 f0" - "47 39 17 c1 40 2b 80 09 9d ca 5c bc 20 70 75 c0", - "f3 33 88 86 00 00 00 00 00 00 4e 91 00 00 00 00" - "64 a0 86 15 75 86 1a f4 60 f0 62 c7 9b e6 43 bd" - "5e 80 5c fd 34 5c f3 89 f1 08 67 0a c7 6c 8c b2" - "4c 6c fc 18 75 5d 43 ee a0 9e e9 4e 38 2d 26 b0" - "bd b7 b7 3c 32 1b 01 00 d4 f0 3b 7f 35 58 94 cf" - "33 2f 83 0e 71 0b 97 ce 98 c8 a8 4a bd 0b 94 81" - "14 ad 17 6e 00 8d 33 bd 60 f9 82 b1 ff 37 c8 55" - "97 97 a0 6e f4 f0 ef 61 c1 86 32 4e 2b 35 06 38" - "36 06 90 7b 6a 7c 02 b0 f9 f6 15 7b 53 c8 67 e4" - "b9 16 6c 76 7b 80 4d 46 a5 9b 52 16 cd e7 a4 e9" - "90 40 c5 a4 04 33 22 5e e2 82 a1 b0 a0 6c 52 3e" - "af 45 34 d7 f8 3f a1 15 5b 00 47 71 8c bc 54 6a" - "0d 07 2b 04 b3 56 4e ea 1b 42 22 73 f5 48 27 1a" - "0b b2 31 60 53 fa 76 99 19 55 eb d6 31 59 43 4e" - "ce bb 4e 46 6d ae 5a 10 73 a6 72 76 27 09 7a 10" - "49 e6 17 d9 1d 36 10 94 fa 68 f0 ff 77 98 71 30" - "30 5b ea ba 2e da 04 df 99 7b 71 4d 6c 6f 2c 29" - "a6 ad 5c b4 02 2b 02 70 9b 00 00 00 00 00 00 00" - "0c 00 00 00 00 00 00 00 09 01 00 00 00 00 00 00", - "ee ad 9d 67 89 0c bb 22 39 23 36 fe a1 85 1f 38", - "RFC7539 A.5", - { 'cipher':ChaCha20, 'nonce':unhexlify("000000000102030405060708") } - ), -] - - -class Poly1305Test_AES(unittest.TestCase): - - key = b'\x11' * 32 - - def test_new_positive(self): - - data = b'r' * 100 - - h1 = Poly1305.new(key=self.key, cipher=AES) - self.assertEqual(h1.digest_size, 16) - self.assertEqual(len(h1.nonce), 16) - d1 = h1.update(data).digest() - self.assertEqual(len(d1), 16) - - h2 = Poly1305.new(key=self.key, nonce=h1.nonce, data=data, cipher=AES) - d2 = h2.digest() - self.assertEqual(h1.nonce, h2.nonce) - self.assertEqual(d1, d2) - - def test_new_negative(self): - from Crypto.Cipher import DES3 - - self.assertRaises(ValueError, Poly1305.new, key=self.key[:31], cipher=AES) - self.assertRaises(ValueError, Poly1305.new, key=self.key, cipher=DES3) - self.assertRaises(ValueError, Poly1305.new, key=self.key, nonce=b'1' * 15, cipher=AES) - self.assertRaises(TypeError, Poly1305.new, key=u"2" * 32, cipher=AES) - self.assertRaises(TypeError, Poly1305.new, key=self.key, data=u"2" * 100, cipher=AES) - - def test_update(self): - pieces = [b"\x0A" * 200, b"\x14" * 300] - h1 = Poly1305.new(key=self.key, cipher=AES) - h1.update(pieces[0]).update(pieces[1]) - d1 = h1.digest() - - h2 = Poly1305.new(key=self.key, cipher=AES, nonce=h1.nonce) - h2.update(pieces[0] + pieces[1]) - d2 = h2.digest() - self.assertEqual(d1, d2) - - def test_update_negative(self): - h = Poly1305.new(key=self.key, cipher=AES) - self.assertRaises(TypeError, h.update, u"string") - - def test_digest(self): - h = Poly1305.new(key=self.key, cipher=AES) - digest = h.digest() - - # hexdigest does not change the state - self.assertEqual(h.digest(), digest) - # digest returns a byte string - self.failUnless(isinstance(digest, type(b"digest"))) - - def test_update_after_digest(self): - msg=b"rrrrttt" - - # Normally, update() cannot be done after digest() - h = Poly1305.new(key=self.key, data=msg[:4], cipher=AES) - h.digest() - self.assertRaises(TypeError, h.update, msg[4:]) - - def test_hex_digest(self): - mac = Poly1305.new(key=self.key, cipher=AES) - digest = mac.digest() - hexdigest = mac.hexdigest() - - # hexdigest is equivalent to digest - self.assertEqual(hexlify(digest), tobytes(hexdigest)) - # hexdigest does not change the state - self.assertEqual(mac.hexdigest(), hexdigest) - # hexdigest returns a string - self.failUnless(isinstance(hexdigest, type("digest"))) - - def test_verify(self): - h = Poly1305.new(key=self.key, cipher=AES) - mac = h.digest() - h.verify(mac) - wrong_mac = strxor_c(mac, 255) - self.assertRaises(ValueError, h.verify, wrong_mac) - - def test_hexverify(self): - h = Poly1305.new(key=self.key, cipher=AES) - mac = h.hexdigest() - h.hexverify(mac) - self.assertRaises(ValueError, h.hexverify, "4556") - - def test_bytearray(self): - - data = b"\x00\x01\x02" - h0 = Poly1305.new(key=self.key, data=data, cipher=AES) - d_ref = h0.digest() - - # Data and key can be a bytearray (during initialization) - key_ba = bytearray(self.key) - data_ba = bytearray(data) - - h1 = Poly1305.new(key=self.key, data=data, cipher=AES, nonce=h0.nonce) - h2 = Poly1305.new(key=key_ba, data=data_ba, cipher=AES, nonce=h0.nonce) - key_ba[:1] = b'\xFF' - data_ba[:1] = b'\xEE' - - self.assertEqual(h1.digest(), d_ref) - self.assertEqual(h2.digest(), d_ref) - - # Data can be a bytearray (during operation) - data_ba = bytearray(data) - - h1 = Poly1305.new(key=self.key, cipher=AES) - h2 = Poly1305.new(key=self.key, cipher=AES, nonce=h1.nonce) - h1.update(data) - h2.update(data_ba) - data_ba[:1] = b'\xFF' - - self.assertEqual(h1.digest(), h2.digest()) - - def test_memoryview(self): - - data = b"\x00\x01\x02" - - def get_mv_ro(data): - return memoryview(data) - - def get_mv_rw(data): - return memoryview(bytearray(data)) - - for get_mv in (get_mv_ro, get_mv_rw): - - # Data and key can be a memoryview (during initialization) - key_mv = get_mv(self.key) - data_mv = get_mv(data) - - h1 = Poly1305.new(key=self.key, data=data, cipher=AES) - h2 = Poly1305.new(key=key_mv, data=data_mv, cipher=AES, - nonce=h1.nonce) - if not data_mv.readonly: - data_mv[:1] = b'\xFF' - key_mv[:1] = b'\xFF' - - self.assertEqual(h1.digest(), h2.digest()) - - # Data can be a memoryview (during operation) - data_mv = get_mv(data) - - h1 = Poly1305.new(key=self.key, cipher=AES) - h2 = Poly1305.new(key=self.key, cipher=AES, nonce=h1.nonce) - h1.update(data) - h2.update(data_mv) - if not data_mv.readonly: - data_mv[:1] = b'\xFF' - - self.assertEqual(h1.digest(), h2.digest()) - - -class Poly1305Test_ChaCha20(unittest.TestCase): - - key = b'\x11' * 32 - - def test_new_positive(self): - data = b'r' * 100 - - h1 = Poly1305.new(key=self.key, cipher=ChaCha20) - self.assertEqual(h1.digest_size, 16) - self.assertEqual(len(h1.nonce), 12) - - h2 = Poly1305.new(key=self.key, cipher=ChaCha20, nonce = b'8' * 8) - self.assertEqual(len(h2.nonce), 8) - self.assertEqual(h2.nonce, b'8' * 8) - - def test_new_negative(self): - - self.assertRaises(ValueError, Poly1305.new, key=self.key, nonce=b'1' * 7, cipher=ChaCha20) - - -# -# make_mac_tests() expect a new() function with signature new(key, data, -# **kwargs), and we need to adapt Poly1305's, as it only uses keywords -# -class Poly1305_New(object): - - @staticmethod - def new(key, *data, **kwds): - _kwds = dict(kwds) - if len(data) == 1: - _kwds['data'] = data[0] - _kwds['key'] = key - return Poly1305.new(**_kwds) - - -class Poly1305_Basic(object): - - @staticmethod - def new(key, *data, **kwds): - from Crypto.Hash.Poly1305 import Poly1305_MAC - - if len(data) == 1: - msg = data[0] - else: - msg = None - - return Poly1305_MAC(key[:16], key[16:], msg) - - -class Poly1305AES_MC(unittest.TestCase): - - def runTest(self): - tag = unhexlify(b"fb447350c4e868c52ac3275cf9d4327e") - - msg = b'' - for msg_len in range(5000 + 1): - key = tag + strxor_c(tag, 0xFF) - nonce = tag[::-1] - if msg_len > 0: - msg = msg + tobytes(tag[0]) - auth = Poly1305.new(key=key, nonce=nonce, cipher=AES, data=msg) - tag = auth.digest() - - # Compare against output of original DJB's poly1305aes-20050218 - self.assertEqual("CDFA436DDD629C7DC20E1128530BAED2", auth.hexdigest().upper()) - - -def get_tests(config={}): - tests = make_mac_tests(Poly1305_Basic, "Poly1305", test_data_basic) - tests += make_mac_tests(Poly1305_New, "Poly1305", test_data_aes) - tests += make_mac_tests(Poly1305_New, "Poly1305", test_data_chacha20) - tests += [ Poly1305AES_MC() ] - tests += list_test_cases(Poly1305Test_AES) - tests += list_test_cases(Poly1305Test_ChaCha20) - return tests - - -if __name__ == '__main__': - suite = lambda: unittest.TestSuite(get_tests()) - unittest.main(defaultTest='suite') diff --git a/Crypto/SelfTest/Hash/test_RIPEMD160.py b/Crypto/SelfTest/Hash/test_RIPEMD160.py deleted file mode 100644 index 153c570..0000000 --- a/Crypto/SelfTest/Hash/test_RIPEMD160.py +++ /dev/null @@ -1,71 +0,0 @@ -# -*- coding: utf-8 -*- -# -# SelfTest/Hash/test_RIPEMD160.py: Self-test for the RIPEMD-160 hash function -# -# Written in 2008 by Dwayne C. Litzenberger -# -# =================================================================== -# The contents of this file are dedicated to the public domain. To -# the extent that dedication to the public domain is not available, -# everyone is granted a worldwide, perpetual, royalty-free, -# non-exclusive license to exercise all rights associated with the -# contents of this file for any purpose whatsoever. -# No rights are reserved. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS -# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN -# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# =================================================================== - -#"""Self-test suite for Crypto.Hash.RIPEMD160""" - -from Crypto.Util.py3compat import * - -# This is a list of (expected_result, input[, description]) tuples. -test_data = [ - # Test vectors downloaded 2008-09-12 from - # http://homes.esat.kuleuven.be/~bosselae/ripemd160.html - ('9c1185a5c5e9fc54612808977ee8f548b2258d31', '', "'' (empty string)"), - ('0bdc9d2d256b3ee9daae347be6f4dc835a467ffe', 'a'), - ('8eb208f7e05d987a9b044a8e98c6b087f15a0bfc', 'abc'), - ('5d0689ef49d2fae572b881b123a85ffa21595f36', 'message digest'), - - ('f71c27109c692c1b56bbdceb5b9d2865b3708dbc', - 'abcdefghijklmnopqrstuvwxyz', - 'a-z'), - - ('12a053384a9c0c88e405a06c27dcf49ada62eb2b', - 'abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq', - 'abcdbcd...pnopq'), - - ('b0e20b6e3116640286ed3a87a5713079b21f5189', - 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789', - 'A-Z, a-z, 0-9'), - - ('9b752e45573d4b39f4dbd3323cab82bf63326bfb', - '1234567890' * 8, - "'1234567890' * 8"), - - ('52783243c1697bdbe16d37f97f68f08325dc1528', - 'a' * 10**6, - '"a" * 10**6'), -] - -def get_tests(config={}): - from Crypto.Hash import RIPEMD160 - from .common import make_hash_tests - return make_hash_tests(RIPEMD160, "RIPEMD160", test_data, - digest_size=20, - oid="1.3.36.3.2.1") - -if __name__ == '__main__': - import unittest - suite = lambda: unittest.TestSuite(get_tests()) - unittest.main(defaultTest='suite') - -# vim:set ts=4 sw=4 sts=4 expandtab: diff --git a/Crypto/SelfTest/Hash/test_SHA1.py b/Crypto/SelfTest/Hash/test_SHA1.py deleted file mode 100644 index a883a44..0000000 --- a/Crypto/SelfTest/Hash/test_SHA1.py +++ /dev/null @@ -1,84 +0,0 @@ -# -*- coding: utf-8 -*- -# -# SelfTest/Hash/SHA1.py: Self-test for the SHA-1 hash function -# -# Written in 2008 by Dwayne C. Litzenberger -# -# =================================================================== -# The contents of this file are dedicated to the public domain. To -# the extent that dedication to the public domain is not available, -# everyone is granted a worldwide, perpetual, royalty-free, -# non-exclusive license to exercise all rights associated with the -# contents of this file for any purpose whatsoever. -# No rights are reserved. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS -# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN -# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# =================================================================== - -"""Self-test suite for Crypto.Hash.SHA""" - -from binascii import hexlify - -from Crypto.SelfTest.loader import load_test_vectors - -# Test vectors from various sources -# This is a list of (expected_result, input[, description]) tuples. -test_data_various = [ - # FIPS PUB 180-2, A.1 - "One-Block Message" - ('a9993e364706816aba3e25717850c26c9cd0d89d', 'abc'), - - # FIPS PUB 180-2, A.2 - "Multi-Block Message" - ('84983e441c3bd26ebaae4aa1f95129e5e54670f1', - 'abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq'), - - # FIPS PUB 180-2, A.3 - "Long Message" -# ('34aa973cd4c4daa4f61eeb2bdbad27316534016f', -# 'a' * 10**6, -# '"a" * 10**6'), - - # RFC 3174: Section 7.3, "TEST4" (multiple of 512 bits) - ('dea356a2cddd90c7a7ecedc5ebb563934f460452', - '01234567' * 80, - '"01234567" * 80'), -] - -def get_tests(config={}): - from Crypto.Hash import SHA1 - from .common import make_hash_tests - - tests = [] - - test_vectors = load_test_vectors(("Hash", "SHA1"), - "SHA1ShortMsg.rsp", - "KAT SHA-1", - { "len" : lambda x: int(x) } ) or [] - - test_data = test_data_various[:] - for tv in test_vectors: - try: - if tv.startswith('['): - continue - except AttributeError: - pass - if tv.len == 0: - tv.msg = b"" - test_data.append((hexlify(tv.md), tv.msg, tv.desc)) - - tests = make_hash_tests(SHA1, "SHA1", test_data, - digest_size=20, - oid="1.3.14.3.2.26") - return tests - -if __name__ == '__main__': - import unittest - suite = lambda: unittest.TestSuite(get_tests()) - unittest.main(defaultTest='suite') - -# vim:set ts=4 sw=4 sts=4 expandtab: diff --git a/Crypto/SelfTest/Hash/test_SHA224.py b/Crypto/SelfTest/Hash/test_SHA224.py deleted file mode 100644 index cf81ad9..0000000 --- a/Crypto/SelfTest/Hash/test_SHA224.py +++ /dev/null @@ -1,63 +0,0 @@ -# -*- coding: utf-8 -*- -# -# SelfTest/Hash/test_SHA224.py: Self-test for the SHA-224 hash function -# -# Written in 2008 by Dwayne C. Litzenberger -# -# =================================================================== -# The contents of this file are dedicated to the public domain. To -# the extent that dedication to the public domain is not available, -# everyone is granted a worldwide, perpetual, royalty-free, -# non-exclusive license to exercise all rights associated with the -# contents of this file for any purpose whatsoever. -# No rights are reserved. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS -# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN -# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# =================================================================== - -"""Self-test suite for Crypto.Hash.SHA224""" - -# Test vectors from various sources -# This is a list of (expected_result, input[, description]) tuples. -test_data = [ - - # RFC 3874: Section 3.1, "Test Vector #1 - ('23097d223405d8228642a477bda255b32aadbce4bda0b3f7e36c9da7', 'abc'), - - # RFC 3874: Section 3.2, "Test Vector #2 - ('75388b16512776cc5dba5da1fd890150b0c6455cb4f58b1952522525', 'abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq'), - - # RFC 3874: Section 3.3, "Test Vector #3 - ('20794655980c91d8bbb4c1ea97618a4bf03f42581948b2ee4ee7ad67', 'a' * 10**6, "'a' * 10**6"), - - # Examples from http://de.wikipedia.org/wiki/Secure_Hash_Algorithm - ('d14a028c2a3a2bc9476102bb288234c415a2b01f828ea62ac5b3e42f', ''), - - ('49b08defa65e644cbf8a2dd9270bdededabc741997d1dadd42026d7b', - 'Franz jagt im komplett verwahrlosten Taxi quer durch Bayern'), - - ('58911e7fccf2971a7d07f93162d8bd13568e71aa8fc86fc1fe9043d1', - 'Frank jagt im komplett verwahrlosten Taxi quer durch Bayern'), - -] - -def get_tests(config={}): - from Crypto.Hash import SHA224 - from .common import make_hash_tests - return make_hash_tests(SHA224, "SHA224", test_data, - digest_size=28, - oid='2.16.840.1.101.3.4.2.4') - -if __name__ == '__main__': - import unittest - suite = lambda: unittest.TestSuite(get_tests()) - unittest.main(defaultTest='suite') - -# vim:set ts=4 sw=4 sts=4 expandtab: diff --git a/Crypto/SelfTest/Hash/test_SHA256.py b/Crypto/SelfTest/Hash/test_SHA256.py deleted file mode 100644 index bb99326..0000000 --- a/Crypto/SelfTest/Hash/test_SHA256.py +++ /dev/null @@ -1,94 +0,0 @@ -# -*- coding: utf-8 -*- -# -# SelfTest/Hash/test_SHA256.py: Self-test for the SHA-256 hash function -# -# Written in 2008 by Dwayne C. Litzenberger -# -# =================================================================== -# The contents of this file are dedicated to the public domain. To -# the extent that dedication to the public domain is not available, -# everyone is granted a worldwide, perpetual, royalty-free, -# non-exclusive license to exercise all rights associated with the -# contents of this file for any purpose whatsoever. -# No rights are reserved. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS -# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN -# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# =================================================================== - -"""Self-test suite for Crypto.Hash.SHA256""" - -import unittest -from Crypto.Util.py3compat import * - -class LargeSHA256Test(unittest.TestCase): - def runTest(self): - """SHA256: 512/520 MiB test""" - from Crypto.Hash import SHA256 - zeros = bchr(0x00) * (1024*1024) - - h = SHA256.new(zeros) - for i in range(511): - h.update(zeros) - - # This test vector is from PyCrypto's old testdata.py file. - self.assertEqual('9acca8e8c22201155389f65abbf6bc9723edc7384ead80503839f49dcc56d767', h.hexdigest()) # 512 MiB - - for i in range(8): - h.update(zeros) - - # This test vector is from PyCrypto's old testdata.py file. - self.assertEqual('abf51ad954b246009dfe5a50ecd582fd5b8f1b8b27f30393853c3ef721e7fa6e', h.hexdigest()) # 520 MiB - -def get_tests(config={}): - # Test vectors from FIPS PUB 180-2 - # This is a list of (expected_result, input[, description]) tuples. - test_data = [ - # FIPS PUB 180-2, B.1 - "One-Block Message" - ('ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad', - 'abc'), - - # FIPS PUB 180-2, B.2 - "Multi-Block Message" - ('248d6a61d20638b8e5c026930c3e6039a33ce45964ff2167f6ecedd419db06c1', - 'abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq'), - - # FIPS PUB 180-2, B.3 - "Long Message" - ('cdc76e5c9914fb9281a1c7e284d73e67f1809a48a497200e046d39ccc7112cd0', - 'a' * 10**6, - '"a" * 10**6'), - - # Test for an old PyCrypto bug. - ('f7fd017a3c721ce7ff03f3552c0813adcc48b7f33f07e5e2ba71e23ea393d103', - 'This message is precisely 55 bytes long, to test a bug.', - 'Length = 55 (mod 64)'), - - # Example from http://de.wikipedia.org/wiki/Secure_Hash_Algorithm - ('e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855', ''), - - ('d32b568cd1b96d459e7291ebf4b25d007f275c9f13149beeb782fac0716613f8', - 'Franz jagt im komplett verwahrlosten Taxi quer durch Bayern'), - ] - - from Crypto.Hash import SHA256 - from .common import make_hash_tests - tests = make_hash_tests(SHA256, "SHA256", test_data, - digest_size=32, - oid="2.16.840.1.101.3.4.2.1") - - if config.get('slow_tests'): - tests += [LargeSHA256Test()] - - return tests - -if __name__ == '__main__': - import unittest - suite = lambda: unittest.TestSuite(get_tests()) - unittest.main(defaultTest='suite') - -# vim:set ts=4 sw=4 sts=4 expandtab: diff --git a/Crypto/SelfTest/Hash/test_SHA384.py b/Crypto/SelfTest/Hash/test_SHA384.py deleted file mode 100644 index c682eb4..0000000 --- a/Crypto/SelfTest/Hash/test_SHA384.py +++ /dev/null @@ -1,61 +0,0 @@ -# -*- coding: utf-8 -*- -# -# SelfTest/Hash/test_SHA.py: Self-test for the SHA-384 hash function -# -# Written in 2008 by Dwayne C. Litzenberger -# -# =================================================================== -# The contents of this file are dedicated to the public domain. To -# the extent that dedication to the public domain is not available, -# everyone is granted a worldwide, perpetual, royalty-free, -# non-exclusive license to exercise all rights associated with the -# contents of this file for any purpose whatsoever. -# No rights are reserved. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS -# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN -# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# =================================================================== - -"""Self-test suite for Crypto.Hash.SHA384""" - -# Test vectors from various sources -# This is a list of (expected_result, input[, description]) tuples. -test_data = [ - - # RFC 4634: Section Page 8.4, "Test 1" - ('cb00753f45a35e8bb5a03d699ac65007272c32ab0eded1631a8b605a43ff5bed8086072ba1e7cc2358baeca134c825a7', 'abc'), - - # RFC 4634: Section Page 8.4, "Test 2.2" - ('09330c33f71147e83d192fc782cd1b4753111b173b3b05d22fa08086e3b0f712fcc7c71a557e2db966c3e9fa91746039', 'abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu'), - - # RFC 4634: Section Page 8.4, "Test 3" - ('9d0e1809716474cb086e834e310a4a1ced149e9c00f248527972cec5704c2a5b07b8b3dc38ecc4ebae97ddd87f3d8985', 'a' * 10**6, "'a' * 10**6"), - - # Taken from http://de.wikipedia.org/wiki/Secure_Hash_Algorithm - ('38b060a751ac96384cd9327eb1b1e36a21fdb71114be07434c0cc7bf63f6e1da274edebfe76f65fbd51ad2f14898b95b', ''), - - # Example from http://de.wikipedia.org/wiki/Secure_Hash_Algorithm - ('71e8383a4cea32d6fd6877495db2ee353542f46fa44bc23100bca48f3366b84e809f0708e81041f427c6d5219a286677', - 'Franz jagt im komplett verwahrlosten Taxi quer durch Bayern'), - -] - -def get_tests(config={}): - from Crypto.Hash import SHA384 - from .common import make_hash_tests - return make_hash_tests(SHA384, "SHA384", test_data, - digest_size=48, - oid='2.16.840.1.101.3.4.2.2') - -if __name__ == '__main__': - import unittest - suite = lambda: unittest.TestSuite(get_tests()) - unittest.main(defaultTest='suite') - -# vim:set ts=4 sw=4 sts=4 expandtab: diff --git a/Crypto/SelfTest/Hash/test_SHA3_224.py b/Crypto/SelfTest/Hash/test_SHA3_224.py deleted file mode 100644 index 6dbf661..0000000 --- a/Crypto/SelfTest/Hash/test_SHA3_224.py +++ /dev/null @@ -1,79 +0,0 @@ -# -*- coding: utf-8 -*- -# -# SelfTest/Hash/test_SHA3_224.py: Self-test for the SHA-3/224 hash function -# -# =================================================================== -# The contents of this file are dedicated to the public domain. To -# the extent that dedication to the public domain is not available, -# everyone is granted a worldwide, perpetual, royalty-free, -# non-exclusive license to exercise all rights associated with the -# contents of this file for any purpose whatsoever. -# No rights are reserved. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS -# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN -# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# =================================================================== - -"""Self-test suite for Crypto.Hash.SHA3_224""" - -import unittest -from binascii import hexlify - -from Crypto.SelfTest.loader import load_test_vectors -from Crypto.SelfTest.st_common import list_test_cases -from Crypto.Hash import SHA3_224 as SHA3 -from Crypto.Util.py3compat import b - - -class APITest(unittest.TestCase): - - def test_update_after_digest(self): - msg=b("rrrrttt") - - # Normally, update() cannot be done after digest() - h = SHA3.new(data=msg[:4]) - dig1 = h.digest() - self.assertRaises(TypeError, h.update, msg[4:]) - dig2 = SHA3.new(data=msg).digest() - - # With the proper flag, it is allowed - h = SHA3.new(data=msg[:4], update_after_digest=True) - self.assertEquals(h.digest(), dig1) - # ... and the subsequent digest applies to the entire message - # up to that point - h.update(msg[4:]) - self.assertEquals(h.digest(), dig2) - - -def get_tests(config={}): - from .common import make_hash_tests - - tests = [] - - test_vectors = load_test_vectors(("Hash", "SHA3"), - "ShortMsgKAT_SHA3-224.txt", - "KAT SHA-3 224", - { "len" : lambda x: int(x) } ) or [] - - test_data = [] - for tv in test_vectors: - if tv.len == 0: - tv.msg = b("") - test_data.append((hexlify(tv.md), tv.msg, tv.desc)) - - tests += make_hash_tests(SHA3, "SHA3_224", test_data, - digest_size=SHA3.digest_size, - oid="2.16.840.1.101.3.4.2.7") - tests += list_test_cases(APITest) - return tests - -if __name__ == '__main__': - import unittest - suite = lambda: unittest.TestSuite(get_tests()) - unittest.main(defaultTest='suite') diff --git a/Crypto/SelfTest/Hash/test_SHA3_256.py b/Crypto/SelfTest/Hash/test_SHA3_256.py deleted file mode 100644 index b017852..0000000 --- a/Crypto/SelfTest/Hash/test_SHA3_256.py +++ /dev/null @@ -1,80 +0,0 @@ -# -*- coding: utf-8 -*- -# -# SelfTest/Hash/test_SHA3_256.py: Self-test for the SHA-3/256 hash function -# -# =================================================================== -# The contents of this file are dedicated to the public domain. To -# the extent that dedication to the public domain is not available, -# everyone is granted a worldwide, perpetual, royalty-free, -# non-exclusive license to exercise all rights associated with the -# contents of this file for any purpose whatsoever. -# No rights are reserved. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS -# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN -# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# =================================================================== - -"""Self-test suite for Crypto.Hash.SHA3_256""" - -import unittest -from binascii import hexlify - -from Crypto.SelfTest.loader import load_test_vectors -from Crypto.SelfTest.st_common import list_test_cases -from Crypto.Hash import SHA3_256 as SHA3 -from Crypto.Util.py3compat import b - - -class APITest(unittest.TestCase): - - def test_update_after_digest(self): - msg=b("rrrrttt") - - # Normally, update() cannot be done after digest() - h = SHA3.new(data=msg[:4]) - dig1 = h.digest() - self.assertRaises(TypeError, h.update, msg[4:]) - dig2 = SHA3.new(data=msg).digest() - - # With the proper flag, it is allowed - h = SHA3.new(data=msg[:4], update_after_digest=True) - self.assertEquals(h.digest(), dig1) - # ... and the subsequent digest applies to the entire message - # up to that point - h.update(msg[4:]) - self.assertEquals(h.digest(), dig2) - - -def get_tests(config={}): - from .common import make_hash_tests - - tests = [] - - test_vectors = load_test_vectors(("Hash", "SHA3"), - "ShortMsgKAT_SHA3-256.txt", - "KAT SHA-3 256", - { "len" : lambda x: int(x) } ) or [] - - test_data = [] - for tv in test_vectors: - if tv.len == 0: - tv.msg = b("") - test_data.append((hexlify(tv.md), tv.msg, tv.desc)) - - - tests += make_hash_tests(SHA3, "SHA3_256", test_data, - digest_size=SHA3.digest_size, - oid="2.16.840.1.101.3.4.2.8") - tests += list_test_cases(APITest) - return tests - -if __name__ == '__main__': - import unittest - suite = lambda: unittest.TestSuite(get_tests()) - unittest.main(defaultTest='suite') diff --git a/Crypto/SelfTest/Hash/test_SHA3_384.py b/Crypto/SelfTest/Hash/test_SHA3_384.py deleted file mode 100644 index 88d8c50..0000000 --- a/Crypto/SelfTest/Hash/test_SHA3_384.py +++ /dev/null @@ -1,79 +0,0 @@ -# -*- coding: utf-8 -*- -# -# SelfTest/Hash/test_SHA3_384.py: Self-test for the SHA-3/384 hash function -# -# =================================================================== -# The contents of this file are dedicated to the public domain. To -# the extent that dedication to the public domain is not available, -# everyone is granted a worldwide, perpetual, royalty-free, -# non-exclusive license to exercise all rights associated with the -# contents of this file for any purpose whatsoever. -# No rights are reserved. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS -# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN -# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# =================================================================== - -"""Self-test suite for Crypto.Hash.SHA3_384""" - -import unittest -from binascii import hexlify - -from Crypto.SelfTest.loader import load_test_vectors -from Crypto.SelfTest.st_common import list_test_cases -from Crypto.Hash import SHA3_384 as SHA3 -from Crypto.Util.py3compat import b - - -class APITest(unittest.TestCase): - - def test_update_after_digest(self): - msg=b("rrrrttt") - - # Normally, update() cannot be done after digest() - h = SHA3.new(data=msg[:4]) - dig1 = h.digest() - self.assertRaises(TypeError, h.update, msg[4:]) - dig2 = SHA3.new(data=msg).digest() - - # With the proper flag, it is allowed - h = SHA3.new(data=msg[:4], update_after_digest=True) - self.assertEquals(h.digest(), dig1) - # ... and the subsequent digest applies to the entire message - # up to that point - h.update(msg[4:]) - self.assertEquals(h.digest(), dig2) - - -def get_tests(config={}): - from .common import make_hash_tests - - tests = [] - - test_vectors = load_test_vectors(("Hash", "SHA3"), - "ShortMsgKAT_SHA3-384.txt", - "KAT SHA-3 384", - { "len" : lambda x: int(x) } ) or [] - - test_data = [] - for tv in test_vectors: - if tv.len == 0: - tv.msg = b("") - test_data.append((hexlify(tv.md), tv.msg, tv.desc)) - - tests += make_hash_tests(SHA3, "SHA3_384", test_data, - digest_size=SHA3.digest_size, - oid="2.16.840.1.101.3.4.2.9") - tests += list_test_cases(APITest) - return tests - -if __name__ == '__main__': - import unittest - suite = lambda: unittest.TestSuite(get_tests()) - unittest.main(defaultTest='suite') diff --git a/Crypto/SelfTest/Hash/test_SHA3_512.py b/Crypto/SelfTest/Hash/test_SHA3_512.py deleted file mode 100644 index d012003..0000000 --- a/Crypto/SelfTest/Hash/test_SHA3_512.py +++ /dev/null @@ -1,79 +0,0 @@ -# -*- coding: utf-8 -*- -# -# SelfTest/Hash/test_SHA3_512.py: Self-test for the SHA-3/512 hash function -# -# =================================================================== -# The contents of this file are dedicated to the public domain. To -# the extent that dedication to the public domain is not available, -# everyone is granted a worldwide, perpetual, royalty-free, -# non-exclusive license to exercise all rights associated with the -# contents of this file for any purpose whatsoever. -# No rights are reserved. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS -# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN -# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# =================================================================== - -"""Self-test suite for Crypto.Hash.SHA3_512""" - -import unittest -from binascii import hexlify - -from Crypto.SelfTest.loader import load_test_vectors -from Crypto.SelfTest.st_common import list_test_cases -from Crypto.Hash import SHA3_512 as SHA3 -from Crypto.Util.py3compat import b - - -class APITest(unittest.TestCase): - - def test_update_after_digest(self): - msg=b("rrrrttt") - - # Normally, update() cannot be done after digest() - h = SHA3.new(data=msg[:4]) - dig1 = h.digest() - self.assertRaises(TypeError, h.update, msg[4:]) - dig2 = SHA3.new(data=msg).digest() - - # With the proper flag, it is allowed - h = SHA3.new(data=msg[:4], update_after_digest=True) - self.assertEquals(h.digest(), dig1) - # ... and the subsequent digest applies to the entire message - # up to that point - h.update(msg[4:]) - self.assertEquals(h.digest(), dig2) - - -def get_tests(config={}): - from .common import make_hash_tests - - tests = [] - - test_vectors = load_test_vectors(("Hash", "SHA3"), - "ShortMsgKAT_SHA3-512.txt", - "KAT SHA-3 512", - { "len" : lambda x: int(x) } ) or [] - - test_data = [] - for tv in test_vectors: - if tv.len == 0: - tv.msg = b("") - test_data.append((hexlify(tv.md), tv.msg, tv.desc)) - - tests += make_hash_tests(SHA3, "SHA3_512", test_data, - digest_size=SHA3.digest_size, - oid="2.16.840.1.101.3.4.2.10") - tests += list_test_cases(APITest) - return tests - -if __name__ == '__main__': - import unittest - suite = lambda: unittest.TestSuite(get_tests()) - unittest.main(defaultTest='suite') diff --git a/Crypto/SelfTest/Hash/test_SHA512.py b/Crypto/SelfTest/Hash/test_SHA512.py deleted file mode 100644 index 20961ac..0000000 --- a/Crypto/SelfTest/Hash/test_SHA512.py +++ /dev/null @@ -1,140 +0,0 @@ -# -*- coding: utf-8 -*- -# -# SelfTest/Hash/test_SHA512.py: Self-test for the SHA-512 hash function -# -# Written in 2008 by Dwayne C. Litzenberger -# -# =================================================================== -# The contents of this file are dedicated to the public domain. To -# the extent that dedication to the public domain is not available, -# everyone is granted a worldwide, perpetual, royalty-free, -# non-exclusive license to exercise all rights associated with the -# contents of this file for any purpose whatsoever. -# No rights are reserved. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS -# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN -# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# =================================================================== - -"""Self-test suite for Crypto.Hash.SHA512""" - -from binascii import hexlify - -from Crypto.Hash import SHA512 -from .common import make_hash_tests -from Crypto.SelfTest.loader import load_test_vectors - -# Test vectors from various sources -# This is a list of (expected_result, input[, description]) tuples. -test_data_512_other = [ - - # RFC 4634: Section Page 8.4, "Test 1" - ('ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f', 'abc'), - - # RFC 4634: Section Page 8.4, "Test 2.1" - ('8e959b75dae313da8cf4f72814fc143f8f7779c6eb9f7fa17299aeadb6889018501d289e4900f7e4331b99dec4b5433ac7d329eeb6dd26545e96e55b874be909', 'abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu'), - - # RFC 4634: Section Page 8.4, "Test 3" - ('e718483d0ce769644e2e42c7bc15b4638e1f98b13b2044285632a803afa973ebde0ff244877ea60a4cb0432ce577c31beb009c5c2c49aa2e4eadb217ad8cc09b', 'a' * 10**6, "'a' * 10**6"), - - # Taken from http://de.wikipedia.org/wiki/Secure_Hash_Algorithm - ('cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e', ''), - - ('af9ed2de700433b803240a552b41b5a472a6ef3fe1431a722b2063c75e9f07451f67a28e37d09cde769424c96aea6f8971389db9e1993d6c565c3c71b855723c', 'Franz jagt im komplett verwahrlosten Taxi quer durch Bayern'), -] - - -def get_tests_SHA512(): - - test_vectors = load_test_vectors(("Hash", "SHA2"), - "SHA512ShortMsg.rsp", - "KAT SHA-512", - {"len": lambda x: int(x)}) or [] - - test_data = test_data_512_other[:] - for tv in test_vectors: - try: - if tv.startswith('['): - continue - except AttributeError: - pass - if tv.len == 0: - tv.msg = b"" - test_data.append((hexlify(tv.md), tv.msg, tv.desc)) - - tests = make_hash_tests(SHA512, "SHA512", test_data, - digest_size=64, - oid="2.16.840.1.101.3.4.2.3") - return tests - - -def get_tests_SHA512_224(): - - test_vectors = load_test_vectors(("Hash", "SHA2"), - "SHA512_224ShortMsg.rsp", - "KAT SHA-512/224", - {"len": lambda x: int(x)}) or [] - - test_data = [] - for tv in test_vectors: - try: - if tv.startswith('['): - continue - except AttributeError: - pass - if tv.len == 0: - tv.msg = b"" - test_data.append((hexlify(tv.md), tv.msg, tv.desc)) - - tests = make_hash_tests(SHA512, "SHA512/224", test_data, - digest_size=28, - oid="2.16.840.1.101.3.4.2.5", - extra_params={ "truncate" : "224" }) - return tests - - -def get_tests_SHA512_256(): - - test_vectors = load_test_vectors(("Hash", "SHA2"), - "SHA512_256ShortMsg.rsp", - "KAT SHA-512/256", - {"len": lambda x: int(x)}) or [] - - test_data = [] - for tv in test_vectors: - try: - if tv.startswith('['): - continue - except AttributeError: - pass - if tv.len == 0: - tv.msg = b"" - test_data.append((hexlify(tv.md), tv.msg, tv.desc)) - - tests = make_hash_tests(SHA512, "SHA512/256", test_data, - digest_size=32, - oid="2.16.840.1.101.3.4.2.6", - extra_params={ "truncate" : "256" }) - return tests - - -def get_tests(config={}): - - tests = [] - tests += get_tests_SHA512() - tests += get_tests_SHA512_224() - tests += get_tests_SHA512_256() - return tests - -if __name__ == '__main__': - import unittest - suite = lambda: unittest.TestSuite(get_tests()) - unittest.main(defaultTest='suite') - -# vim:set ts=4 sw=4 sts=4 expandtab: diff --git a/Crypto/SelfTest/Hash/test_SHAKE.py b/Crypto/SelfTest/Hash/test_SHAKE.py deleted file mode 100644 index 77a07e8..0000000 --- a/Crypto/SelfTest/Hash/test_SHAKE.py +++ /dev/null @@ -1,143 +0,0 @@ -# =================================================================== -# -# Copyright (c) 2015, Legrandin -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# =================================================================== - -"""Self-test suite for Crypto.Hash.SHAKE128 and SHAKE256""" - -import unittest -from binascii import hexlify, unhexlify - -from Crypto.SelfTest.loader import load_test_vectors -from Crypto.SelfTest.st_common import list_test_cases - -from Crypto.Hash import SHAKE128, SHAKE256 -from Crypto.Util.py3compat import b, bchr, bord, tobytes - -class SHAKETest(unittest.TestCase): - - def test_new_positive(self): - - xof1 = self.shake.new() - xof2 = self.shake.new(data=b("90")) - xof3 = self.shake.new().update(b("90")) - - self.assertNotEqual(xof1.read(10), xof2.read(10)) - xof3.read(10) - self.assertEqual(xof2.read(10), xof3.read(10)) - - def test_update(self): - pieces = [bchr(10) * 200, bchr(20) * 300] - h = self.shake.new() - h.update(pieces[0]).update(pieces[1]) - digest = h.read(10) - h = self.shake.new() - h.update(pieces[0] + pieces[1]) - self.assertEqual(h.read(10), digest) - - def test_update_negative(self): - h = self.shake.new() - self.assertRaises(TypeError, h.update, u"string") - - def test_digest(self): - h = self.shake.new() - digest = h.read(90) - - # read returns a byte string of the right length - self.failUnless(isinstance(digest, type(b("digest")))) - self.assertEqual(len(digest), 90) - - def test_update_after_read(self): - mac = self.shake.new() - mac.update(b("rrrr")) - mac.read(90) - self.assertRaises(TypeError, mac.update, b("ttt")) - - -class SHAKE128Test(SHAKETest): - shake = SHAKE128 - - -class SHAKE256Test(SHAKETest): - shake = SHAKE256 - - -class SHAKEVectors(unittest.TestCase): - pass - - -test_vectors_128 = load_test_vectors(("Hash", "SHA3"), - "ShortMsgKAT_SHAKE128.txt", - "Short Messages KAT SHAKE128", - { "len" : lambda x: int(x) } ) or [] - -for idx, tv in enumerate(test_vectors_128): - if tv.len == 0: - data = b("") - else: - data = tobytes(tv.msg) - - def new_test(self, data=data, result=tv.md): - hobj = SHAKE128.new(data=data) - digest = hobj.read(len(result)) - self.assertEqual(digest, result) - - setattr(SHAKEVectors, "test_128_%d" % idx, new_test) - - -test_vectors_256 = load_test_vectors(("Hash", "SHA3"), - "ShortMsgKAT_SHAKE256.txt", - "Short Messages KAT SHAKE256", - { "len" : lambda x: int(x) } ) or [] - -for idx, tv in enumerate(test_vectors_256): - if tv.len == 0: - data = b("") - else: - data = tobytes(tv.msg) - - def new_test(self, data=data, result=tv.md): - hobj = SHAKE256.new(data=data) - digest = hobj.read(len(result)) - self.assertEqual(digest, result) - - setattr(SHAKEVectors, "test_256_%d" % idx, new_test) - - -def get_tests(config={}): - tests = [] - tests += list_test_cases(SHAKE128Test) - tests += list_test_cases(SHAKE256Test) - tests += list_test_cases(SHAKEVectors) - return tests - - -if __name__ == '__main__': - import unittest - suite = lambda: unittest.TestSuite(get_tests()) - unittest.main(defaultTest='suite') diff --git a/Crypto/SelfTest/Hash/test_keccak.py b/Crypto/SelfTest/Hash/test_keccak.py deleted file mode 100644 index 92e2453..0000000 --- a/Crypto/SelfTest/Hash/test_keccak.py +++ /dev/null @@ -1,250 +0,0 @@ -# =================================================================== -# -# Copyright (c) 2015, Legrandin -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# =================================================================== - -"""Self-test suite for Crypto.Hash.keccak""" - -import unittest -from binascii import hexlify, unhexlify - -from Crypto.SelfTest.loader import load_test_vectors -from Crypto.SelfTest.st_common import list_test_cases - -from Crypto.Hash import keccak -from Crypto.Util.py3compat import b, tobytes, bchr - -class KeccakTest(unittest.TestCase): - - def test_new_positive(self): - - for digest_bits in (224, 256, 384, 512): - hobj = keccak.new(digest_bits=digest_bits) - self.assertEqual(hobj.digest_size, digest_bits // 8) - - hobj2 = hobj.new() - self.assertEqual(hobj2.digest_size, digest_bits // 8) - - for digest_bytes in (28, 32, 48, 64): - hobj = keccak.new(digest_bytes=digest_bytes) - self.assertEqual(hobj.digest_size, digest_bytes) - - hobj2 = hobj.new() - self.assertEqual(hobj2.digest_size, digest_bytes) - - def test_new_positive2(self): - - digest1 = keccak.new(data=b("\x90"), digest_bytes=64).digest() - digest2 = keccak.new(digest_bytes=64).update(b("\x90")).digest() - self.assertEqual(digest1, digest2) - - def test_new_negative(self): - - # keccak.new needs digest size - self.assertRaises(TypeError, keccak.new) - - h = keccak.new(digest_bits=512) - - # Either bits or bytes can be specified - self.assertRaises(TypeError, keccak.new, - digest_bytes=64, - digest_bits=512) - - # Range - self.assertRaises(ValueError, keccak.new, digest_bytes=0) - self.assertRaises(ValueError, keccak.new, digest_bytes=1) - self.assertRaises(ValueError, keccak.new, digest_bytes=65) - self.assertRaises(ValueError, keccak.new, digest_bits=0) - self.assertRaises(ValueError, keccak.new, digest_bits=1) - self.assertRaises(ValueError, keccak.new, digest_bits=513) - - def test_update(self): - pieces = [bchr(10) * 200, bchr(20) * 300] - h = keccak.new(digest_bytes=64) - h.update(pieces[0]).update(pieces[1]) - digest = h.digest() - h = keccak.new(digest_bytes=64) - h.update(pieces[0] + pieces[1]) - self.assertEqual(h.digest(), digest) - - def test_update_negative(self): - h = keccak.new(digest_bytes=64) - self.assertRaises(TypeError, h.update, u"string") - - def test_digest(self): - h = keccak.new(digest_bytes=64) - digest = h.digest() - - # hexdigest does not change the state - self.assertEqual(h.digest(), digest) - # digest returns a byte string - self.failUnless(isinstance(digest, type(b("digest")))) - - def test_hex_digest(self): - mac = keccak.new(digest_bits=512) - digest = mac.digest() - hexdigest = mac.hexdigest() - - # hexdigest is equivalent to digest - self.assertEqual(hexlify(digest), tobytes(hexdigest)) - # hexdigest does not change the state - self.assertEqual(mac.hexdigest(), hexdigest) - # hexdigest returns a string - self.failUnless(isinstance(hexdigest, type("digest"))) - - def test_update_after_digest(self): - msg=b("rrrrttt") - - # Normally, update() cannot be done after digest() - h = keccak.new(digest_bits=512, data=msg[:4]) - dig1 = h.digest() - self.assertRaises(TypeError, h.update, msg[4:]) - dig2 = keccak.new(digest_bits=512, data=msg).digest() - - # With the proper flag, it is allowed - h = keccak.new(digest_bits=512, data=msg[:4], update_after_digest=True) - self.assertEquals(h.digest(), dig1) - # ... and the subsequent digest applies to the entire message - # up to that point - h.update(msg[4:]) - self.assertEquals(h.digest(), dig2) - - -class KeccakVectors(unittest.TestCase): - pass - - # TODO: add ExtremelyLong tests - - -test_vectors_224 = load_test_vectors(("Hash", "keccak"), - "ShortMsgKAT_224.txt", - "Short Messages KAT 224", - {"len": lambda x: int(x)}) or [] - -test_vectors_224 += load_test_vectors(("Hash", "keccak"), - "LongMsgKAT_224.txt", - "Long Messages KAT 224", - {"len": lambda x: int(x)}) or [] - -for idx, tv in enumerate(test_vectors_224): - if tv.len == 0: - data = b("") - else: - data = tobytes(tv.msg) - - def new_test(self, data=data, result=tv.md): - hobj = keccak.new(digest_bits=224, data=data) - self.assertEqual(hobj.digest(), result) - - setattr(KeccakVectors, "test_224_%d" % idx, new_test) - -# --- - -test_vectors_256 = load_test_vectors(("Hash", "keccak"), - "ShortMsgKAT_256.txt", - "Short Messages KAT 256", - { "len" : lambda x: int(x) } ) or [] - -test_vectors_256 += load_test_vectors(("Hash", "keccak"), - "LongMsgKAT_256.txt", - "Long Messages KAT 256", - { "len" : lambda x: int(x) } ) or [] - -for idx, tv in enumerate(test_vectors_256): - if tv.len == 0: - data = b("") - else: - data = tobytes(tv.msg) - - def new_test(self, data=data, result=tv.md): - hobj = keccak.new(digest_bits=256, data=data) - self.assertEqual(hobj.digest(), result) - - setattr(KeccakVectors, "test_256_%d" % idx, new_test) - - -# --- - -test_vectors_384 = load_test_vectors(("Hash", "keccak"), - "ShortMsgKAT_384.txt", - "Short Messages KAT 384", - {"len": lambda x: int(x)}) or [] - -test_vectors_384 += load_test_vectors(("Hash", "keccak"), - "LongMsgKAT_384.txt", - "Long Messages KAT 384", - {"len": lambda x: int(x)}) or [] - -for idx, tv in enumerate(test_vectors_384): - if tv.len == 0: - data = b("") - else: - data = tobytes(tv.msg) - - def new_test(self, data=data, result=tv.md): - hobj = keccak.new(digest_bits=384, data=data) - self.assertEqual(hobj.digest(), result) - - setattr(KeccakVectors, "test_384_%d" % idx, new_test) - -# --- - -test_vectors_512 = load_test_vectors(("Hash", "keccak"), - "ShortMsgKAT_512.txt", - "Short Messages KAT 512", - {"len": lambda x: int(x)}) or [] - -test_vectors_512 += load_test_vectors(("Hash", "keccak"), - "LongMsgKAT_512.txt", - "Long Messages KAT 512", - {"len": lambda x: int(x)}) or [] - -for idx, tv in enumerate(test_vectors_512): - if tv.len == 0: - data = b("") - else: - data = tobytes(tv.msg) - - def new_test(self, data=data, result=tv.md): - hobj = keccak.new(digest_bits=512, data=data) - self.assertEqual(hobj.digest(), result) - - setattr(KeccakVectors, "test_512_%d" % idx, new_test) - - -def get_tests(config={}): - tests = [] - tests += list_test_cases(KeccakTest) - tests += list_test_cases(KeccakVectors) - return tests - - -if __name__ == '__main__': - import unittest - suite = lambda: unittest.TestSuite(get_tests()) - unittest.main(defaultTest='suite') diff --git a/Crypto/SelfTest/IO/__init__.py b/Crypto/SelfTest/IO/__init__.py deleted file mode 100644 index c04a2a7..0000000 --- a/Crypto/SelfTest/IO/__init__.py +++ /dev/null @@ -1,47 +0,0 @@ -# -# SelfTest/IO/__init__.py: Self-test for input/output module -# -# =================================================================== -# -# Copyright (c) 2014, Legrandin -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# =================================================================== - -"""Self-test for I/O""" - -def get_tests(config={}): - tests = [] - from Crypto.SelfTest.IO import test_PKCS8; tests += test_PKCS8.get_tests(config=config) - from Crypto.SelfTest.IO import test_PBES; tests += test_PBES.get_tests(config=config) - return tests - -if __name__ == '__main__': - import unittest - suite = lambda: unittest.TestSuite(get_tests()) - unittest.main(defaultTest='suite') - - diff --git a/Crypto/SelfTest/IO/__pycache__/__init__.cpython-36.pyc b/Crypto/SelfTest/IO/__pycache__/__init__.cpython-36.pyc deleted file mode 100644 index af2a366bc795f230aa4fb059a2264fd5642fd896..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 675 zcmYjN&2G~`5T5ngiIb)h@B|g=#S)DVMYIQ0RYV*jP=aJG__Er1*T$)1N4p!OpybqE z`yjjukKijOUV#%cP9tTk8PCq&_sv|Mo(`|Roy*^SfIn~~9Q|8VdyPgx3MJ%BG37n7 zlxa`#d(XU8z6vUya@AA)M@W6m7l8`Z;E6F%K?2e6=gUM_`GwQgo#l-=o5u5u;Y1Su zStt0nw`dC3br2OS+0J9IWm|9IZ9(xTcD2v>nBzO%<@j-K%MdP@{lzg5v35v^;>)K= za*eNE*3@}fpf}jZKYUCgKYcYZo0V(EMDZ)ukEe6vVShU)v=dZm4Uvp|L+5CNeTYiB z_%AScHu(2B{vl0V$-0PF8~44bFXO7bJNV;wu`QjxSjp^O7TU&p)cAlJPv@}^WnDTU z#;c79aO63v9iai{vk|=Lw9B-i5KCFsLKwQ^ETf`>5VP)@)aqctoc90^bQv~_cpI(} zgmy>=v~IFSTHVlYjUy9cdmFy5YBfs9;Vg9$4y&SbCy#F4vW#Sy8X;3!$0} rdC>wyvzAMZ&mnaZq1GqjM=*3e^Nh7@)Vk6)uQ6n)!}mtLkkR)ao8^}I diff --git a/Crypto/SelfTest/IO/__pycache__/test_PBES.cpython-36.pyc b/Crypto/SelfTest/IO/__pycache__/test_PBES.cpython-36.pyc deleted file mode 100644 index 0db76c7f8d1d1581a458c5f2a89971967c929e89..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2436 zcmcgu&2HO95Z+x<6h%o^nl$}G(F#F(U|LDF6e}$d1hHkc4vHuS6r;!@C_!^6nGQv% zyHo)i_DR0>LHbI(_S9GCsWVGUc7U|LD50>k!`YviZ+1DKI@PN4@a0$jd6kgA$hF4= z{RuSnD+ob25md04atgf>vlsYo#>T|tCM7=+Q4rPz5mrc#3k!o=5gAcY6!rz>#n2X| z*GzKZi1G#DC79!gim3iUDG_W)+>O((hhaQwq@hYxeKeKzo;;bQ)8^CXO>cjvKdeut zVjhQoLnvh6(v02*QNWRQfVSnsKzRa9?Scpi1WP!>z`?B{3}HfV=ArU}4v%n4l!OEJ zq9}_B^tPyq4d_dv2BF=`N-rR)+!cjg@xdNl^`NOwK%|h31wA7k1&wKq2?EQF!Kq$f z7k=t%$Z$TX=W%qI9o6{ScK08r}y@Ee%}4D z{Y#V{?LFJ>HHLfJo7;)l?GGFM-F~Oh+v&NML}ytsOaeT2X~CN;YLf`HDJw&cLYek| zoBOeANE-)PkY)^~W2$oDpt*pUH@^c_;WR=k)S?@2Ak{P0jkNxDq}%=BX8ZeVIAsNb zy22>o%Oi3F#3e3SL&Gf;Z$sAZ!pQ$3YrjWiKeX3}tn=t5WSw;*yQB2=f(yCsV|uW2 z6PO3@7R)+NW^3;zFk9~wOna-lzH8PU+ytgOaGlKdyu_b`o|ieEm-7$k70<&Gl#j?V z>?A)xaT~=Q6d$6vi{c{`SD&!futG^JtM{QP{OWCHo3^$5>9IF*iKS83;5sPCWigr1 zbD+*Kftt(CXbOb$Q0tm-Bo=U>$66dg>DTo?0K!qO!9UFjqPZl9CQJyXlgTuZpTQ#S z8;HpYrpYK8Ya1`&Hpmg`8Wde;OXD!#Umd{WRYfwP-pbFxf*G9nQQ~<4yse%Uabg)n zPJ#Hzf*X?I+yaY z2uJ=r)(G5kR`fhE4LnbN0kins%X}Q9Q4IXpfn3b|l-DlJ%YPr5ow$uj=s_lRn(~l7 jMu&BDXd=@82r<7rkMF@eg=O7jHnmyBxcyDV0*(F)1kmkv diff --git a/Crypto/SelfTest/IO/__pycache__/test_PKCS8.cpython-36.pyc b/Crypto/SelfTest/IO/__pycache__/test_PKCS8.cpython-36.pyc deleted file mode 100644 index 9f594fb10d443e209ba80ea31e0224fd82dea94b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 14466 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 E0~!o7@c;k- diff --git a/Crypto/SelfTest/IO/test_PBES.py b/Crypto/SelfTest/IO/test_PBES.py deleted file mode 100644 index b2a4f94..0000000 --- a/Crypto/SelfTest/IO/test_PBES.py +++ /dev/null @@ -1,93 +0,0 @@ -# -# SelfTest/IO/test_PBES.py: Self-test for the _PBES module -# -# =================================================================== -# -# Copyright (c) 2014, Legrandin -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# =================================================================== - -"""Self-tests for Crypto.IO._PBES module""" - -import unittest -from Crypto.Util.py3compat import * - -from Crypto.IO._PBES import PBES2 - - -class TestPBES2(unittest.TestCase): - - def setUp(self): - self.ref = b("Test data") - self.passphrase = b("Passphrase") - - def test1(self): - ct = PBES2.encrypt(self.ref, self.passphrase, - 'PBKDF2WithHMAC-SHA1AndDES-EDE3-CBC') - pt = PBES2.decrypt(ct, self.passphrase) - self.assertEqual(self.ref, pt) - - def test2(self): - ct = PBES2.encrypt(self.ref, self.passphrase, - 'PBKDF2WithHMAC-SHA1AndAES128-CBC') - pt = PBES2.decrypt(ct, self.passphrase) - self.assertEqual(self.ref, pt) - - def test3(self): - ct = PBES2.encrypt(self.ref, self.passphrase, - 'PBKDF2WithHMAC-SHA1AndAES192-CBC') - pt = PBES2.decrypt(ct, self.passphrase) - self.assertEqual(self.ref, pt) - - def test4(self): - ct = PBES2.encrypt(self.ref, self.passphrase, - 'scryptAndAES128-CBC') - pt = PBES2.decrypt(ct, self.passphrase) - self.assertEqual(self.ref, pt) - - def test5(self): - ct = PBES2.encrypt(self.ref, self.passphrase, - 'scryptAndAES192-CBC') - pt = PBES2.decrypt(ct, self.passphrase) - self.assertEqual(self.ref, pt) - - def test6(self): - ct = PBES2.encrypt(self.ref, self.passphrase, - 'scryptAndAES256-CBC') - pt = PBES2.decrypt(ct, self.passphrase) - self.assertEqual(self.ref, pt) - - -def get_tests(config={}): - from Crypto.SelfTest.st_common import list_test_cases - listTests = [] - listTests += list_test_cases(TestPBES2) - return listTests - -if __name__ == '__main__': - suite = lambda: unittest.TestSuite(get_tests()) - unittest.main(defaultTest='suite') diff --git a/Crypto/SelfTest/IO/test_PKCS8.py b/Crypto/SelfTest/IO/test_PKCS8.py deleted file mode 100644 index 49f4b8a..0000000 --- a/Crypto/SelfTest/IO/test_PKCS8.py +++ /dev/null @@ -1,423 +0,0 @@ -# -# SelfTest/IO/test_PKCS8.py: Self-test for the PKCS8 module -# -# =================================================================== -# -# Copyright (c) 2014, Legrandin -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# =================================================================== - -"""Self-tests for Crypto.IO.PKCS8 module""" - -import unittest -from binascii import unhexlify - -from Crypto.Util.py3compat import * -from Crypto.IO import PKCS8 - -oid_key = '1.2.840.113549.1.1.1' - -# Original RSA key (in DER format) -# hexdump -v -e '32/1 "%02x" "\n"' key.der -clear_key=""" -308201ab020100025a00b94a7f7075ab9e79e8196f47be707781e80dd965cf16 -0c951a870b71783b6aaabbd550c0e65e5a3dfe15b8620009f6d7e5efec42a3f0 -6fe20faeebb0c356e79cdec6db4dd427e82d8ae4a5b90996227b8ba54ccfc4d2 -5c08050203010001025a00afa09c70d528299b7552fe766b5d20f9a221d66938 -c3b68371d48515359863ff96f0978d700e08cd6fd3d8a3f97066fc2e0d5f78eb -3a50b8e17ba297b24d1b8e9cdfd18d608668198d724ad15863ef0329195dee89 -3f039395022d0ebe0518df702a8b25954301ec60a97efdcec8eaa4f2e76ca7e8 -8dfbc3f7e0bb83f9a0e8dc47c0f8c746e9df6b022d0c9195de13f09b7be1fdd7 -1f56ae7d973e08bd9fd2c3dfd8936bb05be9cc67bd32d663c7f00d70932a0be3 -c24f022d0ac334eb6cabf1933633db007b763227b0d9971a9ea36aca8b669ec9 -4fcf16352f6b3dcae28e4bd6137db4ddd3022d0400a09f15ee7b351a2481cb03 -09920905c236d09c87afd3022f3afc2a19e3b746672b635238956ee7e6dd62d5 -022d0cd88ed14fcfbda5bbf0257f700147137bbab9c797af7df866704b889aa3 -7e2e93df3ff1a0fd3490111dcdbc4c -""" - -# Same key as above, wrapped in PKCS#8 but w/o password -# -# openssl pkcs8 -topk8 -inform DER -nocrypt -in key.der -outform DER -out keyp8.der -# hexdump -v -e '32/1 "%02x" "\n"' keyp8.der -wrapped_clear_key=""" -308201c5020100300d06092a864886f70d0101010500048201af308201ab0201 -00025a00b94a7f7075ab9e79e8196f47be707781e80dd965cf160c951a870b71 -783b6aaabbd550c0e65e5a3dfe15b8620009f6d7e5efec42a3f06fe20faeebb0 -c356e79cdec6db4dd427e82d8ae4a5b90996227b8ba54ccfc4d25c0805020301 -0001025a00afa09c70d528299b7552fe766b5d20f9a221d66938c3b68371d485 -15359863ff96f0978d700e08cd6fd3d8a3f97066fc2e0d5f78eb3a50b8e17ba2 -97b24d1b8e9cdfd18d608668198d724ad15863ef0329195dee893f039395022d -0ebe0518df702a8b25954301ec60a97efdcec8eaa4f2e76ca7e88dfbc3f7e0bb -83f9a0e8dc47c0f8c746e9df6b022d0c9195de13f09b7be1fdd71f56ae7d973e -08bd9fd2c3dfd8936bb05be9cc67bd32d663c7f00d70932a0be3c24f022d0ac3 -34eb6cabf1933633db007b763227b0d9971a9ea36aca8b669ec94fcf16352f6b -3dcae28e4bd6137db4ddd3022d0400a09f15ee7b351a2481cb0309920905c236 -d09c87afd3022f3afc2a19e3b746672b635238956ee7e6dd62d5022d0cd88ed1 -4fcfbda5bbf0257f700147137bbab9c797af7df866704b889aa37e2e93df3ff1 -a0fd3490111dcdbc4c -""" - -### -# -# The key above will now be encrypted with different algorithms. -# The password is always 'TestTest'. -# -# Each item in the wrapped_enc_keys list contains: -# * wrap algorithm -# * iteration count -# * Salt -# * IV -# * Expected result -### -wrapped_enc_keys = [] - -# -# openssl pkcs8 -topk8 -passin pass:TestTest -inform DER -in key.der -outform DER -out keyenc.der -v2 des3 -# hexdump -v -e '32/1 "%02x" "\n"' keyenc.der -# -wrapped_enc_keys.append(( -'PBKDF2WithHMAC-SHA1AndDES-EDE3-CBC', -2048, -"47EA7227D8B22E2F", # IV -"E3F7A838AB911A4D", # Salt -""" -30820216304006092a864886f70d01050d3033301b06092a864886f70d01050c -300e0408e3f7a838ab911a4d02020800301406082a864886f70d0307040847ea -7227d8b22e2f048201d0ea388b374d2d0e4ceb7a5139f850fdff274884a6e6c0 -64326e09d00dbba9018834edb5a51a6ae3d1806e6e91eebf33788ce71fee0637 -a2ebf58859dd32afc644110c390274a6128b50c39b8d907823810ec471bada86 -6f5b75d8ea04ad310fad2e73621696db8e426cd511ee93ec1714a1a7db45e036 -4bf20d178d1f16bbb250b32c2d200093169d588de65f7d99aad9ddd0104b44f1 -326962e1520dfac3c2a800e8a14f678dff2b3d0bb23f69da635bf2a643ac934e -219a447d2f4460b67149e860e54f365da130763deefa649c72b0dcd48966a2d3 -4a477444782e3e66df5a582b07bbb19778a79bd355074ce331f4a82eb966b0c4 -52a09eab6116f2722064d314ae433b3d6e81d2436e93fdf446112663cde93b87 -9c8be44beb45f18e2c78fee9b016033f01ecda51b9b142091fa69f65ab784d2c -5ad8d34be6f7f1464adfc1e0ef3f7848f40d3bdea4412758f2fcb655c93d8f4d -f6fa48fc5aa4b75dd1c017ab79ac9d737233a6d668f5364ccf47786debd37334 -9c10c9e6efbe78430a61f71c89948aa32cdc3cc7338cf994147819ce7ab23450 -c8f7d9b94c3bb377d17a3fa204b601526317824b142ff6bc843fa7815ece89c0 -839573f234dac8d80cc571a045353d61db904a4398d8ef3df5ac -""" -)) - -# -# openssl pkcs8 -topk8 -passin pass:TestTest -inform DER -in key.der -outform DER -out keyenc.der -# hexdump -v -e '32/1 "%02x" "\n"' keyenc.der -# -wrapped_enc_keys.append(( -'skip encryption', # pbeWithMD5AndDES-CBC, only decoding is supported --1, -"", -"", -""" -308201f1301b06092a864886f70d010503300e0408f9b990c89af1d41b020208 -00048201d0c6267fe8592903891933d559e71a7ca68b2e39150f19daca0f7921 -52f97e249d72f670d5140e9150433310ed7c7ee51927693fd39884cb9551cea5 -a7b746f7edf199f8787d4787a35dad930d7db057b2118851211b645ac8b90fa6 -b0e7d49ac8567cbd5fff226e87aa9129a0f52c45e9307752e8575c3b0ff756b7 -31fda6942d15ecb6b27ea19370ccc79773f47891e80d22b440d81259c4c28eac -e0ca839524116bcf52d8c566e49a95ddb0e5493437279a770a39fd333f3fca91 -55884fad0ba5aaf273121f893059d37dd417da7dcfd0d6fa7494968f13b2cc95 -65633f2c891340193e5ec00e4ee0b0e90b3b93da362a4906360845771ade1754 -9df79140be5993f3424c012598eadd3e7c7c0b4db2c72cf103d7943a5cf61420 -93370b9702386c3dd4eb0a47f34b579624a46a108b2d13921fa1b367495fe345 -6aa128aa70f8ca80ae13eb301e96c380724ce67c54380bbea2316c1faf4d058e -b4ca2e23442047606b9bc4b3bf65b432cb271bea4eb35dd3eb360d3be8612a87 -a50e96a2264490aeabdc07c6e78e5dbf4fe3388726d0e2a228346bf3c2907d68 -2a6276b22ae883fb30fa611f4e4193e7a08480fcd7db48308bacbd72bf4807aa -11fd394859f97d22982f7fe890b2e2a0f7e7ffb693 -""" -)) - -# -# openssl pkcs8 -topk8 -passin pass:TestTest -inform DER -in key.der -# -outform DER -out keyenc.der -v1 PBE-SHA1-RC2-64 -# hexdump -v -e '32/1 "%02x" "\n"' keyenc.der -# -wrapped_enc_keys.append(( -'skip encryption', # pbeWithSHA1AndRC2-CBC, only decoding is supported --1, -"", -"", -""" -308201f1301b06092a864886f70d01050b300e04083ee943bdae185008020208 -00048201d0e4614d9371d3ff10ceabc2f6a7a13a0f449f9a714144e46518ea55 -e3e6f0cde24031d01ef1f37ec40081449ef01914faf45983dde0d2bc496712de -8dd15a5527dff4721d9016c13f34fb93e3ce68577e30146266d71b539f854e56 -753a192cf126ed4812734d86f81884374f1100772f78d0646e9946407637c565 -d070acab413c55952f7237437f2e48cae7fa0ff8d370de2bf446dd08049a3663 -d9c813ac197468c02e2b687e7ca994cf7f03f01b6eca87dbfed94502c2094157 -ea39f73fe4e591df1a68b04d19d9adab90bb9898467c1464ad20bf2b8fb9a5ff -d3ec91847d1c67fd768a4b9cfb46572eccc83806601372b6fad0243f58f623b7 -1c5809dea0feb8278fe27e5560eed8448dc93f5612f546e5dd7c5f6404365eb2 -5bf3396814367ae8b15c5c432b57eaed1f882c05c7f6517ee9e42b87b7b8d071 -9d6125d1b52f7b2cca1f6bd5f584334bf90bce1a7d938274cafe27b68e629698 -b16e27ae528db28593af9adcfccbebb3b9e1f2af5cd5531b51968389caa6c091 -e7de1f1b96f0d258e54e540d961a7c0ef51fda45d6da5fddd33e9bbfd3a5f8d7 -d7ab2e971de495cddbc86d38444fee9f0ac097b00adaf7802dabe0cff5b43b45 -4f26b7b547016f89be52676866189911c53e2f2477""" -)) - -# -# openssl pkcs8 -topk8 -passin pass:TestTest -inform DER -in key.der -# -outform DER -out keyenc.der -v1 PBE-MD5-RC2-64 -# hexdump -v -e '32/1 "%02x" "\n"' keyenc.der -# -wrapped_enc_keys.append(( -'skip encryption', # pbeWithMD5AndRC2-CBC, only decoding is supported --1, -"", -"", -""" -308201f1301b06092a864886f70d010506300e0408f5cd2fee56d9b4b8020208 -00048201d086454942d6166a19d6b108465bd111e7080911f573d54b1369c676 -df28600e84936bfec04f91023ff16499e2e07178c340904f12ffa6886ab66228 -32bf43c2bff5a0ed14e765918cf5fc543ad49566246f7eb3fc044fa5a9c25f40 -8fc8c8296b91658d3bb1067c0aba008c4fefd9e2bcdbbbd63fdc8085482bccf4 -f150cec9a084259ad441a017e5d81a1034ef2484696a7a50863836d0eeda45cd -8cee8ecabfed703f8d9d4bbdf3a767d32a0ccdc38550ee2928d7fe3fa27eda5b -5c7899e75ad55d076d2c2d3c37d6da3d95236081f9671dab9a99afdb1cbc890e -332d1a91105d9a8ce08b6027aa07367bd1daec3059cb51f5d896124da16971e4 -0ca4bcadb06c854bdf39f42dd24174011414e51626d198775eff3449a982df7b -ace874e77e045eb6d7c3faef0750792b29a068a6291f7275df1123fac5789c51 -27ace42836d81633faf9daf38f6787fff0394ea484bbcd465b57d4dbee3cf8df -b77d1db287b3a6264c466805be5a4fe85cfbca180699859280f2dd8e2c2c10b5 -7a7d2ac670c6039d41952fbb0e4f99b560ebe1d020e1b96d02403283819c00cc -529c51f0b0101555e4c58002ba3c6e3c12e3fde1aec94382792e96d9666a2b33 -3dc397b22ecab67ee38a552fec29a1d4ff8719c748""" -)) - -# -# openssl pkcs8 -topk8 -passin pass:TestTest -inform DER -in key.der -# -outform DER -out keyenc.der -v1 PBE-SHA1-DES -# hexdump -v -e '32/1 "%02x" "\n"' keyenc.der -# -wrapped_enc_keys.append(( -'skip encryption', # pbeWithSHA1AndDES-CBC, only decoding is supported --1, -"", -"", -""" -308201f1301b06092a864886f70d01050a300e04089bacc9cf1e8f734e020208 -00048201d03e502f3ceafe8fd19ab2939576bfdded26d719b2441db1459688f5 -9673218b41ec1f739edf1e460bd927bc28470c87b2d4fc8ea02ba17b47a63c49 -c5c1bee40529dadfd3ef8b4472c730bc136678c78abfb34670ec9d7dcd17ee3f -892f93f2629e6e0f4b24ecb9f954069bf722f466dece3913bb6abbd2c471d9a5 -c5eea89b14aaccda43d30b0dd0f6eb6e9850d9747aa8aa8414c383ad01c374ee -26d3552abec9ba22669cc9622ccf2921e3d0c8ecd1a70e861956de0bec6104b5 -b649ac994970c83f8a9e84b14a7dff7843d4ca3dd4af87cea43b5657e15ae0b5 -a940ce5047f006ab3596506600724764f23757205fe374fee04911336d655acc -03e159ec27789191d1517c4f3f9122f5242d44d25eab8f0658cafb928566ca0e -8f6589aa0c0ab13ca7a618008ae3eafd4671ee8fe0b562e70b3623b0e2a16eee -97fd388087d2e03530c9fe7db6e52eccc7c48fd701ede35e08922861a9508d12 -bc8bbf24f0c6bee6e63dbcb489b603d4c4a78ce45bf2eab1d5d10456c42a65a8 -3a606f4e4b9b46eb13b57f2624b651859d3d2d5192b45dbd5a2ead14ff20ca76 -48f321309aa56d8c0c4a192b580821cc6c70c75e6f19d1c5414da898ec4dd39d -b0eb93d6ba387a80702dfd2db610757ba340f63230 -""" -)) - -# -# openssl pkcs8 -topk8 -passin pass:TestTest -inform DER -in key.der -# -outform DER -out keyenc.der -v2 aes128 -# hexdump -v -e '32/1 "%02x" "\n"' keyenc.der -# -wrapped_enc_keys.append(( -'PBKDF2WithHMAC-SHA1AndAES128-CBC', -2048, -"4F66EE5D3BCD531FE6EBF4B4E73016B8", # IV -"479F25156176C53A", # Salt -""" -3082021f304906092a864886f70d01050d303c301b06092a864886f70d01050c -300e0408479f25156176c53a02020800301d060960864801650304010204104f -66ee5d3bcd531fe6ebf4b4e73016b8048201d0e33cfa560423f589d097d21533 -3b880a5ebac5b2ac58b4e73b0d787aee7764f034fe34ca1d1bd845c0a7c3316f -afbfb2129e03dcaf5a5031394206492828dacef1e04639bee5935e0f46114202 -10bc6c37182f4889be11c5d0486c398f4be952e5740f65de9d8edeb275e2b406 -e19bc29ad5ebb97fa536344fc3d84c7e755696f12b810898de4e6f069b8a81c8 -0aab0d45d7d062303aaa4a10c2ce84fdb5a03114039cfe138e38bb15b2ced717 -93549cdad85e730b14d9e2198b663dfdc8d04a4349eb3de59b076ad40b116d4a -25ed917c576bc7c883c95ef0f1180e28fc9981bea069594c309f1aa1b253ceab -a2f0313bb1372bcb51a745056be93d77a1f235a762a45e8856512d436b2ca0f7 -dd60fbed394ba28978d2a2b984b028529d0a58d93aba46c6bbd4ac1e4013cbaa -63b00988bc5f11ccc40141c346762d2b28f64435d4be98ec17c1884985e3807e -e550db606600993efccf6de0dfc2d2d70b5336a3b018fa415d6bdd59f5777118 -16806b7bc17c4c7e20ad7176ebfa5a1aa3f6bc10f04b77afd443944642ac9cca -d740e082b4a3bbb8bafdd34a0b3c5f2f3c2aceccccdccd092b78994b845bfa61 -706c3b9df5165ed1dbcbf1244fe41fc9bf993f52f7658e2f87e1baaeacb0f562 -9d905c -""" -)) - -# -# openssl pkcs8 -topk8 -passin pass:TestTest -inform DER -in key.der -# -outform DER -out keyenc.der -v2 aes192 -# hexdump -v -e '32/1 "%02x" "\n"' keyenc.der -# -wrapped_enc_keys.append(( -'PBKDF2WithHMAC-SHA1AndAES192-CBC', -2048, -"5CFC2A4FF7B63201A4A8A5B021148186", # IV -"D718541C264944CE", # Salt -""" -3082021f304906092a864886f70d01050d303c301b06092a864886f70d01050c -300e0408d718541c264944ce02020800301d060960864801650304011604105c -fc2a4ff7b63201a4a8a5b021148186048201d08e74aaa21b8bcfb15b9790fe95 -b0e09ddb0f189b6fb1682fdb9f122b804650ddec3c67a1df093a828b3e5fbcc6 -286abbcc5354c482fd796d972e919ca8a5eba1eaa2293af1d648013ddad72106 -75622264dfba55dafdda39e338f058f1bdb9846041ffff803797d3fdf3693135 -8a192729ea8346a7e5e58e925a2e2e4af0818581859e8215d87370eb4194a5ff -bae900857d4c591dbc651a241865a817eaede9987c9f9ae4f95c0bf930eea88c -4d7596e535ffb7ca369988aba75027a96b9d0bc9c8b0b75f359067fd145a378b -02aaa15e9db7a23176224da48a83249005460cc6e429168657f2efa8b1af7537 -d7d7042f2d683e8271b21d591090963eeb57aea6172f88da139e1614d6a7d1a2 -1002d5a7a93d6d21156e2b4777f6fc069287a85a1538c46b7722ccde591ab55c -630e1ceeb1ac42d1b41f3f654e9da86b5efced43775ea68b2594e50e4005e052 -0fe753c0898120c2c07265367ff157f6538a1e4080d6f9d1ca9eb51939c9574e -f2e4e1e87c1434affd5808563cddd376776dbbf790c6a40028f311a8b58dafa2 -0970ed34acd6e3e89d063987893b2b9570ddb8cc032b05a723bba9444933ebf3 -c624204be72f4190e0245197d0cb772bec933fd8442445f9a28bd042d5a3a1e9 -9a8a07 -""" -)) - -# -# openssl pkcs8 -topk8 -passin pass:TestTest -inform DER -in key.der -# -outform DER -out keyenc.der -v2 aes192 -# hexdump -v -e '32/1 "%02x" "\n"' keyenc.der -# -wrapped_enc_keys.append(( -'PBKDF2WithHMAC-SHA1AndAES256-CBC', -2048, -"323351F94462AC563E053A056252C2C4", # IV -"02A6CD0D12E727B5", # Salt -""" -3082021f304906092a864886f70d01050d303c301b06092a864886f70d01050c -300e040802a6cd0d12e727b502020800301d060960864801650304012a041032 -3351f94462ac563e053a056252c2c4048201d07f4ef1c7be21aae738a20c5632 -b8bdbbb9083b6e7f68822267b1f481fd27fdafd61a90660de6e4058790e4c912 -bf3f319a7c37e6eb3d956daaa143865020d554bf6215e8d7492359aaeef45d6e -d85a686ed26c0bf7c18d071d827a86f0b73e1db0c0e7f3d42201544093302a90 -551ad530692468c47ac15c69500b8ca67d4a17b64d15cecc035ae50b768a36cf -07c395afa091e9e6f86f665455fbdc1b21ad79c0908b73da5de75a9b43508d5d -44dc97a870cd3cd9f01ca24452e9b11c1b4982946702cfcbfda5b2fcc0203fb5 -0b52a115760bd635c94d4c95ac2c640ee9a04ffaf6ccff5a8d953dd5d88ca478 -c377811c521f2191639c643d657a9e364af88bb7c14a356c2b0b4870a23c2f54 -d41f8157afff731471dccc6058b15e1151bcf84b39b5e622a3a1d65859c912a5 -591b85e034a1f6af664f030a6bfc8c3d20c70f32b54bcf4da9c2da83cef49cf8 -e9a74f0e5d358fe50b88acdce6a9db9a7ad61536212fc5f877ebfc7957b8bda4 -b1582a0f10d515a20ee06cf768db9c977aa6fbdca7540d611ff953012d009dac -e8abd059f8e8ffea637c9c7721f817aaf0bb23403e26a0ef0ff0e2037da67d41 -af728481f53443551a9bff4cea023164e9622b5441a309e1f4bff98e5bf76677 -8d7cd9 -""" -)) - -def txt2bin(inputs): - s = b('').join([b(x) for x in inputs if not (x in '\n\r\t ')]) - return unhexlify(s) - -class Rng: - def __init__(self, output): - self.output=output - self.idx=0 - def __call__(self, n): - output = self.output[self.idx:self.idx+n] - self.idx += n - return output - -class PKCS8_Decrypt(unittest.TestCase): - - def setUp(self): - self.oid_key = oid_key - self.clear_key = txt2bin(clear_key) - self.wrapped_clear_key = txt2bin(wrapped_clear_key) - self.wrapped_enc_keys = [] - for t in wrapped_enc_keys: - self.wrapped_enc_keys.append(( - t[0], - t[1], - txt2bin(t[2]), - txt2bin(t[3]), - txt2bin(t[4]) - )) - - ### NO ENCRYTION - - def test1(self): - """Verify unwrapping w/o encryption""" - res1, res2, res3 = PKCS8.unwrap(self.wrapped_clear_key) - self.assertEqual(res1, self.oid_key) - self.assertEqual(res2, self.clear_key) - - def test2(self): - """Verify wrapping w/o encryption""" - wrapped = PKCS8.wrap(self.clear_key, self.oid_key) - res1, res2, res3 = PKCS8.unwrap(wrapped) - self.assertEqual(res1, self.oid_key) - self.assertEqual(res2, self.clear_key) - - ## ENCRYPTION - - def test3(self): - """Verify unwrapping with encryption""" - - for t in self.wrapped_enc_keys: - res1, res2, res3 = PKCS8.unwrap(t[4], b("TestTest")) - self.assertEqual(res1, self.oid_key) - self.assertEqual(res2, self.clear_key) - - def test4(self): - """Verify wrapping with encryption""" - - for t in self.wrapped_enc_keys: - if t[0] == 'skip encryption': - continue - rng = Rng(t[2]+t[3]) - params = { 'iteration_count':t[1] } - wrapped = PKCS8.wrap( - self.clear_key, - self.oid_key, - b("TestTest"), - protection=t[0], - prot_params=params, - key_params=None, - randfunc=rng) - self.assertEqual(wrapped, t[4]) - -def get_tests(config={}): - from Crypto.SelfTest.st_common import list_test_cases - listTests = [] - listTests += list_test_cases(PKCS8_Decrypt) - return listTests - -if __name__ == '__main__': - suite = lambda: unittest.TestSuite(get_tests()) - unittest.main(defaultTest='suite') - diff --git a/Crypto/SelfTest/Math/__init__.py b/Crypto/SelfTest/Math/__init__.py deleted file mode 100644 index 18e83d1..0000000 --- a/Crypto/SelfTest/Math/__init__.py +++ /dev/null @@ -1,49 +0,0 @@ -# -# SelfTest/Math/__init__.py: Self-test for math module -# -# =================================================================== -# -# Copyright (c) 2014, Legrandin -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# =================================================================== - -"""Self-test for Math""" - -def get_tests(config={}): - tests = [] - from Crypto.SelfTest.Math import test_Numbers - from Crypto.SelfTest.Math import test_Primality - from Crypto.SelfTest.Math import test_modexp - tests += test_Numbers.get_tests(config=config) - tests += test_Primality.get_tests(config=config) - tests += test_modexp.get_tests(config=config) - return tests - -if __name__ == '__main__': - import unittest - suite = lambda: unittest.TestSuite(get_tests()) - unittest.main(defaultTest='suite') diff --git a/Crypto/SelfTest/Math/__pycache__/__init__.cpython-36.pyc b/Crypto/SelfTest/Math/__pycache__/__init__.cpython-36.pyc deleted file mode 100644 index ae742c2f01f6770b5792bdbaccff42485a41878e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 744 zcmZ8e&1&2*5Z3r-IY7D?J3DuXJ&fI*2W$&lXYFmV#}iy)4Py5h_WsAHWfcFy z7A%B*Msj%ERV$?p;uiz{sEbOJh23CgI%KLws&6gAQQFj5k%xZr@>XwJ+bn3RPsp;M zfwY6Xnl`3soPL}u%Zb5+zNR62e?ZUv`@uABo&AoZuR=$qsPm}Z*t@2_h{|HMj~DME zQ&@H0iu7LO%0zz^M0*7hDTp{P>cVoqXg7Lv{SoJ~Nl_OKK{9JmDTGt1oKwyt;RkJKh5BDFe6X%m Q*RL>TCg?n8HVJ_4A05G|;{X5v diff --git a/Crypto/SelfTest/Math/__pycache__/test_Numbers.cpython-36.pyc b/Crypto/SelfTest/Math/__pycache__/test_Numbers.cpython-36.pyc deleted file mode 100644 index 803e469e2a6824f56b76bbcef82c2ba86b8665c7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 37961 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 diff --git a/Crypto/SelfTest/Math/test_Numbers.py b/Crypto/SelfTest/Math/test_Numbers.py deleted file mode 100644 index 058a6c7..0000000 --- a/Crypto/SelfTest/Math/test_Numbers.py +++ /dev/null @@ -1,774 +0,0 @@ -# -# SelfTest/Math/test_Numbers.py: Self-test for Numbers module -# -# =================================================================== -# -# Copyright (c) 2014, Legrandin -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# =================================================================== - -"""Self-test for Math.Numbers""" - -import sys -import unittest - -from Crypto.SelfTest.st_common import list_test_cases - -from Crypto.Util.py3compat import * - -from Crypto.Math._IntegerNative import IntegerNative - - -class TestIntegerBase(unittest.TestCase): - - def setUp(self): - raise NotImplementedError("To be implemented") - - def Integers(self, *arg): - return map(self.Integer, arg) - - def test_init_and_equality(self): - Integer = self.Integer - - v1 = Integer(23) - v2 = Integer(v1) - v3 = Integer(-9) - self.assertRaises(ValueError, Integer, 1.0) - - v4 = Integer(10**10) - v5 = Integer(-10**10) - self.assertEqual(v1, v1) - self.assertEqual(v1, 23) - self.assertEqual(v1, v2) - self.assertEqual(v3, -9) - self.assertEqual(v4, 10 ** 10) - self.assertEqual(v5, -10 ** 10) - - self.failIf(v1 == v4) - - # Init and comparison between Integer's - v6 = Integer(v1) - self.assertEqual(v1, v6) - - self.failIf(Integer(0) == None) - - def test_conversion_to_int(self): - v1, v2 = self.Integers(-23, 2 ** 1000) - self.assertEqual(int(v1), -23) - self.assertEqual(int(v2), 2 ** 1000) - - def test_equality_with_ints(self): - v1, v2, v3 = self.Integers(23, -89, 2 ** 1000) - self.failUnless(v1 == 23) - self.failUnless(v2 == -89) - self.failIf(v1 == 24) - self.failUnless(v3 == 2 ** 1000) - - def test_conversion_to_str(self): - v1, v2, v3, v4 = self.Integers(20, 0, -20, 2 ** 1000) - self.failUnless(str(v1) == "20") - self.failUnless(str(v2) == "0") - self.failUnless(str(v3) == "-20") - self.failUnless(str(v4) == "10715086071862673209484250490600018105614048117055336074437503883703510511249361224931983788156958581275946729175531468251871452856923140435984577574698574803934567774824230985421074605062371141877954182153046474983581941267398767559165543946077062914571196477686542167660429831652624386837205668069376") - - def test_repr(self): - v1, v2 = self.Integers(-1, 2**80) - self.assertEqual(repr(v1), "Integer(-1)") - self.assertEqual(repr(v2), "Integer(1208925819614629174706176)") - - def test_conversion_to_bytes(self): - Integer = self.Integer - - v1 = Integer(0x17) - self.assertEqual(b("\x17"), v1.to_bytes()) - - v2 = Integer(0xFFFF) - self.assertEqual(b("\xFF\xFF"), v2.to_bytes()) - self.assertEqual(b("\x00\xFF\xFF"), v2.to_bytes(3)) - self.assertRaises(ValueError, v2.to_bytes, 1) - - v3 = Integer(-90) - self.assertRaises(ValueError, v3.to_bytes) - - def test_conversion_from_bytes(self): - Integer = self.Integer - - v1 = Integer.from_bytes(b("\x00")) - self.failUnless(isinstance(v1, Integer)) - self.assertEqual(0, v1) - - v2 = Integer.from_bytes(b("\x00\x00")) - self.assertEqual(0, v2) - - v3 = Integer.from_bytes(b("\xFF\xFF")) - self.assertEqual(0xFFFF, v3) - - def test_inequality(self): - # Test Integer!=Integer and Integer!=int - v1, v2, v3, v4 = self.Integers(89, 89, 90, -8) - self.failUnless(v1 != v3) - self.failUnless(v1 != 90) - self.failIf(v1 != v2) - self.failIf(v1 != 89) - self.failUnless(v1 != v4) - self.failUnless(v4 != v1) - self.failUnless(self.Integer(0) != None) - - def test_less_than(self): - # Test IntegerInteger and Integer>int - v1, v2, v3, v4, v5 = self.Integers(13, 13, 14, -8, 2 ** 10) - self.failUnless(v3 > v1) - self.failUnless(v3 > 13) - self.failIf(v1 > v1) - self.failIf(v1 > v2) - self.failIf(v1 > 13) - self.failUnless(v1 > v4) - self.failIf(v4 > v1) - self.failUnless(v5 > v1) - self.failIf(v1 > v5) - - def test_more_than_or_equal(self): - # Test Integer>=Integer and Integer>=int - v1, v2, v3, v4 = self.Integers(13, 13, 14, -4) - self.failUnless(v3 >= v1) - self.failUnless(v3 >= 13) - self.failUnless(v1 >= v2) - self.failUnless(v1 >= v1) - self.failUnless(v1 >= 13) - self.failIf(v4 >= v1) - - def test_bool(self): - v1, v2, v3, v4 = self.Integers(0, 10, -9, 2 ** 10) - self.assertFalse(v1) - self.assertFalse(bool(v1)) - self.failUnless(v2) - self.failUnless(bool(v2)) - self.failUnless(v3) - self.failUnless(v4) - - def test_is_negative(self): - v1, v2, v3, v4, v5 = self.Integers(-3 ** 100, -3, 0, 3, 3**100) - self.failUnless(v1.is_negative()) - self.failUnless(v2.is_negative()) - self.failIf(v4.is_negative()) - self.failIf(v5.is_negative()) - - def test_addition(self): - # Test Integer+Integer and Integer+int - v1, v2, v3 = self.Integers(7, 90, -7) - self.failUnless(isinstance(v1 + v2, self.Integer)) - self.assertEqual(v1 + v2, 97) - self.assertEqual(v1 + 90, 97) - self.assertEqual(v1 + v3, 0) - self.assertEqual(v1 + (-7), 0) - self.assertEqual(v1 + 2 ** 10, 2 ** 10 + 7) - - def test_subtraction(self): - # Test Integer-Integer and Integer-int - v1, v2, v3 = self.Integers(7, 90, -7) - self.failUnless(isinstance(v1 - v2, self.Integer)) - self.assertEqual(v2 - v1, 83) - self.assertEqual(v2 - 7, 83) - self.assertEqual(v2 - v3, 97) - self.assertEqual(v1 - (-7), 14) - self.assertEqual(v1 - 2 ** 10, 7 - 2 ** 10) - - def test_multiplication(self): - # Test Integer-Integer and Integer-int - v1, v2, v3, v4 = self.Integers(4, 5, -2, 2 ** 10) - self.failUnless(isinstance(v1 * v2, self.Integer)) - self.assertEqual(v1 * v2, 20) - self.assertEqual(v1 * 5, 20) - self.assertEqual(v1 * -2, -8) - self.assertEqual(v1 * 2 ** 10, 4 * (2 ** 10)) - - def test_floor_div(self): - v1, v2, v3 = self.Integers(3, 8, 2 ** 80) - self.failUnless(isinstance(v1 // v2, self.Integer)) - self.assertEqual(v2 // v1, 2) - self.assertEqual(v2 // 3, 2) - self.assertEqual(v2 // -3, -3) - self.assertEqual(v3 // 2 ** 79, 2) - self.assertRaises(ZeroDivisionError, lambda: v1 // 0) - - def test_remainder(self): - # Test Integer%Integer and Integer%int - v1, v2, v3 = self.Integers(23, 5, -4) - self.failUnless(isinstance(v1 % v2, self.Integer)) - self.assertEqual(v1 % v2, 3) - self.assertEqual(v1 % 5, 3) - self.assertEqual(v3 % 5, 1) - self.assertEqual(v1 % 2 ** 10, 23) - self.assertRaises(ZeroDivisionError, lambda: v1 % 0) - self.assertRaises(ValueError, lambda: v1 % -6) - - def test_simple_exponentiation(self): - v1, v2, v3 = self.Integers(4, 3, -2) - self.failUnless(isinstance(v1 ** v2, self.Integer)) - self.assertEqual(v1 ** v2, 64) - self.assertEqual(pow(v1, v2), 64) - self.assertEqual(v1 ** 3, 64) - self.assertEqual(pow(v1, 3), 64) - self.assertEqual(v3 ** 2, 4) - self.assertEqual(v3 ** 3, -8) - - self.assertRaises(ValueError, pow, v1, -3) - - def test_modular_exponentiation(self): - v1, v2, v3 = self.Integers(23, 5, 17) - - self.failUnless(isinstance(pow(v1, v2, v3), self.Integer)) - self.assertEqual(pow(v1, v2, v3), 7) - self.assertEqual(pow(v1, 5, v3), 7) - self.assertEqual(pow(v1, v2, 17), 7) - self.assertEqual(pow(v1, 5, 17), 7) - self.assertEqual(pow(v1, 0, 17), 1) - self.assertEqual(pow(v1, 1, 2 ** 80), 23) - self.assertEqual(pow(v1, 2 ** 80, 89298), 17689) - - self.assertRaises(ZeroDivisionError, pow, v1, 5, 0) - self.assertRaises(ValueError, pow, v1, 5, -4) - self.assertRaises(ValueError, pow, v1, -3, 8) - - def test_inplace_exponentiation(self): - v1 = self.Integer(4) - v1.inplace_pow(2) - self.assertEqual(v1, 16) - - v1 = self.Integer(4) - v1.inplace_pow(2, 15) - self.assertEqual(v1, 1) - - def test_abs(self): - v1, v2, v3, v4, v5 = self.Integers(-2 ** 100, -2, 0, 2, 2 ** 100) - self.assertEqual(abs(v1), 2 ** 100) - self.assertEqual(abs(v2), 2) - self.assertEqual(abs(v3), 0) - self.assertEqual(abs(v4), 2) - self.assertEqual(abs(v5), 2 ** 100) - - def test_sqrt(self): - v1, v2, v3, v4 = self.Integers(-2, 0, 49, 10**100) - - self.assertRaises(ValueError, v1.sqrt) - self.assertEqual(v2.sqrt(), 0) - self.assertEqual(v3.sqrt(), 7) - self.assertEqual(v4.sqrt(), 10**50) - - def test_sqrt_module(self): - - # Invalid modulus (non positive) - self.assertRaises(ValueError, self.Integer(5).sqrt, 0) - self.assertRaises(ValueError, self.Integer(5).sqrt, -1) - - # Simple cases - assert self.Integer(0).sqrt(5) == 0 - assert self.Integer(1).sqrt(5) in (1, 4) - - # Test with all quadratic residues in several fields - for p in (11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53): - for i in range(0, p): - square = i**2 % p - res = self.Integer(square).sqrt(p) - assert res in (i, p - i) - - # 2 is a non-quadratic reside in Z_11 - self.assertRaises(ValueError, self.Integer(2).sqrt, 11) - - # 10 is not a prime - self.assertRaises(ValueError, self.Integer(4).sqrt, 10) - - # 5 is square residue of 4 and 7 - assert self.Integer(5 - 11).sqrt(11) in (4, 7) - assert self.Integer(5 + 11).sqrt(11) in (4, 7) - - def test_in_place_add(self): - v1, v2 = self.Integers(10, 20) - - v1 += v2 - self.assertEqual(v1, 30) - v1 += 10 - self.assertEqual(v1, 40) - v1 += -1 - self.assertEqual(v1, 39) - v1 += 2 ** 1000 - self.assertEqual(v1, 39 + 2 ** 1000) - - def test_in_place_sub(self): - v1, v2 = self.Integers(10, 20) - - v1 -= v2 - self.assertEqual(v1, -10) - v1 -= -100 - self.assertEqual(v1, 90) - v1 -= 90000 - self.assertEqual(v1, -89910) - v1 -= -100000 - self.assertEqual(v1, 10090) - - def test_in_place_mul(self): - v1, v2 = self.Integers(3, 5) - - v1 *= v2 - self.assertEqual(v1, 15) - v1 *= 2 - self.assertEqual(v1, 30) - v1 *= -2 - self.assertEqual(v1, -60) - v1 *= 2 ** 1000 - self.assertEqual(v1, -60 * (2 ** 1000)) - - def test_in_place_modulus(self): - v1, v2 = self.Integers(20, 7) - - v1 %= v2 - self.assertEqual(v1, 6) - v1 %= 2 ** 1000 - self.assertEqual(v1, 6) - v1 %= 2 - self.assertEqual(v1, 0) - def t(): - v3 = self.Integer(9) - v3 %= 0 - self.assertRaises(ZeroDivisionError, t) - - def test_and(self): - v1, v2, v3 = self.Integers(0xF4, 0x31, -0xF) - self.failUnless(isinstance(v1 & v2, self.Integer)) - self.assertEqual(v1 & v2, 0x30) - self.assertEqual(v1 & 0x31, 0x30) - self.assertEqual(v1 & v3, 0xF0) - self.assertEqual(v1 & -0xF, 0xF0) - self.assertEqual(v3 & -0xF, -0xF) - self.assertEqual(v2 & (2 ** 1000 + 0x31), 0x31) - - def test_or(self): - v1, v2, v3 = self.Integers(0x40, 0x82, -0xF) - self.failUnless(isinstance(v1 | v2, self.Integer)) - self.assertEqual(v1 | v2, 0xC2) - self.assertEqual(v1 | 0x82, 0xC2) - self.assertEqual(v2 | v3, -0xD) - self.assertEqual(v2 | 2 ** 1000, 2 ** 1000 + 0x82) - - def test_right_shift(self): - v1, v2, v3 = self.Integers(0x10, 1, -0x10) - self.assertEqual(v1 >> 0, v1) - self.failUnless(isinstance(v1 >> v2, self.Integer)) - self.assertEqual(v1 >> v2, 0x08) - self.assertEqual(v1 >> 1, 0x08) - self.assertRaises(ValueError, lambda: v1 >> -1) - self.assertEqual(v1 >> (2 ** 1000), 0) - - self.assertEqual(v3 >> 1, -0x08) - self.assertEqual(v3 >> (2 ** 1000), -1) - - def test_in_place_right_shift(self): - v1, v2, v3 = self.Integers(0x10, 1, -0x10) - v1 >>= 0 - self.assertEqual(v1, 0x10) - v1 >>= 1 - self.assertEqual(v1, 0x08) - v1 >>= v2 - self.assertEqual(v1, 0x04) - v3 >>= 1 - self.assertEqual(v3, -0x08) - def l(): - v4 = self.Integer(0x90) - v4 >>= -1 - self.assertRaises(ValueError, l) - def m1(): - v4 = self.Integer(0x90) - v4 >>= 2 ** 1000 - return v4 - self.assertEqual(0, m1()) - def m2(): - v4 = self.Integer(-1) - v4 >>= 2 ** 1000 - return v4 - self.assertEqual(-1, m2()) - - def _test_left_shift(self): - v1, v2, v3 = self.Integers(0x10, 1, -0x10) - self.assertEqual(v1 << 0, v1) - self.failUnless(isinstance(v1 << v2, self.Integer)) - self.assertEqual(v1 << v2, 0x20) - self.assertEqual(v1 << 1, 0x20) - self.assertEqual(v3 << 1, -0x20) - self.assertRaises(ValueError, lambda: v1 << -1) - self.assertRaises(ValueError, lambda: v1 << (2 ** 1000)) - - def test_in_place_left_shift(self): - v1, v2, v3 = self.Integers(0x10, 1, -0x10) - v1 <<= 0 - self.assertEqual(v1, 0x10) - v1 <<= 1 - self.assertEqual(v1, 0x20) - v1 <<= v2 - self.assertEqual(v1, 0x40) - v3 <<= 1 - self.assertEqual(v3, -0x20) - def l(): - v4 = self.Integer(0x90) - v4 <<= -1 - self.assertRaises(ValueError, l) - def m(): - v4 = self.Integer(0x90) - v4 <<= 2 ** 1000 - self.assertRaises(ValueError, m) - - - def test_get_bit(self): - v1, v2, v3 = self.Integers(0x102, -3, 1) - self.assertEqual(v1.get_bit(0), 0) - self.assertEqual(v1.get_bit(1), 1) - self.assertEqual(v1.get_bit(v3), 1) - self.assertEqual(v1.get_bit(8), 1) - self.assertEqual(v1.get_bit(9), 0) - - self.assertRaises(ValueError, v1.get_bit, -1) - self.assertEqual(v1.get_bit(2 ** 1000), 0) - - self.assertRaises(ValueError, v2.get_bit, -1) - self.assertRaises(ValueError, v2.get_bit, 0) - self.assertRaises(ValueError, v2.get_bit, 1) - self.assertRaises(ValueError, v2.get_bit, 2 * 1000) - - def test_odd_even(self): - v1, v2, v3, v4, v5 = self.Integers(0, 4, 17, -4, -17) - - self.failUnless(v1.is_even()) - self.failUnless(v2.is_even()) - self.failIf(v3.is_even()) - self.failUnless(v4.is_even()) - self.failIf(v5.is_even()) - - self.failIf(v1.is_odd()) - self.failIf(v2.is_odd()) - self.failUnless(v3.is_odd()) - self.failIf(v4.is_odd()) - self.failUnless(v5.is_odd()) - - def test_size_in_bits(self): - v1, v2, v3, v4 = self.Integers(0, 1, 0x100, -90) - self.assertEqual(v1.size_in_bits(), 1) - self.assertEqual(v2.size_in_bits(), 1) - self.assertEqual(v3.size_in_bits(), 9) - self.assertRaises(ValueError, v4.size_in_bits) - - def test_size_in_bytes(self): - v1, v2, v3, v4, v5, v6 = self.Integers(0, 1, 0xFF, 0x1FF, 0x10000, -9) - self.assertEqual(v1.size_in_bytes(), 1) - self.assertEqual(v2.size_in_bytes(), 1) - self.assertEqual(v3.size_in_bytes(), 1) - self.assertEqual(v4.size_in_bytes(), 2) - self.assertEqual(v5.size_in_bytes(), 3) - self.assertRaises(ValueError, v6.size_in_bits) - - def test_perfect_square(self): - - self.failIf(self.Integer(-9).is_perfect_square()) - self.failUnless(self.Integer(0).is_perfect_square()) - self.failUnless(self.Integer(1).is_perfect_square()) - self.failIf(self.Integer(2).is_perfect_square()) - self.failIf(self.Integer(3).is_perfect_square()) - self.failUnless(self.Integer(4).is_perfect_square()) - self.failUnless(self.Integer(39*39).is_perfect_square()) - self.failIf(self.Integer(39*39+1).is_perfect_square()) - - for x in range(100, 1000): - self.failIf(self.Integer(x**2+1).is_perfect_square()) - self.failUnless(self.Integer(x**2).is_perfect_square()) - - def test_fail_if_divisible_by(self): - v1, v2, v3 = self.Integers(12, -12, 4) - - # No failure expected - v1.fail_if_divisible_by(7) - v2.fail_if_divisible_by(7) - v2.fail_if_divisible_by(2 ** 80) - - # Failure expected - self.assertRaises(ValueError, v1.fail_if_divisible_by, 4) - self.assertRaises(ValueError, v1.fail_if_divisible_by, v3) - - def test_multiply_accumulate(self): - v1, v2, v3 = self.Integers(4, 3, 2) - v1.multiply_accumulate(v2, v3) - self.assertEqual(v1, 10) - v1.multiply_accumulate(v2, 2) - self.assertEqual(v1, 16) - v1.multiply_accumulate(3, v3) - self.assertEqual(v1, 22) - v1.multiply_accumulate(1, -2) - self.assertEqual(v1, 20) - v1.multiply_accumulate(-2, 1) - self.assertEqual(v1, 18) - v1.multiply_accumulate(1, 2 ** 1000) - self.assertEqual(v1, 18 + 2 ** 1000) - v1.multiply_accumulate(2 ** 1000, 1) - self.assertEqual(v1, 18 + 2 ** 1001) - - def test_set(self): - v1, v2 = self.Integers(3, 6) - v1.set(v2) - self.assertEqual(v1, 6) - v1.set(9) - self.assertEqual(v1, 9) - v1.set(-2) - self.assertEqual(v1, -2) - v1.set(2 ** 1000) - self.assertEqual(v1, 2 ** 1000) - - def test_inverse(self): - v1, v2, v3, v4, v5, v6 = self.Integers(2, 5, -3, 0, 723872, 3433) - - self.failUnless(isinstance(v1.inverse(v2), self.Integer)) - self.assertEqual(v1.inverse(v2), 3) - self.assertEqual(v1.inverse(5), 3) - self.assertEqual(v3.inverse(5), 3) - self.assertEqual(v5.inverse(92929921), 58610507) - self.assertEqual(v6.inverse(9912), 5353) - - self.assertRaises(ValueError, v2.inverse, 10) - self.assertRaises(ValueError, v1.inverse, -3) - self.assertRaises(ValueError, v4.inverse, 10) - self.assertRaises(ZeroDivisionError, v2.inverse, 0) - - def test_inplace_inverse(self): - v1, v2 = self.Integers(2, 5) - - v1.inplace_inverse(v2) - self.assertEqual(v1, 3) - - def test_gcd(self): - v1, v2, v3, v4 = self.Integers(6, 10, 17, -2) - self.failUnless(isinstance(v1.gcd(v2), self.Integer)) - self.assertEqual(v1.gcd(v2), 2) - self.assertEqual(v1.gcd(10), 2) - self.assertEqual(v1.gcd(v3), 1) - self.assertEqual(v1.gcd(-2), 2) - self.assertEqual(v4.gcd(6), 2) - - def test_lcm(self): - v1, v2, v3, v4, v5 = self.Integers(6, 10, 17, -2, 0) - self.failUnless(isinstance(v1.lcm(v2), self.Integer)) - self.assertEqual(v1.lcm(v2), 30) - self.assertEqual(v1.lcm(10), 30) - self.assertEqual(v1.lcm(v3), 102) - self.assertEqual(v1.lcm(-2), 6) - self.assertEqual(v4.lcm(6), 6) - self.assertEqual(v1.lcm(0), 0) - self.assertEqual(v5.lcm(0), 0) - - def test_jacobi_symbol(self): - - data = ( - (1001, 1, 1), - (19, 45, 1), - (8, 21, -1), - (5, 21, 1), - (610, 987, -1), - (1001, 9907, -1), - (5, 3439601197, -1) - ) - - js = self.Integer.jacobi_symbol - - # Jacobi symbol is always 1 for k==1 or n==1 - for k in range(1, 30): - self.assertEqual(js(k, 1), 1) - for n in range(1, 30, 2): - self.assertEqual(js(1, n), 1) - - # Fail if n is not positive odd - self.assertRaises(ValueError, js, 6, -2) - self.assertRaises(ValueError, js, 6, -1) - self.assertRaises(ValueError, js, 6, 0) - self.assertRaises(ValueError, js, 0, 0) - self.assertRaises(ValueError, js, 6, 2) - self.assertRaises(ValueError, js, 6, 4) - self.assertRaises(ValueError, js, 6, 6) - self.assertRaises(ValueError, js, 6, 8) - - for tv in data: - self.assertEqual(js(tv[0], tv[1]), tv[2]) - self.assertEqual(js(self.Integer(tv[0]), tv[1]), tv[2]) - self.assertEqual(js(tv[0], self.Integer(tv[1])), tv[2]) - - def test_jacobi_symbol_wikipedia(self): - - # Test vectors from https://en.wikipedia.org/wiki/Jacobi_symbol - tv = [ - (3, [(1, 1), (2, -1), (3, 0), (4, 1), (5, -1), (6, 0), (7, 1), (8, -1), (9, 0), (10, 1), (11, -1), (12, 0), (13, 1), (14, -1), (15, 0), (16, 1), (17, -1), (18, 0), (19, 1), (20, -1), (21, 0), (22, 1), (23, -1), (24, 0), (25, 1), (26, -1), (27, 0), (28, 1), (29, -1), (30, 0)]), - (5, [(1, 1), (2, -1), (3, -1), (4, 1), (5, 0), (6, 1), (7, -1), (8, -1), (9, 1), (10, 0), (11, 1), (12, -1), (13, -1), (14, 1), (15, 0), (16, 1), (17, -1), (18, -1), (19, 1), (20, 0), (21, 1), (22, -1), (23, -1), (24, 1), (25, 0), (26, 1), (27, -1), (28, -1), (29, 1), (30, 0)]), - (7, [(1, 1), (2, 1), (3, -1), (4, 1), (5, -1), (6, -1), (7, 0), (8, 1), (9, 1), (10, -1), (11, 1), (12, -1), (13, -1), (14, 0), (15, 1), (16, 1), (17, -1), (18, 1), (19, -1), (20, -1), (21, 0), (22, 1), (23, 1), (24, -1), (25, 1), (26, -1), (27, -1), (28, 0), (29, 1), (30, 1)]), - (9, [(1, 1), (2, 1), (3, 0), (4, 1), (5, 1), (6, 0), (7, 1), (8, 1), (9, 0), (10, 1), (11, 1), (12, 0), (13, 1), (14, 1), (15, 0), (16, 1), (17, 1), (18, 0), (19, 1), (20, 1), (21, 0), (22, 1), (23, 1), (24, 0), (25, 1), (26, 1), (27, 0), (28, 1), (29, 1), (30, 0)]), - (11, [(1, 1), (2, -1), (3, 1), (4, 1), (5, 1), (6, -1), (7, -1), (8, -1), (9, 1), (10, -1), (11, 0), (12, 1), (13, -1), (14, 1), (15, 1), (16, 1), (17, -1), (18, -1), (19, -1), (20, 1), (21, -1), (22, 0), (23, 1), (24, -1), (25, 1), (26, 1), (27, 1), (28, -1), (29, -1), (30, -1)]), - (13, [(1, 1), (2, -1), (3, 1), (4, 1), (5, -1), (6, -1), (7, -1), (8, -1), (9, 1), (10, 1), (11, -1), (12, 1), (13, 0), (14, 1), (15, -1), (16, 1), (17, 1), (18, -1), (19, -1), (20, -1), (21, -1), (22, 1), (23, 1), (24, -1), (25, 1), (26, 0), (27, 1), (28, -1), (29, 1), (30, 1)]), - (15, [(1, 1), (2, 1), (3, 0), (4, 1), (5, 0), (6, 0), (7, -1), (8, 1), (9, 0), (10, 0), (11, -1), (12, 0), (13, -1), (14, -1), (15, 0), (16, 1), (17, 1), (18, 0), (19, 1), (20, 0), (21, 0), (22, -1), (23, 1), (24, 0), (25, 0), (26, -1), (27, 0), (28, -1), (29, -1), (30, 0)]), - (17, [(1, 1), (2, 1), (3, -1), (4, 1), (5, -1), (6, -1), (7, -1), (8, 1), (9, 1), (10, -1), (11, -1), (12, -1), (13, 1), (14, -1), (15, 1), (16, 1), (17, 0), (18, 1), (19, 1), (20, -1), (21, 1), (22, -1), (23, -1), (24, -1), (25, 1), (26, 1), (27, -1), (28, -1), (29, -1), (30, 1)]), - (19, [(1, 1), (2, -1), (3, -1), (4, 1), (5, 1), (6, 1), (7, 1), (8, -1), (9, 1), (10, -1), (11, 1), (12, -1), (13, -1), (14, -1), (15, -1), (16, 1), (17, 1), (18, -1), (19, 0), (20, 1), (21, -1), (22, -1), (23, 1), (24, 1), (25, 1), (26, 1), (27, -1), (28, 1), (29, -1), (30, 1)]), - (21, [(1, 1), (2, -1), (3, 0), (4, 1), (5, 1), (6, 0), (7, 0), (8, -1), (9, 0), (10, -1), (11, -1), (12, 0), (13, -1), (14, 0), (15, 0), (16, 1), (17, 1), (18, 0), (19, -1), (20, 1), (21, 0), (22, 1), (23, -1), (24, 0), (25, 1), (26, 1), (27, 0), (28, 0), (29, -1), (30, 0)]), - (23, [(1, 1), (2, 1), (3, 1), (4, 1), (5, -1), (6, 1), (7, -1), (8, 1), (9, 1), (10, -1), (11, -1), (12, 1), (13, 1), (14, -1), (15, -1), (16, 1), (17, -1), (18, 1), (19, -1), (20, -1), (21, -1), (22, -1), (23, 0), (24, 1), (25, 1), (26, 1), (27, 1), (28, -1), (29, 1), (30, -1)]), - (25, [(1, 1), (2, 1), (3, 1), (4, 1), (5, 0), (6, 1), (7, 1), (8, 1), (9, 1), (10, 0), (11, 1), (12, 1), (13, 1), (14, 1), (15, 0), (16, 1), (17, 1), (18, 1), (19, 1), (20, 0), (21, 1), (22, 1), (23, 1), (24, 1), (25, 0), (26, 1), (27, 1), (28, 1), (29, 1), (30, 0)]), - (27, [(1, 1), (2, -1), (3, 0), (4, 1), (5, -1), (6, 0), (7, 1), (8, -1), (9, 0), (10, 1), (11, -1), (12, 0), (13, 1), (14, -1), (15, 0), (16, 1), (17, -1), (18, 0), (19, 1), (20, -1), (21, 0), (22, 1), (23, -1), (24, 0), (25, 1), (26, -1), (27, 0), (28, 1), (29, -1), (30, 0)]), - (29, [(1, 1), (2, -1), (3, -1), (4, 1), (5, 1), (6, 1), (7, 1), (8, -1), (9, 1), (10, -1), (11, -1), (12, -1), (13, 1), (14, -1), (15, -1), (16, 1), (17, -1), (18, -1), (19, -1), (20, 1), (21, -1), (22, 1), (23, 1), (24, 1), (25, 1), (26, -1), (27, -1), (28, 1), (29, 0), (30, 1)]), - ] - - js = self.Integer.jacobi_symbol - - for n, kj in tv: - for k, j in kj: - self.assertEqual(js(k, n), j) - - def test_hex(self): - v1, = self.Integers(0x10) - self.assertEqual(hex(v1), "0x10") - - -class TestIntegerInt(TestIntegerBase): - - def setUp(self): - self.Integer = IntegerNative - - -class testIntegerRandom(unittest.TestCase): - - def test_random_exact_bits(self): - - for _ in range(1000): - a = IntegerNative.random(exact_bits=8) - self.failIf(a < 128) - self.failIf(a >= 256) - - for bits_value in range(1024, 1024 + 8): - a = IntegerNative.random(exact_bits=bits_value) - self.failIf(a < 2**(bits_value - 1)) - self.failIf(a >= 2**bits_value) - - def test_random_max_bits(self): - - flag = False - for _ in range(1000): - a = IntegerNative.random(max_bits=8) - flag = flag or a < 128 - self.failIf(a>=256) - self.failUnless(flag) - - for bits_value in range(1024, 1024 + 8): - a = IntegerNative.random(max_bits=bits_value) - self.failIf(a >= 2**bits_value) - - def test_random_bits_custom_rng(self): - - class CustomRNG(object): - def __init__(self): - self.counter = 0 - - def __call__(self, size): - self.counter += size - return bchr(0) * size - - custom_rng = CustomRNG() - a = IntegerNative.random(exact_bits=32, randfunc=custom_rng) - self.assertEqual(custom_rng.counter, 4) - - def test_random_range(self): - - func = IntegerNative.random_range - - for x in range(200): - a = func(min_inclusive=1, max_inclusive=15) - self.failUnless(1 <= a <= 15) - - for x in range(200): - a = func(min_inclusive=1, max_exclusive=15) - self.failUnless(1 <= a < 15) - - self.assertRaises(ValueError, func, min_inclusive=1, max_inclusive=2, - max_exclusive=3) - self.assertRaises(ValueError, func, max_inclusive=2, max_exclusive=3) - -def get_tests(config={}): - tests = [] - tests += list_test_cases(TestIntegerInt) - - try: - from Crypto.Math._IntegerGMP import IntegerGMP - - class TestIntegerGMP(TestIntegerBase): - def setUp(self): - self.Integer = IntegerGMP - - tests += list_test_cases(TestIntegerGMP) - except (ImportError, OSError) as e: - if sys.platform == "win32": - sys.stdout.write("Skipping GMP tests on Windows\n") - else: - sys.stdout.write("Skipping GMP tests (%s)\n" % str(e) ) - - try: - from Crypto.Math._IntegerCustom import IntegerCustom - - class TestIntegerCustomModexp(TestIntegerBase): - def setUp(self): - self.Integer = IntegerCustom - - tests += list_test_cases(TestIntegerCustomModexp) - except (ImportError, OSError) as e: - sys.stdout.write("Skipping custom modexp tests (%s)\n" % str(e) ) - - tests += list_test_cases(testIntegerRandom) - return tests - -if __name__ == '__main__': - suite = lambda: unittest.TestSuite(get_tests()) - unittest.main(defaultTest='suite') diff --git a/Crypto/SelfTest/Math/test_Primality.py b/Crypto/SelfTest/Math/test_Primality.py deleted file mode 100644 index 38344f3..0000000 --- a/Crypto/SelfTest/Math/test_Primality.py +++ /dev/null @@ -1,118 +0,0 @@ -# -# SelfTest/Math/test_Primality.py: Self-test for Primality module -# -# =================================================================== -# -# Copyright (c) 2014, Legrandin -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# =================================================================== - -"""Self-test for Math.Numbers""" - -import unittest - -from Crypto.SelfTest.st_common import list_test_cases - -from Crypto.Util.py3compat import * - -from Crypto.Math.Numbers import Integer -from Crypto.Math.Primality import ( - PROBABLY_PRIME, COMPOSITE, - miller_rabin_test, lucas_test, - test_probable_prime, - generate_probable_prime, - generate_probable_safe_prime, - ) - - -class TestPrimality(unittest.TestCase): - - primes = (1, 2, 3, 5, 7, 11, 13, 17, 19, 23, 2**127-1, 175637383534939453397801320455508570374088202376942372758907369518414308188137781042871856139027160010343454418881888953150175357127346872102307696660678617989191485418582475696230580407111841072614783095326672517315988762029036079794994990250662362650625650262324085116467511357592728695033227611029693067539) - composites = (0, 4, 6, 8, 9, 10, 12, 14, 15, 16, 18, 20, 21, 7*23, (2**19-1)*(2**67-1), 9746347772161,) - - def test_miller_rabin(self): - for prime in self.primes: - self.assertEqual(miller_rabin_test(prime, 3), PROBABLY_PRIME) - for composite in self.composites: - self.assertEqual(miller_rabin_test(composite, 3), COMPOSITE) - self.assertRaises(ValueError, miller_rabin_test, -1, 3) - - def test_lucas(self): - for prime in self.primes: - res = lucas_test(prime) - self.assertEqual(res, PROBABLY_PRIME) - for composite in self.composites: - res = lucas_test(composite) - self.assertEqual(res, COMPOSITE) - self.assertRaises(ValueError, lucas_test, -1) - - def test_is_prime(self): - primes = (170141183460469231731687303715884105727, - 19175002942688032928599, - 1363005552434666078217421284621279933627102780881053358473, - 2 ** 521 - 1) - for p in primes: - self.assertEqual(test_probable_prime(p), PROBABLY_PRIME) - - not_primes = ( - 4754868377601046732119933839981363081972014948522510826417784001, - 1334733877147062382486934807105197899496002201113849920496510541601, - 260849323075371835669784094383812120359260783810157225730623388382401, - ) - for np in not_primes: - self.assertEqual(test_probable_prime(np), COMPOSITE) - - from Crypto.Util.number import sieve_base - for p in sieve_base[:100]: - res = test_probable_prime(p) - self.assertEqual(res, PROBABLY_PRIME) - - def test_generate_prime_bit_size(self): - p = generate_probable_prime(exact_bits=512) - self.assertEqual(p.size_in_bits(), 512) - - def test_generate_prime_filter(self): - def ending_with_one(number): - return number % 10 == 1 - - for x in range(20): - q = generate_probable_prime(exact_bits=160, - prime_filter=ending_with_one) - self.assertEqual(q % 10, 1) - - def test_generate_safe_prime(self): - p = generate_probable_safe_prime(exact_bits=161) - self.assertEqual(p.size_in_bits(), 161) - -def get_tests(config={}): - tests = [] - tests += list_test_cases(TestPrimality) - return tests - -if __name__ == '__main__': - suite = lambda: unittest.TestSuite(get_tests()) - unittest.main(defaultTest='suite') diff --git a/Crypto/SelfTest/Math/test_modexp.py b/Crypto/SelfTest/Math/test_modexp.py deleted file mode 100644 index b9eb869..0000000 --- a/Crypto/SelfTest/Math/test_modexp.py +++ /dev/null @@ -1,201 +0,0 @@ -# -# SelfTest/Math/test_modexp.py: Self-test for module exponentiation -# -# =================================================================== -# -# Copyright (c) 2017, Helder Eijs -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# =================================================================== - -"""Self-test for the custom module exponentiation""" - -import unittest - -from Crypto.SelfTest.st_common import list_test_cases - -from Crypto.Util.number import long_to_bytes, bytes_to_long - -from Crypto.Util.py3compat import * - -from Crypto.Util._raw_api import (load_pycryptodome_raw_lib, - create_string_buffer, - get_raw_buffer, - c_size_t, - c_ulonglong) - -from Crypto.Hash import SHAKE128 -from Crypto.Math.Numbers import Integer -from Crypto.Math._IntegerCustom import _raw_montgomery - -from Crypto.Random.random import StrongRandom - - -def create_rng(tag): - rng = StrongRandom(SHAKE128.new(data=tag)) - return rng - -class ExceptionModulus(ValueError): - pass - -def monty_pow(base, exp, modulus): - max_len = len(long_to_bytes(max(base, exp, modulus))) - - base_b, exp_b, modulus_b = [ long_to_bytes(x, max_len) for x in - (base, exp, modulus) ] - - out = create_string_buffer(max_len) - error = _raw_montgomery.monty_pow( - out, - base_b, - exp_b, - modulus_b, - c_size_t(max_len), - c_ulonglong(32) - ) - - if error == 17: - raise ExceptionModulus() - if error: - raise ValueError("monty_pow failed with error: %d" % error) - - result = bytes_to_long(get_raw_buffer(out)) - return result - -exponent1 = 0x2ce0af628901460a419a08ef950d498b9fd6f271a1a52ac293b86fe5c60efe8e8ba93fa1ebe1eb3d614d2e7b328cb60a2591440e163441a190ecf101ceec245f600fffdcf3f5b3a17a7baeacb96a424db1d7ec985e8ec998bb479fecfffed6a75f9a90fc97062fd973303bce855ad7b8d8272a94025e8532be9aabd54a183f303538d2a7e621b4131d59e823a4625f39bd7d518d7784f7c3a8f19061da74974ff42fa1c063dec2db97d461e291a7d6e721708a5229de166c1246363372854e27f3f08ae274bc16bfd205b028a4d81386494433d516dfbb35f495acba5e4e1d1843cb3c3129b6642a85fc7244ce5845fac071c7f622e4ee12ac43fabeeaa0cd01 -modulus1 = 0xd66691b20071be4d66d4b71032b37fa007cfabf579fcb91e50bfc2753b3f0ce7be74e216aef7e26d4ae180bc20d7bd3ea88a6cbf6f87380e613c8979b5b043b200a8ff8856a3b12875e36e98a7569f3852d028e967551000b02c19e9fa52e83115b89309aabb1e1cf1e2cb6369d637d46775ce4523ea31f64ad2794cbc365dd8a35e007ed3b57695877fbf102dbeb8b3212491398e494314e93726926e1383f8abb5889bea954eb8c0ca1c62c8e9d83f41888095c5e645ed6d32515fe0c58c1368cad84694e18da43668c6f43e61d7c9bca633ddcda7aef5b79bc396d4a9f48e2a9abe0836cc455e435305357228e93d25aaed46b952defae0f57339bf26f5a9 - - -class TestModExp(unittest.TestCase): - - def test_small(self): - self.assertEqual(1, monty_pow(11,12,19)) - - def test_large_1(self): - base = 0xfffffffffffffffffffffffffffffffffffffffffffffffffff - expected = pow(base, exponent1, modulus1) - result = monty_pow(base, exponent1, modulus1) - self.assertEqual(result, expected) - - def test_zero_exp(self): - base = 0xfffffffffffffffffffffffffffffffffffffffffffffffffff - result = monty_pow(base, 0, modulus1) - self.assertEqual(result, 1) - - def test_zero_base(self): - result = monty_pow(0, exponent1, modulus1) - self.assertEqual(result, 0) - - def test_zero_modulus(self): - base = 0xfffffffffffffffffffffffffffffffffffffffffffffffff - self.assertRaises(ExceptionModulus, monty_pow, base, exponent1, 0) - self.assertRaises(ExceptionModulus, monty_pow, 0, 0, 0) - - def test_larger_exponent(self): - base = modulus1 - 0xFFFFFFF - expected = pow(base, modulus1<<64, modulus1) - result = monty_pow(base, modulus1<<64, modulus1) - self.assertEqual(result, expected) - - def test_even_modulus(self): - base = modulus1 >> 4 - self.assertRaises(ExceptionModulus, monty_pow, base, exponent1, modulus1-1) - - def test_several_lengths(self): - prng = SHAKE128.new().update(b('Test')) - for length in range(1, 100): - modulus2 = Integer.from_bytes(prng.read(length)) | 1 - base = Integer.from_bytes(prng.read(length)) % modulus2 - exponent2 = Integer.from_bytes(prng.read(length)) - - expected = pow(base, exponent2, modulus2) - result = monty_pow(base, exponent2, modulus2) - self.assertEqual(result, expected) - - def test_variable_exponent(self): - prng = create_rng(b('Test variable exponent')) - for i in range(20): - for j in range(7): - modulus = prng.getrandbits(8*30) | 1 - base = prng.getrandbits(8*30) % modulus - exponent = prng.getrandbits(i*8+j) - - expected = pow(base, exponent, modulus) - result = monty_pow(base, exponent, modulus) - self.assertEqual(result, expected) - - exponent ^= (1 << (i*8+j)) - 1 - - expected = pow(base, exponent, modulus) - result = monty_pow(base, exponent, modulus) - self.assertEqual(result, expected) - - def test_stress_63(self): - prng = create_rng(b('Test 63')) - length = 63 - for _ in range(2000): - modulus = prng.getrandbits(8*length) | 1 - base = prng.getrandbits(8*length) % modulus - exponent = prng.getrandbits(8*length) - - expected = pow(base, exponent, modulus) - result = monty_pow(base, exponent, modulus) - self.assertEqual(result, expected) - - def test_stress_64(self): - prng = create_rng(b('Test 64')) - length = 64 - for _ in range(2000): - modulus = prng.getrandbits(8*length) | 1 - base = prng.getrandbits(8*length) % modulus - exponent = prng.getrandbits(8*length) - - expected = pow(base, exponent, modulus) - result = monty_pow(base, exponent, modulus) - self.assertEqual(result, expected) - - def test_stress_65(self): - prng = create_rng(b('Test 65')) - length = 65 - for _ in range(2000): - modulus = prng.getrandbits(8*length) | 1 - base = prng.getrandbits(8*length) % modulus - exponent = prng.getrandbits(8*length) - - expected = pow(base, exponent, modulus) - result = monty_pow(base, exponent, modulus) - self.assertEqual(result, expected) - - -def get_tests(config={}): - tests = [] - tests += list_test_cases(TestModExp) - return tests - - -if __name__ == '__main__': - suite = lambda: unittest.TestSuite(get_tests()) - unittest.main(defaultTest='suite') diff --git a/Crypto/SelfTest/Protocol/__init__.py b/Crypto/SelfTest/Protocol/__init__.py deleted file mode 100644 index 1c1c095..0000000 --- a/Crypto/SelfTest/Protocol/__init__.py +++ /dev/null @@ -1,44 +0,0 @@ -# -*- coding: utf-8 -*- -# -# SelfTest/Protocol/__init__.py: Self-tests for Crypto.Protocol -# -# Written in 2008 by Dwayne C. Litzenberger -# -# =================================================================== -# The contents of this file are dedicated to the public domain. To -# the extent that dedication to the public domain is not available, -# everyone is granted a worldwide, perpetual, royalty-free, -# non-exclusive license to exercise all rights associated with the -# contents of this file for any purpose whatsoever. -# No rights are reserved. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS -# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN -# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# =================================================================== - -"""Self-test for Crypto.Protocol""" - -__revision__ = "$Id$" - -def get_tests(config={}): - tests = [] - from Crypto.SelfTest.Protocol import test_rfc1751; tests += test_rfc1751.get_tests(config=config) - from Crypto.SelfTest.Protocol import test_KDF; tests += test_KDF.get_tests(config=config) - - from Crypto.SelfTest.Protocol import test_SecretSharing; - tests += test_SecretSharing.get_tests(config=config) - - return tests - -if __name__ == '__main__': - import unittest - suite = lambda: unittest.TestSuite(get_tests()) - unittest.main(defaultTest='suite') - -# vim:set ts=4 sw=4 sts=4 expandtab: diff --git a/Crypto/SelfTest/Protocol/__pycache__/__init__.cpython-36.pyc b/Crypto/SelfTest/Protocol/__pycache__/__init__.cpython-36.pyc deleted file mode 100644 index 9f84cf670f72b083f77342975cd2ccf4a83f4917..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 790 zcmZ8eL2KJE6qaP!aS{hYPuro;LoPlvrj#u^lrrcTj6oR7E;9q+TC(fZv4f-(Qj$}9 z?GM?n+1=Nj_7`^Adrq^3Nxa9?`=s~2@9BIn=uN(kk{=!+Kgq#zAbtyGF2G3=6G>xQ zkc>(uoktoo9 z>Gjgq<4?M_by}DAeDpz%QVM-=xnLaZ3e0>1my<1((6%HCx@DAX=!VVNhDhg$PIedv z%-K3E=KP1bfblJFF@A_`D3J4}zn}#PX%iqnp|kXC^6CuEURqaKkwfIS$j5i@AwFv3 znM$>?vztU0RUW$Wi)Trw^9z*ut4%W~-gI+i1wJ$ym1&e1x*A8^xVt>w`v-m}+K0sN z&(U3?qcW-TXt}mGb#)$<#q~ZOzm7~{)#)-xZ@cZl1@XX@mJ6Y zCBma9@-zJ!#)rkrsW^n8l@4{E!) A3;+NC diff --git a/Crypto/SelfTest/Protocol/__pycache__/test_KDF.cpython-36.pyc b/Crypto/SelfTest/Protocol/__pycache__/test_KDF.cpython-36.pyc deleted file mode 100644 index 43eb404e80acf3e9fdc389635681fa94b5b05b91..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 28548 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 DUukX4 diff --git a/Crypto/SelfTest/Protocol/test_KDF.py b/Crypto/SelfTest/Protocol/test_KDF.py deleted file mode 100644 index b2869f8..0000000 --- a/Crypto/SelfTest/Protocol/test_KDF.py +++ /dev/null @@ -1,732 +0,0 @@ -# -*- coding: utf-8 -*- -# -# SelfTest/Protocol/test_KDF.py: Self-test for key derivation functions -# -# =================================================================== -# The contents of this file are dedicated to the public domain. To -# the extent that dedication to the public domain is not available, -# everyone is granted a worldwide, perpetual, royalty-free, -# non-exclusive license to exercise all rights associated with the -# contents of this file for any purpose whatsoever. -# No rights are reserved. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS -# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN -# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# =================================================================== - -import unittest -from binascii import unhexlify - -from Crypto.Util.py3compat import b, bchr - -from Crypto.SelfTest.st_common import list_test_cases -from Crypto.SelfTest.loader import load_test_vectors_wycheproof -from Crypto.Hash import SHA1, HMAC, SHA256, MD5, SHA224, SHA384, SHA512 -from Crypto.Cipher import AES, DES3 - -from Crypto.Protocol.KDF import (PBKDF1, PBKDF2, _S2V, HKDF, scrypt, - bcrypt, bcrypt_check) - -from Crypto.Protocol.KDF import _bcrypt_decode - - -def t2b(t): - if t is None: - return None - t2 = t.replace(" ", "").replace("\n", "") - return unhexlify(b(t2)) - - -class TestVector(object): - pass - - -class PBKDF1_Tests(unittest.TestCase): - - # List of tuples with test data. - # Each tuple is made up by: - # Item #0: a pass phrase - # Item #1: salt (8 bytes encoded in hex) - # Item #2: output key length - # Item #3: iterations to use - # Item #4: expected result (encoded in hex) - _testData = ( - # From http://www.di-mgt.com.au/cryptoKDFs.html#examplespbkdf - ("password", "78578E5A5D63CB06", 16, 1000, "DC19847E05C64D2FAF10EBFB4A3D2A20"), - ) - - def test1(self): - v = self._testData[0] - res = PBKDF1(v[0], t2b(v[1]), v[2], v[3], SHA1) - self.assertEqual(res, t2b(v[4])) - - -class PBKDF2_Tests(unittest.TestCase): - - # List of tuples with test data. - # Each tuple is made up by: - # Item #0: a pass phrase - # Item #1: salt (encoded in hex) - # Item #2: output key length - # Item #3: iterations to use - # Item #4: hash module - # Item #5: expected result (encoded in hex) - _testData = ( - # From http://www.di-mgt.com.au/cryptoKDFs.html#examplespbkdf - ("password","78578E5A5D63CB06",24,2048, SHA1, "BFDE6BE94DF7E11DD409BCE20A0255EC327CB936FFE93643"), - # From RFC 6050 - ("password","73616c74", 20, 1, SHA1, "0c60c80f961f0e71f3a9b524af6012062fe037a6"), - ("password","73616c74", 20, 2, SHA1, "ea6c014dc72d6f8ccd1ed92ace1d41f0d8de8957"), - ("password","73616c74", 20, 4096, SHA1, "4b007901b765489abead49d926f721d065a429c1"), - ("passwordPASSWORDpassword","73616c7453414c5473616c7453414c5473616c7453414c5473616c7453414c5473616c74", - 25, 4096, SHA1, "3d2eec4fe41c849b80c8d83662c0e44a8b291a964cf2f07038"), - ( 'pass\x00word',"7361006c74",16,4096, SHA1, "56fa6aa75548099dcc37d7f03425e0c3"), - # From draft-josefsson-scrypt-kdf-01, Chapter 10 - ( 'passwd', '73616c74', 64, 1, SHA256, "55ac046e56e3089fec1691c22544b605f94185216dde0465e68b9d57c20dacbc49ca9cccf179b645991664b39d77ef317c71b845b1e30bd509112041d3a19783"), - ( 'Password', '4e61436c', 64, 80000, SHA256, "4ddcd8f60b98be21830cee5ef22701f9641a4418d04c0414aeff08876b34ab56a1d425a1225833549adb841b51c9b3176a272bdebba1d078478f62b397f33c8d"), - ) - - def test1(self): - # Test only for HMAC-SHA1 as PRF - - def prf_SHA1(p,s): - return HMAC.new(p,s,SHA1).digest() - - def prf_SHA256(p,s): - return HMAC.new(p,s,SHA256).digest() - - for i in range(len(self._testData)): - v = self._testData[i] - password = v[0] - salt = t2b(v[1]) - out_len = v[2] - iters = v[3] - hash_mod = v[4] - expected = t2b(v[5]) - - if hash_mod is SHA1: - res = PBKDF2(password, salt, out_len, iters) - self.assertEqual(res, expected) - - res = PBKDF2(password, salt, out_len, iters, prf_SHA1) - self.assertEqual(res, expected) - else: - res = PBKDF2(password, salt, out_len, iters, prf_SHA256) - self.assertEqual(res, expected) - - def test2(self): - # Verify that prf and hmac_hash_module are mutual exclusive - def prf_SHA1(p,s): - return HMAC.new(p,s,SHA1).digest() - - self.assertRaises(ValueError, PBKDF2, b("xxx"), b("yyy"), 16, 100, - prf=prf_SHA1, hmac_hash_module=SHA1) - - def test3(self): - # Verify that hmac_hash_module works like prf - - password = b("xxx") - salt = b("yyy") - - for hashmod in (MD5, SHA1, SHA224, SHA256, SHA384, SHA512): - - pr1 = PBKDF2(password, salt, 16, 100, - prf=lambda p, s: HMAC.new(p,s,hashmod).digest()) - pr2 = PBKDF2(password, salt, 16, 100, hmac_hash_module=hashmod) - - self.assertEqual(pr1, pr2) - - def test4(self): - # Verify that PBKDF2 can take bytes or strings as password or salt - k1 = PBKDF2("xxx", b("yyy"), 16, 10) - k2 = PBKDF2(b("xxx"), b("yyy"), 16, 10) - self.assertEqual(k1, k2) - - k1 = PBKDF2(b("xxx"), "yyy", 16, 10) - k2 = PBKDF2(b("xxx"), b("yyy"), 16, 10) - self.assertEqual(k1, k2) - - -class S2V_Tests(unittest.TestCase): - - # Sequence of test vectors. - # Each test vector is made up by: - # Item #0: a tuple of strings - # Item #1: an AES key - # Item #2: the result - # Item #3: the cipher module S2V is based on - # Everything is hex encoded - _testData = [ - - # RFC5297, A.1 - ( - ( '101112131415161718191a1b1c1d1e1f2021222324252627', - '112233445566778899aabbccddee' ), - 'fffefdfcfbfaf9f8f7f6f5f4f3f2f1f0', - '85632d07c6e8f37f950acd320a2ecc93', - AES - ), - - # RFC5297, A.2 - ( - ( '00112233445566778899aabbccddeeffdeaddadadeaddadaffeeddcc'+ - 'bbaa99887766554433221100', - '102030405060708090a0', - '09f911029d74e35bd84156c5635688c0', - '7468697320697320736f6d6520706c61'+ - '696e7465787420746f20656e63727970'+ - '74207573696e67205349562d414553'), - '7f7e7d7c7b7a79787776757473727170', - '7bdb6e3b432667eb06f4d14bff2fbd0f', - AES - ), - - ] - - def test1(self): - """Verify correctness of test vector""" - for tv in self._testData: - s2v = _S2V.new(t2b(tv[1]), tv[3]) - for s in tv[0]: - s2v.update(t2b(s)) - result = s2v.derive() - self.assertEqual(result, t2b(tv[2])) - - def test2(self): - """Verify that no more than 127(AES) and 63(TDES) - components are accepted.""" - key = bchr(0) * 8 + bchr(255) * 8 - for module in (AES, DES3): - s2v = _S2V.new(key, module) - max_comps = module.block_size*8-1 - for i in range(max_comps): - s2v.update(b("XX")) - self.assertRaises(TypeError, s2v.update, b("YY")) - - -class HKDF_Tests(unittest.TestCase): - - # Test vectors from RFC5869, Appendix A - # Each tuple is made up by: - # Item #0: hash module - # Item #1: secret - # Item #2: salt - # Item #3: context - # Item #4: expected result - _test_vector = ( - ( - SHA256, - "0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b", - "000102030405060708090a0b0c", - "f0f1f2f3f4f5f6f7f8f9", - 42, - "3cb25f25faacd57a90434f64d0362f2a" + - "2d2d0a90cf1a5a4c5db02d56ecc4c5bf" + - "34007208d5b887185865" - ), - ( - SHA256, - "000102030405060708090a0b0c0d0e0f" + - "101112131415161718191a1b1c1d1e1f" + - "202122232425262728292a2b2c2d2e2f" + - "303132333435363738393a3b3c3d3e3f" + - "404142434445464748494a4b4c4d4e4f", - "606162636465666768696a6b6c6d6e6f" + - "707172737475767778797a7b7c7d7e7f" + - "808182838485868788898a8b8c8d8e8f" + - "909192939495969798999a9b9c9d9e9f" + - "a0a1a2a3a4a5a6a7a8a9aaabacadaeaf", - "b0b1b2b3b4b5b6b7b8b9babbbcbdbebf" + - "c0c1c2c3c4c5c6c7c8c9cacbcccdcecf" + - "d0d1d2d3d4d5d6d7d8d9dadbdcdddedf" + - "e0e1e2e3e4e5e6e7e8e9eaebecedeeef" + - "f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", - 82, - "b11e398dc80327a1c8e7f78c596a4934" + - "4f012eda2d4efad8a050cc4c19afa97c" + - "59045a99cac7827271cb41c65e590e09" + - "da3275600c2f09b8367793a9aca3db71" + - "cc30c58179ec3e87c14c01d5c1f3434f" + - "1d87" - ), - ( - SHA256, - "0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b", - None, - None, - 42, - "8da4e775a563c18f715f802a063c5a31" + - "b8a11f5c5ee1879ec3454e5f3c738d2d" + - "9d201395faa4b61a96c8" - ), - ( - SHA1, - "0b0b0b0b0b0b0b0b0b0b0b", - "000102030405060708090a0b0c", - "f0f1f2f3f4f5f6f7f8f9", - 42, - "085a01ea1b10f36933068b56efa5ad81" + - "a4f14b822f5b091568a9cdd4f155fda2" + - "c22e422478d305f3f896" - ), - ( - SHA1, - "000102030405060708090a0b0c0d0e0f" + - "101112131415161718191a1b1c1d1e1f" + - "202122232425262728292a2b2c2d2e2f" + - "303132333435363738393a3b3c3d3e3f" + - "404142434445464748494a4b4c4d4e4f", - "606162636465666768696a6b6c6d6e6f" + - "707172737475767778797a7b7c7d7e7f" + - "808182838485868788898a8b8c8d8e8f" + - "909192939495969798999a9b9c9d9e9f" + - "a0a1a2a3a4a5a6a7a8a9aaabacadaeaf", - "b0b1b2b3b4b5b6b7b8b9babbbcbdbebf" + - "c0c1c2c3c4c5c6c7c8c9cacbcccdcecf" + - "d0d1d2d3d4d5d6d7d8d9dadbdcdddedf" + - "e0e1e2e3e4e5e6e7e8e9eaebecedeeef" + - "f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", - 82, - "0bd770a74d1160f7c9f12cd5912a06eb" + - "ff6adcae899d92191fe4305673ba2ffe" + - "8fa3f1a4e5ad79f3f334b3b202b2173c" + - "486ea37ce3d397ed034c7f9dfeb15c5e" + - "927336d0441f4c4300e2cff0d0900b52" + - "d3b4" - ), - ( - SHA1, - "0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b", - "", - "", - 42, - "0ac1af7002b3d761d1e55298da9d0506" + - "b9ae52057220a306e07b6b87e8df21d0" + - "ea00033de03984d34918" - ), - ( - SHA1, - "0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c", - None, - "", - 42, - "2c91117204d745f3500d636a62f64f0a" + - "b3bae548aa53d423b0d1f27ebba6f5e5" + - "673a081d70cce7acfc48" - ) - ) - - def test1(self): - for tv in self._test_vector: - secret, salt, info, exp = [ t2b(tv[x]) for x in (1,2,3,5) ] - key_len, hashmod = [ tv[x] for x in (4,0) ] - - output = HKDF(secret, key_len, salt, hashmod, 1, info) - self.assertEqual(output, exp) - - def test2(self): - ref = HKDF(b("XXXXXX"), 12, b("YYYY"), SHA1) - - # Same output, but this time split over 2 keys - key1, key2 = HKDF(b("XXXXXX"), 6, b("YYYY"), SHA1, 2) - self.assertEqual((ref[:6], ref[6:]), (key1, key2)) - - # Same output, but this time split over 3 keys - key1, key2, key3 = HKDF(b("XXXXXX"), 4, b("YYYY"), SHA1, 3) - self.assertEqual((ref[:4], ref[4:8], ref[8:]), (key1, key2, key3)) - - -class scrypt_Tests(unittest.TestCase): - - # Test vectors taken from - # https://tools.ietf.org/html/rfc7914 - # - password - # - salt - # - N - # - r - # - p - data = ( - ( - "", - "", - 16, # 2K - 1, - 1, - """ - 77 d6 57 62 38 65 7b 20 3b 19 ca 42 c1 8a 04 97 - f1 6b 48 44 e3 07 4a e8 df df fa 3f ed e2 14 42 - fc d0 06 9d ed 09 48 f8 32 6a 75 3a 0f c8 1f 17 - e8 d3 e0 fb 2e 0d 36 28 cf 35 e2 0c 38 d1 89 06 - """ - ), - ( - "password", - "NaCl", - 1024, # 1M - 8, - 16, - """ - fd ba be 1c 9d 34 72 00 78 56 e7 19 0d 01 e9 fe - 7c 6a d7 cb c8 23 78 30 e7 73 76 63 4b 37 31 62 - 2e af 30 d9 2e 22 a3 88 6f f1 09 27 9d 98 30 da - c7 27 af b9 4a 83 ee 6d 83 60 cb df a2 cc 06 40 - """ - ), - ( - "pleaseletmein", - "SodiumChloride", - 16384, # 16M - 8, - 1, - """ - 70 23 bd cb 3a fd 73 48 46 1c 06 cd 81 fd 38 eb - fd a8 fb ba 90 4f 8e 3e a9 b5 43 f6 54 5d a1 f2 - d5 43 29 55 61 3f 0f cf 62 d4 97 05 24 2a 9a f9 - e6 1e 85 dc 0d 65 1e 40 df cf 01 7b 45 57 58 87 - """ - ), - ( - "pleaseletmein", - "SodiumChloride", - 1048576, # 1G - 8, - 1, - """ - 21 01 cb 9b 6a 51 1a ae ad db be 09 cf 70 f8 81 - ec 56 8d 57 4a 2f fd 4d ab e5 ee 98 20 ad aa 47 - 8e 56 fd 8f 4b a5 d0 9f fa 1c 6d 92 7c 40 f4 c3 - 37 30 40 49 e8 a9 52 fb cb f4 5c 6f a7 7a 41 a4 - """ - ), - ) - - def setUp(self): - new_test_vectors = [] - for tv in self.data: - new_tv = TestVector() - new_tv.P = b(tv[0]) - new_tv.S = b(tv[1]) - new_tv.N = tv[2] - new_tv.r = tv[3] - new_tv.p = tv[4] - new_tv.output = t2b(tv[5]) - new_tv.dkLen = len(new_tv.output) - new_test_vectors.append(new_tv) - self.data = new_test_vectors - - def test2(self): - - for tv in self.data: - try: - output = scrypt(tv.P, tv.S, tv.dkLen, tv.N, tv.r, tv.p) - except ValueError as e: - if " 2 " in str(e) and tv.N >= 1048576: - import warnings - warnings.warn("Not enough memory to unit test scrypt() with N=1048576", RuntimeWarning) - continue - else: - raise e - self.assertEqual(output, tv.output) - - def test3(self): - ref = scrypt(b("password"), b("salt"), 12, 16, 1, 1) - - # Same output, but this time split over 2 keys - key1, key2 = scrypt(b("password"), b("salt"), 6, 16, 1, 1, 2) - self.assertEqual((ref[:6], ref[6:]), (key1, key2)) - - # Same output, but this time split over 3 keys - key1, key2, key3 = scrypt(b("password"), b("salt"), 4, 16, 1, 1, 3) - self.assertEqual((ref[:4], ref[4:8], ref[8:]), (key1, key2, key3)) - - -class bcrypt_Tests(unittest.TestCase): - - def test_negative_cases(self): - self.assertRaises(ValueError, bcrypt, b"1" * 73, 10) - self.assertRaises(ValueError, bcrypt, b"1" * 10, 3) - self.assertRaises(ValueError, bcrypt, b"1" * 10, 32) - self.assertRaises(ValueError, bcrypt, b"1" * 10, 4, salt=b"") - self.assertRaises(ValueError, bcrypt, b"1" * 10, 4, salt=b"1") - self.assertRaises(ValueError, bcrypt, b"1" * 10, 4, salt=b"1" * 17) - self.assertRaises(ValueError, bcrypt, b"1\x00" * 10, 4) - - def test_bytearray_mismatch(self): - ref = bcrypt("pwd", 4) - bcrypt_check("pwd", ref) - bref = bytearray(ref) - bcrypt_check("pwd", bref) - - wrong = ref[:-1] + bchr(bref[-1] ^ 0x01) - self.assertRaises(ValueError, bcrypt_check, "pwd", wrong) - - wrong = b"x" + ref[1:] - self.assertRaises(ValueError, bcrypt_check, "pwd", wrong) - - # https://github.com/patrickfav/bcrypt/wiki/Published-Test-Vectors - - def test_empty_password(self): - # password, cost, salt, bcrypt hash - tvs = [ - (b"", 4, b"zVHmKQtGGQob.b/Nc7l9NO", b"$2a$04$zVHmKQtGGQob.b/Nc7l9NO8UlrYcW05FiuCj/SxsFO/ZtiN9.mNzy"), - (b"", 5, b"zVHmKQtGGQob.b/Nc7l9NO", b"$2a$05$zVHmKQtGGQob.b/Nc7l9NOWES.1hkVBgy5IWImh9DOjKNU8atY4Iy"), - (b"", 6, b"zVHmKQtGGQob.b/Nc7l9NO", b"$2a$06$zVHmKQtGGQob.b/Nc7l9NOjOl7l4oz3WSh5fJ6414Uw8IXRAUoiaO"), - (b"", 7, b"zVHmKQtGGQob.b/Nc7l9NO", b"$2a$07$zVHmKQtGGQob.b/Nc7l9NOBsj1dQpBA1HYNGpIETIByoNX9jc.hOi"), - (b"", 8, b"zVHmKQtGGQob.b/Nc7l9NO", b"$2a$08$zVHmKQtGGQob.b/Nc7l9NOiLTUh/9MDpX86/DLyEzyiFjqjBFePgO"), - ] - - for (idx, (password, cost, salt64, result)) in enumerate(tvs): - x = bcrypt(password, cost, salt=_bcrypt_decode(salt64)) - self.assertEqual(x, result) - bcrypt_check(password, result) - - def test_random_password_and_salt_short_pw(self): - # password, cost, salt, bcrypt hash - tvs = [ - (b"<.S.2K(Zq'", 4, b"VYAclAMpaXY/oqAo9yUpku", b"$2a$04$VYAclAMpaXY/oqAo9yUpkuWmoYywaPzyhu56HxXpVltnBIfmO9tgu"), - (b"5.rApO%5jA", 5, b"kVNDrnYKvbNr5AIcxNzeIu", b"$2a$05$kVNDrnYKvbNr5AIcxNzeIuRcyIF5cZk6UrwHGxENbxP5dVv.WQM/G"), - (b"oW++kSrQW^", 6, b"QLKkRMH9Am6irtPeSKN5sO", b"$2a$06$QLKkRMH9Am6irtPeSKN5sObJGr3j47cO6Pdf5JZ0AsJXuze0IbsNm"), - (b"ggJ\\KbTnDG", 7, b"4H896R09bzjhapgCPS/LYu", b"$2a$07$4H896R09bzjhapgCPS/LYuMzAQluVgR5iu/ALF8L8Aln6lzzYXwbq"), - (b"49b0:;VkH/", 8, b"hfvO2retKrSrx5f2RXikWe", b"$2a$08$hfvO2retKrSrx5f2RXikWeFWdtSesPlbj08t/uXxCeZoHRWDz/xFe"), - (b">9N^5jc##'", 9, b"XZLvl7rMB3EvM0c1.JHivu", b"$2a$09$XZLvl7rMB3EvM0c1.JHivuIDPJWeNJPTVrpjZIEVRYYB/mF6cYgJK"), - (b"\\$ch)s4WXp", 10, b"aIjpMOLK5qiS9zjhcHR5TO", b"$2a$10$aIjpMOLK5qiS9zjhcHR5TOU7v2NFDmcsBmSFDt5EHOgp/jeTF3O/q"), - (b"RYoj\\_>2P7", 12, b"esIAHiQAJNNBrsr5V13l7.", b"$2a$12$esIAHiQAJNNBrsr5V13l7.RFWWJI2BZFtQlkFyiWXjou05GyuREZa"), - ] - - for (idx, (password, cost, salt64, result)) in enumerate(tvs): - x = bcrypt(password, cost, salt=_bcrypt_decode(salt64)) - self.assertEqual(x, result) - bcrypt_check(password, result) - - def test_random_password_and_salt_long_pw(self): - # password, cost, salt, bcrypt hash - tvs = [ - (b"^Q&\"]A`%/A(BVGt>QaX0M-#1ghq_+\":Y0CRmY", 5, b"YuQvhokOGVnevctykUYpKu", b"$2a$05$YuQvhokOGVnevctykUYpKutZD2pWeGGYn3auyLOasguMY3/0BbIyq"), - (b"F%uN/j>[GuB7-jB'_Yj!Tnb7Y!u^6)", 6, b"5L3vpQ0tG9O7k5gQ8nAHAe", b"$2a$06$5L3vpQ0tG9O7k5gQ8nAHAe9xxQiOcOLh8LGcI0PLWhIznsDt.S.C6"), - (b"Z>BobP32ub\"Cfe*Q<-q-=tRSjOBh8\\mLNW.", 9, b"nArqOfdCsD9kIbVnAixnwe", b"$2a$09$nArqOfdCsD9kIbVnAixnwe6s8QvyPYWtQBpEXKir2OJF9/oNBsEFe"), - (b"/MH51`!BP&0tj3%YCA;Xk%e3S`o\\EI", 10, b"ePiAc.s.yoBi3B6p1iQUCe", b"$2a$10$ePiAc.s.yoBi3B6p1iQUCezn3mraLwpVJ5XGelVyYFKyp5FZn/y.u"), - (b"ptAP\"mcg6oH.\";c0U2_oll.OKi5?Ui\"^ai#iQH7ZFtNMfs3AROnIncE9\"BNNoEgO[[*Yk8;RQ(#S,;I+aT", - 5, b"wgkOlGNXIVE2fWkT3gyRoO", b"$2a$05$wgkOlGNXIVE2fWkT3gyRoOqWi4gbi1Wv2Q2Jx3xVs3apl1w.Wtj8C"), - (b"M.E1=dt<.L0Q&p;94NfGm_Oo23+Kpl@M5?WIAL.[@/:'S)W96G8N^AWb7_smmC]>7#fGoB", - 6, b"W9zTCl35nEvUukhhFzkKMe", b"$2a$06$W9zTCl35nEvUukhhFzkKMekjT9/pj7M0lihRVEZrX3m8/SBNZRX7i"), - ] - - for (idx, (password, cost, salt64, result)) in enumerate(tvs): - x = bcrypt(password, cost, salt=_bcrypt_decode(salt64)) - self.assertEqual(x, result) - bcrypt_check(password, result) - - def test_increasing_password_length(self): - # password, cost, salt, bcrypt hash - tvs = [ - (b"a", 4, b"5DCebwootqWMCp59ISrMJ.", b"$2a$04$5DCebwootqWMCp59ISrMJ.l4WvgHIVg17ZawDIrDM2IjlE64GDNQS"), - (b"aa", 4, b"5DCebwootqWMCp59ISrMJ.", b"$2a$04$5DCebwootqWMCp59ISrMJ.AyUxBk.ThHlsLvRTH7IqcG7yVHJ3SXq"), - (b"aaa", 4, b"5DCebwootqWMCp59ISrMJ.", b"$2a$04$5DCebwootqWMCp59ISrMJ.BxOVac5xPB6XFdRc/ZrzM9FgZkqmvbW"), - (b"aaaa", 4, b"5DCebwootqWMCp59ISrMJ.", b"$2a$04$5DCebwootqWMCp59ISrMJ.Qbr209bpCtfl5hN7UQlG/L4xiD3AKau"), - (b"aaaaa", 4, b"5DCebwootqWMCp59ISrMJ.", b"$2a$04$5DCebwootqWMCp59ISrMJ.oWszihPjDZI0ypReKsaDOW1jBl7oOii"), - (b"aaaaaa", 4, b"5DCebwootqWMCp59ISrMJ.", b"$2a$04$5DCebwootqWMCp59ISrMJ./k.Xxn9YiqtV/sxh3EHbnOHd0Qsq27K"), - (b"aaaaaaa", 4, b"5DCebwootqWMCp59ISrMJ.", b"$2a$04$5DCebwootqWMCp59ISrMJ.PYJqRFQbgRbIjMd5VNKmdKS4sBVOyDe"), - (b"aaaaaaaa", 4, b"5DCebwootqWMCp59ISrMJ.", b"$2a$04$5DCebwootqWMCp59ISrMJ..VMYfzaw1wP/SGxowpLeGf13fxCCt.q"), - (b"aaaaaaaaa", 4, b"5DCebwootqWMCp59ISrMJ.", b"$2a$04$5DCebwootqWMCp59ISrMJ.5B0p054nO5WgAD1n04XslDY/bqY9RJi"), - (b"aaaaaaaaaa", 4, b"5DCebwootqWMCp59ISrMJ.", b"$2a$04$5DCebwootqWMCp59ISrMJ.INBTgqm7sdlBJDg.J5mLMSRK25ri04y"), - (b"aaaaaaaaaaa", 4, b"5DCebwootqWMCp59ISrMJ.", b"$2a$04$5DCebwootqWMCp59ISrMJ.s3y7CdFD0OR5p6rsZw/eZ.Dla40KLfm"), - (b"aaaaaaaaaaaa", 4, b"5DCebwootqWMCp59ISrMJ.", b"$2a$04$5DCebwootqWMCp59ISrMJ.Jx742Djra6Q7PqJWnTAS.85c28g.Siq"), - (b"aaaaaaaaaaaaa", 4, b"5DCebwootqWMCp59ISrMJ.", b"$2a$04$5DCebwootqWMCp59ISrMJ.oKMXW3EZcPHcUV0ib5vDBnh9HojXnLu"), - (b"aaaaaaaaaaaaaa", 4, b"5DCebwootqWMCp59ISrMJ.", b"$2a$04$5DCebwootqWMCp59ISrMJ.w6nIjWpDPNSH5pZUvLjC1q25ONEQpeS"), - (b"aaaaaaaaaaaaaaa", 4, b"5DCebwootqWMCp59ISrMJ.", b"$2a$04$5DCebwootqWMCp59ISrMJ.k1b2/r9A/hxdwKEKurg6OCn4MwMdiGq"), - (b"aaaaaaaaaaaaaaaa", 4, b"5DCebwootqWMCp59ISrMJ.", b"$2a$04$5DCebwootqWMCp59ISrMJ.3prCNHVX1Ws.7Hm2bJxFUnQOX9f7DFa"), - ] - - for (idx, (password, cost, salt64, result)) in enumerate(tvs): - x = bcrypt(password, cost, salt=_bcrypt_decode(salt64)) - self.assertEqual(x, result) - bcrypt_check(password, result) - - def test_non_ascii_characters(self): - # password, cost, salt, bcrypt hash - tvs = [ - ("àèìòùÀÈÌÒÙáéíóúýÁÉÍÓÚÝðÐ", 4, b"D3qS2aoTVyqM7z8v8crLm.", b"$2a$04$D3qS2aoTVyqM7z8v8crLm.3nKt4CzBZJbyFB.ZebmfCvRw7BGs.Xm"), - ("àèìòùÀÈÌÒÙáéíóúýÁÉÍÓÚÝðÐ", 5, b"VA1FujiOCMPkUHQ8kF7IaO", b"$2a$05$VA1FujiOCMPkUHQ8kF7IaOg7NGaNvpxwWzSluQutxEVmbZItRTsAa"), - ("àèìòùÀÈÌÒÙáéíóúýÁÉÍÓÚÝðÐ", 6, b"TXiaNrPeBSz5ugiQlehRt.", b"$2a$06$TXiaNrPeBSz5ugiQlehRt.gwpeDQnXWteQL4z2FulouBr6G7D9KUi"), - ("âêîôûÂÊÎÔÛãñõÃÑÕäëïöüÿ", 4, b"YTn1Qlvps8e1odqMn6G5x.", b"$2a$04$YTn1Qlvps8e1odqMn6G5x.85pqKql6w773EZJAExk7/BatYAI4tyO"), - ("âêîôûÂÊÎÔÛãñõÃÑÕäëïöüÿ", 5, b"C.8k5vJKD2NtfrRI9o17DO", b"$2a$05$C.8k5vJKD2NtfrRI9o17DOfIW0XnwItA529vJnh2jzYTb1QdoY0py"), - ("âêîôûÂÊÎÔÛãñõÃÑÕäëïöüÿ", 6, b"xqfRPj3RYAgwurrhcA6uRO", b"$2a$06$xqfRPj3RYAgwurrhcA6uROtGlXDp/U6/gkoDYHwlubtcVcNft5.vW"), - ("ÄËÏÖÜŸåÅæÆœŒßçÇøØ¢¿¡€", 4, b"y8vGgMmr9EdyxP9rmMKjH.", b"$2a$04$y8vGgMmr9EdyxP9rmMKjH.wv2y3r7yRD79gykQtmb3N3zrwjKsyay"), - ("ÄËÏÖÜŸåÅæÆœŒßçÇøØ¢¿¡€", 5, b"iYH4XIKAOOm/xPQs7xKP1u", b"$2a$05$iYH4XIKAOOm/xPQs7xKP1upD0cWyMn3Jf0ZWiizXbEkVpS41K1dcO"), - ("ÄËÏÖÜŸåÅæÆœŒßçÇøØ¢¿¡€", 6, b"wCOob.D0VV8twafNDB2ape", b"$2a$06$wCOob.D0VV8twafNDB2apegiGD5nqF6Y1e6K95q6Y.R8C4QGd265q"), - ("ΔημοσιεύθηκεστηνΕφημερίδατης", 4, b"E5SQtS6P4568MDXW7cyUp.", b"$2a$04$E5SQtS6P4568MDXW7cyUp.18wfDisKZBxifnPZjAI1d/KTYMfHPYO"), - ("АБбВвГгДдЕеЁёЖжЗзИиЙйКкЛлМмН", 4, b"03e26gQFHhQwRNf81/ww9.", b"$2a$04$03e26gQFHhQwRNf81/ww9.p1UbrNwxpzWjLuT.zpTLH4t/w5WhAhC"), - ("нОоПпРрСсТтУуФфХхЦцЧчШшЩщЪъЫыЬьЭэЮю", 4, b"PHNoJwpXCfe32nUtLv2Upu", b"$2a$04$PHNoJwpXCfe32nUtLv2UpuhJXOzd4k7IdFwnEpYwfJVCZ/f/.8Pje"), - ("電电電島岛島兔兔兎龜龟亀國国国區区区", 4, b"wU4/0i1TmNl2u.1jIwBX.u", b"$2a$04$wU4/0i1TmNl2u.1jIwBX.uZUaOL3Rc5ID7nlQRloQh6q5wwhV/zLW"), - ("诶比伊艾弗豆贝尔维吾艾尺开艾丝维贼德", 4, b"P4kreGLhCd26d4WIy7DJXu", b"$2a$04$P4kreGLhCd26d4WIy7DJXusPkhxLvBouzV6OXkL5EB0jux0osjsry"), - ] - - for (idx, (password, cost, salt64, result)) in enumerate(tvs): - x = bcrypt(password, cost, salt=_bcrypt_decode(salt64)) - self.assertEqual(x, result) - bcrypt_check(password, result) - - def test_special_case_salt(self): - # password, cost, salt, bcrypt hash - tvs = [ - ("-O_=*N!2JP", 4, b"......................", b"$2a$04$......................JjuKLOX9OOwo5PceZZXSkaLDvdmgb82"), - ("7B[$Q<4b>U", 5, b"......................", b"$2a$05$......................DRiedDQZRL3xq5A5FL8y7/6NM8a2Y5W"), - (">d5-I_8^.h", 6, b"......................", b"$2a$06$......................5Mq1Ng8jgDY.uHNU4h5p/x6BedzNH2W"), - (")V`/UM/]1t", 4, b".OC/.OC/.OC/.OC/.OC/.O", b"$2a$04$.OC/.OC/.OC/.OC/.OC/.OQIvKRDAam.Hm5/IaV/.hc7P8gwwIbmi"), - (":@t2.bWuH]", 5, b".OC/.OC/.OC/.OC/.OC/.O", b"$2a$05$.OC/.OC/.OC/.OC/.OC/.ONDbUvdOchUiKmQORX6BlkPofa/QxW9e"), - ("b(#KljF5s\"", 6, b".OC/.OC/.OC/.OC/.OC/.O", b"$2a$06$.OC/.OC/.OC/.OC/.OC/.OHfTd9e7svOu34vi1PCvOcAEq07ST7.K"), - ("@3YaJ^Xs]*", 4, b"eGA.eGA.eGA.eGA.eGA.e.", b"$2a$04$eGA.eGA.eGA.eGA.eGA.e.stcmvh.R70m.0jbfSFVxlONdj1iws0C"), - ("'\"5\\!k*C(p", 5, b"eGA.eGA.eGA.eGA.eGA.e.", b"$2a$05$eGA.eGA.eGA.eGA.eGA.e.vR37mVSbfdHwu.F0sNMvgn8oruQRghy"), - ("edEu7C?$'W", 6, b"eGA.eGA.eGA.eGA.eGA.e.", b"$2a$06$eGA.eGA.eGA.eGA.eGA.e.tSq0FN8MWHQXJXNFnHTPQKtA.n2a..G"), - ("N7dHmg\\PI^", 4, b"999999999999999999999u", b"$2a$04$999999999999999999999uCZfA/pLrlyngNDMq89r1uUk.bQ9icOu"), - ("\"eJuHh!)7*", 5, b"999999999999999999999u", b"$2a$05$999999999999999999999uj8Pfx.ufrJFAoWFLjapYBS5vVEQQ/hK"), - ("ZeDRJ:_tu:", 6, b"999999999999999999999u", b"$2a$06$999999999999999999999u6RB0P9UmbdbQgjoQFEJsrvrKe.BoU6q"), - ] - - for (idx, (password, cost, salt64, result)) in enumerate(tvs): - x = bcrypt(password, cost, salt=_bcrypt_decode(salt64)) - self.assertEqual(x, result) - bcrypt_check(password, result) - - -class TestVectorsHKDFWycheproof(unittest.TestCase): - - def __init__(self, wycheproof_warnings): - unittest.TestCase.__init__(self) - self._wycheproof_warnings = wycheproof_warnings - self._id = "None" - - def add_tests(self, filename): - - def filter_algo(root): - algo_name = root['algorithm'] - if algo_name == "HKDF-SHA-1": - return SHA1 - elif algo_name == "HKDF-SHA-256": - return SHA256 - elif algo_name == "HKDF-SHA-384": - return SHA384 - elif algo_name == "HKDF-SHA-512": - return SHA512 - else: - raise ValueError("Unknown algorithm " + algo_name) - - def filter_size(unit): - return int(unit['size']) - - result = load_test_vectors_wycheproof(("Protocol", "wycheproof"), - filename, - "Wycheproof HMAC (%s)" % filename, - root_tag={'hash_module': filter_algo}, - unit_tag={'size': filter_size}) - return result - - def setUp(self): - self.tv = [] - self.add_tests("hkdf_sha1_test.json") - self.add_tests("hkdf_sha256_test.json") - self.add_tests("hkdf_sha384_test.json") - self.add_tests("hkdf_sha512_test.json") - - def shortDescription(self): - return self._id - - def warn(self, tv): - if tv.warning and self._wycheproof_warnings: - import warnings - warnings.warn("Wycheproof warning: %s (%s)" % (self._id, tv.comment)) - - def test_verify(self, tv): - self._id = "Wycheproof HKDF Test #%d (%s, %s)" % (tv.id, tv.comment, tv.filename) - - try: - key = HKDF(tv.ikm, tv.size, tv.salt, tv.hash_module, 1, tv.info) - except ValueError: - assert not tv.valid - else: - if key != tv.okm: - assert not tv.valid - else: - assert tv.valid - self.warn(tv) - - def runTest(self): - for tv in self.tv: - self.test_verify(tv) - - -def get_tests(config={}): - wycheproof_warnings = config.get('wycheproof_warnings') - - if not config.get('slow_tests'): - PBKDF2_Tests._testData = PBKDF2_Tests._testData[:3] - scrypt_Tests.data = scrypt_Tests.data[:3] - - tests = [] - tests += list_test_cases(PBKDF1_Tests) - tests += list_test_cases(PBKDF2_Tests) - tests += list_test_cases(S2V_Tests) - tests += list_test_cases(HKDF_Tests) - tests += [TestVectorsHKDFWycheproof(wycheproof_warnings)] - tests += list_test_cases(scrypt_Tests) - tests += list_test_cases(bcrypt_Tests) - - return tests - - -if __name__ == '__main__': - suite = lambda: unittest.TestSuite(get_tests()) - unittest.main(defaultTest='suite') diff --git a/Crypto/SelfTest/Protocol/test_SecretSharing.py b/Crypto/SelfTest/Protocol/test_SecretSharing.py deleted file mode 100644 index 368d3c0..0000000 --- a/Crypto/SelfTest/Protocol/test_SecretSharing.py +++ /dev/null @@ -1,267 +0,0 @@ -# -# SelfTest/Protocol/test_secret_sharing.py: Self-test for secret sharing protocols -# -# =================================================================== -# -# Copyright (c) 2014, Legrandin -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# =================================================================== - -from unittest import main, TestCase, TestSuite -from binascii import unhexlify, hexlify - -from Crypto.Util.py3compat import * -from Crypto.SelfTest.st_common import list_test_cases - -from Crypto.Protocol.SecretSharing import Shamir, _Element, \ - _mult_gf2, _div_gf2 - -class GF2_Tests(TestCase): - - def test_mult_gf2(self): - # Prove mult by zero - x = _mult_gf2(0,0) - self.assertEqual(x, 0) - - # Prove mult by unity - x = _mult_gf2(34, 1) - self.assertEqual(x, 34) - - z = 3 # (x+1) - y = _mult_gf2(z, z) - self.assertEqual(y, 5) # (x+1)^2 = x^2 + 1 - y = _mult_gf2(y, z) - self.assertEqual(y, 15) # (x+1)^3 = x^3 + x^2 + x + 1 - y = _mult_gf2(y, z) - self.assertEqual(y, 17) # (x+1)^4 = x^4 + 1 - - # Prove linearity works - comps = [1, 4, 128, 2**34] - sum_comps = 1+4+128+2**34 - y = 908 - z = _mult_gf2(sum_comps, y) - w = 0 - for x in comps: - w ^= _mult_gf2(x, y) - self.assertEqual(w, z) - - def test_div_gf2(self): - from Crypto.Util.number import size as deg - - x, y = _div_gf2(567, 7) - self.failUnless(deg(y) < deg(7)) - - w = _mult_gf2(x, 7) ^ y - self.assertEqual(567, w) - - x, y = _div_gf2(7, 567) - self.assertEqual(x, 0) - self.assertEqual(y, 7) - -class Element_Tests(TestCase): - - def test1(self): - # Test encondings - e = _Element(256) - self.assertEqual(int(e), 256) - self.assertEqual(e.encode(), bchr(0)*14 + b("\x01\x00")) - - e = _Element(bchr(0)*14 + b("\x01\x10")) - self.assertEqual(int(e), 0x110) - self.assertEqual(e.encode(), bchr(0)*14 + b("\x01\x10")) - - # Only 16 byte string are a valid encoding - self.assertRaises(ValueError, _Element, bchr(0)) - - def test2(self): - # Test addition - e = _Element(0x10) - f = _Element(0x0A) - self.assertEqual(int(e+f), 0x1A) - - def test3(self): - # Test multiplication - zero = _Element(0) - one = _Element(1) - two = _Element(2) - - x = _Element(6) * zero - self.assertEqual(int(x), 0) - - x = _Element(6) * one - self.assertEqual(int(x), 6) - - x = _Element(2**127) * two - self.assertEqual(int(x), 1 + 2 + 4 + 128) - - def test4(self): - # Test inversion - one = _Element(1) - - x = one.inverse() - self.assertEqual(int(x), 1) - - x = _Element(82323923) - y = x.inverse() - self.assertEqual(int(x * y), 1) - -class Shamir_Tests(TestCase): - - def test1(self): - # Test splitting - shares = Shamir.split(2, 3, bchr(90)*16) - self.assertEqual(len(shares), 3) - for index in range(3): - self.assertEqual(shares[index][0], index+1) - self.assertEqual(len(shares[index][1]), 16) - - def test2(self): - # Test recombine - from itertools import permutations - - test_vectors = ( - (2, "d9fe73909bae28b3757854c0af7ad405", - "1-594ae8964294174d95c33756d2504170", - "2-d897459d29da574eb40e93ec552ffe6e", - "3-5823de9bf0e068b054b5f07a28056b1b", - "4-db2c1f8bff46d748f795da995bd080cb"), - (2, "bf4f902d9a7efafd1f3ffd9291fd5de9", - "1-557bd3b0748064b533469722d1cc7935", - "2-6b2717164783c66d47cd28f2119f14d0", - "3-8113548ba97d58256bb4424251ae300c", - "4-179e9e5a218483ddaeda57539139cf04"), - (3, "ec96aa5c14c9faa699354cf1da74e904", - "1-64579fbf1908d66f7239bf6e2b4e41e1", - "2-6cd9428df8017b52322561e8c672ae3e", - "3-e418776ef5c0579bd9299277374806dd", - "4-ab3f77a0107398d23b323e581bb43f5d", - "5-23fe42431db2b41bd03ecdc7ea8e97ac"), - (3, "44cf249b68b80fcdc27b47be60c2c145", - "1-d6515a3905cd755119b86e311c801e31", - "2-16693d9ac9f10c254036ced5f8917fa3", - "3-84f74338a48476b99bf5e75a84d3a0d1", - "4-3fe8878dc4a5d35811cf3cbcd33dbe52", - "5-ad76f92fa9d0a9c4ca0c1533af7f6132"), - (5, "5398717c982db935d968eebe53a47f5a", - "1-be7be2dd4c068e7ef576aaa1b1c11b01", - "2-f821f5848441cb98b3eb467e2733ee21", - "3-25ee52f53e203f6e29a0297b5ab486b5", - "4-fc9fb58ef74dab947fbf9acd9d5d83cd", - "5-b1949cce46d81552e65f248d3f74cc5c", - "6-d64797f59977c4d4a7956ad916da7699", - "7-ab608a6546a8b9af8820ff832b1135c7"), - (5, "4a78db90fbf35da5545d2fb728e87596", - "1-08daf9a25d8aa184cfbf02b30a0ed6a0", - "2-dda28261e36f0b14168c2cf153fb734e", - "3-e9fdec5505d674a57f9836c417c1ecaa", - "4-4dce5636ae06dee42d2c82e65f06c735", - "5-3963dc118afc2ba798fa1d452b28ef00", - "6-6dfe6ff5b09e94d2f84c382b12f42424", - "7-6faea9d4d4a4e201bf6c90b9000630c3"), - (10, "eccbf6d66d680b49b073c4f1ddf804aa", - "01-7d8ac32fe4ae209ead1f3220fda34466", - "02-f9144e76988aad647d2e61353a6e96d5", - "03-b14c3b80179203363922d60760271c98", - "04-770bb2a8c28f6cee89e00f4d5cc7f861", - "05-6e3d7073ea368334ef67467871c66799", - "06-248792bc74a98ce024477c13c8fb5f8d", - "07-fcea4640d2db820c0604851e293d2487", - "08-2776c36fb714bb1f8525a0be36fc7dba", - "09-6ee7ac8be773e473a4bf75ee5f065762", - "10-33657fc073354cf91d4a68c735aacfc8", - "11-7645c65094a5868bf225c516fdee2d0c", - "12-840485aacb8226631ecd9c70e3018086"), - (10, "377e63bdbb5f7d4dc58a483d035212bb", - "01-32c53260103be431c843b1a633afe3bd", - "02-0107eb16cb8695084d452d2cc50bc7d6", - "03-df1e5c66cd755287fb0446faccd72a06", - "04-361bbcd5d40797f49dfa1898652da197", - "05-160d3ad1512f7dec7fd9344aed318591", - "06-659af6d95df4f25beca4fb9bfee3b7e8", - "07-37f3b208977bad50b3724566b72bfa9d", - "08-6c1de2dfc69c2986142c26a8248eb316", - "09-5e19220837a396bd4bc8cd685ff314c3", - "10-86e7b864fb0f3d628e46d50c1ba92f1c", - "11-065d0082c80b1aea18f4abe0c49df72e", - "12-84a09430c1d20ea9f388f3123c3733a3"), - ) - - def get_share(p): - pos = p.find('-') - return int(p[:pos]), unhexlify(p[pos + 1:]) - - for tv in test_vectors: - k = tv[0] - secret = unhexlify(tv[1]) - max_perms = 10 - for perm, shares_idx in enumerate(permutations(range(2, len(tv)), k)): - if perm > max_perms: - break - shares = [ get_share(tv[x]) for x in shares_idx ] - result = Shamir.combine(shares, True) - self.assertEqual(secret, result) - - def test3(self): - # Loopback split/recombine - secret = unhexlify(b("000102030405060708090a0b0c0d0e0f")) - - shares = Shamir.split(2, 3, secret) - - secret2 = Shamir.combine(shares[:2]) - self.assertEqual(secret, secret2) - - secret3 = Shamir.combine([ shares[0], shares[2] ]) - self.assertEqual(secret, secret3) - - def test4(self): - # Loopback split/recombine (SSSS) - secret = unhexlify(b("000102030405060708090a0b0c0d0e0f")) - - shares = Shamir.split(2, 3, secret, ssss=True) - - secret2 = Shamir.combine(shares[:2], ssss=True) - self.assertEqual(secret, secret2) - - def test5(self): - # Detect duplicate shares - secret = unhexlify(b("000102030405060708090a0b0c0d0e0f")) - - shares = Shamir.split(2, 3, secret) - self.assertRaises(ValueError, Shamir.combine, (shares[0], shares[0])) - - -def get_tests(config={}): - tests = [] - tests += list_test_cases(GF2_Tests) - tests += list_test_cases(Element_Tests) - tests += list_test_cases(Shamir_Tests) - return tests - -if __name__ == '__main__': - suite = lambda: TestSuite(get_tests()) - main(defaultTest='suite') - diff --git a/Crypto/SelfTest/Protocol/test_rfc1751.py b/Crypto/SelfTest/Protocol/test_rfc1751.py deleted file mode 100644 index 0878cc5..0000000 --- a/Crypto/SelfTest/Protocol/test_rfc1751.py +++ /dev/null @@ -1,62 +0,0 @@ -# -# Test script for Crypto.Util.RFC1751. -# -# Part of the Python Cryptography Toolkit -# -# Written by Andrew Kuchling and others -# -# =================================================================== -# The contents of this file are dedicated to the public domain. To -# the extent that dedication to the public domain is not available, -# everyone is granted a worldwide, perpetual, royalty-free, -# non-exclusive license to exercise all rights associated with the -# contents of this file for any purpose whatsoever. -# No rights are reserved. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS -# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN -# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# =================================================================== - -__revision__ = "$Id$" - -import binascii -import unittest -from Crypto.Util import RFC1751 -from Crypto.Util.py3compat import * - -test_data = [('EB33F77EE73D4053', 'TIDE ITCH SLOW REIN RULE MOT'), - ('CCAC2AED591056BE4F90FD441C534766', - 'RASH BUSH MILK LOOK BAD BRIM AVID GAFF BAIT ROT POD LOVE'), - ('EFF81F9BFBC65350920CDD7416DE8009', - 'TROD MUTE TAIL WARM CHAR KONG HAAG CITY BORE O TEAL AWL') - ] - -class RFC1751Test_k2e (unittest.TestCase): - - def runTest (self): - "Check converting keys to English" - for key, words in test_data: - key=binascii.a2b_hex(b(key)) - self.assertEqual(RFC1751.key_to_english(key), words) - -class RFC1751Test_e2k (unittest.TestCase): - - def runTest (self): - "Check converting English strings to keys" - for key, words in test_data: - key=binascii.a2b_hex(b(key)) - self.assertEqual(RFC1751.english_to_key(words), key) - -# class RFC1751Test - -def get_tests(config={}): - return [RFC1751Test_k2e(), RFC1751Test_e2k()] - -if __name__ == "__main__": - unittest.main() diff --git a/Crypto/SelfTest/PublicKey/__init__.py b/Crypto/SelfTest/PublicKey/__init__.py deleted file mode 100644 index d4f51bc..0000000 --- a/Crypto/SelfTest/PublicKey/__init__.py +++ /dev/null @@ -1,54 +0,0 @@ -# -*- coding: utf-8 -*- -# -# SelfTest/PublicKey/__init__.py: Self-test for public key crypto -# -# Written in 2008 by Dwayne C. Litzenberger -# -# =================================================================== -# The contents of this file are dedicated to the public domain. To -# the extent that dedication to the public domain is not available, -# everyone is granted a worldwide, perpetual, royalty-free, -# non-exclusive license to exercise all rights associated with the -# contents of this file for any purpose whatsoever. -# No rights are reserved. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS -# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN -# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# =================================================================== - -"""Self-test for public-key crypto""" - -__revision__ = "$Id$" - -import os - -def get_tests(config={}): - tests = [] - from Crypto.SelfTest.PublicKey import test_DSA; tests += test_DSA.get_tests(config=config) - from Crypto.SelfTest.PublicKey import test_RSA; tests += test_RSA.get_tests(config=config) - from Crypto.SelfTest.PublicKey import test_ECC; tests += test_ECC.get_tests(config=config) - - from Crypto.SelfTest.PublicKey import test_import_DSA - tests +=test_import_DSA.get_tests(config=config) - - from Crypto.SelfTest.PublicKey import test_import_RSA - tests += test_import_RSA.get_tests(config=config) - - from Crypto.SelfTest.PublicKey import test_import_ECC - tests += test_import_ECC.get_tests(config=config) - - from Crypto.SelfTest.PublicKey import test_ElGamal; tests += test_ElGamal.get_tests(config=config) - return tests - -if __name__ == '__main__': - import unittest - suite = lambda: unittest.TestSuite(get_tests()) - unittest.main(defaultTest='suite') - -# vim:set ts=4 sw=4 sts=4 expandtab: diff --git a/Crypto/SelfTest/PublicKey/__pycache__/__init__.cpython-36.pyc b/Crypto/SelfTest/PublicKey/__pycache__/__init__.cpython-36.pyc deleted file mode 100644 index 444d993a15209bae1864bb5afcf513ca6ce1cee3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1035 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 diff --git a/Crypto/SelfTest/PublicKey/__pycache__/test_ECC.cpython-36.pyc b/Crypto/SelfTest/PublicKey/__pycache__/test_ECC.cpython-36.pyc deleted file mode 100644 index 5549fe2a16cd141f2ec7963ef8ddfdbedf0a6d02..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 27502 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 Kd@_C??SBC@I!S*3 diff --git a/Crypto/SelfTest/PublicKey/__pycache__/test_ElGamal.cpython-36.pyc b/Crypto/SelfTest/PublicKey/__pycache__/test_ElGamal.cpython-36.pyc deleted file mode 100644 index 06dbbe6dd4008a3f5a6178fd72a0eda951a65979..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 7369 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�d0_W^s0)Xe?@B!n?4A#G0j7Od>Um)Ie5eaf`mWUT!0!1_ z7vRZvrJe_N&xg9kt(`0NJg|E{)CCQ`EA>3Edp^{~Sop5g^T6%{P*>#Sx57K)qyIkw zyvshoqY%e?Tt&C@GCqcmll~E%*6$VBonhgJG@OCD=nn?csgDuok3@F&{EQEvI;j1} zLVVTtsriKWsrjVerY!Q;jrJ+tqppi5-o*zgnSX-SJKr62&j z$PeO(WT+?dgE%4?>WTayj!1@jB0q>DlA)f+58{Yqs3-EB9g(Gm-YGjvV;qc#sl>?W zL?SJ78;`_G>1Mrcl)m(!$L}oze2M}7T!X61KB)3l%Z~(7$tQF!y?00@pR)5utZ*pQ zdcO)sexC|Q{=N6EaAY$JBNNN?uaep9hK|3mkl&gSu5SxDTt(h>RpW!`k`Jm%-lj=F zal90n=a!WmD~q|ZnP^Qqf&Sb{MN`R^l3Jla>g~%KA4HjaP+fAqDxvhAzn<|_NTr)Y}M zYC_1~3XI;<;;V6~FmXneO7cA{S!ihV{aAX+|E45A{(7ro{@2IwZxy|<{c3eHaY8r5 z&&TqSa;sR4MVV+U^J;43jzc%}SmjlYS6_{UBcE5;u#5l$P0*sU6w~5-EUal7JYKw} zsA?p}Fk)R!B+JoB#3P293-_$eMA8R|n%7%;d~w7({IYA$^YNtIs@BWd*kCA5>z*Yo@`lhUuUxA?@B)*H7gh?IliX@`Y33G6 z>rEkAVU_ec!(d^M6lMw=94~UsY+Q>qT-_)P8#UWDGReF(sIA)EgsXW*Y74K|N+h*d za69cRn;n@1x)DZ?&QcLG9O*^8aw(mOP9(M?1V*IP>$k$0dNMHSsnu>t(Q3*-Uy_Ls z=;qp;QeJK~XWEdYn09>9SOr~888>obB5A~@$#kGz$>rm{a5vu3m#w;_Dn!ZlMbe3? zvxsZ0;WI0a+;Y2?n%m51RGcQ)!%nU=-i907R!$t27Gt4l#reiymXBM7E&Pp%&Wa1K zxtYdIm(6g!k?!#0t=C{@GLvjY>x$90tHVK1?DzB_2@IExoHf+`Vo~O%k*=|py}s*q zI$S%N4|2_|kgP9Ln;*@L0tP9FeFq`XnWL6wm;r4^b?(tn_-^9dO z|3x~{A99(E?z_woU2*V(UeZNtk9L|NV&hV=5v|55)tgsOo_)Z3b{ky3-d?x+FzBqkoSDQocATFcMp8$9G2J- z2Q=w;=FE8yjym6`Ntd19kNQ?WOu0>~*z?U*8sU>>30*_iVcTLxmC1XO0kKE5Kaesm6aON+ig9Jc$-?%=Io|1iLFyHZ5~k=#oKfn z0jb-WL%a7E-c)czR!y`j`a+rw)4e=zElbVewj2*{)rO#ER43)QGBP;LjUda18+;c9hgit}NBD@pY-5 z9xPR%D#mk+V~G7gz7(}$SvAp34&&=>v{BL*#iEf(H)63^ou34&<3OVT^j(Q2OREPp z<2%d8>CAlyJpMV;kGq+A_2lVOBlt(H88zYkX-4h7a~;u@2v0>YE`lX#Y%-!H6_y}w zL}C$XDj>oWVWp3Hinv@vqB?k4B?^x~QqGdG{!QbF;jTw?uA|~z5$~!G)hw_IeTP?Q zJgSWdTM@$LI0#-AX}q+=B9_>831W#|)gh*32@WVx6%7R0z;7}FUroi)5GP8oL;%_e z?W5pt0R5Dn`_? zjY`G05aQxOL*O@29m)el6JU&7o|rc42)3Z`yr>$t9Ld!z*;KGrf&pMfMAm{^8VByV ziiJpI(1oA`L~avNQF%!=RgFb}0zsIpNgRwO&zU0O5R=U*nu+jeftUo*%^G@#NMJ-W zh%#|a#kDyJVaF0rh$17_*0OjP-aTLx1?=6G|a}M0}5~8jZ+2#nMl@Z#mNg`-P zSg$E!kSQUE7Du!&k7!+xjTmW5L$oo=IS63Zz%hhhYpfULX0%x?1`iZ4(PK%4Wcq6N0bqHj#^a?g)~b+V7ZMrVX&7|BuCXu z(?PVeC<=#KQ~&=1`soL-67b~1al>qhDx;mnOFi7DpyA`^ zh8we|x}GAmi%7o7`vy+X!*^K=m|vP7&o9%cW8{e7ejY)PZz9$O5g%9trr3>K0BXDV z?W4O#sO>7!wL52+>r&ph&MP_>k>!ZU>+x7D5;Lwxq0qu{E-Z(sLW_%joJe)Y*Fztd zdAC5_$+2gSh`SisH=lTn$dQvvVY;0qRoHEB*|$!PJjWyt#0W-F>CFp%P~-zkt8v_Y zWT2qW{?kA~jx{Lz8I<1Pwh!+=wZDB7>mPXKl=XP^EWn0_X;RkDcX6Zus$lTZJ(zls zH;z}{c+{S($ju8US9fvhWwSfORvo5JcjUx8Z~R~=sNb*sUBBKE?0Ef5g#5QSO3@4` z5}nw7;vMDYtSl|*2UF3lMZVyC5hw31I4A+pfsjCW?t%OZXF%K!40;fV`vd-X2t0%K zJsNWEkL>-BfgAM3OEh~F2X;f^_lkEZ2k11|4dWxZ@L>7VF{E6haLMPw4|!t)-ClaI z{aoGgu#fac_x{$x8{OFrb9BQTbj{g~`S{)g8peOR34+-b_Cx!h2DOh9D16Rpq(2Gn z@76*)eabz5t?ls4P<-Sxc;KZ|7E<<|+KG>HxhW?Sahg z+ru$g4CwjQ+qdc7nB9||`h7UO+>hAtK1AvB{B#*nP#7**-e_!I6m)Hngwab z(u|`SPcwmLBF!Y4(KQ)Qp_xiE>Lc~OKr^a#yf4%2D>Tz-7N!}UjviHkUW{gGn&oJg zr&*C^C7M-ecBUNsv+ML8704S%vnI0RgQNX>{|=5{au^u z9DnFD^x5U(r|^t9zU-HH&Od)1`A1&cJ-vKhFVUA6ye)#6a^)2!Q_A;ni24*2$=DKIq|ylwyr&GrwvzIK4$*sz^(FXs=^iy&P`m>tWrlGLb$vAj$O7 zPG~c;nOn!IdU5x#U5&(~0ojBNOGtaU(rgte!Gl^VC1R^|y|&#^JsSeARqBPs zNn<+BCaiE~%aq6FvYL0xSs0I-G=IlfvQ6IZl=;!1hZRr7rjot zFz1XdH*h0tKE*T6c$94vgt?v*n~99eRkJ-ysx?RL#7Jbv{o>5jRjw72jZ|jHvzt|K zP-qFIz8)hvGh1&7j8;r9b80ye)`rR?n^|v?ZX)N#MK)K@i#*S7GfrZntUEb2lJ7=p zZ=05;&UoXT7*N^jr)zw+g^}5Y0yl`A{HP!UIF&=gnVvMZW^(3jzr=%0K zqVrLXXR1T8F!C*}(CAyN(qSX>MpQQDs@o|K2K8B`;td)k$d5fG-pog&l@l*L5Ek+_ z{dD8rpZQbx9c6ekq^cp)3JG?IRYJrLnMz19L&OTnPDpY>0v{r3Na8{w8)A4qBw8WK z4M|qWRzj{CadcyvBw&E<}V7htfQuR0?QO z47q$rc0+;?vc-@n`z+EzmK8F^kj2xc7+Vb~=n7uoLM|6lP$lRFdFX=>l1a#tL$=RW z6}?11EITBFEHDIQ5XydDVopcpXXvQxdTyc%PKb3Vt5r8-f~$mb8|3p^$N{}>NL50N zfNLwHN+H_}*(AiVv}?#w0{8KP!_t1RcuISx(IEn#L8gr1@!v%C8cWAbL?_%3QE0Da zj5w$ROTadT3#pdhbBvG_;^mMG{$r@rkf?-2Eu@hUgLXj>ng&y3E963;xDW>+vO+A{ z5kiti+eB-Q9b#BJ1o6W_b7IIum3~d85HcZUCLK~1Jhv(Hz)J=M(W2-X22%(r=pR_& zQsKa0g7Z{XP{5(@FbX>4j{zMzly+%THiQ-3VCm?APBel$EXL5qNVp-_3TYS{o1HG4Mi;Rm2c4i314am5JWJ}O05 z8MNwxA|)h13j>JbfmEXv`dlzZ}Ah zpf5wt!3K;PL=VD@aX@eI%#uO`f(}syXKXs;Xcm;)Juexh=Zp@j~>tNx@%Qy3`wY*Zd)0-PM(#-`Nm<*)u2`>JNX>VEBH@B0)| z!-9F#e$*@Y&d1#AP9E4Bb#XAZ&B5&CusfQc9C*&j;S8}ObZPD6QhWDVk~0Gq{sHR! zGOn%xfNw9k+crS($%PFi0(*>hhw1LnrU&04aB|rm4=28fb8_sT(&9(->;ZFtl6`W; zH>POqOYSG3Xl9g(Ma665a-ovkb-PK4#Tdk!r29j`e^$chDP{J>9XA z<%tD+3p`)S>7rj&U#*gL3Z^6BC{wD&+*}xIlojm!Pgz2=6ie&nR>?=(vGBl2#OHQm zJ;)C8ORM@I`pyAq*S1Wq7k&VKxBZ*+UM{Bl@cSY3eb$9kR8Qy2(O8Aag>|2-@M@JV z4dXMC7|dZ1402^1>!&_c$F6>SAF7#W?ct!~f3JY@?B4eZn74hfAPbj%dlQ?~i#lth zWGyohMw_&~kn*fy2pKM;bp}o;o1bQ4wo&Nd$37V0(_FPkhRJF+&3gJOY;dE-dZgon z0Od(%+f78{vq>h>Dy>>}CAU>G<9K`7w3?HJ-PthXxE|@2`0Uge*;3BzFS4b1)-KuD zOqFQ$gzeBEt=t%2l@a5d8Etrh=(?1WqxFaowCMK=n9j7Bi=<_@lo1kqL8}PCNF=za z8_md!ez2h2EEfhsneTU+%7A0DrCv1F9t&YEwe2-)!CsNc*}3pQZWaQgaJsqnf-~Ei zs(P=xRI=4kVp8d~y-jkybbI(LOy6CO)sj`I2>pq$oJxzzG{r2sN=)&DUVG6nvpt!U z^#q5{HQ4iJy4IV{x~65UW)r@{YVBloJ50u!;li-1mlx_fzRu`LW<6VsmGMZoR`_56 zA}m4nX3*$0Dx*v?rVf*9PM3y3Hc?vR`wE>#$`Jy&v_6V;%850;dmu8E$joij*uttk zNR_JN4!4ySwVF1Lb~U@z&KJYZvJfwiq8*#xnCX^W*IT1hAR3UdXKm@Xp9-fh{RLN?@Cst&4pE;eXtyIw%l~>teU4(hQvJ$mL zi`VA4$SM(OL=qJ}kqE?6;b^Jk#yecmPSh7QE}vskF*2}*^-Zf;9vDy%Ml;Qt4P(;c zs>BZXfV3n5lXP|%U<1$6x;~b@MD8ify3Ha&~vb9 zG2TkBY_{B0OZ{?svDWi-rBxB<*#+rrlIaN3FY|*A$>oQ!#kP?N%=k?}va=o;DpRr~ zv3x0F*JWj~Oce2T3p)@qW6GKnD)u(hYlP?4m?=eOa=Kb*1Y-SSc_12NUdf1slpzYi zbRe-_u4-DTR!<76Vx3r4Hopp#oN7GWf=9w$Z)}n2FC{iv49Csx9J-?!j&GJEHRH5+ zuOHto*xEMeuv?1@EOXn^Af1b9VzOTFa-&pFs^F_ZStgSqt!71Bbk_0okkna?Yc4z~ z-EXy4vF*Z4m`f!sYzy1gV(z69)pm5S$VQfW08tWUyE@x2Jp)^`EB#h*84%P`auTqI zL$y&JEEbb=b*8Rb+xkR~FW7F}G&9O}9v_;#BI1a^SEMeGe9gwb&^bVNoTRhFG^WC#U{-$CX|?C3?V+NhjX2JbR`;! zJRQZ0o;oyQ{M_^ep;H;8Q$b-;30mRqqQ40D)tXWdvrTHf*G5Gl!YCGRhzT_@pGNC; zCXw6rm$_b59BE#L1hYM{yTL1t88^Yj%DG9g@Gz&We z<^iBB@GsCmY%&cv6t*8wFYFfBNWg$1wel#amZ+h}pb(%W@E|}j5G>3j4n{2?G^|0` zTQHVzjz>H5k%y@T@C*D66bwrkrV&6eAT-|bQ6=iaO%?_bOjBxypcOO+m<$^M79fmB zSO72)0aQVWOf3VTW7uU3fHe#RP>kkaKEXzX5d#DZdjJR+PeD4Y5(n5B;2Y!uKf^wU zX-aXrLJeNL18%^!MisCSaT69XfG>moQA5%1HHd?a1mg>~G0X+nazN4O6)Xmj3d@fH z1{Yw%__i2wYIjSh{>*H-Zz#5Ep8K_!d3n28IaO!9ZkS>wu*w3hxE@0(%oorp794LUb0Sqk0S@ zj0G?WW&#~wj2`F%hcKQHC|D491Vd!!ZGia>x?xmkXcwad%L;vfZ$J%MFii;k52=F< z1>Xc(!_d=FK__5f;vJZ1Xa_zPYVDwBkQlfSe5r@61zV4S84OnjT7R}*ZU@&g5hA=tKs@j>Rka6@I zQwd4@P(iRPbWDX64dzt(Lf6j zEqE=!D@-KFICzZt13#4lmSb4_1~Gj2zw>rka8)^=1co-$h3}>TN6<6ai+DgiEWT?4 zMB@a#mtn|)3|wIRF@Zq|h6aKS!Gd=OodK;7PY5gs2Dho%3xxpfLa7N-@Xt>T(3jtz0V?DX>`JW z-iYCNWITKCQElEG;Jc^-byAq~lVhtpGG}(T>xZ@&$F!vg7cP+b{+}5_0-2B@U^WfW^@n&0MEdo8`$@sFZu~vTW&G@rzv9@d=7Ra{8+Ie0} zrXzbPc8Q<+GM(AWvCI6tHFG6`SME8lOS*9wVBZp4^e48( zuJ5>V?rqn!OALtZ4_soqbo0I^c1!FPFNvKGgxGEIvUufzEB2gtRlJ7p=f&&d4Sc^K z-V|@)`$h4#_#D1pLJ7}{FQ9}MBv1Nfl<^93UKC$K&P#gEtH^m-d<8kL=s8`;c~$H} zPM4nZ8RUFMd<{9T={c_<=d+_&Ko$b$b&}y(NBLeETB-Z5GyC-F*+Ki=y3v+E&aRNGF-pUI`bMGbve#D-x1q zLYCxikLumcGf{0(^0LCzt5d0r6wNDB`C?9tFqUU{>C$cqZ^V^+Jd@AuBg4No6P%9> z436X66A6XZr;_w*#s_quQ3R2OI;i0Sx)8l*HMK{DXHXHZ)crKBZ;&C+)k7x5@F+=Aa@%Y_hBBR~;zKeCDT%P=CtnVnn`Z9^!eqW)a9OQFD zeVNp*ao#)HC#MwY?Ls1XnAn%(z7Q)FlziWsl-Z*S^eq>6GpXdfRO;i9q_TxPQ{re* zZ=u8j_?00XvKxtC;Mb~~?I!7(KCL*e;0WQ6e+`M~y5}yX6_?zl2#P!HQM~CE`o1rm zy6$^E6vWnhl;=ygD*klaec_&$Uj?-E)Vn8~dVb0Mbr+s?-)m9YPg_of`|h9ayyrXh zr91AU^ez0xifh%i?E zow{zh?h79Zr*8CxKdQEw?PqPMe)+Af1k0gw-szGLQ-uP~x}+0D%88QLMF7cNdwJFc zcpef2==^}J0NRXnBxTA0y=S{#m%H8UDjwj4c3)L*ad3}#Z_Dw-Q6iN|>}Dk9!!v4& z#8@t``XbS#NOWCw=VjFoNya&ZRXvA775zZb+7sTRC z=TkY=n=eR6nUoM!|FPCAS@qJH+P)!6Om8ah)$Ufcjla!*#S6NV)K(_R#f&1y+VJb~ zWIkJvWBybwrNnU^>)b15GTJZFJF!;&dMZ~TO?H`D*OtjAME=|uF6BE&T!Po_7QBK_ z2nas6SLhU85;}xi?oQ;mg-*9$=y0<)@LZC{5q$`3FAh#;bVn4@L?gmIf#?i0BBVW{ zTlCxqt)chveV;~KOY~3huW>N zhtwAjx#XapWyIOpFcRuxJPn>j{mMp>=zYv+%(8LH(E655P=>uz**la+?34W!deXEU2>>uy*`=4J+n`6&N(*cg`^%RF5-b{Xh6iLNehZ{Ho6vxgu#;u1J#q0 zj#Xc=AYy#7SCM0(6HYN)nsn|<3WUjtB*qIYw|@`MaplA%utl8LRN*~(;0BV45+=H# zE_y_&hF1-&L#WSkrNl2B|S<0MrW6#hbw1#66VJk>EUSHIafk zsRlL^nWALjZUJ4V0>6R2;FY0yS(?UM72twg$`+K;eUz!UsC=_hx!%eXQ6R<{HR+b@ z5+!StRECua7mMP?kKxc1I5)qxVdTM0`pDlvVqo-DQnUr&FXsYF1ZO0?@!i4J`#aY>&_bZQfc*kx_{5WAvH8e&(q zsY2}9SJ4Hr>%jRl>g5Uy@ny&&v!kf;bP$GIu~5)Wq&cRc5uCcej+ubsx$pXt`_vWp z;%MO=CqyA-TI6B@3f4N_B*lqqHF3`E)pimNy1-Eb{DO-cu*6k*+?!zgvg$j8BDF80 zN894@WCkPYVs6nJKfD$42 z)813}eK#5>q@f;*q$=0m@j1PrQ*QaXp#{V>+1V>fth<#6xXR%F7BqGwwh}4 zY;G^Fwrdn0p(zR5Morar<9QUsNKG=(@{`CW)ll`|%tEA`@HM?y|0!LJqlAwL0it4; z;CBb05q97R2<11bG32A7=5=R8sh)O3>mc`tnBJ&hs%a}Vpk6mXGSnFY>xWS-wnfR0 zP-4N3#VO-`N-ATU!*<)&Ze2G*VZVT9P231G9k(|d;#PUz890*R%>q|Tqz1{oTn$gW zFphyEB^bxaS0O$Phzc%ELGr2-B!$DItpCV&2^yNu5=rT>^fd#Er3`0y?$p5ZNFWrX zY-~LoCj>0vpe*>k;r0Z)Vt328~1lD4lk$4ZqRuKyLlml;~ z5$14*lZq!=zU@FNL?o(DmY~36mSDk&kD7B5%j@;Ql5%{04gF%^H_;p$$#e+ik>>HT zl;jN88%@F05ES$)+e0yrLpe=>G5D_u41;hU6^KD+ATEZ%Ts5iYWTbzh0aGDC&>Ww= zVWkr)H4ZBL0U=SvN$xZv3*$xS#-E3M)QIi+OoJMECev^dzbNuQTKl?5v5VIpzkRhL zw0;9gWS-eTM?r})|8rFfn-Y-KO(ZK4*VS&}#Lo9f0@N3LQnHX>iLBg9t@BuTSyPhE zdAx$bAE%UqxKZ|hr54gG28_O0wpCq**`ZVpS&2-|^ki9V3%h=J2D+&WMpc1~sxW7f zp6V7`!ShK=)ihO@;<%>jR$8F7!mw3)_pXnOy3q9lQPnF-@{sCFNHUD;+V{jD|AywT z29S^M_ly3#lRop$7Gtbk@2vD>mXNz@<1cb;aHB@D;^X@2k({hu#qZG zNmS^pc{IgDYMCSo{2!>7DK5Z5&SsE!$+=}@OsXASCVg3ELiP173$19TL$Zy_@&OrR ztOTImGE{W^0eya?DPqkFju))dU@z*A2^m9t(A);-e6A4@*k3m>qVZ_<{;(AzZgkd1 zBh4B;+PK6SCczk$o>MQ4Nkg%Csb(A*;Gj#&UG?t9^BIvdFmDwD<5+>9Xw>lWqIMW_ zKzfJ0k9^I_OIKAh8{054TdvPg_-x_-;B^B(K05?{4F{29Db6sCqHL4YY%r2Xp&^jo zXalGU#~iBiow{J+2?J1>%wYx0u#e%D1ot5|QM0a^+{ubAJEr^ZQ*uH{6`*$iF!%5wj?EZpLB~0HMv`0f0Z8M))zACd=-b>g#^<*ufGF-ZGNA5`1~#Y0KfKg zBM?>2{LrwXkNhhQUy75;9eq4g%nO#xS;lSJ){fytk(4j9VnE z{C|gXV@M37IiYd5>8&s*cC2AU*Fc}fI{yhm>6^BF{!PT}ZMh=*Y`Js8+6d&f#TQR9; zhpNFu=Ovh8IfHUB(?rbUOA;}H_QMzU`c}y!3mte!yU0rP&X$*xqIfxH9(>w|PDn@Xo;jF5? z=P>wV6-B0z}QfC<_qRO+wXu405;4XR7=7q76R0L;1XgE8LGhSL0gN zg0&yf6q{3}x+%J#syjJ5&$Lss?(oLwLgz905UGo+RjsjEa%x&*sH>K_=F_un)HOlq zrVI-*WHoqVrVPeNw%2nman*a9P;G3hXn<|S=HblL&OD&__m*&n8fViOy}GicP@M^ozF%e4CnY zNMR?NK)t3v0h@qhL+fi+P1^*%Pi?Gc6KLGNr)?9kLvXP+fqzup)zy>b#!x&Fn?O~2 z(b*Sb6ZkD_k3VWNpMp(*nt!1-f#0p}<7%5gbst}}O@Mdkh1mrDy|o{!Z35Lzxpb)U-wyG1f`mvttvmAoFqC1pW)5+Sn%00NabV2@o_FWfSNYWEL+##;)|txQOCfUDb*8>tRfP~huH9JLP5;l2dIeZr>J4XP|L>Z zIx!?~WH9%l?&7!H#ax;SdQe|mDyokrO8c3oC zt5r>tL#8ZlEEjhv1X#UpE>5cy zq~3POq@dx7Wl@V=)t0N(B3~)$GU2XES}d!g;C5}fS`(O8N-+^9mSZArT@ay>J8h7_ z*ZA3q-N4^=kCSvuv|PLBnmptL{FFh-ZADp%b3=qd%48EzuN$OntW%{Ixrc%%v|HUj8=r;lLtsZ`zOd9G=zr zDmO-yyOt;C!&8G>SjRrI7!19QJyr&SIWZVn!&>mSLz5xwLJ%O0p>V*kbqmf}UO{jo zb`#L>_i+5#Pon|sXQ(IIH2FjEglvhDWlAVi9SaGKxIufz*djxSY_a)<)CAkrX;4Gg zwBfu>y>tVm&@z0#=Nc{h_WH5Q1@^c&i}^a2XzMeR6}*pMAm&S9RoZ?N)MH@1*m;Hb zkC!51b@|tl_VFE3>fP~(K3)EqZ}EO=b&!9U2VqAT1u}3svS>`%^VXN2S*v&z#sw1n&KT!A`ivbMBWb(_T&n3@kq!H?>R(Xby+6rHjx*uL7jrc z^}t(qnrj(cmmtCCGy8^?VYk@CUmaxGHwciQL(;qqM9qyA?cb!g`MwN%2rly8 zZm5}6mtX_XWaYHp0nq5I9HPy}$oXCdAlE~m{5i#kt!6Zqj_3f+GFs_PlWDlpe(V9@ z1sS*MES*Gw!?PT2f0R1{^ynLbv*dDTB-FLMI=dNMk95sPb~w}L)I9}V;R94vm%kJ4lmTU2KtDNtPP&5uXf}-ffMvwCKuM>;FPGTdDsv^ zBTR}MJ_nWC*|GsMkHSvmuw@4T8cVPX0j^* z(wAg`^BkWfv!UadZ|R+A4J@p&zH)IfrM501er#=R#u!{yg-4%&^2z>XqqlTxrm6V#mo2{EXtwnV6Cw#W|thu)L49-MMrCIjmwFqP4J*uC9d+&i%rU38< zR1(Q(OLSu*UeS~s&O`0EuPzWkI;@zze?cWL1Dy7-1rM% zs-%4*jH@cA{JdkgP&v*$K+YKxNiYr*Yob-72e4tK-Y>OC`l6b`!l85q!>af+!i9a0 zAp1Tgj`T@ej>ZvjOcSTve!Md8{Q*IA4e!yM(hgA_I;~rji4v@?E{Z$kbowuFLU_<- zN_-Lt2}s*%>Q{WslSJe>m8U4b^&^-DZ14Js4byH>ANeeIyqKDjKG|OLyhrSyy{10G z_PDlkD8Eg-RFmIn{3@sP%Td*{y}hmTW!_i3s~j{;oo91n0a?46Fh5ua1|I=jGV2BL zjBXTEBfA+fGgyTx(zr5ONKBx%tN5xWgKHX_qHRFY`?O)ez#mjb#|;mSj82H#PEG{$ zO$Tg@xTdr6YmTD>Ho8iICIJw;zk-7kz>nYr`&V-7PsWvn48=afoyOc&pq*C-y_gzc z=hbDwbq|D4z9nKOSI+!>@_WSmx3K%Fh`)QDAN6dza)E7_e&rb5;T;7b@CR?xXEHK9 z8^w;QRuzcf2rN$Thk`4S$V?JqO$Sn-jC^(XpNF;Yi0^HolVRJEZtVm)cnViCglSL+#I|h1(dIyFEd;5EbhNilGu^ZY}yuHg@$(WZ) zz1UWk{RR<&IcHZr82wzl8Io;;?$bjtPqEe>t!?O0tW+S*H|_jmA{$~du2wHJ1njYj zJuY8!YoQ-CvznUMO(G#l=E1>Cc}c zhYUFEX^X>CEmj@j_c_@0$)ijEEKVgknas|t7nA)H>Cni)$#y=wIl8zR3P*dwg<$Y# zEt{Czib2z!SsV?I%nam%`RP#T?)2K?@I=5UD0m#1$*--1XZM4lt*PSl?u;~Enj0Qs zDK@sexE`4}9zU8X_fM`BwrB26^lzue`sAKO|GQ=Zji{r1?&eJG@28fd6KgBWJyXHu z_0V#me|&FsqddlD3WIl}ldH+exqL1m z>u90pc)6#rH8eRlyS}l|cbuLGHrJdKgpVurfB%8YmDy8Ys`u*=}-=gGiQ}Roce4CQ*Py!rW z>{lrHRZ4!Hl7CFezoMkUnsoA({uzX?{02_+HR*nTJN~ZuI}xqk?!S)6^_w{N`=7(r ztNyEu-bvyxKQtuiBU4?TWj{3cKi`D^`E|Sh8Ic1fkD%-84e88o}qkDTf z6q?R-n%pM!LWefC*^aP;BU0HIrfKsUDL69gd~7wE&aG~Tw( z-!_b_?dR^p=7$bRj(4itU+tZ(*ZxnmcedhrJ-0uW{SBa2A+j1Ttdmuri{}U--JFND zG3KTr)kc3Nt9l>xGc1o!-owgiRO9eufhRxU6rasHSse9^d%sBt@&WtvbjAsml=P;| zj9kmvA}lqAPkYBYdrWIk)EGY5_8pChHijQYee5V2vr4#}9?4_sfD{L+c?p1;+uVKT z>`Sv}5sucSLuZHqQWT}i=y&#sHo)*KF)&qwpl+6V44){+P!|UVxoLJTW9bzcH*6qr zI^*8C<{2ZY&p8V;j-JjMXbks&;VZQbPa>`m4%u#7{mbj=Z4krG8KQuYc&B6Lw!FtoRzYjRL7o|Dr{T)31>x82wz3ck{tMN13Uyh=ilpi`m zIOHei2W$WqH=Wx=xw9XTeHT?cryr18ZGOjO19hBz^#H3Qr+o%oc7asK)l_jn*<4K~ z=dilINw3h=lAQGJ@5(l>v7xQe$XNW4{Ih`HSGZ<0jz$UZMH(dh5*IclOp1mqFngV}8Ppn8d5FPoLq7S)83d4DLrJ zC&R(T{!C={;Ap!j9nKG~Z7JgJ{!%igOeRhe6YD2?g{8jfWOypJ5SkmB+uTm9?;jsZ zxxmVLPpD^mK?#p;S^RkO2eDu@1vj4De;8XlmA>M|aDOAaIkyxYoY>B9q%z4VR!)br#ga5MIl9u=_jf*w!ZXWL>vCpi zA)`bFM)zjKweY$U=^LC`&x%8f`*Q?-#~Pd|2~{3@VlJU!LadQXr~z6P{$v{q zC{dIA7wHn>P&`SO&=)K~IJ$&tfOvW?Axq;crYDS}i*yN1SGT{~B~-8dpSpxJLp&|| zHB5UCh^0FjlxW4qDj}_zKhFxfYmB+G0TiWc!|#2ZI2l0A1?gtc1}5~69dyTO^r^dq zM8fhcmrxCgAFoTu0jat!p~|yX32^Z)Ax1cAV!+uY)BwY?#K4nq32|JWj!Wpv7HAw@ zLN(BQ>JkF?tMR)%06TKziL_$vCkSMXC!XaJY6Q14M zA=YsT)kWr0myqj1T|(cbo@mx3)LgH8>@Fcr%TL)Q^xK5vSuUY!{GJ7uPy?`@xJ&5w zOg2!*B~%ZvI&%6`mk{Jqm9_3yAT9nA;d}=t=XVL2J@6O7CG{3|~lOx;N^+;Yx^~i&(!_zCn+2GMopufDca8x?X94*Zp_xF@a<6?iZG##0n-W^{b zifztk_XjO*kfnqDox||{&Q5SLI8#oq&kh8VhbJpT>-qgu|3dI2HQm2lOp23}lk!M@ zwlpN}O^lozjjqk+3S<4{p5ePIgAur6vSM^mmS@JLC6);+j)Zo^*l2DyIkUK#nA&sDCEE zD~^q!pxHys+>{$!PQklsm`EVo|7)?g!!i(j>$jR2q z(Me`FbR3>j=BAZ_o`sps`KjsB*ibYWy}Nm`xVu{H8Jrr=ES(%i3w`C()cWpbX)|zi zG@9QzT%4Uvjj@sZ%2qJ75@xG|*$iV-;f0CKvFVvUHomsCa(o8hnzQPAh)+m`zWHRF zRoAd~QFB(cd)w+etIT0v(Jr1TXB9bDUNg8_Q_d=S!?b53mdn+SgHIoiaI)`0I6VHX zw1S|JF`Snc_!Yti>589YGXeA5YdOc(f@Z$Ya^9+)BWm@A*QNLowOSAmz9t|-HRs-T zoeGFZ5~A2FjOMW{O36AUrqBIlXv|3W5_-4zpG3{sWoC)mHG{1%zs>lR|| zqO_MNW)vz5>o6$FuDhGvrU!3Q(nZO?L8AJ1Q@MnkOr;prF!sD2&AKLK_UPqaSs{a3 z7F)9ss60qG?G1%CCjqB$+E+it%ENP>!t|Zd~<|vjzIXL@Ws5?j<6k$kPr6%Cr~J$y1KjA zng|W5@Mpe<%(s01|Ni&C|1JD0uTcK#huZ)71()l;xVAp`;QllC4nJ_aT*O7(9an92 zb=TZZ*i-X3*S*@FbKS4)!`0Kd(>1j%u%0 zT|H05MZQWXa`*f0+MDES*NiHd1D>(uK6B$v+c3}7lgn11oCLQEH`&-&OlMK1JRo z@BPpXrE%w7kG}o|f|q*aUhd`c$|KM6P~-IThB;fl+G!3)=OYt{p$*O9qrIhDU)~w@ zha-FWTBO-AQ~gn-KkgCLw)-}uaMO8&u_WlY0u|(Mt2|IdF+1T`R)6kA3Q#2-FpJ5mm!a=E9a`XfEgd|yGCwc#_z6} zF?ywSpX`lZCHv&g5BJ=z6=NQI0F=Yj@;EcrJ5A%voZDFb#kb0u-D~#h0eaYO4hC>X zo3oMGBPO8{qakheZ5kl_0v`tisNqO6+8uLZb{=``yAbIl^ytCzEeF$yX^i^z@LZc{ z&5ovbOdIi8-Z5>v*Iyo}skE9ZEIs|<@(2Kj*uK5oA84b-@{ly`p4K&&?+oUKJs*tv zq~A4HoLZ;4JUTzOfJ5i!%l%fr*<0@S2PRP4)X4H^x~j@>xsP|tyTzetudDayaCz*! z=wz_p?Gtl(Xq&@vXEdxGL&oPuzdIP#j+(vZ=p4ee`_{PAS!IUr)DE53o4r4A*)&w> zFKZ_g%|7X9z52;uK5F!P{7I*&U*3P>I~g`d=EnoTN~@d0laN!Plf2on3IOZLh7BhU zYR>Z;#Fa=T8Rn<#DI45hw3&Lsmn~&*k3tc-;H$12^S9@a((qyT9tb=YGp`A7VW2 z`yTrPcxHK!DFzd<&_*=(A@UA<_uxCM0U@9(IBjyYWYz6yhI9i?ngO)dioeo$VJ z^{>Nsh^4E8K!5Mu&)q+8wOl`NKZZZzdfWA@o_8RZ-|<}RLmKWc7Kkkp94J{9h#<Ba0LZU-i7NsEr^vV9N|Q(A+i-oKc*#d_{eXN-K7s2u$q8ZL z`XONn2iKnj{aHQ@AoDM&fW~$r(w&l_N=#f-6tbBm-B0WJwOLBFU2iTz#Yn zf?i$Tk2y^q6fx?9q4qz3rH;U@WDzt0oyo;YN_ft&Z4L2s@25V`;l~ zQk+P-?BmPvbi6sv8l@B`Pi95Yo1DwhOwFHD_=X)0s!IQ~7|z%+DxHlrluRs>SO{d$ zXolrxS7|pVRi4cmqGFxKo7tS=uQX=`qoua{Ev2a{^Tx>_e%cM%3$x;9hG>Z+RmZ`Q!ek+>^x2S1N zSv0b-u##1RN?VENV#$1O7D@T7nwPVuEk&Pc&2*((4e}MG9IN|AJvo0eoA5TNwuSB) zB?f0jUgu6Cg`TiTFjcuXQp09+m{hZ&I>{!z!@7t}mg>?Z)8M+%ScW^RhVo}J@Het( zQ$fk-#)E2jWF{i1c`~1GCV>y(vr})oZRQu!ygc!Z7>UVun@lt%SL%y;G_O>Zu=lJp zuk}MzY6>D3Grgx_Wl&TnnN)f<%T$S&V{(EzZ^ntyZ!59T#GH1NwyrjmX7FMZ?fLXl zEjFkWXVg5Q%mzsx85JgBwY*@GC*`hePcBOJ({vE!Il)=kGt!Rr`i)L=aK>k?Ha`)= z{#vwUH%&hktVm)!C@n6gr@#qJ?7s1FVLmVewD6Id3gxPq zf*Pj6>eZ)kiAWJy5tv|@izr+qL{Xu3M>c0{TPvyMMm5A`gI!CD zc&nLaPDn-Cxr*ZNwRmFm#u0T9>{Z1|F)i{j~!3i(pAEE|iL)0IWR zoSw{*T#WOzGt<-9L?aj8laf}D>WM6AkyECXZkAG-Icb%9iMrimyNL`H45e~OVwki3 zqC8R}snkV&VUH;H`c#MCfM>!iG>9%noE}3ns=<&={PG$IlUzhU!X&l2h(P6WZHl6o4aze zk&2tUkwGh{Y-^NYmYF6OioP2+ora;7W-T_<%Y51!H$qCiu29KfHW~_DMDsD74`-97 zL8YEgaswtTMVg&DsHJkS5t(PWQ8Rj08bn)sH!WSnf{SLa=wp;Yj^f9?NyeMu9vh)!5h-!St`|v z`z@)M7!CZhNls4lO6O!A7s?a9DU@ar*5Z?)%A(OJhJ_fDPIYXi9WU3-ti)WL80E&4 z>WwD#__P=5ag`j~@Ff(fJn%C0Mz}CcaH&RoP$qt95$Z%6^P*t$jf*i`3Ag$c&0h^w zLd_Y~3YA#VTWW^mi%u#ut$WM9POi>M!+fG0D)_a|q#0A0qBuG=e8r5epH2&6_ClE{ zN>Iyqdo?N)y@*HW&1rC9pP72Ap6{NV<%kfH*~*16oDb)xT>C6z6+||fQ2JqEW_HrW zTrhK`!k#T;i$C4&*PKzwmK_rT!OB+SXZ>2NF)>omodttgC7hos)BG)L8|o(G=JvMD zcDKA5Fl~yq_|@UC@v%MBXazn&KDE$7?A+j>dsUzl#!e7E*=*?Kv}tBT7okLqRkcd+ zENFMRLNY(~o($BJ_T1-Xmc z%a&vqI$+AttLCJOg)7dm=D~r5O@0GaLsvSsY`ns$lUZOEe!VNxbEQ$}uv> z=|m!yD2RqBFn+_&`2bs%;dRmE43YP9P!U1ncqf5XdWObYrpyU`nKLZIkbSzP>3+fD z1wr#ky1-(Bet=J6d;)xdUzWK75%?p^8pHAaRZ@~)H(4k+;w|U~Bw-qUmM4EOqu8+ zuR94CJj?nFOW=7+)O?mt*G)|XHW(%YY(%(pV1vMbohxvhU*lNW$7zB_2;+AWFoC6( zDexwdS&i2~0(G4c{T2_1fTH6y9TH=mNB`1I+g=!=YX5B`!6M2EWWqBH0c2!Olc2nk z&+YW5$O7z!K?n)A~#Lo*7kFtik; zIi40-npJ2qM6(<%v9zMnzA!EGG|$pph~`x~qC)pW^AU{XR63~AVS$!8Isy-bY1T&v z1=`2b3_J`egy^7;RymrHXeCIC5n2#w1tKA9nHC{aNSUK$iH`7?BV@tKbi_|fPMTpz z9A07Q2t%tp9b&PxJWosF7Y{%cHPJ7=_;W_41p!ln1Z1cdOABFI4bu@H?S}*uIvB#5 zF)ZGQ3N1;rD$=Tt_AxXYro(>x$p@K3CJG&f{KK>mq$45P7lH8>9rV+pgw>T~T2g3L zpjk*qpu=H02>+0yNb~TPM2DbefC1D7vJPUY7$^y#2w*Ty&;bM(5j42`+-6cLUc%`eNa~b$xjQAy+FeYJ_)%9CBV#p8NeioW_+~Z zP$({x6|zx8d|g&(hJ*Z^JfQl(0^pe9r+os=akL-u2fjfW6-*jHgHl7;0ay?vfk#e( zKq)-R8pvZXNHZeshoU$Ig%Sh9L3V&gA$G?HjlOTkC)|UZk*fuhFfDM1eva3@$Kcg| z0{&+=_@-On@opW!_27wT6F!9S;a2zv!be--V+bE_g((PA7J7_}b5FR-Y+Ah2kym(&lAqemv3gk2$Dnwj647_OwO)#!ajoj1lsQ! zbPR8Uj^S<4F}w{rhBu%?${4=V3M(cg{>n_y=OdGb2~?P{1xBp&h9mT=*{B#I?Fjfw z^WpVfK46B!|8&KLD;@wBK6ow{oL6t=!Dnk808ZC*@&^CsHi93uP)Aaa4!4AQM}a&; zv~MrV!djO90#UrwABf}grTFr-n-N5P^;ebRHH!JCr1FLO_GS&SC7b~0mPTF)X99|R zlW;x{$z5p_9Fh93S2(Vu@%eJNdTE0q+65ci;G;E)8##2ZYy*%&)C;H~?mUL6R;OoQ zwPDFYt7*b2kA^k^Vy-)RP?ylz(#;{X&t|7XYxG3xGzoV6^gwIcUsNHp)T4tdIkU03 z!rBJVwzy0H?uhB!IVe5ayXu*i`%SW*O@3xaF8+5&ZFm3#`zMgD=XT)Yj{zXqFYE#m zfEYW2B#Q(!*)|Mz4rA#JxuKW#{crg7)+qQkD1h7IN-P)%+|);-THorEH+}TlaQWs_ z4Ji%FRPy;#df=?SLHXFJ@ACC+OJ)7=s)=m6(C4*|T}#gYf4@xC{hO*|YrwS(A$YJ#x1^uwujgjteNR+3+~6V(+nM$Ab3k^p((NcKS*TZ}*iL-tH?g zyy+`1j$oP79vChA3*S?KuA2(9wJT%#DQoZxH&nt|l>%Ml^5M#qR#%P8B&g4k+pBK# zr}6FvyYRZ@vTBS=_vjXuq6Fg#*YE+Pj4knvTN~BVh9x`F_}4OkS*f}00nE5}EAV%$ zk|nhn$4K^Vp}w_6F5g3(zwFRO{xL#1{*-{<66L2m;2UuVS^tsX{_2iV$TDv|1Ng5$ z&me>e2yB@6L6w7FN9ADaLv0I-)I4=C2f-wCf#TUi6Z)zXZXIk)Lr1+3kJBly6veln z!VyO|mrEXZhKgUj2HAaqnWKqv4Aw8zI*X}l&;(u`;f&3rAveFI!Y^yaIGmW(}P8N;K+Eq*E-ywg`uMz zv_8E(T2ITF{R>!e4M^(Iv4fwjV~l}>MRKKFuOYX;GH4v+u#3G7eB4hVd=xzG@;ro9 za<>5RYT%9FZ2&|yO582<_&6elxh z1XtD`H5_!BqfWDD4xb6s&3#Yp7#0+s8}@m}x)HdqVH-Vfu2z(SrEv}m1W126T)lFF zFgmIdOhanz;{hY_qZ?Z6GZWdgUr5Y_(iwv9@C_gU6RbwY)y^Pyd$^3;ss8_jpP(aO z-dnkFY&!e!MY9e^{)cr~{R;j<80SN!R-=LA$2cZfdHPmWT<(E~ zY2(2&`aKw(kB!llhv^zOVbyc2H(65V%vt)2{yC?apy|79>n;yK37tK|d#5@t!>{b8 z2!mtvyFUQF-e~k+J-vg&re%BrSznsFP`f=;!cM*SH}!_LfT%bscU5n@iv?bfnz3zd z)p&qGr&bYsXlo#2U*J#lhP)4VD?i(&keqT=B~+NtuhMQ~->^0a>26mE3V#dMj?f6b z3qwD2dx|D9N}%(e|Z3n_=Q~MBUcc-n5+B_ zS2xX)gRHk9xS6XXN78qyY@>(la`=9&%GaugL;CIN*<*-!K6{0;tGd0Iy~3t$Sg%dp zN)UK<-O!Kcj8YDqJ8aj7Fp7uK%VStFjbj+c&5Ch*P8`q;%lA{Y!^@Evl+mWGN?1NX)9EIk z#zu4O4rw}O4ts%Baoc|bFE6bdejeZ6#^c3}NBX%hgU9Z8 za)XBt^1THfFyS>iMkn@8kG{AMyP`DkYkdqGgu2@3OGrW!^0iw?P>a0Kud!jPtYM|G z?Yp3ld%g%<4es#yO_l!;0=KBL)6=7=>}Zc;U_TB=?h=?KAO~%rj^4P6zXS1yt9VHL z9_ko)7xm360GtO5Z)cFQ4#SQbm~U9=9{hbD!j3!1>1tpfjU!q-6m@ZTYk9AufEI7w zxIf^F{|6uY7vYsh_rF{hxS$LRsEv_TX|| zZ#g5K4VzfTL_R%$mtA`wz-E@Oz#lpy!OFa8#IyC{j*{On?Vm$Jw`UsJBl|zxyT-UJ z1_2YU7zc(OIrXNK{w09vX7<^?j6eMf5_&`4hr8u9 z&aoHUoO^J4&h3s>f7F~?b7+Tihrqex9}(xMZO(0}^c~Kvn%`@y=C`$W|Hp)N+~+UJ zx+}wZM^pX_5RWg{=wQ3){m!V#_vbJnLx zCG>IrRAH4K!95XbSmkkJ1avysXV<8K-5-G5f|<&Oat>=YIp){t)Vd zx|RaR$gQ>Q)o@{l@%EQyJZf7I6|fgK-5zzV+r#j7w};`~Ztu>@y0o#|+cB%wbKAGI zFmd6>Q|9-r6`=6@2&c0X6X1MsyKd`hY~q2;H_8tO^0#O~TjmuSolowphn#D3dj*Iy z_P9L~x3{pabpYZYVf|4aP@G=SU0)41u-+Rl!nQZX@gIDtbyn*sw3D@K(wSSm@(SUs zs@9{y?u3OXqyBov6~@tFz{d$>W3%fl(LPgCjClZe&RA@!k_WfxzP&l!1p~xIbU{X78Xs zXFZZSczg%umM^E}k0FFj2rLh0RCSor&OnG(TbEYddPvO`Vv!hZqE(%}N)&9b4y9Y6 zkfJ3+uqEmG79|z7C{3-Fno26esKOT2Py;rxmQ$lzK}{r;c9e1=XUR~pot?pMQ*C=Q zT_~%T!6PZrc!x=`ek zt(@k>Efgjhu5RLzDl-c$lsL7@ty)kzr9v_X7)+g9V(PS!u2qbBxh&7Mb#5=jAiThB z%UHK$A=sTY$Z2g*ErfzSC;s|&=5(+H08{m9J5;a2uJ5R~Js*)=i!Vg z^GH5hYqku&H&lb;lSE$_mupPP$=}#AZ9@o$5t1R1(j$Rx}mX zIyEW64%$5D4F!i%gPo;jVt76qtEcN-^M%zeZR%>9b{4j2r-SuusFaP!)svH~kQvUs zVR$!8;gceMmQ%AI}dPqh+y{c)DnYrhBG1;sD{Lkjq; zfF=YCEkOJMkqt;zzz;z&;3EN64oLn0LjsZ(p#1)TKmvX}pfLea3@}!J7XyAS!1@C^ z6Chkb^9Ljo-;~7wg?CoKAOS|gSRw{ANQ?~-J|JrWMhjS6K=uWAA;9SYN;U!(A7I1) z%LXhVz{1ly-b0KIFIxd3;A;XDj0;dE7Z9B1ID!=r;WsAW^9495K#Tw}v5<@qV0;17 z3Qz`=m=8!gX6J)CK$2E~6#{-JG>bKX0+>(?cmbY?VSnLy6!nD_#+9N_%{0tqu%X`RP%QhqUD2v|hFjCpZJz-I(}QWaXIv= zKi!y6uv!iEbnV^@)cE;?J%?Tx)~TV@0INYp%ezjmJ|3P!^2@_@;Ktd>yUqk2CNp9G z9oia>pXlMy-u~Tv_ZuFZ)&=+O`#1I-&eHSq)w_Rv{YVIUt{3$qs)7AT=c2CQaUFH| zu64teY8Xb8aIkTMCQne`ZMb*>xWQolCr-pXLTSC}QY%vPng7o>ivP z(-La^P%uno3#ye2GSN`}a+9_iS8~;?(=DjMjv0-NjOeVB=%yxmVY{1%P1A)WOC<~O zt$xCAA~6m+Jg1-7=_al^BRD4_p31>M8@7lmPO*a1X*}DF3`w*zf}X3B%w?x)-RV=p zVP#aTRZ>hWlIj?}S_d%ObPZcN6py-C^$nL@!%5yBjhDEz5h3$bGAo?<#WTAa870*o zU+Sq5k~!6=);!PqE1l#l-(dQAA!-()rD7-^>vhD?U^tP=S<+zmh-Ie9WHAt9HNlrQ zT4p-aEcd#tdWYhoV#{xGdid0z%Nvbo$(s)QB08(oC*v`9A~)xfMJ(RVWKaC2LdfE* zXfLLkQPO*5@2JjE*-^f7mV-U>c%q7y4zkeoF)cVw2D-%4ESyhJ&lXS0(@@19vC7F< zCLFQi-k79up>)*Sk*3rscD^~L6%5v=k-k#Y7!V(e&m}cmYnDgDbh=jSB*yYIK3$mu zIi?U)VpG_uoWM+|)2yUI=Nk%|u(29ZhchpNYI2&b#uBwkqoG%VLoh^II>&{=JmJY) z+>s4Rug0=^IWo{gyFWmDrq;_%6Wx*k7R^+T7ROai9wkH5Xs8^51302luNn(d;cV85 zG}w$0Escw8Dj8ErNAH&A)k>~Y15vG2;*3@Xvw({*wHw+91-yqt2jFOvv~OmSVN~z+ z&xGWhH{)>V7AYvLWGgd`l&UPxCr%k5n=nEXQ7FvL8lz&JwVG6>PFf|CJslM0qfF4M z%sD+@(<@4f(ezqqG-d6o-Rt@LY@HjVq~?53y5JY39@9(~7TLvYNG;S%n%4)plVT&4 zw`3;M4Gr_6eNh`IO0SaFlsOyfOi#=06UK~kgKE2>vRzgQmXay1GgQiyDVJx_wl5aB z&|+{oG%uQbkE!dGP%R$!^}At3oW(mttDaG5&3~5T zhbI@U;BYJ#m1cR62#zEDeBm?};WRUMmWyNu9tqj0Q+*w4tcCUY)X+{I5W0~ zS!&#}2C+fcPG?RQgUKXY?oG{1jPJy}VozY(gk2jrM$@x9hy1HU{OmZ!*ah z^;|QR>qE~T(?=(BO|HsgCay`*L}lV5(+bmJ-~gs%J0YDltx7SXltSayfQ%$w;d*3qy-2MmjYa~IpH)Gs}`jJ z+lNzp27Z$7H6^NW8g8-?Z!{``4cASETcS}u6FAG8U9?J5F=Lmyk&6r4R{P1$ObVA9 zVs-26j;HLXUHi!bD*-GWusy_p2zCZ zCXgA>b+j@8E3m@AsA8ccA_gf_5Aa|j!f!ej4vGsP8b&~KtTHelp{`&Xf{~`nV4Fdz zV5Uj|-iH-Mo6sNNWUxSAWIx$|7i}Z7p6uU4^7oM7p!jOy#o0~veDjHS%qRQz@x8x~ z1W%28k+sDC=Z&@W^)G8J@hLdB?uVGkZz1_@B>w=(KSVgB z8K!WBvrXZ|K#%2VAJ{aG=vV8}VODkzd=}eB^S=+-9u{tEuHm&8+ zWvF(DcMx?WQ{UZQ!*;nYWR=0|AWQ4jc}MP}y?gF`IN=eNK7IQdZYxW8?HAom;$}$0 zH$w_b`k#jM8l2#_--YwN4RWgus2k`I)^9xH$Mb%NAnq`&yo>ENp7uY6VlMAp!ievz z=ARurF+{@yD}rLWeE&u$*TphAre=TRX+$Y-j4jw(A-bK?&A_6o`370N0a)=zZ>L z&EEO>hJo15f_ia>*j(gP6i%v$c z*ZKgKeOk>roF)uvZn#xU2g&2QxjJ}w_#G@K1xdiMt}w@hfA+tG&{O&q2i?we6iy_K zU_Ja3_o@VY%OluLIKq5t#|UzM4Cl={iEL#{!|N+99(~%;x;oLm8^Nq0+GYPMAm9(c z_a4Fdpm4;C2FKxITCk!C3kR2P;^iCmYxum=;o(8Y_Pa>_7)b5G>Rj7THcRXsomqQl z9esJ+?I(EHGMsJH@7bv29rS8%t{*DGE;%^$mdDduwb9Dyk34h^4z4}ieyTU_>TvEW zI`eCHw|-bHKYtTnx({S|cjZ15K2a4L=TXssq&Y>d)D0_XhIP<8fj@aqm%YQ^yZ~(e;b2*2D9M-*Qy?5l+(n Ee -# -# =================================================================== -# The contents of this file are dedicated to the public domain. To -# the extent that dedication to the public domain is not available, -# everyone is granted a worldwide, perpetual, royalty-free, -# non-exclusive license to exercise all rights associated with the -# contents of this file for any purpose whatsoever. -# No rights are reserved. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS -# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN -# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# =================================================================== - -"""Self-test suite for Crypto.PublicKey.DSA""" - -import os -from Crypto.Util.py3compat import * - -import unittest -from Crypto.SelfTest.st_common import list_test_cases, a2b_hex, b2a_hex - -def _sws(s): - """Remove whitespace from a text or byte string""" - if isinstance(s,str): - return "".join(s.split()) - else: - return b("").join(s.split()) - -class DSATest(unittest.TestCase): - # Test vector from "Appendix 5. Example of the DSA" of - # "Digital Signature Standard (DSS)", - # U.S. Department of Commerce/National Institute of Standards and Technology - # FIPS 186-2 (+Change Notice), 2000 January 27. - # http://csrc.nist.gov/publications/fips/fips186-2/fips186-2-change1.pdf - - y = _sws("""19131871 d75b1612 a819f29d 78d1b0d7 346f7aa7 7bb62a85 - 9bfd6c56 75da9d21 2d3a36ef 1672ef66 0b8c7c25 5cc0ec74 - 858fba33 f44c0669 9630a76b 030ee333""") - - g = _sws("""626d0278 39ea0a13 413163a5 5b4cb500 299d5522 956cefcb - 3bff10f3 99ce2c2e 71cb9de5 fa24babf 58e5b795 21925c9c - c42e9f6f 464b088c c572af53 e6d78802""") - - p = _sws("""8df2a494 492276aa 3d25759b b06869cb eac0d83a fb8d0cf7 - cbb8324f 0d7882e5 d0762fc5 b7210eaf c2e9adac 32ab7aac - 49693dfb f83724c2 ec0736ee 31c80291""") - - q = _sws("""c773218c 737ec8ee 993b4f2d ed30f48e dace915f""") - - x = _sws("""2070b322 3dba372f de1c0ffc 7b2e3b49 8b260614""") - - k = _sws("""358dad57 1462710f 50e254cf 1a376b2b deaadfbf""") - k_inverse = _sws("""0d516729 8202e49b 4116ac10 4fc3f415 ae52f917""") - m = b2a_hex(b("abc")) - m_hash = _sws("""a9993e36 4706816a ba3e2571 7850c26c 9cd0d89d""") - r = _sws("""8bac1ab6 6410435c b7181f95 b16ab97c 92b341c0""") - s = _sws("""41e2345f 1f56df24 58f426d1 55b4ba2d b6dcd8c8""") - - def setUp(self): - global DSA, Random, bytes_to_long, size - from Crypto.PublicKey import DSA - from Crypto import Random - from Crypto.Util.number import bytes_to_long, inverse, size - - self.dsa = DSA - - def test_generate_1arg(self): - """DSA (default implementation) generated key (1 argument)""" - dsaObj = self.dsa.generate(1024) - self._check_private_key(dsaObj) - pub = dsaObj.public_key() - self._check_public_key(pub) - - def test_generate_2arg(self): - """DSA (default implementation) generated key (2 arguments)""" - dsaObj = self.dsa.generate(1024, Random.new().read) - self._check_private_key(dsaObj) - pub = dsaObj.public_key() - self._check_public_key(pub) - - def test_construct_4tuple(self): - """DSA (default implementation) constructed key (4-tuple)""" - (y, g, p, q) = [bytes_to_long(a2b_hex(param)) for param in (self.y, self.g, self.p, self.q)] - dsaObj = self.dsa.construct((y, g, p, q)) - self._test_verification(dsaObj) - - def test_construct_5tuple(self): - """DSA (default implementation) constructed key (5-tuple)""" - (y, g, p, q, x) = [bytes_to_long(a2b_hex(param)) for param in (self.y, self.g, self.p, self.q, self.x)] - dsaObj = self.dsa.construct((y, g, p, q, x)) - self._test_signing(dsaObj) - self._test_verification(dsaObj) - - def test_construct_bad_key4(self): - (y, g, p, q) = [bytes_to_long(a2b_hex(param)) for param in (self.y, self.g, self.p, self.q)] - tup = (y, g, p+1, q) - self.assertRaises(ValueError, self.dsa.construct, tup) - - tup = (y, g, p, q+1) - self.assertRaises(ValueError, self.dsa.construct, tup) - - tup = (y, 1, p, q) - self.assertRaises(ValueError, self.dsa.construct, tup) - - def test_construct_bad_key5(self): - (y, g, p, q, x) = [bytes_to_long(a2b_hex(param)) for param in (self.y, self.g, self.p, self.q, self.x)] - tup = (y, g, p, q, x+1) - self.assertRaises(ValueError, self.dsa.construct, tup) - - tup = (y, g, p, q, q+10) - self.assertRaises(ValueError, self.dsa.construct, tup) - - def _check_private_key(self, dsaObj): - # Check capabilities - self.assertEqual(1, dsaObj.has_private()) - self.assertEqual(1, dsaObj.can_sign()) - self.assertEqual(0, dsaObj.can_encrypt()) - - # Sanity check key data - self.assertEqual(1, dsaObj.p > dsaObj.q) # p > q - self.assertEqual(160, size(dsaObj.q)) # size(q) == 160 bits - self.assertEqual(0, (dsaObj.p - 1) % dsaObj.q) # q is a divisor of p-1 - self.assertEqual(dsaObj.y, pow(dsaObj.g, dsaObj.x, dsaObj.p)) # y == g**x mod p - self.assertEqual(1, 0 < dsaObj.x < dsaObj.q) # 0 < x < q - - def _check_public_key(self, dsaObj): - k = bytes_to_long(a2b_hex(self.k)) - m_hash = bytes_to_long(a2b_hex(self.m_hash)) - - # Check capabilities - self.assertEqual(0, dsaObj.has_private()) - self.assertEqual(1, dsaObj.can_sign()) - self.assertEqual(0, dsaObj.can_encrypt()) - - # Check that private parameters are all missing - self.assertEqual(0, hasattr(dsaObj, 'x')) - - # Sanity check key data - self.assertEqual(1, dsaObj.p > dsaObj.q) # p > q - self.assertEqual(160, size(dsaObj.q)) # size(q) == 160 bits - self.assertEqual(0, (dsaObj.p - 1) % dsaObj.q) # q is a divisor of p-1 - - # Public-only key objects should raise an error when .sign() is called - self.assertRaises(TypeError, dsaObj._sign, m_hash, k) - - # Check __eq__ and __ne__ - self.assertEqual(dsaObj.public_key() == dsaObj.public_key(),True) # assert_ - self.assertEqual(dsaObj.public_key() != dsaObj.public_key(),False) # failIf - - self.assertEqual(dsaObj.public_key(), dsaObj.publickey()) - - def _test_signing(self, dsaObj): - k = bytes_to_long(a2b_hex(self.k)) - m_hash = bytes_to_long(a2b_hex(self.m_hash)) - r = bytes_to_long(a2b_hex(self.r)) - s = bytes_to_long(a2b_hex(self.s)) - (r_out, s_out) = dsaObj._sign(m_hash, k) - self.assertEqual((r, s), (r_out, s_out)) - - def _test_verification(self, dsaObj): - m_hash = bytes_to_long(a2b_hex(self.m_hash)) - r = bytes_to_long(a2b_hex(self.r)) - s = bytes_to_long(a2b_hex(self.s)) - self.failUnless(dsaObj._verify(m_hash, (r, s))) - self.failIf(dsaObj._verify(m_hash + 1, (r, s))) - - def test_repr(self): - (y, g, p, q) = [bytes_to_long(a2b_hex(param)) for param in (self.y, self.g, self.p, self.q)] - dsaObj = self.dsa.construct((y, g, p, q)) - repr(dsaObj) - - -class DSADomainTest(unittest.TestCase): - - def test_domain1(self): - """Verify we can generate new keys in a given domain""" - dsa_key_1 = DSA.generate(1024) - domain_params = dsa_key_1.domain() - - dsa_key_2 = DSA.generate(1024, domain=domain_params) - self.assertEqual(dsa_key_1.p, dsa_key_2.p) - self.assertEqual(dsa_key_1.q, dsa_key_2.q) - self.assertEqual(dsa_key_1.g, dsa_key_2.g) - - self.assertEqual(dsa_key_1.domain(), dsa_key_2.domain()) - - def _get_weak_domain(self): - - from Crypto.Math.Numbers import Integer - from Crypto.Math import Primality - - p = Integer(4) - while p.size_in_bits() != 1024 or Primality.test_probable_prime(p) != Primality.PROBABLY_PRIME: - q1 = Integer.random(exact_bits=80) - q2 = Integer.random(exact_bits=80) - q = q1 * q2 - z = Integer.random(exact_bits=1024-160) - p = z * q + 1 - - h = Integer(2) - g = 1 - while g == 1: - g = pow(h, z, p) - h += 1 - - return (p, q, g) - - - def test_generate_error_weak_domain(self): - """Verify that domain parameters with composite q are rejected""" - - domain_params = self._get_weak_domain() - self.assertRaises(ValueError, DSA.generate, 1024, domain=domain_params) - - - def test_construct_error_weak_domain(self): - """Verify that domain parameters with composite q are rejected""" - - from Crypto.Math.Numbers import Integer - - p, q, g = self._get_weak_domain() - y = pow(g, 89, p) - self.assertRaises(ValueError, DSA.construct, (y, g, p, q)) - - -def get_tests(config={}): - tests = [] - tests += list_test_cases(DSATest) - tests += list_test_cases(DSADomainTest) - return tests - -if __name__ == '__main__': - suite = lambda: unittest.TestSuite(get_tests()) - unittest.main(defaultTest='suite') - -# vim:set ts=4 sw=4 sts=4 expandtab: diff --git a/Crypto/SelfTest/PublicKey/test_ECC.py b/Crypto/SelfTest/PublicKey/test_ECC.py deleted file mode 100644 index ea07a9d..0000000 --- a/Crypto/SelfTest/PublicKey/test_ECC.py +++ /dev/null @@ -1,859 +0,0 @@ -# =================================================================== -# -# Copyright (c) 2015, Legrandin -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# =================================================================== - -import unittest -import time -from Crypto.SelfTest.st_common import list_test_cases -from Crypto.SelfTest.loader import load_test_vectors - -from Crypto.PublicKey import ECC -from Crypto.PublicKey.ECC import EccPoint, _curves, EccKey - -from Crypto.Math.Numbers import Integer - -class TestEccPoint(unittest.TestCase): - - def test_mix(self): - - p1 = ECC.generate(curve='P-256').pointQ - p2 = ECC.generate(curve='P-384').pointQ - - try: - p1 + p2 - assert(False) - except ValueError as e: - assert "not on the same curve" in str(e) - - try: - p1 += p2 - assert(False) - except ValueError as e: - assert "not on the same curve" in str(e) - - def test_repr(self): - p1 = ECC.construct(curve='P-256', - d=75467964919405407085864614198393977741148485328036093939970922195112333446269, - point_x=20573031766139722500939782666697015100983491952082159880539639074939225934381, - point_y=108863130203210779921520632367477406025152638284581252625277850513266505911389) - self.assertEqual(repr(p1), "EccKey(curve='NIST P-256', point_x=20573031766139722500939782666697015100983491952082159880539639074939225934381, point_y=108863130203210779921520632367477406025152638284581252625277850513266505911389, d=75467964919405407085864614198393977741148485328036093939970922195112333446269)") - - -class TestEccPoint_NIST_P256(unittest.TestCase): - """Tests defined in section 4.3 of https://www.nsa.gov/ia/_files/nist-routines.pdf""" - - pointS = EccPoint( - 0xde2444bebc8d36e682edd27e0f271508617519b3221a8fa0b77cab3989da97c9, - 0xc093ae7ff36e5380fc01a5aad1e66659702de80f53cec576b6350b243042a256) - - pointT = EccPoint( - 0x55a8b00f8da1d44e62f6b3b25316212e39540dc861c89575bb8cf92e35e0986b, - 0x5421c3209c2d6c704835d82ac4c3dd90f61a8a52598b9e7ab656e9d8c8b24316) - - def test_set(self): - pointW = EccPoint(0, 0) - pointW.set(self.pointS) - self.assertEqual(pointW, self.pointS) - - def test_copy(self): - pointW = self.pointS.copy() - self.assertEqual(pointW, self.pointS) - pointW.set(self.pointT) - self.assertEqual(pointW, self.pointT) - self.assertNotEqual(self.pointS, self.pointT) - - def test_negate(self): - negS = -self.pointS - sum = self.pointS + negS - self.assertEqual(sum, self.pointS.point_at_infinity()) - - def test_addition(self): - pointRx = 0x72b13dd4354b6b81745195e98cc5ba6970349191ac476bd4553cf35a545a067e - pointRy = 0x8d585cbb2e1327d75241a8a122d7620dc33b13315aa5c9d46d013011744ac264 - - pointR = self.pointS + self.pointT - self.assertEqual(pointR.x, pointRx) - self.assertEqual(pointR.y, pointRy) - - pai = pointR.point_at_infinity() - - # S + 0 - pointR = self.pointS + pai - self.assertEqual(pointR, self.pointS) - - # 0 + S - pointR = pai + self.pointS - self.assertEqual(pointR, self.pointS) - - # 0 + 0 - pointR = pai + pai - self.assertEqual(pointR, pai) - - def test_inplace_addition(self): - pointRx = 0x72b13dd4354b6b81745195e98cc5ba6970349191ac476bd4553cf35a545a067e - pointRy = 0x8d585cbb2e1327d75241a8a122d7620dc33b13315aa5c9d46d013011744ac264 - - pointR = self.pointS.copy() - pointR += self.pointT - self.assertEqual(pointR.x, pointRx) - self.assertEqual(pointR.y, pointRy) - - pai = pointR.point_at_infinity() - - # S + 0 - pointR = self.pointS.copy() - pointR += pai - self.assertEqual(pointR, self.pointS) - - # 0 + S - pointR = pai.copy() - pointR += self.pointS - self.assertEqual(pointR, self.pointS) - - # 0 + 0 - pointR = pai.copy() - pointR += pai - self.assertEqual(pointR, pai) - - def test_doubling(self): - pointRx = 0x7669e6901606ee3ba1a8eef1e0024c33df6c22f3b17481b82a860ffcdb6127b0 - pointRy = 0xfa878162187a54f6c39f6ee0072f33de389ef3eecd03023de10ca2c1db61d0c7 - - pointR = self.pointS.copy() - pointR.double() - self.assertEqual(pointR.x, pointRx) - self.assertEqual(pointR.y, pointRy) - - # 2*0 - pai = self.pointS.point_at_infinity() - pointR = pai.copy() - pointR.double() - self.assertEqual(pointR, pai) - - # S + S - pointR = self.pointS.copy() - pointR += pointR - self.assertEqual(pointR.x, pointRx) - self.assertEqual(pointR.y, pointRy) - - def test_scalar_multiply(self): - d = 0xc51e4753afdec1e6b6c6a5b992f43f8dd0c7a8933072708b6522468b2ffb06fd - pointRx = 0x51d08d5f2d4278882946d88d83c97d11e62becc3cfc18bedacc89ba34eeca03f - pointRy = 0x75ee68eb8bf626aa5b673ab51f6e744e06f8fcf8a6c0cf3035beca956a7b41d5 - - pointR = self.pointS * d - self.assertEqual(pointR.x, pointRx) - self.assertEqual(pointR.y, pointRy) - - # 0*S - pai = self.pointS.point_at_infinity() - pointR = self.pointS * 0 - self.assertEqual(pointR, pai) - - # -1*S - self.assertRaises(ValueError, lambda: self.pointS * -1) - - # Reverse order - pointR = d * self.pointS - self.assertEqual(pointR.x, pointRx) - self.assertEqual(pointR.y, pointRy) - - pointR = Integer(d) * self.pointS - self.assertEqual(pointR.x, pointRx) - self.assertEqual(pointR.y, pointRy) - - - def test_joing_scalar_multiply(self): - d = 0xc51e4753afdec1e6b6c6a5b992f43f8dd0c7a8933072708b6522468b2ffb06fd - e = 0xd37f628ece72a462f0145cbefe3f0b355ee8332d37acdd83a358016aea029db7 - pointRx = 0xd867b4679221009234939221b8046245efcf58413daacbeff857b8588341f6b8 - pointRy = 0xf2504055c03cede12d22720dad69c745106b6607ec7e50dd35d54bd80f615275 - - t = self.pointS * d - - pointR = self.pointS * d + self.pointT * e - self.assertEqual(pointR.x, pointRx) - self.assertEqual(pointR.y, pointRy) - - def test_sizes(self): - self.assertEqual(self.pointS.size_in_bits(), 256) - self.assertEqual(self.pointS.size_in_bytes(), 32) - -class TestEccPoint_NIST_P384(unittest.TestCase): - """Tests defined in section 4.4 of https://www.nsa.gov/ia/_files/nist-routines.pdf""" - - pointS = EccPoint( - 0xfba203b81bbd23f2b3be971cc23997e1ae4d89e69cb6f92385dda82768ada415ebab4167459da98e62b1332d1e73cb0e, - 0x5ffedbaefdeba603e7923e06cdb5d0c65b22301429293376d5c6944e3fa6259f162b4788de6987fd59aed5e4b5285e45, - "p384") - - pointT = EccPoint( - 0xaacc05202e7fda6fc73d82f0a66220527da8117ee8f8330ead7d20ee6f255f582d8bd38c5a7f2b40bcdb68ba13d81051, - 0x84009a263fefba7c2c57cffa5db3634d286131afc0fca8d25afa22a7b5dce0d9470da89233cee178592f49b6fecb5092, - "p384") - - def test_set(self): - pointW = EccPoint(0, 0, "p384") - pointW.set(self.pointS) - self.assertEqual(pointW, self.pointS) - - def test_copy(self): - pointW = self.pointS.copy() - self.assertEqual(pointW, self.pointS) - pointW.set(self.pointT) - self.assertEqual(pointW, self.pointT) - self.assertNotEqual(self.pointS, self.pointT) - - def test_negate(self): - negS = -self.pointS - sum = self.pointS + negS - self.assertEqual(sum, self.pointS.point_at_infinity()) - - def test_addition(self): - pointRx = 0x12dc5ce7acdfc5844d939f40b4df012e68f865b89c3213ba97090a247a2fc009075cf471cd2e85c489979b65ee0b5eed - pointRy = 0x167312e58fe0c0afa248f2854e3cddcb557f983b3189b67f21eee01341e7e9fe67f6ee81b36988efa406945c8804a4b0 - - pointR = self.pointS + self.pointT - self.assertEqual(pointR.x, pointRx) - self.assertEqual(pointR.y, pointRy) - - pai = pointR.point_at_infinity() - - # S + 0 - pointR = self.pointS + pai - self.assertEqual(pointR, self.pointS) - - # 0 + S - pointR = pai + self.pointS - self.assertEqual(pointR, self.pointS) - - # 0 + 0 - pointR = pai + pai - self.assertEqual(pointR, pai) - - def _test_inplace_addition(self): - pointRx = 0x72b13dd4354b6b81745195e98cc5ba6970349191ac476bd4553cf35a545a067e - pointRy = 0x8d585cbb2e1327d75241a8a122d7620dc33b13315aa5c9d46d013011744ac264 - - pointR = self.pointS.copy() - pointR += self.pointT - self.assertEqual(pointR.x, pointRx) - self.assertEqual(pointR.y, pointRy) - - pai = pointR.point_at_infinity() - - # S + 0 - pointR = self.pointS.copy() - pointR += pai - self.assertEqual(pointR, self.pointS) - - # 0 + S - pointR = pai.copy() - pointR += self.pointS - self.assertEqual(pointR, self.pointS) - - # 0 + 0 - pointR = pai.copy() - pointR += pai - self.assertEqual(pointR, pai) - - def test_doubling(self): - pointRx = 0x2a2111b1e0aa8b2fc5a1975516bc4d58017ff96b25e1bdff3c229d5fac3bacc319dcbec29f9478f42dee597b4641504c - pointRy = 0xfa2e3d9dc84db8954ce8085ef28d7184fddfd1344b4d4797343af9b5f9d837520b450f726443e4114bd4e5bdb2f65ddd - - pointR = self.pointS.copy() - pointR.double() - self.assertEqual(pointR.x, pointRx) - self.assertEqual(pointR.y, pointRy) - - # 2*0 - pai = self.pointS.point_at_infinity() - pointR = pai.copy() - pointR.double() - self.assertEqual(pointR, pai) - - # S + S - pointR = self.pointS.copy() - pointR += pointR - self.assertEqual(pointR.x, pointRx) - self.assertEqual(pointR.y, pointRy) - - def test_scalar_multiply(self): - d = 0xa4ebcae5a665983493ab3e626085a24c104311a761b5a8fdac052ed1f111a5c44f76f45659d2d111a61b5fdd97583480 - pointRx = 0xe4f77e7ffeb7f0958910e3a680d677a477191df166160ff7ef6bb5261f791aa7b45e3e653d151b95dad3d93ca0290ef2 - pointRy = 0xac7dee41d8c5f4a7d5836960a773cfc1376289d3373f8cf7417b0c6207ac32e913856612fc9ff2e357eb2ee05cf9667f - - pointR = self.pointS * d - self.assertEqual(pointR.x, pointRx) - self.assertEqual(pointR.y, pointRy) - - # 0*S - pai = self.pointS.point_at_infinity() - pointR = self.pointS * 0 - self.assertEqual(pointR, pai) - - # -1*S - self.assertRaises(ValueError, lambda: self.pointS * -1) - - def test_joing_scalar_multiply(self): - d = 0xa4ebcae5a665983493ab3e626085a24c104311a761b5a8fdac052ed1f111a5c44f76f45659d2d111a61b5fdd97583480 - e = 0xafcf88119a3a76c87acbd6008e1349b29f4ba9aa0e12ce89bcfcae2180b38d81ab8cf15095301a182afbc6893e75385d - pointRx = 0x917ea28bcd641741ae5d18c2f1bd917ba68d34f0f0577387dc81260462aea60e2417b8bdc5d954fc729d211db23a02dc - pointRy = 0x1a29f7ce6d074654d77b40888c73e92546c8f16a5ff6bcbd307f758d4aee684beff26f6742f597e2585c86da908f7186 - - t = self.pointS * d - - pointR = self.pointS * d + self.pointT * e - self.assertEqual(pointR.x, pointRx) - self.assertEqual(pointR.y, pointRy) - - def test_sizes(self): - self.assertEqual(self.pointS.size_in_bits(), 384) - self.assertEqual(self.pointS.size_in_bytes(), 48) - - -class TestEccPoint_NIST_P521(unittest.TestCase): - """Tests defined in section 4.5 of https://www.nsa.gov/ia/_files/nist-routines.pdf""" - - pointS = EccPoint( - 0x000001d5c693f66c08ed03ad0f031f937443458f601fd098d3d0227b4bf62873af50740b0bb84aa157fc847bcf8dc16a8b2b8bfd8e2d0a7d39af04b089930ef6dad5c1b4, - 0x00000144b7770963c63a39248865ff36b074151eac33549b224af5c8664c54012b818ed037b2b7c1a63ac89ebaa11e07db89fcee5b556e49764ee3fa66ea7ae61ac01823, - "p521") - - pointT = EccPoint( - 0x000000f411f2ac2eb971a267b80297ba67c322dba4bb21cec8b70073bf88fc1ca5fde3ba09e5df6d39acb2c0762c03d7bc224a3e197feaf760d6324006fe3be9a548c7d5, - 0x000001fdf842769c707c93c630df6d02eff399a06f1b36fb9684f0b373ed064889629abb92b1ae328fdb45534268384943f0e9222afe03259b32274d35d1b9584c65e305, - "p521") - - def test_set(self): - pointW = EccPoint(0, 0) - pointW.set(self.pointS) - self.assertEqual(pointW, self.pointS) - - def test_copy(self): - pointW = self.pointS.copy() - self.assertEqual(pointW, self.pointS) - pointW.set(self.pointT) - self.assertEqual(pointW, self.pointT) - self.assertNotEqual(self.pointS, self.pointT) - - def test_negate(self): - negS = -self.pointS - sum = self.pointS + negS - self.assertEqual(sum, self.pointS.point_at_infinity()) - - def test_addition(self): - pointRx = 0x000001264ae115ba9cbc2ee56e6f0059e24b52c8046321602c59a339cfb757c89a59c358a9a8e1f86d384b3f3b255ea3f73670c6dc9f45d46b6a196dc37bbe0f6b2dd9e9 - pointRy = 0x00000062a9c72b8f9f88a271690bfa017a6466c31b9cadc2fc544744aeb817072349cfddc5ad0e81b03f1897bd9c8c6efbdf68237dc3bb00445979fb373b20c9a967ac55 - - pointR = self.pointS + self.pointT - self.assertEqual(pointR.x, pointRx) - self.assertEqual(pointR.y, pointRy) - - pai = pointR.point_at_infinity() - - # S + 0 - pointR = self.pointS + pai - self.assertEqual(pointR, self.pointS) - - # 0 + S - pointR = pai + self.pointS - self.assertEqual(pointR, self.pointS) - - # 0 + 0 - pointR = pai + pai - self.assertEqual(pointR, pai) - - def test_inplace_addition(self): - pointRx = 0x000001264ae115ba9cbc2ee56e6f0059e24b52c8046321602c59a339cfb757c89a59c358a9a8e1f86d384b3f3b255ea3f73670c6dc9f45d46b6a196dc37bbe0f6b2dd9e9 - pointRy = 0x00000062a9c72b8f9f88a271690bfa017a6466c31b9cadc2fc544744aeb817072349cfddc5ad0e81b03f1897bd9c8c6efbdf68237dc3bb00445979fb373b20c9a967ac55 - - pointR = self.pointS.copy() - pointR += self.pointT - self.assertEqual(pointR.x, pointRx) - self.assertEqual(pointR.y, pointRy) - - pai = pointR.point_at_infinity() - - # S + 0 - pointR = self.pointS.copy() - pointR += pai - self.assertEqual(pointR, self.pointS) - - # 0 + S - pointR = pai.copy() - pointR += self.pointS - self.assertEqual(pointR, self.pointS) - - # 0 + 0 - pointR = pai.copy() - pointR += pai - self.assertEqual(pointR, pai) - - def test_doubling(self): - pointRx = 0x0000012879442f2450c119e7119a5f738be1f1eba9e9d7c6cf41b325d9ce6d643106e9d61124a91a96bcf201305a9dee55fa79136dc700831e54c3ca4ff2646bd3c36bc6 - pointRy = 0x0000019864a8b8855c2479cbefe375ae553e2393271ed36fadfc4494fc0583f6bd03598896f39854abeae5f9a6515a021e2c0eef139e71de610143f53382f4104dccb543 - - pointR = self.pointS.copy() - pointR.double() - self.assertEqual(pointR.x, pointRx) - self.assertEqual(pointR.y, pointRy) - - # 2*0 - pai = self.pointS.point_at_infinity() - pointR = pai.copy() - pointR.double() - self.assertEqual(pointR, pai) - - # S + S - pointR = self.pointS.copy() - pointR += pointR - self.assertEqual(pointR.x, pointRx) - self.assertEqual(pointR.y, pointRy) - - def test_scalar_multiply(self): - d = 0x000001eb7f81785c9629f136a7e8f8c674957109735554111a2a866fa5a166699419bfa9936c78b62653964df0d6da940a695c7294d41b2d6600de6dfcf0edcfc89fdcb1 - pointRx = 0x00000091b15d09d0ca0353f8f96b93cdb13497b0a4bb582ae9ebefa35eee61bf7b7d041b8ec34c6c00c0c0671c4ae063318fb75be87af4fe859608c95f0ab4774f8c95bb - pointRy = 0x00000130f8f8b5e1abb4dd94f6baaf654a2d5810411e77b7423965e0c7fd79ec1ae563c207bd255ee9828eb7a03fed565240d2cc80ddd2cecbb2eb50f0951f75ad87977f - - pointR = self.pointS * d - self.assertEqual(pointR.x, pointRx) - self.assertEqual(pointR.y, pointRy) - - # 0*S - pai = self.pointS.point_at_infinity() - pointR = self.pointS * 0 - self.assertEqual(pointR, pai) - - # -1*S - self.assertRaises(ValueError, lambda: self.pointS * -1) - - def test_joing_scalar_multiply(self): - d = 0x000001eb7f81785c9629f136a7e8f8c674957109735554111a2a866fa5a166699419bfa9936c78b62653964df0d6da940a695c7294d41b2d6600de6dfcf0edcfc89fdcb1 - e = 0x00000137e6b73d38f153c3a7575615812608f2bab3229c92e21c0d1c83cfad9261dbb17bb77a63682000031b9122c2f0cdab2af72314be95254de4291a8f85f7c70412e3 - pointRx = 0x0000009d3802642b3bea152beb9e05fba247790f7fc168072d363340133402f2585588dc1385d40ebcb8552f8db02b23d687cae46185b27528adb1bf9729716e4eba653d - pointRy = 0x0000000fe44344e79da6f49d87c1063744e5957d9ac0a505bafa8281c9ce9ff25ad53f8da084a2deb0923e46501de5797850c61b229023dd9cf7fc7f04cd35ebb026d89d - - t = self.pointS * d - - pointR = self.pointS * d - pointR += self.pointT * e - self.assertEqual(pointR.x, pointRx) - self.assertEqual(pointR.y, pointRy) - - def test_sizes(self): - self.assertEqual(self.pointS.size_in_bits(), 521) - self.assertEqual(self.pointS.size_in_bytes(), 66) - - -class TestEccPoint_PAI_P256(unittest.TestCase): - """Test vectors from http://point-at-infinity.org/ecc/nisttv""" - - curve = _curves['p256'] - pointG = EccPoint(curve.Gx, curve.Gy, "p256") - - -tv_pai = load_test_vectors(("PublicKey", "ECC"), - "point-at-infinity.org-P256.txt", - "P-256 tests from point-at-infinity.org", - {"k": lambda k: int(k), - "x": lambda x: int(x, 16), - "y": lambda y: int(y, 16)}) or [] -for tv in tv_pai: - def new_test(self, scalar=tv.k, x=tv.x, y=tv.y): - result = self.pointG * scalar - self.assertEqual(result.x, x) - self.assertEqual(result.y, y) - setattr(TestEccPoint_PAI_P256, "test_%d" % tv.count, new_test) - - -class TestEccPoint_PAI_P384(unittest.TestCase): - """Test vectors from http://point-at-infinity.org/ecc/nisttv""" - - curve = _curves['p384'] - pointG = EccPoint(curve.Gx, curve.Gy, "p384") - - -tv_pai = load_test_vectors(("PublicKey", "ECC"), - "point-at-infinity.org-P384.txt", - "P-384 tests from point-at-infinity.org", - {"k" : lambda k: int(k), - "x" : lambda x: int(x, 16), - "y" : lambda y: int(y, 16)}) or [] -for tv in tv_pai: - def new_test(self, scalar=tv.k, x=tv.x, y=tv.y): - result = self.pointG * scalar - self.assertEqual(result.x, x) - self.assertEqual(result.y, y) - setattr(TestEccPoint_PAI_P384, "test_%d" % tv.count, new_test) - - -class TestEccPoint_PAI_P521(unittest.TestCase): - """Test vectors from http://point-at-infinity.org/ecc/nisttv""" - - curve = _curves['p521'] - pointG = EccPoint(curve.Gx, curve.Gy, "p521") - - -tv_pai = load_test_vectors(("PublicKey", "ECC"), - "point-at-infinity.org-P521.txt", - "P-521 tests from point-at-infinity.org", - {"k": lambda k: int(k), - "x": lambda x: int(x, 16), - "y": lambda y: int(y, 16)}) or [] -for tv in tv_pai: - def new_test(self, scalar=tv.k, x=tv.x, y=tv.y): - result = self.pointG * scalar - self.assertEqual(result.x, x) - self.assertEqual(result.y, y) - setattr(TestEccPoint_PAI_P521, "test_%d" % tv.count, new_test) - - -class TestEccKey_P256(unittest.TestCase): - - def test_private_key(self): - - key = EccKey(curve="P-256", d=1) - self.assertEqual(key.d, 1) - self.failUnless(key.has_private()) - self.assertEqual(key.pointQ.x, _curves['p256'].Gx) - self.assertEqual(key.pointQ.y, _curves['p256'].Gy) - - point = EccPoint(_curves['p256'].Gx, _curves['p256'].Gy) - key = EccKey(curve="P-256", d=1, point=point) - self.assertEqual(key.d, 1) - self.failUnless(key.has_private()) - self.assertEqual(key.pointQ, point) - - # Other names - key = EccKey(curve="secp256r1", d=1) - key = EccKey(curve="prime256v1", d=1) - - def test_public_key(self): - - point = EccPoint(_curves['p256'].Gx, _curves['p256'].Gy) - key = EccKey(curve="P-256", point=point) - self.failIf(key.has_private()) - self.assertEqual(key.pointQ, point) - - def test_public_key_derived(self): - - priv_key = EccKey(curve="P-256", d=3) - pub_key = priv_key.public_key() - self.failIf(pub_key.has_private()) - self.assertEqual(priv_key.pointQ, pub_key.pointQ) - - def test_invalid_curve(self): - self.assertRaises(ValueError, lambda: EccKey(curve="P-257", d=1)) - - def test_invalid_d(self): - self.assertRaises(ValueError, lambda: EccKey(curve="P-256", d=0)) - self.assertRaises(ValueError, lambda: EccKey(curve="P-256", d=_curves['p256'].order)) - - def test_equality(self): - - private_key = ECC.construct(d=3, curve="P-256") - private_key2 = ECC.construct(d=3, curve="P-256") - private_key3 = ECC.construct(d=4, curve="P-256") - - public_key = private_key.public_key() - public_key2 = private_key2.public_key() - public_key3 = private_key3.public_key() - - self.assertEqual(private_key, private_key2) - self.assertNotEqual(private_key, private_key3) - - self.assertEqual(public_key, public_key2) - self.assertNotEqual(public_key, public_key3) - - self.assertNotEqual(public_key, private_key) - - -class TestEccKey_P384(unittest.TestCase): - - def test_private_key(self): - - p384 = _curves['p384'] - - key = EccKey(curve="P-384", d=1) - self.assertEqual(key.d, 1) - self.failUnless(key.has_private()) - self.assertEqual(key.pointQ.x, p384.Gx) - self.assertEqual(key.pointQ.y, p384.Gy) - - point = EccPoint(p384.Gx, p384.Gy, "p384") - key = EccKey(curve="P-384", d=1, point=point) - self.assertEqual(key.d, 1) - self.failUnless(key.has_private()) - self.assertEqual(key.pointQ, point) - - # Other names - key = EccKey(curve="p384", d=1) - key = EccKey(curve="secp384r1", d=1) - key = EccKey(curve="prime384v1", d=1) - - def test_public_key(self): - - p384 = _curves['p384'] - point = EccPoint(p384.Gx, p384.Gy, 'p384') - key = EccKey(curve="P-384", point=point) - self.failIf(key.has_private()) - self.assertEqual(key.pointQ, point) - - def test_public_key_derived(self): - - priv_key = EccKey(curve="P-384", d=3) - pub_key = priv_key.public_key() - self.failIf(pub_key.has_private()) - self.assertEqual(priv_key.pointQ, pub_key.pointQ) - - def test_invalid_curve(self): - self.assertRaises(ValueError, lambda: EccKey(curve="P-385", d=1)) - - def test_invalid_d(self): - self.assertRaises(ValueError, lambda: EccKey(curve="P-384", d=0)) - self.assertRaises(ValueError, lambda: EccKey(curve="P-384", - d=_curves['p384'].order)) - - def test_equality(self): - - private_key = ECC.construct(d=3, curve="P-384") - private_key2 = ECC.construct(d=3, curve="P-384") - private_key3 = ECC.construct(d=4, curve="P-384") - - public_key = private_key.public_key() - public_key2 = private_key2.public_key() - public_key3 = private_key3.public_key() - - self.assertEqual(private_key, private_key2) - self.assertNotEqual(private_key, private_key3) - - self.assertEqual(public_key, public_key2) - self.assertNotEqual(public_key, public_key3) - - self.assertNotEqual(public_key, private_key) - - -class TestEccKey_P521(unittest.TestCase): - - def test_private_key(self): - - p521 = _curves['p521'] - - key = EccKey(curve="P-521", d=1) - self.assertEqual(key.d, 1) - self.failUnless(key.has_private()) - self.assertEqual(key.pointQ.x, p521.Gx) - self.assertEqual(key.pointQ.y, p521.Gy) - - point = EccPoint(p521.Gx, p521.Gy, "p521") - key = EccKey(curve="P-521", d=1, point=point) - self.assertEqual(key.d, 1) - self.failUnless(key.has_private()) - self.assertEqual(key.pointQ, point) - - # Other names - key = EccKey(curve="p521", d=1) - key = EccKey(curve="secp521r1", d=1) - key = EccKey(curve="prime521v1", d=1) - - def test_public_key(self): - - p521 = _curves['p521'] - point = EccPoint(p521.Gx, p521.Gy, 'p521') - key = EccKey(curve="P-384", point=point) - self.failIf(key.has_private()) - self.assertEqual(key.pointQ, point) - - def test_public_key_derived(self): - - priv_key = EccKey(curve="P-521", d=3) - pub_key = priv_key.public_key() - self.failIf(pub_key.has_private()) - self.assertEqual(priv_key.pointQ, pub_key.pointQ) - - def test_invalid_curve(self): - self.assertRaises(ValueError, lambda: EccKey(curve="P-522", d=1)) - - def test_invalid_d(self): - self.assertRaises(ValueError, lambda: EccKey(curve="P-521", d=0)) - self.assertRaises(ValueError, lambda: EccKey(curve="P-521", - d=_curves['p521'].order)) - - def test_equality(self): - - private_key = ECC.construct(d=3, curve="P-521") - private_key2 = ECC.construct(d=3, curve="P-521") - private_key3 = ECC.construct(d=4, curve="P-521") - - public_key = private_key.public_key() - public_key2 = private_key2.public_key() - public_key3 = private_key3.public_key() - - self.assertEqual(private_key, private_key2) - self.assertNotEqual(private_key, private_key3) - - self.assertEqual(public_key, public_key2) - self.assertNotEqual(public_key, public_key3) - - self.assertNotEqual(public_key, private_key) - - -class TestEccModule_P256(unittest.TestCase): - - def test_generate(self): - - key = ECC.generate(curve="P-256") - self.failUnless(key.has_private()) - self.assertEqual(key.pointQ, EccPoint(_curves['p256'].Gx, - _curves['p256'].Gy) * key.d, - "p256") - - # Other names - ECC.generate(curve="secp256r1") - ECC.generate(curve="prime256v1") - - def test_construct(self): - - key = ECC.construct(curve="P-256", d=1) - self.failUnless(key.has_private()) - self.assertEqual(key.pointQ, _curves['p256'].G) - - key = ECC.construct(curve="P-256", point_x=_curves['p256'].Gx, - point_y=_curves['p256'].Gy) - self.failIf(key.has_private()) - self.assertEqual(key.pointQ, _curves['p256'].G) - - # Other names - ECC.construct(curve="p256", d=1) - ECC.construct(curve="secp256r1", d=1) - ECC.construct(curve="prime256v1", d=1) - - def test_negative_construct(self): - coord = dict(point_x=10, point_y=4) - coordG = dict(point_x=_curves['p256'].Gx, point_y=_curves['p256'].Gy) - - self.assertRaises(ValueError, ECC.construct, curve="P-256", **coord) - self.assertRaises(ValueError, ECC.construct, curve="P-256", d=2, **coordG) - - -class TestEccModule_P384(unittest.TestCase): - - def test_generate(self): - - curve = _curves['p384'] - key = ECC.generate(curve="P-384") - self.failUnless(key.has_private()) - self.assertEqual(key.pointQ, EccPoint(curve.Gx, curve.Gy, "p384") * key.d) - - # Other names - ECC.generate(curve="secp384r1") - ECC.generate(curve="prime384v1") - - def test_construct(self): - - curve = _curves['p384'] - key = ECC.construct(curve="P-384", d=1) - self.failUnless(key.has_private()) - self.assertEqual(key.pointQ, _curves['p384'].G) - - key = ECC.construct(curve="P-384", point_x=curve.Gx, point_y=curve.Gy) - self.failIf(key.has_private()) - self.assertEqual(key.pointQ, curve.G) - - # Other names - ECC.construct(curve="p384", d=1) - ECC.construct(curve="secp384r1", d=1) - ECC.construct(curve="prime384v1", d=1) - - def test_negative_construct(self): - coord = dict(point_x=10, point_y=4) - coordG = dict(point_x=_curves['p384'].Gx, point_y=_curves['p384'].Gy) - - self.assertRaises(ValueError, ECC.construct, curve="P-384", **coord) - self.assertRaises(ValueError, ECC.construct, curve="P-384", d=2, **coordG) - - -class TestEccModule_P521(unittest.TestCase): - - def test_generate(self): - - curve = _curves['p521'] - key = ECC.generate(curve="P-521") - self.failUnless(key.has_private()) - self.assertEqual(key.pointQ, EccPoint(curve.Gx, curve.Gy, "p521") * key.d) - - # Other names - ECC.generate(curve="secp521r1") - ECC.generate(curve="prime521v1") - - def test_construct(self): - - curve = _curves['p521'] - key = ECC.construct(curve="P-521", d=1) - self.failUnless(key.has_private()) - self.assertEqual(key.pointQ, _curves['p521'].G) - - key = ECC.construct(curve="P-521", point_x=curve.Gx, point_y=curve.Gy) - self.failIf(key.has_private()) - self.assertEqual(key.pointQ, curve.G) - - # Other names - ECC.construct(curve="p521", d=1) - ECC.construct(curve="secp521r1", d=1) - ECC.construct(curve="prime521v1", d=1) - - def test_negative_construct(self): - coord = dict(point_x=10, point_y=4) - coordG = dict(point_x=_curves['p521'].Gx, point_y=_curves['p521'].Gy) - - self.assertRaises(ValueError, ECC.construct, curve="P-521", **coord) - self.assertRaises(ValueError, ECC.construct, curve="P-521", d=2, **coordG) - - -def get_tests(config={}): - tests = [] - tests += list_test_cases(TestEccPoint) - tests += list_test_cases(TestEccPoint_NIST_P256) - tests += list_test_cases(TestEccPoint_NIST_P384) - tests += list_test_cases(TestEccPoint_NIST_P521) - tests += list_test_cases(TestEccPoint_PAI_P256) - tests += list_test_cases(TestEccPoint_PAI_P384) - tests += list_test_cases(TestEccPoint_PAI_P521) - tests += list_test_cases(TestEccKey_P256) - tests += list_test_cases(TestEccKey_P384) - tests += list_test_cases(TestEccKey_P521) - tests += list_test_cases(TestEccModule_P256) - tests += list_test_cases(TestEccModule_P384) - tests += list_test_cases(TestEccModule_P521) - return tests - -if __name__ == '__main__': - suite = lambda: unittest.TestSuite(get_tests()) - unittest.main(defaultTest='suite') diff --git a/Crypto/SelfTest/PublicKey/test_ElGamal.py b/Crypto/SelfTest/PublicKey/test_ElGamal.py deleted file mode 100644 index 0af6738..0000000 --- a/Crypto/SelfTest/PublicKey/test_ElGamal.py +++ /dev/null @@ -1,217 +0,0 @@ -# -*- coding: utf-8 -*- -# -# SelfTest/PublicKey/test_ElGamal.py: Self-test for the ElGamal primitive -# -# =================================================================== -# The contents of this file are dedicated to the public domain. To -# the extent that dedication to the public domain is not available, -# everyone is granted a worldwide, perpetual, royalty-free, -# non-exclusive license to exercise all rights associated with the -# contents of this file for any purpose whatsoever. -# No rights are reserved. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS -# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN -# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# =================================================================== - -"""Self-test suite for Crypto.PublicKey.ElGamal""" - -__revision__ = "$Id$" - -import unittest -from Crypto.SelfTest.st_common import list_test_cases, a2b_hex, b2a_hex -from Crypto import Random -from Crypto.PublicKey import ElGamal -from Crypto.Util.number import bytes_to_long -from Crypto.Util.py3compat import * - -class ElGamalTest(unittest.TestCase): - - # - # Test vectors - # - # There seem to be no real ElGamal test vectors available in the - # public domain. The following test vectors have been generated - # with libgcrypt 1.5.0. - # - # Encryption - tve=[ - { - # 256 bits - 'p' :'BA4CAEAAED8CBE952AFD2126C63EB3B345D65C2A0A73D2A3AD4138B6D09BD933', - 'g' :'05', - 'y' :'60D063600ECED7C7C55146020E7A31C4476E9793BEAED420FEC9E77604CAE4EF', - 'x' :'1D391BA2EE3C37FE1BA175A69B2C73A11238AD77675932', - 'k' :'F5893C5BAB4131264066F57AB3D8AD89E391A0B68A68A1', - 'pt' :'48656C6C6F207468657265', - 'ct1':'32BFD5F487966CEA9E9356715788C491EC515E4ED48B58F0F00971E93AAA5EC7', - 'ct2':'7BE8FBFF317C93E82FCEF9BD515284BA506603FEA25D01C0CB874A31F315EE68' - }, - - { - # 512 bits - 'p' :'F1B18AE9F7B4E08FDA9A04832F4E919D89462FD31BF12F92791A93519F75076D6CE3942689CDFF2F344CAFF0F82D01864F69F3AECF566C774CBACF728B81A227', - 'g' :'07', - 'y' :'688628C676E4F05D630E1BE39D0066178CA7AA83836B645DE5ADD359B4825A12B02EF4252E4E6FA9BEC1DB0BE90F6D7C8629CABB6E531F472B2664868156E20C', - 'x' :'14E60B1BDFD33436C0DA8A22FDC14A2CCDBBED0627CE68', - 'k' :'38DBF14E1F319BDA9BAB33EEEADCAF6B2EA5250577ACE7', - 'pt' :'48656C6C6F207468657265', - 'ct1':'290F8530C2CC312EC46178724F196F308AD4C523CEABB001FACB0506BFED676083FE0F27AC688B5C749AB3CB8A80CD6F7094DBA421FB19442F5A413E06A9772B', - 'ct2':'1D69AAAD1DC50493FB1B8E8721D621D683F3BF1321BE21BC4A43E11B40C9D4D9C80DE3AAC2AB60D31782B16B61112E68220889D53C4C3136EE6F6CE61F8A23A0' - } - ] - - # Signature - tvs=[ - { - # 256 bits - 'p' :'D2F3C41EA66530838A704A48FFAC9334F4701ECE3A97CEE4C69DD01AE7129DD7', - 'g' :'05', - 'y' :'C3F9417DC0DAFEA6A05C1D2333B7A95E63B3F4F28CC962254B3256984D1012E7', - 'x' :'165E4A39BE44D5A2D8B1332D416BC559616F536BC735BB', - 'k' :'C7F0C794A7EAD726E25A47FF8928013680E73C51DD3D7D99BFDA8F492585928F', - 'h' :'48656C6C6F207468657265', - 'sig1':'35CA98133779E2073EF31165AFCDEB764DD54E96ADE851715495F9C635E1E7C2', - 'sig2':'0135B88B1151279FE5D8078D4FC685EE81177EE9802AB123A73925FC1CB059A7', - }, - { - # 512 bits - 'p' :'E24CF3A4B8A6AF749DCA6D714282FE4AABEEE44A53BB6ED15FBE32B5D3C3EF9CC4124A2ECA331F3C1C1B667ACA3766825217E7B5F9856648D95F05330C6A19CF', - 'g' :'0B', - 'y' :'2AD3A1049CA5D4ED207B2431C79A8719BB4073D4A94E450EA6CEE8A760EB07ADB67C0D52C275EE85D7B52789061EE45F2F37D9B2AE522A51C28329766BFE68AC', - 'x' :'16CBB4F46D9ECCF24FF9F7E63CAA3BD8936341555062AB', - 'k' :'8A3D89A4E429FD2476D7D717251FB79BF900FFE77444E6BB8299DC3F84D0DD57ABAB50732AE158EA52F5B9E7D8813E81FD9F79470AE22F8F1CF9AEC820A78C69', - 'h' :'48656C6C6F207468657265', - 'sig1':'BE001AABAFFF976EC9016198FBFEA14CBEF96B000CCC0063D3324016F9E91FE80D8F9325812ED24DDB2B4D4CF4430B169880B3CE88313B53255BD4EC0378586F', - 'sig2':'5E266F3F837BA204E3BBB6DBECC0611429D96F8C7CE8F4EFDF9D4CB681C2A954468A357BF4242CEC7418B51DFC081BCD21299EF5B5A0DDEF3A139A1817503DDE', - } - ] - - def test_generate_180(self): - self._test_random_key(180) - - def test_encryption(self): - for tv in self.tve: - d = self.convert_tv(tv, True) - key = ElGamal.construct(d['key']) - ct = key._encrypt(d['pt'], d['k']) - self.assertEquals(ct[0], d['ct1']) - self.assertEquals(ct[1], d['ct2']) - - def test_decryption(self): - for tv in self.tve: - d = self.convert_tv(tv, True) - key = ElGamal.construct(d['key']) - pt = key._decrypt((d['ct1'], d['ct2'])) - self.assertEquals(pt, d['pt']) - - def test_signing(self): - for tv in self.tvs: - d = self.convert_tv(tv, True) - key = ElGamal.construct(d['key']) - sig1, sig2 = key._sign(d['h'], d['k']) - self.assertEquals(sig1, d['sig1']) - self.assertEquals(sig2, d['sig2']) - - def test_verification(self): - for tv in self.tvs: - d = self.convert_tv(tv, True) - key = ElGamal.construct(d['key']) - # Positive test - res = key._verify( d['h'], (d['sig1'],d['sig2']) ) - self.failUnless(res) - # Negative test - res = key._verify( d['h'], (d['sig1']+1,d['sig2']) ) - self.failIf(res) - - def test_bad_key3(self): - tup = tup0 = list(self.convert_tv(self.tvs[0], 1)['key'])[:3] - tup[0] += 1 # p += 1 (not prime) - self.assertRaises(ValueError, ElGamal.construct, tup) - - tup = tup0 - tup[1] = 1 # g = 1 - self.assertRaises(ValueError, ElGamal.construct, tup) - - tup = tup0 - tup[2] = tup[0]*2 # y = 2*p - self.assertRaises(ValueError, ElGamal.construct, tup) - - def test_bad_key4(self): - tup = tup0 = list(self.convert_tv(self.tvs[0], 1)['key']) - tup[3] += 1 # x += 1 - self.assertRaises(ValueError, ElGamal.construct, tup) - - def convert_tv(self, tv, as_longs=0): - """Convert a test vector from textual form (hexadecimal ascii - to either integers or byte strings.""" - key_comps = 'p','g','y','x' - tv2 = {} - for c in tv.keys(): - tv2[c] = a2b_hex(tv[c]) - if as_longs or c in key_comps or c in ('sig1','sig2'): - tv2[c] = bytes_to_long(tv2[c]) - tv2['key']=[] - for c in key_comps: - tv2['key'] += [tv2[c]] - del tv2[c] - return tv2 - - def _test_random_key(self, bits): - elgObj = ElGamal.generate(bits, Random.new().read) - self._check_private_key(elgObj) - self._exercise_primitive(elgObj) - pub = elgObj.publickey() - self._check_public_key(pub) - self._exercise_public_primitive(elgObj) - - def _check_private_key(self, elgObj): - - # Check capabilities - self.failUnless(elgObj.has_private()) - - # Sanity check key data - self.failUnless(1 -# -# =================================================================== -# The contents of this file are dedicated to the public domain. To -# the extent that dedication to the public domain is not available, -# everyone is granted a worldwide, perpetual, royalty-free, -# non-exclusive license to exercise all rights associated with the -# contents of this file for any purpose whatsoever. -# No rights are reserved. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS -# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN -# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# =================================================================== - -"""Self-test suite for Crypto.PublicKey.RSA""" - -__revision__ = "$Id$" - -import os -import pickle -from pickle import PicklingError -from Crypto.Util.py3compat import * - -import unittest -from Crypto.SelfTest.st_common import list_test_cases, a2b_hex, b2a_hex - -class RSATest(unittest.TestCase): - # Test vectors from "RSA-OAEP and RSA-PSS test vectors (.zip file)" - # ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-1/pkcs-1v2-1-vec.zip - # See RSADSI's PKCS#1 page at - # http://www.rsa.com/rsalabs/node.asp?id=2125 - - # from oaep-int.txt - - # TODO: PyCrypto treats the message as starting *after* the leading "00" - # TODO: That behaviour should probably be changed in the future. - plaintext = """ - eb 7a 19 ac e9 e3 00 63 50 e3 29 50 4b 45 e2 - ca 82 31 0b 26 dc d8 7d 5c 68 f1 ee a8 f5 52 67 - c3 1b 2e 8b b4 25 1f 84 d7 e0 b2 c0 46 26 f5 af - f9 3e dc fb 25 c9 c2 b3 ff 8a e1 0e 83 9a 2d db - 4c dc fe 4f f4 77 28 b4 a1 b7 c1 36 2b aa d2 9a - b4 8d 28 69 d5 02 41 21 43 58 11 59 1b e3 92 f9 - 82 fb 3e 87 d0 95 ae b4 04 48 db 97 2f 3a c1 4f - 7b c2 75 19 52 81 ce 32 d2 f1 b7 6d 4d 35 3e 2d - """ - - ciphertext = """ - 12 53 e0 4d c0 a5 39 7b b4 4a 7a b8 7e 9b f2 a0 - 39 a3 3d 1e 99 6f c8 2a 94 cc d3 00 74 c9 5d f7 - 63 72 20 17 06 9e 52 68 da 5d 1c 0b 4f 87 2c f6 - 53 c1 1d f8 23 14 a6 79 68 df ea e2 8d ef 04 bb - 6d 84 b1 c3 1d 65 4a 19 70 e5 78 3b d6 eb 96 a0 - 24 c2 ca 2f 4a 90 fe 9f 2e f5 c9 c1 40 e5 bb 48 - da 95 36 ad 87 00 c8 4f c9 13 0a de a7 4e 55 8d - 51 a7 4d df 85 d8 b5 0d e9 68 38 d6 06 3e 09 55 - """ - - modulus = """ - bb f8 2f 09 06 82 ce 9c 23 38 ac 2b 9d a8 71 f7 - 36 8d 07 ee d4 10 43 a4 40 d6 b6 f0 74 54 f5 1f - b8 df ba af 03 5c 02 ab 61 ea 48 ce eb 6f cd 48 - 76 ed 52 0d 60 e1 ec 46 19 71 9d 8a 5b 8b 80 7f - af b8 e0 a3 df c7 37 72 3e e6 b4 b7 d9 3a 25 84 - ee 6a 64 9d 06 09 53 74 88 34 b2 45 45 98 39 4e - e0 aa b1 2d 7b 61 a5 1f 52 7a 9a 41 f6 c1 68 7f - e2 53 72 98 ca 2a 8f 59 46 f8 e5 fd 09 1d bd cb - """ - - e = 0x11 # public exponent - - prime_factor = """ - c9 7f b1 f0 27 f4 53 f6 34 12 33 ea aa d1 d9 35 - 3f 6c 42 d0 88 66 b1 d0 5a 0f 20 35 02 8b 9d 86 - 98 40 b4 16 66 b4 2e 92 ea 0d a3 b4 32 04 b5 cf - ce 33 52 52 4d 04 16 a5 a4 41 e7 00 af 46 15 03 - """ - - def setUp(self): - global RSA, Random, bytes_to_long - from Crypto.PublicKey import RSA - from Crypto import Random - from Crypto.Util.number import bytes_to_long, inverse - self.n = bytes_to_long(a2b_hex(self.modulus)) - self.p = bytes_to_long(a2b_hex(self.prime_factor)) - - # Compute q, d, and u from n, e, and p - self.q = self.n // self.p - self.d = inverse(self.e, (self.p-1)*(self.q-1)) - self.u = inverse(self.p, self.q) # u = e**-1 (mod q) - - self.rsa = RSA - - def test_generate_1arg(self): - """RSA (default implementation) generated key (1 argument)""" - rsaObj = self.rsa.generate(1024) - self._check_private_key(rsaObj) - self._exercise_primitive(rsaObj) - pub = rsaObj.public_key() - self._check_public_key(pub) - self._exercise_public_primitive(rsaObj) - - def test_generate_2arg(self): - """RSA (default implementation) generated key (2 arguments)""" - rsaObj = self.rsa.generate(1024, Random.new().read) - self._check_private_key(rsaObj) - self._exercise_primitive(rsaObj) - pub = rsaObj.public_key() - self._check_public_key(pub) - self._exercise_public_primitive(rsaObj) - - def test_generate_3args(self): - rsaObj = self.rsa.generate(1024, Random.new().read,e=65537) - self._check_private_key(rsaObj) - self._exercise_primitive(rsaObj) - pub = rsaObj.public_key() - self._check_public_key(pub) - self._exercise_public_primitive(rsaObj) - self.assertEqual(65537,rsaObj.e) - - def test_construct_2tuple(self): - """RSA (default implementation) constructed key (2-tuple)""" - pub = self.rsa.construct((self.n, self.e)) - self._check_public_key(pub) - self._check_encryption(pub) - - def test_construct_3tuple(self): - """RSA (default implementation) constructed key (3-tuple)""" - rsaObj = self.rsa.construct((self.n, self.e, self.d)) - self._check_encryption(rsaObj) - self._check_decryption(rsaObj) - - def test_construct_4tuple(self): - """RSA (default implementation) constructed key (4-tuple)""" - rsaObj = self.rsa.construct((self.n, self.e, self.d, self.p)) - self._check_encryption(rsaObj) - self._check_decryption(rsaObj) - - def test_construct_5tuple(self): - """RSA (default implementation) constructed key (5-tuple)""" - rsaObj = self.rsa.construct((self.n, self.e, self.d, self.p, self.q)) - self._check_private_key(rsaObj) - self._check_encryption(rsaObj) - self._check_decryption(rsaObj) - - def test_construct_6tuple(self): - """RSA (default implementation) constructed key (6-tuple)""" - rsaObj = self.rsa.construct((self.n, self.e, self.d, self.p, self.q, self.u)) - self._check_private_key(rsaObj) - self._check_encryption(rsaObj) - self._check_decryption(rsaObj) - - def test_construct_bad_key2(self): - tup = (self.n, 1) - self.assertRaises(ValueError, self.rsa.construct, tup) - - # An even modulus is wrong - tup = (self.n+1, self.e) - self.assertRaises(ValueError, self.rsa.construct, tup) - - def test_construct_bad_key3(self): - tup = (self.n, self.e, self.d+1) - self.assertRaises(ValueError, self.rsa.construct, tup) - - def test_construct_bad_key5(self): - tup = (self.n, self.e, self.d, self.p, self.p) - self.assertRaises(ValueError, self.rsa.construct, tup) - - tup = (self.p*self.p, self.e, self.p, self.p) - self.assertRaises(ValueError, self.rsa.construct, tup) - - tup = (self.p*self.p, 3, self.p, self.q) - self.assertRaises(ValueError, self.rsa.construct, tup) - - def test_construct_bad_key6(self): - tup = (self.n, self.e, self.d, self.p, self.q, 10) - self.assertRaises(ValueError, self.rsa.construct, tup) - - from Crypto.Util.number import inverse - tup = (self.n, self.e, self.d, self.p, self.q, inverse(self.q, self.p)) - self.assertRaises(ValueError, self.rsa.construct, tup) - - def test_factoring(self): - rsaObj = self.rsa.construct([self.n, self.e, self.d]) - self.failUnless(rsaObj.p==self.p or rsaObj.p==self.q) - self.failUnless(rsaObj.q==self.p or rsaObj.q==self.q) - self.failUnless(rsaObj.q*rsaObj.p == self.n) - - self.assertRaises(ValueError, self.rsa.construct, [self.n, self.e, self.n-1]) - - def test_repr(self): - rsaObj = self.rsa.construct((self.n, self.e, self.d, self.p, self.q)) - repr(rsaObj) - - def test_serialization(self): - """RSA keys are unpickable""" - - rsa_key = self.rsa.generate(1024) - self.assertRaises(PicklingError, pickle.dumps, rsa_key) - - def test_raw_rsa_boundary(self): - # The argument of every RSA raw operation (encrypt/decrypt) must be - # non-negative and no larger than the modulus - rsa_obj = self.rsa.generate(1024) - - self.assertRaises(ValueError, rsa_obj._decrypt, rsa_obj.n) - self.assertRaises(ValueError, rsa_obj._encrypt, rsa_obj.n) - - self.assertRaises(ValueError, rsa_obj._decrypt, -1) - self.assertRaises(ValueError, rsa_obj._encrypt, -1) - - def test_size(self): - pub = self.rsa.construct((self.n, self.e)) - self.assertEquals(pub.size_in_bits(), 1024) - self.assertEquals(pub.size_in_bytes(), 128) - - def _check_private_key(self, rsaObj): - from Crypto.Math.Numbers import Integer - - # Check capabilities - self.assertEqual(1, rsaObj.has_private()) - - # Sanity check key data - self.assertEqual(rsaObj.n, rsaObj.p * rsaObj.q) # n = pq - lcm = int(Integer(rsaObj.p-1).lcm(rsaObj.q-1)) - self.assertEqual(1, rsaObj.d * rsaObj.e % lcm) # ed = 1 (mod LCM(p-1, q-1)) - self.assertEqual(1, rsaObj.p * rsaObj.u % rsaObj.q) # pu = 1 (mod q) - self.assertEqual(1, rsaObj.p > 1) # p > 1 - self.assertEqual(1, rsaObj.q > 1) # q > 1 - self.assertEqual(1, rsaObj.e > 1) # e > 1 - self.assertEqual(1, rsaObj.d > 1) # d > 1 - - def _check_public_key(self, rsaObj): - ciphertext = a2b_hex(self.ciphertext) - - # Check capabilities - self.assertEqual(0, rsaObj.has_private()) - - # Check rsaObj.[ne] -> rsaObj.[ne] mapping - self.assertEqual(rsaObj.n, rsaObj.n) - self.assertEqual(rsaObj.e, rsaObj.e) - - # Check that private parameters are all missing - self.assertEqual(0, hasattr(rsaObj, 'd')) - self.assertEqual(0, hasattr(rsaObj, 'p')) - self.assertEqual(0, hasattr(rsaObj, 'q')) - self.assertEqual(0, hasattr(rsaObj, 'u')) - - # Sanity check key data - self.assertEqual(1, rsaObj.e > 1) # e > 1 - - # Public keys should not be able to sign or decrypt - self.assertRaises(TypeError, rsaObj._decrypt, - bytes_to_long(ciphertext)) - - # Check __eq__ and __ne__ - self.assertEqual(rsaObj.public_key() == rsaObj.public_key(),True) # assert_ - self.assertEqual(rsaObj.public_key() != rsaObj.public_key(),False) # failIf - - self.assertEqual(rsaObj.publickey(), rsaObj.public_key()) - - def _exercise_primitive(self, rsaObj): - # Since we're using a randomly-generated key, we can't check the test - # vector, but we can make sure encryption and decryption are inverse - # operations. - ciphertext = bytes_to_long(a2b_hex(self.ciphertext)) - - # Test decryption - plaintext = rsaObj._decrypt(ciphertext) - - # Test encryption (2 arguments) - new_ciphertext2 = rsaObj._encrypt(plaintext) - self.assertEqual(ciphertext, new_ciphertext2) - - def _exercise_public_primitive(self, rsaObj): - plaintext = a2b_hex(self.plaintext) - - # Test encryption (2 arguments) - new_ciphertext2 = rsaObj._encrypt(bytes_to_long(plaintext)) - - def _check_encryption(self, rsaObj): - plaintext = a2b_hex(self.plaintext) - ciphertext = a2b_hex(self.ciphertext) - - # Test encryption - new_ciphertext2 = rsaObj._encrypt(bytes_to_long(plaintext)) - self.assertEqual(bytes_to_long(ciphertext), new_ciphertext2) - - def _check_decryption(self, rsaObj): - plaintext = bytes_to_long(a2b_hex(self.plaintext)) - ciphertext = bytes_to_long(a2b_hex(self.ciphertext)) - - # Test plain decryption - new_plaintext = rsaObj._decrypt(ciphertext) - self.assertEqual(plaintext, new_plaintext) - - -def get_tests(config={}): - tests = [] - tests += list_test_cases(RSATest) - return tests - -if __name__ == '__main__': - suite = lambda: unittest.TestSuite(get_tests()) - unittest.main(defaultTest='suite') - -# vim:set ts=4 sw=4 sts=4 expandtab: diff --git a/Crypto/SelfTest/PublicKey/test_import_DSA.py b/Crypto/SelfTest/PublicKey/test_import_DSA.py deleted file mode 100644 index 2a12ea2..0000000 --- a/Crypto/SelfTest/PublicKey/test_import_DSA.py +++ /dev/null @@ -1,554 +0,0 @@ -# -*- coding: utf-8 -*- -# -# SelfTest/PublicKey/test_import_DSA.py: Self-test for importing DSA keys -# -# =================================================================== -# The contents of this file are dedicated to the public domain. To -# the extent that dedication to the public domain is not available, -# everyone is granted a worldwide, perpetual, royalty-free, -# non-exclusive license to exercise all rights associated with the -# contents of this file for any purpose whatsoever. -# No rights are reserved. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS -# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN -# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# =================================================================== - -import unittest -import re - -from Crypto.PublicKey import DSA -from Crypto.SelfTest.st_common import * -from Crypto.Util.py3compat import * - -from binascii import unhexlify - -class ImportKeyTests(unittest.TestCase): - - y = 92137165128186062214622779787483327510946462589285775188003362705875131352591574106484271700740858696583623951844732128165434284507709057439633739849986759064015013893156866539696757799934634945787496920169462601722830899660681779448742875054459716726855443681559131362852474817534616736104831095601710736729 - p = 162452170958135306109773853318304545923250830605675936228618290525164105310663722368377131295055868997377338797580997938253236213714988311430600065853662861806894003694743806769284131194035848116051021923956699231855223389086646903420682639786976554552864568460372266462812137447840653688476258666833303658691 - q = 988791743931120302950649732173330531512663554851 - g = 85583152299197514738065570254868711517748965097380456700369348466136657764813442044039878840094809620913085570225318356734366886985903212775602770761953571967834823306046501307810937486758039063386311593890777319935391363872375452381836756832784184928202587843258855704771836753434368484556809100537243908232 - x = 540873410045082450874416847965843801027716145253 - - def setUp(self): - - # It is easier to write test vectors in text form, - # and convert them to byte strigs dynamically here - for mname, mvalue in ImportKeyTests.__dict__.items(): - if mname[:4] in ('der_', 'pem_', 'ssh_'): - if mname[:4] == 'der_': - mvalue = unhexlify(tobytes(mvalue)) - mvalue = tobytes(mvalue) - setattr(self, mname, mvalue) - - # 1. SubjectPublicKeyInfo - der_public=\ - '308201b73082012b06072a8648ce3804013082011e02818100e756ee1717f4b6'+\ - '794c7c214724a19763742c45572b4b3f8ff3b44f3be9f44ce039a2757695ec91'+\ - '5697da74ef914fcd1b05660e2419c761d639f45d2d79b802dbd23e7ab8b81b47'+\ - '9a380e1f30932584ba2a0b955032342ebc83cb5ca906e7b0d7cd6fe656cecb4c'+\ - '8b5a77123a8c6750a481e3b06057aff6aa6eba620b832d60c3021500ad32f48c'+\ - 'd3ae0c45a198a61fa4b5e20320763b2302818079dfdc3d614fe635fceb7eaeae'+\ - '3718dc2efefb45282993ac6749dc83c223d8c1887296316b3b0b54466cf444f3'+\ - '4b82e3554d0b90a778faaf1306f025dae6a3e36c7f93dd5bac4052b92370040a'+\ - 'ca70b8d5820599711900efbc961812c355dd9beffe0981da85c5548074b41c56'+\ - 'ae43fd300d89262e4efd89943f99a651b03888038185000281810083352a69a1'+\ - '32f34843d2a0eb995bff4e2f083a73f0049d2c91ea2f0ce43d144abda48199e4'+\ - 'b003c570a8af83303d45105f606c5c48d925a40ed9c2630c2fa4cdbf838539de'+\ - 'b9a29f919085f2046369f627ca84b2cb1e2c7940564b670f963ab1164d4e2ca2'+\ - 'bf6ffd39f12f548928bf4d2d1b5e6980b4f1be4c92a91986fba559' - - def testImportKey1(self): - key_obj = DSA.importKey(self.der_public) - self.failIf(key_obj.has_private()) - self.assertEqual(self.y, key_obj.y) - self.assertEqual(self.p, key_obj.p) - self.assertEqual(self.q, key_obj.q) - self.assertEqual(self.g, key_obj.g) - - def testExportKey1(self): - tup = (self.y, self.g, self.p, self.q) - key = DSA.construct(tup) - encoded = key.export_key('DER') - self.assertEqual(self.der_public, encoded) - - # 2. - pem_public="""\ ------BEGIN PUBLIC KEY----- -MIIBtzCCASsGByqGSM44BAEwggEeAoGBAOdW7hcX9LZ5THwhRyShl2N0LEVXK0s/ -j/O0Tzvp9EzgOaJ1dpXskVaX2nTvkU/NGwVmDiQZx2HWOfRdLXm4AtvSPnq4uBtH -mjgOHzCTJYS6KguVUDI0LryDy1ypBuew181v5lbOy0yLWncSOoxnUKSB47BgV6/2 -qm66YguDLWDDAhUArTL0jNOuDEWhmKYfpLXiAyB2OyMCgYB539w9YU/mNfzrfq6u -NxjcLv77RSgpk6xnSdyDwiPYwYhyljFrOwtURmz0RPNLguNVTQuQp3j6rxMG8CXa -5qPjbH+T3VusQFK5I3AECspwuNWCBZlxGQDvvJYYEsNV3Zvv/gmB2oXFVIB0tBxW -rkP9MA2JJi5O/YmUP5mmUbA4iAOBhQACgYEAgzUqaaEy80hD0qDrmVv/Ti8IOnPw -BJ0skeovDOQ9FEq9pIGZ5LADxXCor4MwPUUQX2BsXEjZJaQO2cJjDC+kzb+DhTne -uaKfkZCF8gRjafYnyoSyyx4seUBWS2cPljqxFk1OLKK/b/058S9UiSi/TS0bXmmA -tPG+TJKpGYb7pVk= ------END PUBLIC KEY-----""" - - def testImportKey2(self): - for pem in (self.pem_public, tostr(self.pem_public)): - key_obj = DSA.importKey(pem) - self.failIf(key_obj.has_private()) - self.assertEqual(self.y, key_obj.y) - self.assertEqual(self.p, key_obj.p) - self.assertEqual(self.q, key_obj.q) - self.assertEqual(self.g, key_obj.g) - - def testExportKey2(self): - tup = (self.y, self.g, self.p, self.q) - key = DSA.construct(tup) - encoded = key.export_key('PEM') - self.assertEqual(self.pem_public, encoded) - - # 3. OpenSSL/OpenSSH format - der_private=\ - '308201bb02010002818100e756ee1717f4b6794c7c214724a19763742c45572b'+\ - '4b3f8ff3b44f3be9f44ce039a2757695ec915697da74ef914fcd1b05660e2419'+\ - 'c761d639f45d2d79b802dbd23e7ab8b81b479a380e1f30932584ba2a0b955032'+\ - '342ebc83cb5ca906e7b0d7cd6fe656cecb4c8b5a77123a8c6750a481e3b06057'+\ - 'aff6aa6eba620b832d60c3021500ad32f48cd3ae0c45a198a61fa4b5e2032076'+\ - '3b2302818079dfdc3d614fe635fceb7eaeae3718dc2efefb45282993ac6749dc'+\ - '83c223d8c1887296316b3b0b54466cf444f34b82e3554d0b90a778faaf1306f0'+\ - '25dae6a3e36c7f93dd5bac4052b92370040aca70b8d5820599711900efbc9618'+\ - '12c355dd9beffe0981da85c5548074b41c56ae43fd300d89262e4efd89943f99'+\ - 'a651b038880281810083352a69a132f34843d2a0eb995bff4e2f083a73f0049d'+\ - '2c91ea2f0ce43d144abda48199e4b003c570a8af83303d45105f606c5c48d925'+\ - 'a40ed9c2630c2fa4cdbf838539deb9a29f919085f2046369f627ca84b2cb1e2c'+\ - '7940564b670f963ab1164d4e2ca2bf6ffd39f12f548928bf4d2d1b5e6980b4f1'+\ - 'be4c92a91986fba55902145ebd9a3f0b82069d98420986b314215025756065' - - def testImportKey3(self): - key_obj = DSA.importKey(self.der_private) - self.failUnless(key_obj.has_private()) - self.assertEqual(self.y, key_obj.y) - self.assertEqual(self.p, key_obj.p) - self.assertEqual(self.q, key_obj.q) - self.assertEqual(self.g, key_obj.g) - self.assertEqual(self.x, key_obj.x) - - def testExportKey3(self): - tup = (self.y, self.g, self.p, self.q, self.x) - key = DSA.construct(tup) - encoded = key.export_key('DER', pkcs8=False) - self.assertEqual(self.der_private, encoded) - - # 4. - pem_private="""\ ------BEGIN DSA PRIVATE KEY----- -MIIBuwIBAAKBgQDnVu4XF/S2eUx8IUckoZdjdCxFVytLP4/ztE876fRM4DmidXaV -7JFWl9p075FPzRsFZg4kGcdh1jn0XS15uALb0j56uLgbR5o4Dh8wkyWEuioLlVAy -NC68g8tcqQbnsNfNb+ZWzstMi1p3EjqMZ1CkgeOwYFev9qpuumILgy1gwwIVAK0y -9IzTrgxFoZimH6S14gMgdjsjAoGAed/cPWFP5jX8636urjcY3C7++0UoKZOsZ0nc -g8Ij2MGIcpYxazsLVEZs9ETzS4LjVU0LkKd4+q8TBvAl2uaj42x/k91brEBSuSNw -BArKcLjVggWZcRkA77yWGBLDVd2b7/4JgdqFxVSAdLQcVq5D/TANiSYuTv2JlD+Z -plGwOIgCgYEAgzUqaaEy80hD0qDrmVv/Ti8IOnPwBJ0skeovDOQ9FEq9pIGZ5LAD -xXCor4MwPUUQX2BsXEjZJaQO2cJjDC+kzb+DhTneuaKfkZCF8gRjafYnyoSyyx4s -eUBWS2cPljqxFk1OLKK/b/058S9UiSi/TS0bXmmAtPG+TJKpGYb7pVkCFF69mj8L -ggadmEIJhrMUIVAldWBl ------END DSA PRIVATE KEY-----""" - - def testImportKey4(self): - for pem in (self.pem_private, tostr(self.pem_private)): - key_obj = DSA.importKey(pem) - self.failUnless(key_obj.has_private()) - self.assertEqual(self.y, key_obj.y) - self.assertEqual(self.p, key_obj.p) - self.assertEqual(self.q, key_obj.q) - self.assertEqual(self.g, key_obj.g) - self.assertEqual(self.x, key_obj.x) - - def testExportKey4(self): - tup = (self.y, self.g, self.p, self.q, self.x) - key = DSA.construct(tup) - encoded = key.export_key('PEM', pkcs8=False) - self.assertEqual(self.pem_private, encoded) - - # 5. PKCS8 (unencrypted) - der_pkcs8=\ - '3082014a0201003082012b06072a8648ce3804013082011e02818100e756ee17'+\ - '17f4b6794c7c214724a19763742c45572b4b3f8ff3b44f3be9f44ce039a27576'+\ - '95ec915697da74ef914fcd1b05660e2419c761d639f45d2d79b802dbd23e7ab8'+\ - 'b81b479a380e1f30932584ba2a0b955032342ebc83cb5ca906e7b0d7cd6fe656'+\ - 'cecb4c8b5a77123a8c6750a481e3b06057aff6aa6eba620b832d60c3021500ad'+\ - '32f48cd3ae0c45a198a61fa4b5e20320763b2302818079dfdc3d614fe635fceb'+\ - '7eaeae3718dc2efefb45282993ac6749dc83c223d8c1887296316b3b0b54466c'+\ - 'f444f34b82e3554d0b90a778faaf1306f025dae6a3e36c7f93dd5bac4052b923'+\ - '70040aca70b8d5820599711900efbc961812c355dd9beffe0981da85c5548074'+\ - 'b41c56ae43fd300d89262e4efd89943f99a651b03888041602145ebd9a3f0b82'+\ - '069d98420986b314215025756065' - - def testImportKey5(self): - key_obj = DSA.importKey(self.der_pkcs8) - self.failUnless(key_obj.has_private()) - self.assertEqual(self.y, key_obj.y) - self.assertEqual(self.p, key_obj.p) - self.assertEqual(self.q, key_obj.q) - self.assertEqual(self.g, key_obj.g) - self.assertEqual(self.x, key_obj.x) - - def testExportKey5(self): - tup = (self.y, self.g, self.p, self.q, self.x) - key = DSA.construct(tup) - encoded = key.export_key('DER') - self.assertEqual(self.der_pkcs8, encoded) - encoded = key.export_key('DER', pkcs8=True) - self.assertEqual(self.der_pkcs8, encoded) - - # 6. - pem_pkcs8="""\ ------BEGIN PRIVATE KEY----- -MIIBSgIBADCCASsGByqGSM44BAEwggEeAoGBAOdW7hcX9LZ5THwhRyShl2N0LEVX -K0s/j/O0Tzvp9EzgOaJ1dpXskVaX2nTvkU/NGwVmDiQZx2HWOfRdLXm4AtvSPnq4 -uBtHmjgOHzCTJYS6KguVUDI0LryDy1ypBuew181v5lbOy0yLWncSOoxnUKSB47Bg -V6/2qm66YguDLWDDAhUArTL0jNOuDEWhmKYfpLXiAyB2OyMCgYB539w9YU/mNfzr -fq6uNxjcLv77RSgpk6xnSdyDwiPYwYhyljFrOwtURmz0RPNLguNVTQuQp3j6rxMG -8CXa5qPjbH+T3VusQFK5I3AECspwuNWCBZlxGQDvvJYYEsNV3Zvv/gmB2oXFVIB0 -tBxWrkP9MA2JJi5O/YmUP5mmUbA4iAQWAhRevZo/C4IGnZhCCYazFCFQJXVgZQ== ------END PRIVATE KEY-----""" - - def testImportKey6(self): - for pem in (self.pem_pkcs8, tostr(self.pem_pkcs8)): - key_obj = DSA.importKey(pem) - self.failUnless(key_obj.has_private()) - self.assertEqual(self.y, key_obj.y) - self.assertEqual(self.p, key_obj.p) - self.assertEqual(self.q, key_obj.q) - self.assertEqual(self.g, key_obj.g) - self.assertEqual(self.x, key_obj.x) - - def testExportKey6(self): - tup = (self.y, self.g, self.p, self.q, self.x) - key = DSA.construct(tup) - encoded = key.export_key('PEM') - self.assertEqual(self.pem_pkcs8, encoded) - encoded = key.export_key('PEM', pkcs8=True) - self.assertEqual(self.pem_pkcs8, encoded) - - # 7. OpenSSH/RFC4253 - ssh_pub="""ssh-dss AAAAB3NzaC1kc3MAAACBAOdW7hcX9LZ5THwhRyShl2N0LEVXK0s/j/O0Tzvp9EzgOaJ1dpXskVaX2nTvkU/NGwVmDiQZx2HWOfRdLXm4AtvSPnq4uBtHmjgOHzCTJYS6KguVUDI0LryDy1ypBuew181v5lbOy0yLWncSOoxnUKSB47BgV6/2qm66YguDLWDDAAAAFQCtMvSM064MRaGYph+kteIDIHY7IwAAAIB539w9YU/mNfzrfq6uNxjcLv77RSgpk6xnSdyDwiPYwYhyljFrOwtURmz0RPNLguNVTQuQp3j6rxMG8CXa5qPjbH+T3VusQFK5I3AECspwuNWCBZlxGQDvvJYYEsNV3Zvv/gmB2oXFVIB0tBxWrkP9MA2JJi5O/YmUP5mmUbA4iAAAAIEAgzUqaaEy80hD0qDrmVv/Ti8IOnPwBJ0skeovDOQ9FEq9pIGZ5LADxXCor4MwPUUQX2BsXEjZJaQO2cJjDC+kzb+DhTneuaKfkZCF8gRjafYnyoSyyx4seUBWS2cPljqxFk1OLKK/b/058S9UiSi/TS0bXmmAtPG+TJKpGYb7pVk=""" - - def testImportKey7(self): - for ssh in (self.ssh_pub, tostr(self.ssh_pub)): - key_obj = DSA.importKey(ssh) - self.failIf(key_obj.has_private()) - self.assertEqual(self.y, key_obj.y) - self.assertEqual(self.p, key_obj.p) - self.assertEqual(self.q, key_obj.q) - self.assertEqual(self.g, key_obj.g) - - def testExportKey7(self): - tup = (self.y, self.g, self.p, self.q) - key = DSA.construct(tup) - encoded = key.export_key('OpenSSH') - self.assertEqual(self.ssh_pub, encoded) - - # 8. Encrypted OpenSSL/OpenSSH - pem_private_encrypted="""\ ------BEGIN DSA PRIVATE KEY----- -Proc-Type: 4,ENCRYPTED -DEK-Info: AES-128-CBC,70B6908939D65E9F2EB999E8729788CE - -4V6GHRDpCrdZ8MBjbyp5AlGUrjvr2Pn2e2zVxy5RBt4FBj9/pa0ae0nnyUPMLSUU -kKyOR0topRYTVRLElm4qVrb5uNZ3hRwfbklr+pSrB7O9eHz9V5sfOQxyODS07JxK -k1OdOs70/ouMXLF9EWfAZOmWUccZKHNblUwg1p1UrZIz5jXw4dUE/zqhvXh6d+iC -ADsICaBCjCrRQJKDp50h3+ndQjkYBKVH+pj8TiQ79U7lAvdp3+iMghQN6YXs9mdI -gFpWw/f97oWM4GHZFqHJ+VSMNFjBiFhAvYV587d7Lk4dhD8sCfbxj42PnfRgUItc -nnPqHxmhMQozBWzYM4mQuo3XbF2WlsNFbOzFVyGhw1Bx1s91qvXBVWJh2ozrW0s6 -HYDV7ZkcTml/4kjA/d+mve6LZ8kuuR1qCiZx6rkffhh1gDN/1Xz3HVvIy/dQ+h9s -5zp7PwUoWbhqp3WCOr156P6gR8qo7OlT6wMh33FSXK/mxikHK136fV2shwTKQVII -rJBvXpj8nACUmi7scKuTWGeUoXa+dwTZVVe+b+L2U1ZM7+h/neTJiXn7u99PFUwu -xVJtxaV37m3aXxtCsPnbBg== ------END DSA PRIVATE KEY-----""" - - def testImportKey8(self): - for pem in (self.pem_private_encrypted, tostr(self.pem_private_encrypted)): - key_obj = DSA.importKey(pem, "PWDTEST") - self.failUnless(key_obj.has_private()) - self.assertEqual(self.y, key_obj.y) - self.assertEqual(self.p, key_obj.p) - self.assertEqual(self.q, key_obj.q) - self.assertEqual(self.g, key_obj.g) - self.assertEqual(self.x, key_obj.x) - - def testExportKey8(self): - tup = (self.y, self.g, self.p, self.q, self.x) - key = DSA.construct(tup) - encoded = key.export_key('PEM', pkcs8=False, passphrase="PWDTEST") - key = DSA.importKey(encoded, "PWDTEST") - self.assertEqual(self.y, key.y) - self.assertEqual(self.p, key.p) - self.assertEqual(self.q, key.q) - self.assertEqual(self.g, key.g) - self.assertEqual(self.x, key.x) - - # 9. Encrypted PKCS8 - # pbeWithMD5AndDES-CBC - pem_pkcs8_encrypted="""\ ------BEGIN ENCRYPTED PRIVATE KEY----- -MIIBcTAbBgkqhkiG9w0BBQMwDgQI0GC3BJ/jSw8CAggABIIBUHc1cXZpExIE9tC7 -7ryiW+5ihtF2Ekurq3e408GYSAu5smJjN2bvQXmzRFBz8W38K8eMf1sbWroZ4+zn -kZSbb9nSm5kAa8lR2+oF2k+WRswMR/PTC3f/D9STO2X0QxdrzKgIHEcSGSHp5jTx -aVvbkCDHo9vhBTl6S3ogZ48As/MEro76+9igUwJ1jNhIQZPJ7e20QH5qDpQFFJN4 -CKl2ENSEuwGiqBszItFy4dqH0g63ZGZV/xt9wSO9Rd7SK/EbA/dklOxBa5Y/VItM -gnIhs9XDMoGYyn6F023EicNJm6g/bVQk81BTTma4tm+12TKGdYm+QkeZvCOMZylr -Wv67cKwO3cAXt5C3QXMDgYR64XvuaT5h7C0igMp2afSXJlnbHEbFxQVJlv83T4FM -eZ4k+NQDbEL8GiHmFxzDWQAuPPZKJWEEEV2p/To+WOh+kSDHQw== ------END ENCRYPTED PRIVATE KEY-----""" - - def testImportKey9(self): - for pem in (self.pem_pkcs8_encrypted, tostr(self.pem_pkcs8_encrypted)): - key_obj = DSA.importKey(pem, "PWDTEST") - self.failUnless(key_obj.has_private()) - self.assertEqual(self.y, key_obj.y) - self.assertEqual(self.p, key_obj.p) - self.assertEqual(self.q, key_obj.q) - self.assertEqual(self.g, key_obj.g) - self.assertEqual(self.x, key_obj.x) - - # 10. Encrypted PKCS8 - # pkcs5PBES2 / - # pkcs5PBKDF2 (rounds=1000, salt=D725BF1B6B8239F4) / - # des-EDE3-CBC (iv=27A1C66C42AFEECE) - # - der_pkcs8_encrypted=\ - '30820196304006092a864886f70d01050d3033301b06092a864886f70d01050c'+\ - '300e0408d725bf1b6b8239f4020203e8301406082a864886f70d0307040827a1'+\ - 'c66c42afeece048201505cacfde7bf8edabb3e0d387950dc872662ea7e9b1ed4'+\ - '400d2e7e6186284b64668d8d0328c33a9d9397e6f03df7cb68268b0a06b4e22f'+\ - '7d132821449ecf998a8b696dbc6dd2b19e66d7eb2edfeb4153c1771d49702395'+\ - '4f36072868b5fcccf93413a5ac4b2eb47d4b3f681c6bd67ae363ed776f45ae47'+\ - '174a00098a7c930a50f820b227ddf50f9742d8e950d02586ff2dac0e3c372248'+\ - 'e5f9b6a7a02f4004f20c87913e0f7b52bccc209b95d478256a890b31d4c9adec'+\ - '21a4d157a179a93a3dad06f94f3ce486b46dfa7fc15fd852dd7680bbb2f17478'+\ - '7e71bd8dbaf81eca7518d76c1d26256e95424864ba45ca5d47d7c5a421be02fa'+\ - 'b94ab01e18593f66cf9094eb5c94b9ecf3aa08b854a195cf87612fbe5e96c426'+\ - '2b0d573e52dc71ba3f5e468c601e816c49b7d32c698b22175e89aaef0c443770'+\ - '5ef2f88a116d99d8e2869a4fd09a771b84b49e4ccb79aadcb1c9' - - def testImportKey10(self): - key_obj = DSA.importKey(self.der_pkcs8_encrypted, "PWDTEST") - self.failUnless(key_obj.has_private()) - self.assertEqual(self.y, key_obj.y) - self.assertEqual(self.p, key_obj.p) - self.assertEqual(self.q, key_obj.q) - self.assertEqual(self.g, key_obj.g) - self.assertEqual(self.x, key_obj.x) - - def testExportKey10(self): - tup = (self.y, self.g, self.p, self.q, self.x) - key = DSA.construct(tup) - randfunc = BytesIO(unhexlify(b("27A1C66C42AFEECE") + b("D725BF1B6B8239F4"))).read - encoded = key.export_key('DER', pkcs8=True, passphrase="PWDTEST", randfunc=randfunc) - self.assertEqual(self.der_pkcs8_encrypted, encoded) - - # ---- - - def testImportError1(self): - self.assertRaises(ValueError, DSA.importKey, self.der_pkcs8_encrypted, "wrongpwd") - - def testExportError2(self): - tup = (self.y, self.g, self.p, self.q, self.x) - key = DSA.construct(tup) - self.assertRaises(ValueError, key.export_key, 'DER', pkcs8=False, passphrase="PWDTEST") - - def test_import_key(self): - """Verify importKey is an alias to import_key""" - - key_obj = DSA.import_key(self.der_public) - self.failIf(key_obj.has_private()) - self.assertEqual(self.y, key_obj.y) - self.assertEqual(self.p, key_obj.p) - self.assertEqual(self.q, key_obj.q) - self.assertEqual(self.g, key_obj.g) - - def test_exportKey(self): - tup = (self.y, self.g, self.p, self.q, self.x) - key = DSA.construct(tup) - self.assertEquals(key.exportKey(), key.export_key()) - - - def test_import_empty(self): - self.assertRaises(ValueError, DSA.import_key, b'') - - -class ImportKeyFromX509Cert(unittest.TestCase): - - def test_x509v1(self): - - # Sample V1 certificate with a 1024 bit DSA key - x509_v1_cert = """ ------BEGIN CERTIFICATE----- -MIIDUjCCArsCAQIwDQYJKoZIhvcNAQEFBQAwfjENMAsGA1UEChMEQWNtZTELMAkG -A1UECxMCUkQxHDAaBgkqhkiG9w0BCQEWDXNwYW1AYWNtZS5vcmcxEzARBgNVBAcT -Ck1ldHJvcG9saXMxETAPBgNVBAgTCE5ldyBZb3JrMQswCQYDVQQGEwJVUzENMAsG -A1UEAxMEdGVzdDAeFw0xNDA3MTEyMDM4NDNaFw0xNzA0MDYyMDM4NDNaME0xCzAJ -BgNVBAYTAlVTMREwDwYDVQQIEwhOZXcgWW9yazENMAsGA1UEChMEQWNtZTELMAkG -A1UECxMCUkQxDzANBgNVBAMTBnBvbGFuZDCCAbYwggErBgcqhkjOOAQBMIIBHgKB -gQDOrN4Ox4+t3T6wKeHfhzArhcrNEFMQ4Ss+4PIKyimDy9Bn64WPkL1B/9dvYIga -23GLu6tVJmXo6EdJnVOHEMhr99EeOwuDWWeP7Awq7RSlKEejokr4BEzMTW/tExSD -cO6/GI7xzh0eTH+VTTPDfyrJMYCkh0rJAfCP+5xrmPNetwIVALtXYOV1yoRrzJ2Q -M5uEjidH6GiZAoGAfUqA1SAm5g5U68SILMVX9l5rq0OpB0waBMpJQ31/R/yXNDqo -c3gGWZTOJFU4IzwNpGhrGNADUByz/lc1SAOAdEJIr0JVrhbGewQjB4pWqoLGbBKz -RoavTNDc/zD7SYa12evWDHADwvlXoeQg+lWop1zS8OqaDC7aLGKpWN3/m8kDgYQA -AoGAKoirPAfcp1rbbl4y2FFAIktfW8f4+T7d2iKSg73aiVfujhNOt1Zz1lfC0NI2 -eonLWO3tAM4XGKf1TLjb5UXngGn40okPsaA81YE6ZIKm20ywjlOY3QkAEdMaLVY3 -9PJvM8RGB9m7pLKxyHfGMfF40MVN4222zKeGp7xhM0CNiCUwDQYJKoZIhvcNAQEF -BQADgYEAfbNZfpYa2KlALEM1FZnwvQDvJHntHz8LdeJ4WM7CXDlKi67wY2HKM30w -s2xej75imkVOFd1kF2d0A8sjfriXLVIt1Hwq9ANZomhu4Edx0xpH8tqdh/bDtnM2 -TmduZNY9OWkb07h0CtWD6Zt8fhRllVsSSrlWd/2or7FXNC5weFQ= ------END CERTIFICATE----- - """.strip() - - # DSA public key as dumped by openssl - y_str = """ -2a:88:ab:3c:07:dc:a7:5a:db:6e:5e:32:d8:51:40: -22:4b:5f:5b:c7:f8:f9:3e:dd:da:22:92:83:bd:da: -89:57:ee:8e:13:4e:b7:56:73:d6:57:c2:d0:d2:36: -7a:89:cb:58:ed:ed:00:ce:17:18:a7:f5:4c:b8:db: -e5:45:e7:80:69:f8:d2:89:0f:b1:a0:3c:d5:81:3a: -64:82:a6:db:4c:b0:8e:53:98:dd:09:00:11:d3:1a: -2d:56:37:f4:f2:6f:33:c4:46:07:d9:bb:a4:b2:b1: -c8:77:c6:31:f1:78:d0:c5:4d:e3:6d:b6:cc:a7:86: -a7:bc:61:33:40:8d:88:25 - """ - p_str = """ -00:ce:ac:de:0e:c7:8f:ad:dd:3e:b0:29:e1:df:87: -30:2b:85:ca:cd:10:53:10:e1:2b:3e:e0:f2:0a:ca: -29:83:cb:d0:67:eb:85:8f:90:bd:41:ff:d7:6f:60: -88:1a:db:71:8b:bb:ab:55:26:65:e8:e8:47:49:9d: -53:87:10:c8:6b:f7:d1:1e:3b:0b:83:59:67:8f:ec: -0c:2a:ed:14:a5:28:47:a3:a2:4a:f8:04:4c:cc:4d: -6f:ed:13:14:83:70:ee:bf:18:8e:f1:ce:1d:1e:4c: -7f:95:4d:33:c3:7f:2a:c9:31:80:a4:87:4a:c9:01: -f0:8f:fb:9c:6b:98:f3:5e:b7 - """ - q_str = """ -00:bb:57:60:e5:75:ca:84:6b:cc:9d:90:33:9b:84: -8e:27:47:e8:68:99 - """ - g_str = """ -7d:4a:80:d5:20:26:e6:0e:54:eb:c4:88:2c:c5:57: -f6:5e:6b:ab:43:a9:07:4c:1a:04:ca:49:43:7d:7f: -47:fc:97:34:3a:a8:73:78:06:59:94:ce:24:55:38: -23:3c:0d:a4:68:6b:18:d0:03:50:1c:b3:fe:57:35: -48:03:80:74:42:48:af:42:55:ae:16:c6:7b:04:23: -07:8a:56:aa:82:c6:6c:12:b3:46:86:af:4c:d0:dc: -ff:30:fb:49:86:b5:d9:eb:d6:0c:70:03:c2:f9:57: -a1:e4:20:fa:55:a8:a7:5c:d2:f0:ea:9a:0c:2e:da: -2c:62:a9:58:dd:ff:9b:c9 - """ - - key = DSA.importKey(x509_v1_cert) - for comp_name in ('y', 'p', 'q', 'g'): - comp_str = locals()[comp_name + "_str"] - comp = int(re.sub("[^0-9a-f]", "", comp_str), 16) - self.assertEqual(getattr(key, comp_name), comp) - self.failIf(key.has_private()) - - def test_x509v3(self): - - # Sample V3 certificate with a 1024 bit DSA key - x509_v3_cert = """ ------BEGIN CERTIFICATE----- -MIIFhjCCA26gAwIBAgIBAzANBgkqhkiG9w0BAQsFADBhMQswCQYDVQQGEwJVUzEL -MAkGA1UECAwCTUQxEjAQBgNVBAcMCUJhbHRpbW9yZTEQMA4GA1UEAwwHVGVzdCBD -QTEfMB0GCSqGSIb3DQEJARYQdGVzdEBleGFtcGxlLmNvbTAeFw0xNDA3MTMyMDUz -MjBaFw0xNzA0MDgyMDUzMjBaMEAxCzAJBgNVBAYTAlVTMQswCQYDVQQIDAJNRDES -MBAGA1UEBwwJQmFsdGltb3JlMRAwDgYDVQQDDAdhdXN0cmlhMIIBtjCCASsGByqG -SM44BAEwggEeAoGBALfd8gyEpVPA0ZI69Kp3nyJcu5N0ZZ3K1K9hleQLNqKEcZOh -7a/C2J1TPdmHTLJ0rAwBZ1nWxnARSgRphziGDFspKCYQwYcSMz8KoFgvXbXpuchy -oFACiQ2LqZnc5MakuLQtLcQciSYGYj3zmZdYMoa904F1aDWr+DxQI6DVC3/bAhUA -hqXMCJ6fQK3G2O9S3/CC/yVZXCsCgYBRXROl3R2khX7l10LQjDEgo3B1IzjXU/jP -McMBl6XO+nBJXxr/scbq8Ajiv7LTnGpSjgryHtvfj887kfvo8QbSS3kp3vq5uSqI -ui7E7r3jguWaLj616AG1HWOctXJUjqsiabZwsp2h09gHTzmHEXBOmiARu8xFxKAH -xsuo7onAbwOBhAACgYBylWjWSnKHE8mHx1A5m/0GQx6xnhWIe3+MJAnEhRGxA2J4 -SCsfWU0OwglIQToh1z5uUU9oDi9cYgNPBevOFRnDhc2yaJY6VAYnI+D+6J5IU6Yd -0iaG/iSc4sV4bFr0axcPpse3SN0XaQxiKeSFBfFnoMqL+dd9Gb3QPZSllBcVD6OB -1TCB0jAdBgNVHQ4EFgQUx5wN0Puotv388M9Tp/fsPbZpzAUwHwYDVR0jBBgwFoAU -a0hkif3RMaraiWtsOOZZlLu9wJwwCQYDVR0TBAIwADALBgNVHQ8EBAMCBeAwSgYD -VR0RBEMwQYILZXhhbXBsZS5jb22CD3d3dy5leGFtcGxlLmNvbYIQbWFpbC5leGFt -cGxlLmNvbYIPZnRwLmV4YW1wbGUuY29tMCwGCWCGSAGG+EIBDQQfFh1PcGVuU1NM -IEdlbmVyYXRlZCBDZXJ0aWZpY2F0ZTANBgkqhkiG9w0BAQsFAAOCAgEAyWf1TiJI -aNEIA9o/PG8/JiGASTS2/HBVTJbkq03k6NkJVk/GxC1DPziTUJ+CdWlHWcAi1EOW -Ach3QxNDRrVfCOfCMDgElIO1094/reJgdFYG00LRi8QkRJuxANV7YS4tLudhyHJC -kR2lhdMNmEuzWK+s2y+5cLrdm7qdvdENQCcV67uvGPx4sc+EaE7x13SczKjWBtbo -QCs6JTOW+EkPRl4Zo27K4OIZ43/J+GxvwU9QUVH3wPVdbbLNw+QeTFBYMTEcxyc4 -kv50HPBFaithziXBFyvdIs19FjkFzu0Uz/e0zb1+vMzQlJMD94HVOrMnIj5Sb2cL -KKdYXS4uhxFJmdV091Xur5JkYYwEzuaGav7J3zOzYutrIGTgDluLCvA+VQkRcTsy -jZ065SkY/v+38QHp+cmm8WRluupJTs8wYzVp6Fu0iFaaK7ztFmaZmHpiPIfDFjva -aCIgzzT5NweJd/b71A2SyzHXJ14zBXsr1PMylMp2TpHIidhuuNuQL6I0HaollB4M -Z3FsVBMhVDw4Z76qnFPr8mZE2tar33hSlJI/3pS/bBiukuBk8U7VB0X8OqaUnP3C -7b2Z4G8GtqDVcKGMzkvMjT4n9rKd/Le+qHSsQOGO9W/0LB7UDAZSwUsfAPnoBgdS -5t9tIomLCOstByXi+gGZue1TcdCa3Ph4kO0= ------END CERTIFICATE----- - """.strip() - - # DSA public key as dumped by openssl - y_str = """ -72:95:68:d6:4a:72:87:13:c9:87:c7:50:39:9b:fd: -06:43:1e:b1:9e:15:88:7b:7f:8c:24:09:c4:85:11: -b1:03:62:78:48:2b:1f:59:4d:0e:c2:09:48:41:3a: -21:d7:3e:6e:51:4f:68:0e:2f:5c:62:03:4f:05:eb: -ce:15:19:c3:85:cd:b2:68:96:3a:54:06:27:23:e0: -fe:e8:9e:48:53:a6:1d:d2:26:86:fe:24:9c:e2:c5: -78:6c:5a:f4:6b:17:0f:a6:c7:b7:48:dd:17:69:0c: -62:29:e4:85:05:f1:67:a0:ca:8b:f9:d7:7d:19:bd: -d0:3d:94:a5:94:17:15:0f - """ - p_str = """ -00:b7:dd:f2:0c:84:a5:53:c0:d1:92:3a:f4:aa:77: -9f:22:5c:bb:93:74:65:9d:ca:d4:af:61:95:e4:0b: -36:a2:84:71:93:a1:ed:af:c2:d8:9d:53:3d:d9:87: -4c:b2:74:ac:0c:01:67:59:d6:c6:70:11:4a:04:69: -87:38:86:0c:5b:29:28:26:10:c1:87:12:33:3f:0a: -a0:58:2f:5d:b5:e9:b9:c8:72:a0:50:02:89:0d:8b: -a9:99:dc:e4:c6:a4:b8:b4:2d:2d:c4:1c:89:26:06: -62:3d:f3:99:97:58:32:86:bd:d3:81:75:68:35:ab: -f8:3c:50:23:a0:d5:0b:7f:db - """ - q_str = """ -00:86:a5:cc:08:9e:9f:40:ad:c6:d8:ef:52:df:f0: -82:ff:25:59:5c:2b - """ - g_str = """ -51:5d:13:a5:dd:1d:a4:85:7e:e5:d7:42:d0:8c:31: -20:a3:70:75:23:38:d7:53:f8:cf:31:c3:01:97:a5: -ce:fa:70:49:5f:1a:ff:b1:c6:ea:f0:08:e2:bf:b2: -d3:9c:6a:52:8e:0a:f2:1e:db:df:8f:cf:3b:91:fb: -e8:f1:06:d2:4b:79:29:de:fa:b9:b9:2a:88:ba:2e: -c4:ee:bd:e3:82:e5:9a:2e:3e:b5:e8:01:b5:1d:63: -9c:b5:72:54:8e:ab:22:69:b6:70:b2:9d:a1:d3:d8: -07:4f:39:87:11:70:4e:9a:20:11:bb:cc:45:c4:a0: -07:c6:cb:a8:ee:89:c0:6f - """ - - key = DSA.importKey(x509_v3_cert) - for comp_name in ('y', 'p', 'q', 'g'): - comp_str = locals()[comp_name + "_str"] - comp = int(re.sub("[^0-9a-f]", "", comp_str), 16) - self.assertEqual(getattr(key, comp_name), comp) - self.failIf(key.has_private()) - - -if __name__ == '__main__': - unittest.main() - -def get_tests(config={}): - tests = [] - tests += list_test_cases(ImportKeyTests) - tests += list_test_cases(ImportKeyFromX509Cert) - return tests - -if __name__ == '__main__': - suite = lambda: unittest.TestSuite(get_tests()) - unittest.main(defaultTest='suite') - diff --git a/Crypto/SelfTest/PublicKey/test_import_ECC.py b/Crypto/SelfTest/PublicKey/test_import_ECC.py deleted file mode 100644 index bce8d6f..0000000 --- a/Crypto/SelfTest/PublicKey/test_import_ECC.py +++ /dev/null @@ -1,1346 +0,0 @@ -# =================================================================== -# -# Copyright (c) 2015, Legrandin -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# =================================================================== - -import os -import errno -import warnings -import unittest -from binascii import unhexlify - -from Crypto.SelfTest.st_common import list_test_cases -from Crypto.Util.py3compat import bord, tostr, FileNotFoundError -from Crypto.Util.number import bytes_to_long -from Crypto.Hash import SHAKE128 - -from Crypto.PublicKey import ECC - -try: - import pycryptodome_test_vectors # type: ignore - test_vectors_available = True -except ImportError: - test_vectors_available = False - - -class MissingTestVectorException(ValueError): - pass - - -def load_file(file_name, mode="rb"): - results = None - - try: - if not test_vectors_available: - raise FileNotFoundError(errno.ENOENT, - os.strerror(errno.ENOENT), - file_name) - - dir_comps = ("PublicKey", "ECC") - init_dir = os.path.dirname(pycryptodome_test_vectors.__file__) - full_file_name = os.path.join(os.path.join(init_dir, *dir_comps), file_name) - with open(full_file_name, mode) as file_in: - results = file_in.read() - - except FileNotFoundError: - warnings.warn("Warning: skipping extended tests for ECC", - UserWarning, - stacklevel=2) - - if results is None: - raise MissingTestVectorException("Missing %s" % file_name) - - return results - - -def compact(lines): - ext = b"".join(lines) - return unhexlify(tostr(ext).replace(" ", "").replace(":", "")) - - -def create_ref_keys_p256(): - key_len = 32 - key_lines = load_file("ecc_p256.txt").splitlines() - private_key_d = bytes_to_long(compact(key_lines[2:5])) - public_key_xy = compact(key_lines[6:11]) - assert bord(public_key_xy[0]) == 4 # Uncompressed - public_key_x = bytes_to_long(public_key_xy[1:key_len+1]) - public_key_y = bytes_to_long(public_key_xy[key_len+1:]) - - return (ECC.construct(curve="P-256", d=private_key_d), - ECC.construct(curve="P-256", point_x=public_key_x, point_y=public_key_y)) - -def create_ref_keys_p384(): - key_len = 48 - key_lines = load_file("ecc_p384.txt").splitlines() - private_key_d = bytes_to_long(compact(key_lines[2:6])) - public_key_xy = compact(key_lines[7:14]) - assert bord(public_key_xy[0]) == 4 # Uncompressed - public_key_x = bytes_to_long(public_key_xy[1:key_len+1]) - public_key_y = bytes_to_long(public_key_xy[key_len+1:]) - - return (ECC.construct(curve="P-384", d=private_key_d), - ECC.construct(curve="P-384", point_x=public_key_x, point_y=public_key_y)) - -def create_ref_keys_p521(): - key_len = 66 - key_lines = load_file("ecc_p521.txt").splitlines() - private_key_d = bytes_to_long(compact(key_lines[2:7])) - public_key_xy = compact(key_lines[8:17]) - assert bord(public_key_xy[0]) == 4 # Uncompressed - public_key_x = bytes_to_long(public_key_xy[1:key_len+1]) - public_key_y = bytes_to_long(public_key_xy[key_len+1:]) - - return (ECC.construct(curve="P-521", d=private_key_d), - ECC.construct(curve="P-521", point_x=public_key_x, point_y=public_key_y)) - -# Create reference key pair -# ref_private, ref_public = create_ref_keys_p521() - -def get_fixed_prng(): - return SHAKE128.new().update(b"SEED").read - - -class TestImport(unittest.TestCase): - - def test_empty(self): - self.assertRaises(ValueError, ECC.import_key, b"") - - -class TestImport_P256(unittest.TestCase): - - def __init__(self, *args, **kwargs): - super(TestImport_P256, self).__init__(*args, **kwargs) - self.ref_private, self.ref_public = create_ref_keys_p256() - - def test_import_public_der(self): - key_file = load_file("ecc_p256_public.der") - - key = ECC._import_subjectPublicKeyInfo(key_file) - self.assertEqual(self.ref_public, key) - - key = ECC._import_der(key_file, None) - self.assertEqual(self.ref_public, key) - - key = ECC.import_key(key_file) - self.assertEqual(self.ref_public, key) - - def test_import_private_der(self): - key_file = load_file("ecc_p256_private.der") - - key = ECC._import_private_der(key_file, None) - self.assertEqual(self.ref_private, key) - - key = ECC._import_der(key_file, None) - self.assertEqual(self.ref_private, key) - - key = ECC.import_key(key_file) - self.assertEqual(self.ref_private, key) - - def test_import_private_pkcs8_clear(self): - key_file = load_file("ecc_p256_private_p8_clear.der") - - key = ECC._import_der(key_file, None) - self.assertEqual(self.ref_private, key) - - key = ECC.import_key(key_file) - self.assertEqual(self.ref_private, key) - - def test_import_private_pkcs8_in_pem_clear(self): - key_file = load_file("ecc_p256_private_p8_clear.pem") - - key = ECC.import_key(key_file) - self.assertEqual(self.ref_private, key) - - def test_import_private_pkcs8_encrypted_1(self): - key_file = load_file("ecc_p256_private_p8.der") - - key = ECC._import_der(key_file, "secret") - self.assertEqual(self.ref_private, key) - - key = ECC.import_key(key_file, "secret") - self.assertEqual(self.ref_private, key) - - def test_import_private_pkcs8_encrypted_2(self): - key_file = load_file("ecc_p256_private_p8.pem") - - key = ECC.import_key(key_file, "secret") - self.assertEqual(self.ref_private, key) - - def test_import_x509_der(self): - key_file = load_file("ecc_p256_x509.der") - - key = ECC._import_der(key_file, None) - self.assertEqual(self.ref_public, key) - - key = ECC.import_key(key_file) - self.assertEqual(self.ref_public, key) - - def test_import_public_pem(self): - key_file = load_file("ecc_p256_public.pem") - - key = ECC.import_key(key_file) - self.assertEqual(self.ref_public, key) - - def test_import_private_pem(self): - key_file = load_file("ecc_p256_private.pem") - - key = ECC.import_key(key_file) - self.assertEqual(self.ref_private, key) - - def test_import_private_pem_with_ecparams(self): - key_file = load_file("ecc_p256_private_ecparams.pem") - key = ECC.import_key(key_file) - # We just check if the import succeeds - - def test_import_private_pem_encrypted(self): - for algo in "des3", "aes128", "aes192", "aes256", "aes256_gcm": - key_file = load_file("ecc_p256_private_enc_%s.pem" % algo) - - key = ECC.import_key(key_file, "secret") - self.assertEqual(self.ref_private, key) - - key = ECC.import_key(tostr(key_file), b"secret") - self.assertEqual(self.ref_private, key) - - def test_import_x509_pem(self): - key_file = load_file("ecc_p256_x509.pem") - - key = ECC.import_key(key_file) - self.assertEqual(self.ref_public, key) - - def test_import_openssh_public(self): - key_file = load_file("ecc_p256_public_openssh.txt") - - key = ECC._import_openssh_public(key_file) - self.assertEqual(self.ref_public, key) - - key = ECC.import_key(key_file) - self.assertEqual(self.ref_public, key) - - def test_import_openssh_private_clear(self): - key_file = load_file("ecc_p256_private_openssh.pem") - key_file_old = load_file("ecc_p256_private_openssh_old.pem") - - key = ECC.import_key(key_file) - key_old = ECC.import_key(key_file_old) - self.assertEqual(key, key_old) - - def test_import_openssh_private_password(self): - key_file = load_file("ecc_p256_private_openssh_pwd.pem") - key_file_old = load_file("ecc_p256_private_openssh_pwd_old.pem") - - key = ECC.import_key(key_file, b"password") - key_old = ECC.import_key(key_file_old) - self.assertEqual(key, key_old) - - -class TestImport_P384(unittest.TestCase): - - def __init__(self, *args, **kwargs): - super(TestImport_P384, self).__init__(*args, **kwargs) - self.ref_private, self.ref_public = create_ref_keys_p384() - - def test_import_public_der(self): - key_file = load_file("ecc_p384_public.der") - - key = ECC._import_subjectPublicKeyInfo(key_file) - self.assertEqual(self.ref_public, key) - - key = ECC._import_der(key_file, None) - self.assertEqual(self.ref_public, key) - - key = ECC.import_key(key_file) - self.assertEqual(self.ref_public, key) - - def test_import_private_der(self): - key_file = load_file("ecc_p384_private.der") - - key = ECC._import_private_der(key_file, None) - self.assertEqual(self.ref_private, key) - - key = ECC._import_der(key_file, None) - self.assertEqual(self.ref_private, key) - - key = ECC.import_key(key_file) - self.assertEqual(self.ref_private, key) - - def test_import_private_pkcs8_clear(self): - key_file = load_file("ecc_p384_private_p8_clear.der") - - key = ECC._import_der(key_file, None) - self.assertEqual(self.ref_private, key) - - key = ECC.import_key(key_file) - self.assertEqual(self.ref_private, key) - - def test_import_private_pkcs8_in_pem_clear(self): - key_file = load_file("ecc_p384_private_p8_clear.pem") - - key = ECC.import_key(key_file) - self.assertEqual(self.ref_private, key) - - def test_import_private_pkcs8_encrypted_1(self): - key_file = load_file("ecc_p384_private_p8.der") - - key = ECC._import_der(key_file, "secret") - self.assertEqual(self.ref_private, key) - - key = ECC.import_key(key_file, "secret") - self.assertEqual(self.ref_private, key) - - def test_import_private_pkcs8_encrypted_2(self): - key_file = load_file("ecc_p384_private_p8.pem") - - key = ECC.import_key(key_file, "secret") - self.assertEqual(self.ref_private, key) - - def test_import_x509_der(self): - key_file = load_file("ecc_p384_x509.der") - - key = ECC._import_der(key_file, None) - self.assertEqual(self.ref_public, key) - - key = ECC.import_key(key_file) - self.assertEqual(self.ref_public, key) - - def test_import_public_pem(self): - key_file = load_file("ecc_p384_public.pem") - - key = ECC.import_key(key_file) - self.assertEqual(self.ref_public, key) - - def test_import_private_pem(self): - key_file = load_file("ecc_p384_private.pem") - - key = ECC.import_key(key_file) - self.assertEqual(self.ref_private, key) - - def test_import_private_pem_encrypted(self): - for algo in "des3", "aes128", "aes192", "aes256", "aes256_gcm": - key_file = load_file("ecc_p384_private_enc_%s.pem" % algo) - - key = ECC.import_key(key_file, "secret") - self.assertEqual(self.ref_private, key) - - key = ECC.import_key(tostr(key_file), b"secret") - self.assertEqual(self.ref_private, key) - - def test_import_x509_pem(self): - key_file = load_file("ecc_p384_x509.pem") - - key = ECC.import_key(key_file) - self.assertEqual(self.ref_public, key) - - def test_import_openssh_public(self): - key_file = load_file("ecc_p384_public_openssh.txt") - - key = ECC._import_openssh_public(key_file) - self.assertEqual(self.ref_public, key) - - key = ECC.import_key(key_file) - self.assertEqual(self.ref_public, key) - - def test_import_openssh_private_clear(self): - key_file = load_file("ecc_p384_private_openssh.pem") - key_file_old = load_file("ecc_p384_private_openssh_old.pem") - - key = ECC.import_key(key_file) - key_old = ECC.import_key(key_file_old) - self.assertEqual(key, key_old) - - def test_import_openssh_private_password(self): - key_file = load_file("ecc_p384_private_openssh_pwd.pem") - key_file_old = load_file("ecc_p384_private_openssh_pwd_old.pem") - - key = ECC.import_key(key_file, b"password") - key_old = ECC.import_key(key_file_old) - self.assertEqual(key, key_old) - - -class TestImport_P521(unittest.TestCase): - - def __init__(self, *args, **kwargs): - super(TestImport_P521, self).__init__(*args, **kwargs) - self.ref_private, self.ref_public = create_ref_keys_p521() - - def test_import_public_der(self): - key_file = load_file("ecc_p521_public.der") - - key = ECC._import_subjectPublicKeyInfo(key_file) - self.assertEqual(self.ref_public, key) - - key = ECC._import_der(key_file, None) - self.assertEqual(self.ref_public, key) - - key = ECC.import_key(key_file) - self.assertEqual(self.ref_public, key) - - def test_import_private_der(self): - key_file = load_file("ecc_p521_private.der") - - key = ECC._import_private_der(key_file, None) - self.assertEqual(self.ref_private, key) - - key = ECC._import_der(key_file, None) - self.assertEqual(self.ref_private, key) - - key = ECC.import_key(key_file) - self.assertEqual(self.ref_private, key) - - def test_import_private_pkcs8_clear(self): - key_file = load_file("ecc_p521_private_p8_clear.der") - - key = ECC._import_der(key_file, None) - self.assertEqual(self.ref_private, key) - - key = ECC.import_key(key_file) - self.assertEqual(self.ref_private, key) - - def test_import_private_pkcs8_in_pem_clear(self): - key_file = load_file("ecc_p521_private_p8_clear.pem") - - key = ECC.import_key(key_file) - self.assertEqual(self.ref_private, key) - - def test_import_private_pkcs8_encrypted_1(self): - key_file = load_file("ecc_p521_private_p8.der") - - key = ECC._import_der(key_file, "secret") - self.assertEqual(self.ref_private, key) - - key = ECC.import_key(key_file, "secret") - self.assertEqual(self.ref_private, key) - - def test_import_private_pkcs8_encrypted_2(self): - key_file = load_file("ecc_p521_private_p8.pem") - - key = ECC.import_key(key_file, "secret") - self.assertEqual(self.ref_private, key) - - def test_import_x509_der(self): - key_file = load_file("ecc_p521_x509.der") - - key = ECC._import_der(key_file, None) - self.assertEqual(self.ref_public, key) - - key = ECC.import_key(key_file) - self.assertEqual(self.ref_public, key) - - def test_import_public_pem(self): - key_file = load_file("ecc_p521_public.pem") - - key = ECC.import_key(key_file) - self.assertEqual(self.ref_public, key) - - def test_import_private_pem(self): - key_file = load_file("ecc_p521_private.pem") - - key = ECC.import_key(key_file) - self.assertEqual(self.ref_private, key) - - def test_import_private_pem_encrypted(self): - for algo in "des3", "aes128", "aes192", "aes256", "aes256_gcm": - key_file = load_file("ecc_p521_private_enc_%s.pem" % algo) - - key = ECC.import_key(key_file, "secret") - self.assertEqual(self.ref_private, key) - - key = ECC.import_key(tostr(key_file), b"secret") - self.assertEqual(self.ref_private, key) - - def test_import_x509_pem(self): - key_file = load_file("ecc_p521_x509.pem") - - key = ECC.import_key(key_file) - self.assertEqual(self.ref_public, key) - - def test_import_openssh_public(self): - key_file = load_file("ecc_p521_public_openssh.txt") - - key = ECC._import_openssh_public(key_file) - self.assertEqual(self.ref_public, key) - - key = ECC.import_key(key_file) - self.assertEqual(self.ref_public, key) - - def test_import_openssh_private_clear(self): - key_file = load_file("ecc_p521_private_openssh.pem") - key_file_old = load_file("ecc_p521_private_openssh_old.pem") - - key = ECC.import_key(key_file) - key_old = ECC.import_key(key_file_old) - self.assertEqual(key, key_old) - - def test_import_openssh_private_password(self): - key_file = load_file("ecc_p521_private_openssh_pwd.pem") - key_file_old = load_file("ecc_p521_private_openssh_pwd_old.pem") - - key = ECC.import_key(key_file, b"password") - key_old = ECC.import_key(key_file_old) - self.assertEqual(key, key_old) - - -class TestExport_P256(unittest.TestCase): - - def __init__(self, *args, **kwargs): - super(TestExport_P256, self).__init__(*args, **kwargs) - self.ref_private, self.ref_public = create_ref_keys_p256() - - def test_export_public_der_uncompressed(self): - key_file = load_file("ecc_p256_public.der") - - encoded = self.ref_public._export_subjectPublicKeyInfo(False) - self.assertEqual(key_file, encoded) - - encoded = self.ref_public.export_key(format="DER") - self.assertEqual(key_file, encoded) - - encoded = self.ref_public.export_key(format="DER", compress=False) - self.assertEqual(key_file, encoded) - - def test_export_public_der_compressed(self): - key_file = load_file("ecc_p256_public.der") - pub_key = ECC.import_key(key_file) - key_file_compressed = pub_key.export_key(format="DER", compress=True) - - key_file_compressed_ref = load_file("ecc_p256_public_compressed.der") - self.assertEqual(key_file_compressed, key_file_compressed_ref) - - def test_export_private_der(self): - key_file = load_file("ecc_p256_private.der") - - encoded = self.ref_private._export_private_der() - self.assertEqual(key_file, encoded) - - # --- - - encoded = self.ref_private.export_key(format="DER", use_pkcs8=False) - self.assertEqual(key_file, encoded) - - def test_export_private_pkcs8_clear(self): - key_file = load_file("ecc_p256_private_p8_clear.der") - - encoded = self.ref_private._export_pkcs8() - self.assertEqual(key_file, encoded) - - # --- - - encoded = self.ref_private.export_key(format="DER") - self.assertEqual(key_file, encoded) - - def test_export_private_pkcs8_encrypted(self): - encoded = self.ref_private._export_pkcs8(passphrase="secret", - protection="PBKDF2WithHMAC-SHA1AndAES128-CBC") - - # This should prove that the output is password-protected - self.assertRaises(ValueError, ECC._import_pkcs8, encoded, None) - - decoded = ECC._import_pkcs8(encoded, "secret") - self.assertEqual(self.ref_private, decoded) - - # --- - - encoded = self.ref_private.export_key(format="DER", - passphrase="secret", - protection="PBKDF2WithHMAC-SHA1AndAES128-CBC") - decoded = ECC.import_key(encoded, "secret") - self.assertEqual(self.ref_private, decoded) - - def test_export_public_pem_uncompressed(self): - key_file = load_file("ecc_p256_public.pem", "rt").strip() - - encoded = self.ref_private._export_public_pem(False) - self.assertEqual(key_file, encoded) - - # --- - - encoded = self.ref_public.export_key(format="PEM") - self.assertEqual(key_file, encoded) - - encoded = self.ref_public.export_key(format="PEM", compress=False) - self.assertEqual(key_file, encoded) - - def test_export_public_pem_compressed(self): - key_file = load_file("ecc_p256_public.pem", "rt").strip() - pub_key = ECC.import_key(key_file) - - key_file_compressed = pub_key.export_key(format="PEM", compress=True) - key_file_compressed_ref = load_file("ecc_p256_public_compressed.pem", "rt").strip() - - self.assertEqual(key_file_compressed, key_file_compressed_ref) - - def test_export_private_pem_clear(self): - key_file = load_file("ecc_p256_private.pem", "rt").strip() - - encoded = self.ref_private._export_private_pem(None) - self.assertEqual(key_file, encoded) - - # --- - - encoded = self.ref_private.export_key(format="PEM", use_pkcs8=False) - self.assertEqual(key_file, encoded) - - def test_export_private_pem_encrypted(self): - encoded = self.ref_private._export_private_pem(passphrase=b"secret") - - # This should prove that the output is password-protected - self.assertRaises(ValueError, ECC.import_key, encoded) - - assert "EC PRIVATE KEY" in encoded - - decoded = ECC.import_key(encoded, "secret") - self.assertEqual(self.ref_private, decoded) - - # --- - - encoded = self.ref_private.export_key(format="PEM", - passphrase="secret", - use_pkcs8=False) - decoded = ECC.import_key(encoded, "secret") - self.assertEqual(self.ref_private, decoded) - - def test_export_private_pkcs8_and_pem_1(self): - # PKCS8 inside PEM with both unencrypted - key_file = load_file("ecc_p256_private_p8_clear.pem", "rt").strip() - - encoded = self.ref_private._export_private_clear_pkcs8_in_clear_pem() - self.assertEqual(key_file, encoded) - - # --- - - encoded = self.ref_private.export_key(format="PEM") - self.assertEqual(key_file, encoded) - - def test_export_private_pkcs8_and_pem_2(self): - # PKCS8 inside PEM with PKCS8 encryption - encoded = self.ref_private._export_private_encrypted_pkcs8_in_clear_pem("secret", - protection="PBKDF2WithHMAC-SHA1AndAES128-CBC") - - # This should prove that the output is password-protected - self.assertRaises(ValueError, ECC.import_key, encoded) - - assert "ENCRYPTED PRIVATE KEY" in encoded - - decoded = ECC.import_key(encoded, "secret") - self.assertEqual(self.ref_private, decoded) - - # --- - - encoded = self.ref_private.export_key(format="PEM", - passphrase="secret", - protection="PBKDF2WithHMAC-SHA1AndAES128-CBC") - decoded = ECC.import_key(encoded, "secret") - self.assertEqual(self.ref_private, decoded) - - def test_export_openssh_uncompressed(self): - key_file = load_file("ecc_p256_public_openssh.txt", "rt") - - encoded = self.ref_public._export_openssh(False) - self.assertEquals(key_file, encoded) - - # --- - - encoded = self.ref_public.export_key(format="OpenSSH") - self.assertEquals(key_file, encoded) - - encoded = self.ref_public.export_key(format="OpenSSH", compress=False) - self.assertEquals(key_file, encoded) - - def test_export_openssh_compressed(self): - key_file = load_file("ecc_p256_public_openssh.txt", "rt") - pub_key = ECC.import_key(key_file) - - key_file_compressed = pub_key.export_key(format="OpenSSH", compress=True) - assert len(key_file) > len(key_file_compressed) - self.assertEquals(pub_key, ECC.import_key(key_file_compressed)) - - def test_prng(self): - # Test that password-protected containers use the provided PRNG - encoded1 = self.ref_private.export_key(format="PEM", - passphrase="secret", - protection="PBKDF2WithHMAC-SHA1AndAES128-CBC", - randfunc=get_fixed_prng()) - encoded2 = self.ref_private.export_key(format="PEM", - passphrase="secret", - protection="PBKDF2WithHMAC-SHA1AndAES128-CBC", - randfunc=get_fixed_prng()) - self.assertEquals(encoded1, encoded2) - - # --- - - encoded1 = self.ref_private.export_key(format="PEM", - use_pkcs8=False, - passphrase="secret", - randfunc=get_fixed_prng()) - encoded2 = self.ref_private.export_key(format="PEM", - use_pkcs8=False, - passphrase="secret", - randfunc=get_fixed_prng()) - self.assertEquals(encoded1, encoded2) - - def test_byte_or_string_passphrase(self): - encoded1 = self.ref_private.export_key(format="PEM", - use_pkcs8=False, - passphrase="secret", - randfunc=get_fixed_prng()) - encoded2 = self.ref_private.export_key(format="PEM", - use_pkcs8=False, - passphrase=b"secret", - randfunc=get_fixed_prng()) - self.assertEquals(encoded1, encoded2) - - def test_error_params1(self): - # Unknown format - self.assertRaises(ValueError, self.ref_private.export_key, format="XXX") - - # Missing 'protection' parameter when PKCS#8 is used - self.ref_private.export_key(format="PEM", passphrase="secret", - use_pkcs8=False) - self.assertRaises(ValueError, self.ref_private.export_key, format="PEM", - passphrase="secret") - - # DER format but no PKCS#8 - self.assertRaises(ValueError, self.ref_private.export_key, format="DER", - passphrase="secret", - use_pkcs8=False, - protection="PBKDF2WithHMAC-SHA1AndAES128-CBC") - - # Incorrect parameters for public keys - self.assertRaises(ValueError, self.ref_public.export_key, format="DER", - use_pkcs8=False) - - # Empty password - self.assertRaises(ValueError, self.ref_private.export_key, format="PEM", - passphrase="", use_pkcs8=False) - self.assertRaises(ValueError, self.ref_private.export_key, format="PEM", - passphrase="", - protection="PBKDF2WithHMAC-SHA1AndAES128-CBC") - - # No private keys with OpenSSH - self.assertRaises(ValueError, self.ref_private.export_key, format="OpenSSH", - passphrase="secret") - - def test_unsupported_curve(self): - - # openssl ecparam -name secp224r1 -genkey -noout -out strange-curve.pem -conv_form uncompressed - curve = """-----BEGIN EC PRIVATE KEY----- -MGgCAQEEHEi7xTHW+5oT8wgpjoEKV7uwMuY8rt2YUZe4j1SgBwYFK4EEACGhPAM6 -AATJgfOG+Bnki8robpNM8MtArji43GU9up4B0x9sVhqB+fZP+hXgV9ITN7YX4E/k -gVnJp9EBND/tHQ== ------END EC PRIVATE KEY-----""" - - from Crypto.PublicKey.ECC import UnsupportedEccFeature - try: - ECC.import_key(curve) - except UnsupportedEccFeature as uef: - assert("1.3.132.0.33" in str(uef)) - else: - assert(False) - - def test_compressed_curve(self): - - # Compressed P-256 curve (Y-point is even) - pem1 = """-----BEGIN EC PRIVATE KEY----- - MFcCAQEEIHTuc09jC51xXomV6MVCDN+DpAAvSmaJWZPTEHM6D5H1oAoGCCqGSM49 - AwEHoSQDIgACWFuGbHe8yJ43rir7PMTE9w8vHz0BSpXHq90Xi7/s+a0= - -----END EC PRIVATE KEY-----""" - - # Compressed P-256 curve (Y-point is odd) - pem2 = """-----BEGIN EC PRIVATE KEY----- - MFcCAQEEIFggiPN9SQP+FAPTCPp08fRUz7rHp2qNBRcBJ1DXhb3ZoAoGCCqGSM49 - AwEHoSQDIgADLpph1trTIlVfa8NJvlMUPyWvL+wP+pW3BJITUL/wj9A= - -----END EC PRIVATE KEY-----""" - - key1 = ECC.import_key(pem1) - low16 = int(key1.pointQ.y % 65536) - self.assertEqual(low16, 0xA6FC) - - key2 = ECC.import_key(pem2) - low16 = int(key2.pointQ.y % 65536) - self.assertEqual(low16, 0x6E57) - - -class TestExport_P384(unittest.TestCase): - - def __init__(self, *args, **kwargs): - super(TestExport_P384, self).__init__(*args, **kwargs) - self.ref_private, self.ref_public = create_ref_keys_p384() - - def test_export_public_der_uncompressed(self): - key_file = load_file("ecc_p384_public.der") - - encoded = self.ref_public._export_subjectPublicKeyInfo(False) - self.assertEqual(key_file, encoded) - - encoded = self.ref_public.export_key(format="DER") - self.assertEqual(key_file, encoded) - - encoded = self.ref_public.export_key(format="DER", compress=False) - self.assertEqual(key_file, encoded) - - def test_export_public_der_compressed(self): - key_file = load_file("ecc_p384_public.der") - pub_key = ECC.import_key(key_file) - key_file_compressed = pub_key.export_key(format="DER", compress=True) - - key_file_compressed_ref = load_file("ecc_p384_public_compressed.der") - self.assertEqual(key_file_compressed, key_file_compressed_ref) - - def test_export_private_der(self): - key_file = load_file("ecc_p384_private.der") - - encoded = self.ref_private._export_private_der() - self.assertEqual(key_file, encoded) - - # --- - - encoded = self.ref_private.export_key(format="DER", use_pkcs8=False) - self.assertEqual(key_file, encoded) - - def test_export_private_pkcs8_clear(self): - key_file = load_file("ecc_p384_private_p8_clear.der") - - encoded = self.ref_private._export_pkcs8() - self.assertEqual(key_file, encoded) - - # --- - - encoded = self.ref_private.export_key(format="DER") - self.assertEqual(key_file, encoded) - - def test_export_private_pkcs8_encrypted(self): - encoded = self.ref_private._export_pkcs8(passphrase="secret", - protection="PBKDF2WithHMAC-SHA1AndAES128-CBC") - - # This should prove that the output is password-protected - self.assertRaises(ValueError, ECC._import_pkcs8, encoded, None) - - decoded = ECC._import_pkcs8(encoded, "secret") - self.assertEqual(self.ref_private, decoded) - - # --- - - encoded = self.ref_private.export_key(format="DER", - passphrase="secret", - protection="PBKDF2WithHMAC-SHA1AndAES128-CBC") - decoded = ECC.import_key(encoded, "secret") - self.assertEqual(self.ref_private, decoded) - - def test_export_public_pem_uncompressed(self): - key_file = load_file("ecc_p384_public.pem", "rt").strip() - - encoded = self.ref_private._export_public_pem(False) - self.assertEqual(key_file, encoded) - - # --- - - encoded = self.ref_public.export_key(format="PEM") - self.assertEqual(key_file, encoded) - - encoded = self.ref_public.export_key(format="PEM", compress=False) - self.assertEqual(key_file, encoded) - - def test_export_public_pem_compressed(self): - key_file = load_file("ecc_p384_public.pem", "rt").strip() - pub_key = ECC.import_key(key_file) - - key_file_compressed = pub_key.export_key(format="PEM", compress=True) - key_file_compressed_ref = load_file("ecc_p384_public_compressed.pem", "rt").strip() - - self.assertEqual(key_file_compressed, key_file_compressed_ref) - - def test_export_private_pem_clear(self): - key_file = load_file("ecc_p384_private.pem", "rt").strip() - - encoded = self.ref_private._export_private_pem(None) - self.assertEqual(key_file, encoded) - - # --- - - encoded = self.ref_private.export_key(format="PEM", use_pkcs8=False) - self.assertEqual(key_file, encoded) - - def test_export_private_pem_encrypted(self): - encoded = self.ref_private._export_private_pem(passphrase=b"secret") - - # This should prove that the output is password-protected - self.assertRaises(ValueError, ECC.import_key, encoded) - - assert "EC PRIVATE KEY" in encoded - - decoded = ECC.import_key(encoded, "secret") - self.assertEqual(self.ref_private, decoded) - - # --- - - encoded = self.ref_private.export_key(format="PEM", - passphrase="secret", - use_pkcs8=False) - decoded = ECC.import_key(encoded, "secret") - self.assertEqual(self.ref_private, decoded) - - def test_export_private_pkcs8_and_pem_1(self): - # PKCS8 inside PEM with both unencrypted - key_file = load_file("ecc_p384_private_p8_clear.pem", "rt").strip() - - encoded = self.ref_private._export_private_clear_pkcs8_in_clear_pem() - self.assertEqual(key_file, encoded) - - # --- - - encoded = self.ref_private.export_key(format="PEM") - self.assertEqual(key_file, encoded) - - def test_export_private_pkcs8_and_pem_2(self): - # PKCS8 inside PEM with PKCS8 encryption - encoded = self.ref_private._export_private_encrypted_pkcs8_in_clear_pem("secret", - protection="PBKDF2WithHMAC-SHA1AndAES128-CBC") - - # This should prove that the output is password-protected - self.assertRaises(ValueError, ECC.import_key, encoded) - - assert "ENCRYPTED PRIVATE KEY" in encoded - - decoded = ECC.import_key(encoded, "secret") - self.assertEqual(self.ref_private, decoded) - - # --- - - encoded = self.ref_private.export_key(format="PEM", - passphrase="secret", - protection="PBKDF2WithHMAC-SHA1AndAES128-CBC") - decoded = ECC.import_key(encoded, "secret") - self.assertEqual(self.ref_private, decoded) - - def test_export_openssh_uncompressed(self): - key_file = load_file("ecc_p384_public_openssh.txt", "rt") - - encoded = self.ref_public._export_openssh(False) - self.assertEquals(key_file, encoded) - - # --- - - encoded = self.ref_public.export_key(format="OpenSSH") - self.assertEquals(key_file, encoded) - - encoded = self.ref_public.export_key(format="OpenSSH", compress=False) - self.assertEquals(key_file, encoded) - - def test_export_openssh_compressed(self): - key_file = load_file("ecc_p384_public_openssh.txt", "rt") - pub_key = ECC.import_key(key_file) - - key_file_compressed = pub_key.export_key(format="OpenSSH", compress=True) - assert len(key_file) > len(key_file_compressed) - self.assertEquals(pub_key, ECC.import_key(key_file_compressed)) - - def test_prng(self): - # Test that password-protected containers use the provided PRNG - encoded1 = self.ref_private.export_key(format="PEM", - passphrase="secret", - protection="PBKDF2WithHMAC-SHA1AndAES128-CBC", - randfunc=get_fixed_prng()) - encoded2 = self.ref_private.export_key(format="PEM", - passphrase="secret", - protection="PBKDF2WithHMAC-SHA1AndAES128-CBC", - randfunc=get_fixed_prng()) - self.assertEquals(encoded1, encoded2) - - # --- - - encoded1 = self.ref_private.export_key(format="PEM", - use_pkcs8=False, - passphrase="secret", - randfunc=get_fixed_prng()) - encoded2 = self.ref_private.export_key(format="PEM", - use_pkcs8=False, - passphrase="secret", - randfunc=get_fixed_prng()) - self.assertEquals(encoded1, encoded2) - - def test_byte_or_string_passphrase(self): - encoded1 = self.ref_private.export_key(format="PEM", - use_pkcs8=False, - passphrase="secret", - randfunc=get_fixed_prng()) - encoded2 = self.ref_private.export_key(format="PEM", - use_pkcs8=False, - passphrase=b"secret", - randfunc=get_fixed_prng()) - self.assertEquals(encoded1, encoded2) - - def test_error_params1(self): - # Unknown format - self.assertRaises(ValueError, self.ref_private.export_key, format="XXX") - - # Missing 'protection' parameter when PKCS#8 is used - self.ref_private.export_key(format="PEM", passphrase="secret", - use_pkcs8=False) - self.assertRaises(ValueError, self.ref_private.export_key, format="PEM", - passphrase="secret") - - # DER format but no PKCS#8 - self.assertRaises(ValueError, self.ref_private.export_key, format="DER", - passphrase="secret", - use_pkcs8=False, - protection="PBKDF2WithHMAC-SHA1AndAES128-CBC") - - # Incorrect parameters for public keys - self.assertRaises(ValueError, self.ref_public.export_key, format="DER", - use_pkcs8=False) - - # Empty password - self.assertRaises(ValueError, self.ref_private.export_key, format="PEM", - passphrase="", use_pkcs8=False) - self.assertRaises(ValueError, self.ref_private.export_key, format="PEM", - passphrase="", - protection="PBKDF2WithHMAC-SHA1AndAES128-CBC") - - # No private keys with OpenSSH - self.assertRaises(ValueError, self.ref_private.export_key, format="OpenSSH", - passphrase="secret") - - def test_compressed_curve(self): - - # Compressed P-384 curve (Y-point is even) - # openssl ecparam -name secp384p1 -genkey -noout -conv_form compressed -out /tmp/a.pem - # openssl ec -in /tmp/a.pem -text -noout - pem1 = """-----BEGIN EC PRIVATE KEY----- -MIGkAgEBBDAM0lEIhvXuekK2SWtdbgOcZtBaxa9TxfpO/GcDFZLCJ3JVXaTgwken -QT+C+XLtD6WgBwYFK4EEACKhZANiAATs0kZMhFDu8DoBC21jrSDPyAUn4aXZ/DM4 -ylhDfWmb4LEbeszXceIzfhIUaaGs5y1xXaqf5KXTiAAYx2pKUzAAM9lcGUHCGKJG -k4AgUmVJON29XoUilcFrzjDmuye3B6Q= ------END EC PRIVATE KEY-----""" - - # Compressed P-384 curve (Y-point is odd) - pem2 = """-----BEGIN EC PRIVATE KEY----- -MIGkAgEBBDDHPFTslYLltE16fHdSDTtE/2HTmd3M8mqy5MttAm4wZ833KXiGS9oe -kFdx9sNV0KygBwYFK4EEACKhZANiAASLIE5RqVMtNhtBH/u/p/ifqOAlKnK/+RrQ -YC46ZRsnKNayw3wATdPjgja7L/DSII3nZK0G6KOOVwJBznT/e+zudUJYhZKaBLRx -/bgXyxUtYClOXxb1Y/5N7txLstYRyP0= ------END EC PRIVATE KEY-----""" - - key1 = ECC.import_key(pem1) - low16 = int(key1.pointQ.y % 65536) - self.assertEqual(low16, 0x07a4) - - key2 = ECC.import_key(pem2) - low16 = int(key2.pointQ.y % 65536) - self.assertEqual(low16, 0xc8fd) - - -class TestExport_P521(unittest.TestCase): - - def __init__(self, *args, **kwargs): - super(TestExport_P521, self).__init__(*args, **kwargs) - self.ref_private, self.ref_public = create_ref_keys_p521() - - def test_export_public_der_uncompressed(self): - key_file = load_file("ecc_p521_public.der") - - encoded = self.ref_public._export_subjectPublicKeyInfo(False) - self.assertEqual(key_file, encoded) - - encoded = self.ref_public.export_key(format="DER") - self.assertEqual(key_file, encoded) - - encoded = self.ref_public.export_key(format="DER", compress=False) - self.assertEqual(key_file, encoded) - - def test_export_public_der_compressed(self): - key_file = load_file("ecc_p521_public.der") - pub_key = ECC.import_key(key_file) - key_file_compressed = pub_key.export_key(format="DER", compress=True) - - key_file_compressed_ref = load_file("ecc_p521_public_compressed.der") - self.assertEqual(key_file_compressed, key_file_compressed_ref) - - def test_export_private_der(self): - key_file = load_file("ecc_p521_private.der") - - encoded = self.ref_private._export_private_der() - self.assertEqual(key_file, encoded) - - # --- - - encoded = self.ref_private.export_key(format="DER", use_pkcs8=False) - self.assertEqual(key_file, encoded) - - def test_export_private_pkcs8_clear(self): - key_file = load_file("ecc_p521_private_p8_clear.der") - - encoded = self.ref_private._export_pkcs8() - self.assertEqual(key_file, encoded) - - # --- - - encoded = self.ref_private.export_key(format="DER") - self.assertEqual(key_file, encoded) - - def test_export_private_pkcs8_encrypted(self): - encoded = self.ref_private._export_pkcs8(passphrase="secret", - protection="PBKDF2WithHMAC-SHA1AndAES128-CBC") - - # This should prove that the output is password-protected - self.assertRaises(ValueError, ECC._import_pkcs8, encoded, None) - - decoded = ECC._import_pkcs8(encoded, "secret") - self.assertEqual(self.ref_private, decoded) - - # --- - - encoded = self.ref_private.export_key(format="DER", - passphrase="secret", - protection="PBKDF2WithHMAC-SHA1AndAES128-CBC") - decoded = ECC.import_key(encoded, "secret") - self.assertEqual(self.ref_private, decoded) - - def test_export_public_pem_uncompressed(self): - key_file = load_file("ecc_p521_public.pem", "rt").strip() - - encoded = self.ref_private._export_public_pem(False) - self.assertEqual(key_file, encoded) - - # --- - - encoded = self.ref_public.export_key(format="PEM") - self.assertEqual(key_file, encoded) - - encoded = self.ref_public.export_key(format="PEM", compress=False) - self.assertEqual(key_file, encoded) - - def test_export_public_pem_compressed(self): - key_file = load_file("ecc_p521_public.pem", "rt").strip() - pub_key = ECC.import_key(key_file) - - key_file_compressed = pub_key.export_key(format="PEM", compress=True) - key_file_compressed_ref = load_file("ecc_p521_public_compressed.pem", "rt").strip() - - self.assertEqual(key_file_compressed, key_file_compressed_ref) - - def test_export_private_pem_clear(self): - key_file = load_file("ecc_p521_private.pem", "rt").strip() - - encoded = self.ref_private._export_private_pem(None) - self.assertEqual(key_file, encoded) - - # --- - - encoded = self.ref_private.export_key(format="PEM", use_pkcs8=False) - self.assertEqual(key_file, encoded) - - def test_export_private_pem_encrypted(self): - encoded = self.ref_private._export_private_pem(passphrase=b"secret") - - # This should prove that the output is password-protected - self.assertRaises(ValueError, ECC.import_key, encoded) - - assert "EC PRIVATE KEY" in encoded - - decoded = ECC.import_key(encoded, "secret") - self.assertEqual(self.ref_private, decoded) - - # --- - - encoded = self.ref_private.export_key(format="PEM", - passphrase="secret", - use_pkcs8=False) - decoded = ECC.import_key(encoded, "secret") - self.assertEqual(self.ref_private, decoded) - - def test_export_private_pkcs8_and_pem_1(self): - # PKCS8 inside PEM with both unencrypted - key_file = load_file("ecc_p521_private_p8_clear.pem", "rt").strip() - - encoded = self.ref_private._export_private_clear_pkcs8_in_clear_pem() - self.assertEqual(key_file, encoded) - - # --- - - encoded = self.ref_private.export_key(format="PEM") - self.assertEqual(key_file, encoded) - - def test_export_private_pkcs8_and_pem_2(self): - # PKCS8 inside PEM with PKCS8 encryption - encoded = self.ref_private._export_private_encrypted_pkcs8_in_clear_pem("secret", - protection="PBKDF2WithHMAC-SHA1AndAES128-CBC") - - # This should prove that the output is password-protected - self.assertRaises(ValueError, ECC.import_key, encoded) - - assert "ENCRYPTED PRIVATE KEY" in encoded - - decoded = ECC.import_key(encoded, "secret") - self.assertEqual(self.ref_private, decoded) - - # --- - - encoded = self.ref_private.export_key(format="PEM", - passphrase="secret", - protection="PBKDF2WithHMAC-SHA1AndAES128-CBC") - decoded = ECC.import_key(encoded, "secret") - self.assertEqual(self.ref_private, decoded) - - def test_export_openssh_uncompressed(self): - key_file = load_file("ecc_p521_public_openssh.txt", "rt") - - encoded = self.ref_public._export_openssh(False) - self.assertEquals(key_file, encoded) - - # --- - - encoded = self.ref_public.export_key(format="OpenSSH") - self.assertEquals(key_file, encoded) - - encoded = self.ref_public.export_key(format="OpenSSH", compress=False) - self.assertEquals(key_file, encoded) - - def test_export_openssh_compressed(self): - key_file = load_file("ecc_p521_public_openssh.txt", "rt") - pub_key = ECC.import_key(key_file) - - key_file_compressed = pub_key.export_key(format="OpenSSH", compress=True) - assert len(key_file) > len(key_file_compressed) - self.assertEquals(pub_key, ECC.import_key(key_file_compressed)) - - def test_prng(self): - # Test that password-protected containers use the provided PRNG - encoded1 = self.ref_private.export_key(format="PEM", - passphrase="secret", - protection="PBKDF2WithHMAC-SHA1AndAES128-CBC", - randfunc=get_fixed_prng()) - encoded2 = self.ref_private.export_key(format="PEM", - passphrase="secret", - protection="PBKDF2WithHMAC-SHA1AndAES128-CBC", - randfunc=get_fixed_prng()) - self.assertEquals(encoded1, encoded2) - - # --- - - encoded1 = self.ref_private.export_key(format="PEM", - use_pkcs8=False, - passphrase="secret", - randfunc=get_fixed_prng()) - encoded2 = self.ref_private.export_key(format="PEM", - use_pkcs8=False, - passphrase="secret", - randfunc=get_fixed_prng()) - self.assertEquals(encoded1, encoded2) - - def test_byte_or_string_passphrase(self): - encoded1 = self.ref_private.export_key(format="PEM", - use_pkcs8=False, - passphrase="secret", - randfunc=get_fixed_prng()) - encoded2 = self.ref_private.export_key(format="PEM", - use_pkcs8=False, - passphrase=b"secret", - randfunc=get_fixed_prng()) - self.assertEquals(encoded1, encoded2) - - def test_error_params1(self): - # Unknown format - self.assertRaises(ValueError, self.ref_private.export_key, format="XXX") - - # Missing 'protection' parameter when PKCS#8 is used - self.ref_private.export_key(format="PEM", passphrase="secret", - use_pkcs8=False) - self.assertRaises(ValueError, self.ref_private.export_key, format="PEM", - passphrase="secret") - - # DER format but no PKCS#8 - self.assertRaises(ValueError, self.ref_private.export_key, format="DER", - passphrase="secret", - use_pkcs8=False, - protection="PBKDF2WithHMAC-SHA1AndAES128-CBC") - - # Incorrect parameters for public keys - self.assertRaises(ValueError, self.ref_public.export_key, format="DER", - use_pkcs8=False) - - # Empty password - self.assertRaises(ValueError, self.ref_private.export_key, format="PEM", - passphrase="", use_pkcs8=False) - self.assertRaises(ValueError, self.ref_private.export_key, format="PEM", - passphrase="", - protection="PBKDF2WithHMAC-SHA1AndAES128-CBC") - - # No private keys with OpenSSH - self.assertRaises(ValueError, self.ref_private.export_key, format="OpenSSH", - passphrase="secret") - - def test_compressed_curve(self): - - # Compressed P-521 curve (Y-point is even) - # openssl ecparam -name secp521r1 -genkey -noout -conv_form compressed -out /tmp/a.pem - # openssl ec -in /tmp/a.pem -text -noout - pem1 = """-----BEGIN EC PRIVATE KEY----- -MIHcAgEBBEIAnm1CEjVjvNfXEN730p+D6su5l+mOztdc5XmTEoti+s2R4GQ4mAv3 -0zYLvyklvOHw0+yy8d0cyGEJGb8T3ZVKmg2gBwYFK4EEACOhgYkDgYYABAHzjTI1 -ckxQ3Togi0LAxiG0PucdBBBs5oIy3df95xv6SInp70z+4qQ2EltEmdNMssH8eOrl -M5CYdZ6nbcHMVaJUvQEzTrYxvFjOgJiOd+E9eBWbLkbMNqsh1UKVO6HbMbW0ohCI -uGxO8tM6r3w89/qzpG2SvFM/fvv3mIR30wSZDD84qA== ------END EC PRIVATE KEY-----""" - - # Compressed P-521 curve (Y-point is odd) - pem2 = """-----BEGIN EC PRIVATE KEY----- -MIHcAgEBBEIB84OfhJluLBRLn3+cC/RQ37C2SfQVP/t0gQK2tCsTf5avRcWYRrOJ -PmX9lNnkC0Hobd75QFRmdxrB0Wd1/M4jZOWgBwYFK4EEACOhgYkDgYYABAAMZcdJ -1YLCGHt3bHCEzdidVy6+brlJIbv1aQ9fPQLF7WKNv4c8w3H8d5a2+SDZilBOsk5c -6cNJDMz2ExWQvxl4CwDJtJGt1+LHVKFGy73NANqVxMbRu+2F8lOxkNp/ziFTbVyV -vv6oYkMIIi7r5oQWAiQDrR2mlrrFDL9V7GH/r8SWQw== ------END EC PRIVATE KEY-----""" - - key1 = ECC.import_key(pem1) - low16 = int(key1.pointQ.y % 65536) - self.assertEqual(low16, 0x38a8) - - key2 = ECC.import_key(pem2) - low16 = int(key2.pointQ.y % 65536) - self.assertEqual(low16, 0x9643) - - -def get_tests(config={}): - tests = [] - tests += list_test_cases(TestImport) - try: - tests += list_test_cases(TestImport_P256) - tests += list_test_cases(TestImport_P384) - tests += list_test_cases(TestImport_P521) - tests += list_test_cases(TestExport_P256) - tests += list_test_cases(TestExport_P384) - tests += list_test_cases(TestExport_P521) - except MissingTestVectorException: - pass - return tests - - -if __name__ == '__main__': - suite = lambda: unittest.TestSuite(get_tests()) - unittest.main(defaultTest='suite') diff --git a/Crypto/SelfTest/PublicKey/test_import_RSA.py b/Crypto/SelfTest/PublicKey/test_import_RSA.py deleted file mode 100644 index a2963c6..0000000 --- a/Crypto/SelfTest/PublicKey/test_import_RSA.py +++ /dev/null @@ -1,585 +0,0 @@ -# -*- coding: utf-8 -*- -# -# SelfTest/PublicKey/test_importKey.py: Self-test for importing RSA keys -# -# =================================================================== -# The contents of this file are dedicated to the public domain. To -# the extent that dedication to the public domain is not available, -# everyone is granted a worldwide, perpetual, royalty-free, -# non-exclusive license to exercise all rights associated with the -# contents of this file for any purpose whatsoever. -# No rights are reserved. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS -# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN -# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# =================================================================== - -import os -import re -import errno -import warnings -import unittest - -from Crypto.PublicKey import RSA -from Crypto.SelfTest.st_common import a2b_hex, list_test_cases -from Crypto.Util.py3compat import b, tostr, FileNotFoundError -from Crypto.Util.number import inverse -from Crypto.Util import asn1 - -try: - import pycryptodome_test_vectors # type: ignore - test_vectors_available = True -except ImportError: - test_vectors_available = False - - -def load_file(file_name, mode="rb"): - results = None - - try: - if not test_vectors_available: - raise FileNotFoundError(errno.ENOENT, - os.strerror(errno.ENOENT), - file_name) - - dir_comps = ("PublicKey", "RSA") - init_dir = os.path.dirname(pycryptodome_test_vectors.__file__) - full_file_name = os.path.join(os.path.join(init_dir, *dir_comps), file_name) - with open(full_file_name, mode) as file_in: - results = file_in.read() - - except FileNotFoundError: - warnings.warn("Warning: skipping extended tests for RSA", - UserWarning, - stacklevel=2) - - return results - - -def der2pem(der, text='PUBLIC'): - import binascii - chunks = [binascii.b2a_base64(der[i:i+48]) for i in range(0, len(der), 48)] - pem = b('-----BEGIN %s KEY-----\n' % text) - pem += b('').join(chunks) - pem += b('-----END %s KEY-----' % text) - return pem - - -class ImportKeyTests(unittest.TestCase): - # 512-bit RSA key generated with openssl - rsaKeyPEM = u'''-----BEGIN RSA PRIVATE KEY----- -MIIBOwIBAAJBAL8eJ5AKoIsjURpcEoGubZMxLD7+kT+TLr7UkvEtFrRhDDKMtuII -q19FrL4pUIMymPMSLBn3hJLe30Dw48GQM4UCAwEAAQJACUSDEp8RTe32ftq8IwG8 -Wojl5mAd1wFiIOrZ/Uv8b963WJOJiuQcVN29vxU5+My9GPZ7RA3hrDBEAoHUDPrI -OQIhAPIPLz4dphiD9imAkivY31Rc5AfHJiQRA7XixTcjEkojAiEAyh/pJHks/Mlr -+rdPNEpotBjfV4M4BkgGAA/ipcmaAjcCIQCHvhwwKVBLzzTscT2HeUdEeBMoiXXK -JACAr3sJQJGxIQIgarRp+m1WSKV1MciwMaTOnbU7wxFs9DP1pva76lYBzgUCIQC9 -n0CnZCJ6IZYqSt0H5N7+Q+2Ro64nuwV/OSQfM6sBwQ== ------END RSA PRIVATE KEY-----''' - - # As above, but this is actually an unencrypted PKCS#8 key - rsaKeyPEM8 = u'''-----BEGIN PRIVATE KEY----- -MIIBVQIBADANBgkqhkiG9w0BAQEFAASCAT8wggE7AgEAAkEAvx4nkAqgiyNRGlwS -ga5tkzEsPv6RP5MuvtSS8S0WtGEMMoy24girX0WsvilQgzKY8xIsGfeEkt7fQPDj -wZAzhQIDAQABAkAJRIMSnxFN7fZ+2rwjAbxaiOXmYB3XAWIg6tn9S/xv3rdYk4mK -5BxU3b2/FTn4zL0Y9ntEDeGsMEQCgdQM+sg5AiEA8g8vPh2mGIP2KYCSK9jfVFzk -B8cmJBEDteLFNyMSSiMCIQDKH+kkeSz8yWv6t080Smi0GN9XgzgGSAYAD+KlyZoC -NwIhAIe+HDApUEvPNOxxPYd5R0R4EyiJdcokAICvewlAkbEhAiBqtGn6bVZIpXUx -yLAxpM6dtTvDEWz0M/Wm9rvqVgHOBQIhAL2fQKdkInohlipK3Qfk3v5D7ZGjrie7 -BX85JB8zqwHB ------END PRIVATE KEY-----''' - - # The same RSA private key as in rsaKeyPEM, but now encrypted - rsaKeyEncryptedPEM = ( - - # PEM encryption - # With DES and passphrase 'test' - ('test', u'''-----BEGIN RSA PRIVATE KEY----- -Proc-Type: 4,ENCRYPTED -DEK-Info: DES-CBC,AF8F9A40BD2FA2FC - -Ckl9ex1kaVEWhYC2QBmfaF+YPiR4NFkRXA7nj3dcnuFEzBnY5XULupqQpQI3qbfA -u8GYS7+b3toWWiHZivHbAAUBPDIZG9hKDyB9Sq2VMARGsX1yW1zhNvZLIiVJzUHs -C6NxQ1IJWOXzTew/xM2I26kPwHIvadq+/VaT8gLQdjdH0jOiVNaevjWnLgrn1mLP -BCNRMdcexozWtAFNNqSzfW58MJL2OdMi21ED184EFytIc1BlB+FZiGZduwKGuaKy -9bMbdb/1PSvsSzPsqW7KSSrTw6MgJAFJg6lzIYvR5F4poTVBxwBX3+EyEmShiaNY -IRX3TgQI0IjrVuLmvlZKbGWP18FXj7I7k9tSsNOOzllTTdq3ny5vgM3A+ynfAaxp -dysKznQ6P+IoqML1WxAID4aGRMWka+uArOJ148Rbj9s= ------END RSA PRIVATE KEY-----'''), - - # PKCS8 encryption - ('winter', u'''-----BEGIN ENCRYPTED PRIVATE KEY----- -MIIBpjBABgkqhkiG9w0BBQ0wMzAbBgkqhkiG9w0BBQwwDgQIeZIsbW3O+JcCAggA -MBQGCCqGSIb3DQMHBAgSM2p0D8FilgSCAWBhFyP2tiGKVpGj3mO8qIBzinU60ApR -3unvP+N6j7LVgnV2lFGaXbJ6a1PbQXe+2D6DUyBLo8EMXrKKVLqOMGkFMHc0UaV6 -R6MmrsRDrbOqdpTuVRW+NVd5J9kQQh4xnfU/QrcPPt7vpJvSf4GzG0n666Ki50OV -M/feuVlIiyGXY6UWdVDpcOV72cq02eNUs/1JWdh2uEBvA9fCL0c07RnMrdT+CbJQ -NjJ7f8ULtp7xvR9O3Al/yJ4Wv3i4VxF1f3MCXzhlUD4I0ONlr0kJWgeQ80q/cWhw -ntvgJwnCn2XR1h6LA8Wp+0ghDTsL2NhJpWd78zClGhyU4r3hqu1XDjoXa7YCXCix -jCV15+ViDJzlNCwg+W6lRg18sSLkCT7alviIE0U5tHc6UPbbHwT5QqAxAABaP+nZ -CGqJGyiwBzrKebjgSm/KRd4C91XqcsysyH2kKPfT51MLAoD4xelOURBP ------END ENCRYPTED PRIVATE KEY-----''' - ), - ) - - rsaPublicKeyPEM = u'''-----BEGIN PUBLIC KEY----- -MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAL8eJ5AKoIsjURpcEoGubZMxLD7+kT+T -Lr7UkvEtFrRhDDKMtuIIq19FrL4pUIMymPMSLBn3hJLe30Dw48GQM4UCAwEAAQ== ------END PUBLIC KEY-----''' - - # Obtained using 'ssh-keygen -i -m PKCS8 -f rsaPublicKeyPEM' - rsaPublicKeyOpenSSH = b('''ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAQQC/HieQCqCLI1EaXBKBrm2TMSw+/pE/ky6+1JLxLRa0YQwyjLbiCKtfRay+KVCDMpjzEiwZ94SS3t9A8OPBkDOF comment\n''') - - # The private key, in PKCS#1 format encoded with DER - rsaKeyDER = a2b_hex( - '''3082013b020100024100bf1e27900aa08b23511a5c1281ae6d93312c3efe - 913f932ebed492f12d16b4610c328cb6e208ab5f45acbe2950833298f312 - 2c19f78492dedf40f0e3c190338502030100010240094483129f114dedf6 - 7edabc2301bc5a88e5e6601dd7016220ead9fd4bfc6fdeb75893898ae41c - 54ddbdbf1539f8ccbd18f67b440de1ac30440281d40cfac839022100f20f - 2f3e1da61883f62980922bd8df545ce407c726241103b5e2c53723124a23 - 022100ca1fe924792cfcc96bfab74f344a68b418df578338064806000fe2 - a5c99a023702210087be1c3029504bcf34ec713d877947447813288975ca - 240080af7b094091b12102206ab469fa6d5648a57531c8b031a4ce9db53b - c3116cf433f5a6f6bbea5601ce05022100bd9f40a764227a21962a4add07 - e4defe43ed91a3ae27bb057f39241f33ab01c1 - '''.replace(" ","")) - - # The private key, in unencrypted PKCS#8 format encoded with DER - rsaKeyDER8 = a2b_hex( - '''30820155020100300d06092a864886f70d01010105000482013f3082013 - b020100024100bf1e27900aa08b23511a5c1281ae6d93312c3efe913f932 - ebed492f12d16b4610c328cb6e208ab5f45acbe2950833298f3122c19f78 - 492dedf40f0e3c190338502030100010240094483129f114dedf67edabc2 - 301bc5a88e5e6601dd7016220ead9fd4bfc6fdeb75893898ae41c54ddbdb - f1539f8ccbd18f67b440de1ac30440281d40cfac839022100f20f2f3e1da - 61883f62980922bd8df545ce407c726241103b5e2c53723124a23022100c - a1fe924792cfcc96bfab74f344a68b418df578338064806000fe2a5c99a0 - 23702210087be1c3029504bcf34ec713d877947447813288975ca240080a - f7b094091b12102206ab469fa6d5648a57531c8b031a4ce9db53bc3116cf - 433f5a6f6bbea5601ce05022100bd9f40a764227a21962a4add07e4defe4 - 3ed91a3ae27bb057f39241f33ab01c1 - '''.replace(" ","")) - - rsaPublicKeyDER = a2b_hex( - '''305c300d06092a864886f70d0101010500034b003048024100bf1e27900a - a08b23511a5c1281ae6d93312c3efe913f932ebed492f12d16b4610c328c - b6e208ab5f45acbe2950833298f3122c19f78492dedf40f0e3c190338502 - 03010001 - '''.replace(" ","")) - - n = int('BF 1E 27 90 0A A0 8B 23 51 1A 5C 12 81 AE 6D 93 31 2C 3E FE 91 3F 93 2E BE D4 92 F1 2D 16 B4 61 0C 32 8C B6 E2 08 AB 5F 45 AC BE 29 50 83 32 98 F3 12 2C 19 F7 84 92 DE DF 40 F0 E3 C1 90 33 85'.replace(" ",""),16) - e = 65537 - d = int('09 44 83 12 9F 11 4D ED F6 7E DA BC 23 01 BC 5A 88 E5 E6 60 1D D7 01 62 20 EA D9 FD 4B FC 6F DE B7 58 93 89 8A E4 1C 54 DD BD BF 15 39 F8 CC BD 18 F6 7B 44 0D E1 AC 30 44 02 81 D4 0C FA C8 39'.replace(" ",""),16) - p = int('00 F2 0F 2F 3E 1D A6 18 83 F6 29 80 92 2B D8 DF 54 5C E4 07 C7 26 24 11 03 B5 E2 C5 37 23 12 4A 23'.replace(" ",""),16) - q = int('00 CA 1F E9 24 79 2C FC C9 6B FA B7 4F 34 4A 68 B4 18 DF 57 83 38 06 48 06 00 0F E2 A5 C9 9A 02 37'.replace(" ",""),16) - - # This is q^{-1} mod p). fastmath and slowmath use pInv (p^{-1} - # mod q) instead! - qInv = int('00 BD 9F 40 A7 64 22 7A 21 96 2A 4A DD 07 E4 DE FE 43 ED 91 A3 AE 27 BB 05 7F 39 24 1F 33 AB 01 C1'.replace(" ",""),16) - pInv = inverse(p,q) - - def testImportKey1(self): - """Verify import of RSAPrivateKey DER SEQUENCE""" - key = RSA.importKey(self.rsaKeyDER) - self.failUnless(key.has_private()) - self.assertEqual(key.n, self.n) - self.assertEqual(key.e, self.e) - self.assertEqual(key.d, self.d) - self.assertEqual(key.p, self.p) - self.assertEqual(key.q, self.q) - - def testImportKey2(self): - """Verify import of SubjectPublicKeyInfo DER SEQUENCE""" - key = RSA.importKey(self.rsaPublicKeyDER) - self.failIf(key.has_private()) - self.assertEqual(key.n, self.n) - self.assertEqual(key.e, self.e) - - def testImportKey3unicode(self): - """Verify import of RSAPrivateKey DER SEQUENCE, encoded with PEM as unicode""" - key = RSA.importKey(self.rsaKeyPEM) - self.assertEqual(key.has_private(),True) # assert_ - self.assertEqual(key.n, self.n) - self.assertEqual(key.e, self.e) - self.assertEqual(key.d, self.d) - self.assertEqual(key.p, self.p) - self.assertEqual(key.q, self.q) - - def testImportKey3bytes(self): - """Verify import of RSAPrivateKey DER SEQUENCE, encoded with PEM as byte string""" - key = RSA.importKey(b(self.rsaKeyPEM)) - self.assertEqual(key.has_private(),True) # assert_ - self.assertEqual(key.n, self.n) - self.assertEqual(key.e, self.e) - self.assertEqual(key.d, self.d) - self.assertEqual(key.p, self.p) - self.assertEqual(key.q, self.q) - - def testImportKey4unicode(self): - """Verify import of RSAPrivateKey DER SEQUENCE, encoded with PEM as unicode""" - key = RSA.importKey(self.rsaPublicKeyPEM) - self.assertEqual(key.has_private(),False) # failIf - self.assertEqual(key.n, self.n) - self.assertEqual(key.e, self.e) - - def testImportKey4bytes(self): - """Verify import of SubjectPublicKeyInfo DER SEQUENCE, encoded with PEM as byte string""" - key = RSA.importKey(b(self.rsaPublicKeyPEM)) - self.assertEqual(key.has_private(),False) # failIf - self.assertEqual(key.n, self.n) - self.assertEqual(key.e, self.e) - - def testImportKey5(self): - """Verifies that the imported key is still a valid RSA pair""" - key = RSA.importKey(self.rsaKeyPEM) - idem = key._encrypt(key._decrypt(89)) - self.assertEqual(idem, 89) - - def testImportKey6(self): - """Verifies that the imported key is still a valid RSA pair""" - key = RSA.importKey(self.rsaKeyDER) - idem = key._encrypt(key._decrypt(65)) - self.assertEqual(idem, 65) - - def testImportKey7(self): - """Verify import of OpenSSH public key""" - key = RSA.importKey(self.rsaPublicKeyOpenSSH) - self.assertEqual(key.n, self.n) - self.assertEqual(key.e, self.e) - - def testImportKey8(self): - """Verify import of encrypted PrivateKeyInfo DER SEQUENCE""" - for t in self.rsaKeyEncryptedPEM: - key = RSA.importKey(t[1], t[0]) - self.failUnless(key.has_private()) - self.assertEqual(key.n, self.n) - self.assertEqual(key.e, self.e) - self.assertEqual(key.d, self.d) - self.assertEqual(key.p, self.p) - self.assertEqual(key.q, self.q) - - def testImportKey9(self): - """Verify import of unencrypted PrivateKeyInfo DER SEQUENCE""" - key = RSA.importKey(self.rsaKeyDER8) - self.failUnless(key.has_private()) - self.assertEqual(key.n, self.n) - self.assertEqual(key.e, self.e) - self.assertEqual(key.d, self.d) - self.assertEqual(key.p, self.p) - self.assertEqual(key.q, self.q) - - def testImportKey10(self): - """Verify import of unencrypted PrivateKeyInfo DER SEQUENCE, encoded with PEM""" - key = RSA.importKey(self.rsaKeyPEM8) - self.failUnless(key.has_private()) - self.assertEqual(key.n, self.n) - self.assertEqual(key.e, self.e) - self.assertEqual(key.d, self.d) - self.assertEqual(key.p, self.p) - self.assertEqual(key.q, self.q) - - def testImportKey11(self): - """Verify import of RSAPublicKey DER SEQUENCE""" - der = asn1.DerSequence([17, 3]).encode() - key = RSA.importKey(der) - self.assertEqual(key.n, 17) - self.assertEqual(key.e, 3) - - def testImportKey12(self): - """Verify import of RSAPublicKey DER SEQUENCE, encoded with PEM""" - der = asn1.DerSequence([17, 3]).encode() - pem = der2pem(der) - key = RSA.importKey(pem) - self.assertEqual(key.n, 17) - self.assertEqual(key.e, 3) - - def test_import_key_windows_cr_lf(self): - pem_cr_lf = "\r\n".join(self.rsaKeyPEM.splitlines()) - key = RSA.importKey(pem_cr_lf) - self.assertEqual(key.n, self.n) - self.assertEqual(key.e, self.e) - self.assertEqual(key.d, self.d) - self.assertEqual(key.p, self.p) - self.assertEqual(key.q, self.q) - - def test_import_empty(self): - self.assertRaises(ValueError, RSA.import_key, b"") - - ### - def testExportKey1(self): - key = RSA.construct([self.n, self.e, self.d, self.p, self.q, self.pInv]) - derKey = key.export_key("DER") - self.assertEqual(derKey, self.rsaKeyDER) - - def testExportKey2(self): - key = RSA.construct([self.n, self.e]) - derKey = key.export_key("DER") - self.assertEqual(derKey, self.rsaPublicKeyDER) - - def testExportKey3(self): - key = RSA.construct([self.n, self.e, self.d, self.p, self.q, self.pInv]) - pemKey = key.export_key("PEM") - self.assertEqual(pemKey, b(self.rsaKeyPEM)) - - def testExportKey4(self): - key = RSA.construct([self.n, self.e]) - pemKey = key.export_key("PEM") - self.assertEqual(pemKey, b(self.rsaPublicKeyPEM)) - - def testExportKey5(self): - key = RSA.construct([self.n, self.e]) - openssh_1 = key.export_key("OpenSSH").split() - openssh_2 = self.rsaPublicKeyOpenSSH.split() - self.assertEqual(openssh_1[0], openssh_2[0]) - self.assertEqual(openssh_1[1], openssh_2[1]) - - def testExportKey7(self): - key = RSA.construct([self.n, self.e, self.d, self.p, self.q, self.pInv]) - derKey = key.export_key("DER", pkcs=8) - self.assertEqual(derKey, self.rsaKeyDER8) - - def testExportKey8(self): - key = RSA.construct([self.n, self.e, self.d, self.p, self.q, self.pInv]) - pemKey = key.export_key("PEM", pkcs=8) - self.assertEqual(pemKey, b(self.rsaKeyPEM8)) - - def testExportKey9(self): - key = RSA.construct([self.n, self.e, self.d, self.p, self.q, self.pInv]) - self.assertRaises(ValueError, key.export_key, "invalid-format") - - def testExportKey10(self): - # Export and re-import the encrypted key. It must match. - # PEM envelope, PKCS#1, old PEM encryption - key = RSA.construct([self.n, self.e, self.d, self.p, self.q, self.pInv]) - outkey = key.export_key('PEM', 'test') - self.failUnless(tostr(outkey).find('4,ENCRYPTED')!=-1) - self.failUnless(tostr(outkey).find('BEGIN RSA PRIVATE KEY')!=-1) - inkey = RSA.importKey(outkey, 'test') - self.assertEqual(key.n, inkey.n) - self.assertEqual(key.e, inkey.e) - self.assertEqual(key.d, inkey.d) - - def testExportKey11(self): - # Export and re-import the encrypted key. It must match. - # PEM envelope, PKCS#1, old PEM encryption - key = RSA.construct([self.n, self.e, self.d, self.p, self.q, self.pInv]) - outkey = key.export_key('PEM', 'test', pkcs=1) - self.failUnless(tostr(outkey).find('4,ENCRYPTED')!=-1) - self.failUnless(tostr(outkey).find('BEGIN RSA PRIVATE KEY')!=-1) - inkey = RSA.importKey(outkey, 'test') - self.assertEqual(key.n, inkey.n) - self.assertEqual(key.e, inkey.e) - self.assertEqual(key.d, inkey.d) - - def testExportKey12(self): - # Export and re-import the encrypted key. It must match. - # PEM envelope, PKCS#8, old PEM encryption - key = RSA.construct([self.n, self.e, self.d, self.p, self.q, self.pInv]) - outkey = key.export_key('PEM', 'test', pkcs=8) - self.failUnless(tostr(outkey).find('4,ENCRYPTED')!=-1) - self.failUnless(tostr(outkey).find('BEGIN PRIVATE KEY')!=-1) - inkey = RSA.importKey(outkey, 'test') - self.assertEqual(key.n, inkey.n) - self.assertEqual(key.e, inkey.e) - self.assertEqual(key.d, inkey.d) - - def testExportKey13(self): - # Export and re-import the encrypted key. It must match. - # PEM envelope, PKCS#8, PKCS#8 encryption - key = RSA.construct([self.n, self.e, self.d, self.p, self.q, self.pInv]) - outkey = key.export_key('PEM', 'test', pkcs=8, - protection='PBKDF2WithHMAC-SHA1AndDES-EDE3-CBC') - self.failUnless(tostr(outkey).find('4,ENCRYPTED')==-1) - self.failUnless(tostr(outkey).find('BEGIN ENCRYPTED PRIVATE KEY')!=-1) - inkey = RSA.importKey(outkey, 'test') - self.assertEqual(key.n, inkey.n) - self.assertEqual(key.e, inkey.e) - self.assertEqual(key.d, inkey.d) - - def testExportKey14(self): - # Export and re-import the encrypted key. It must match. - # DER envelope, PKCS#8, PKCS#8 encryption - key = RSA.construct([self.n, self.e, self.d, self.p, self.q, self.pInv]) - outkey = key.export_key('DER', 'test', pkcs=8) - inkey = RSA.importKey(outkey, 'test') - self.assertEqual(key.n, inkey.n) - self.assertEqual(key.e, inkey.e) - self.assertEqual(key.d, inkey.d) - - def testExportKey15(self): - # Verify that that error an condition is detected when trying to - # use a password with DER encoding and PKCS#1. - key = RSA.construct([self.n, self.e, self.d, self.p, self.q, self.pInv]) - self.assertRaises(ValueError, key.export_key, 'DER', 'test', 1) - - def test_import_key(self): - """Verify that import_key is an alias to importKey""" - key = RSA.import_key(self.rsaPublicKeyDER) - self.failIf(key.has_private()) - self.assertEqual(key.n, self.n) - self.assertEqual(key.e, self.e) - - def test_exportKey(self): - key = RSA.construct([self.n, self.e, self.d, self.p, self.q, self.pInv]) - self.assertEqual(key.export_key(), key.exportKey()) - - -class ImportKeyFromX509Cert(unittest.TestCase): - - def test_x509v1(self): - - # Sample V1 certificate with a 1024 bit RSA key - x509_v1_cert = """ ------BEGIN CERTIFICATE----- -MIICOjCCAaMCAQEwDQYJKoZIhvcNAQEEBQAwfjENMAsGA1UEChMEQWNtZTELMAkG -A1UECxMCUkQxHDAaBgkqhkiG9w0BCQEWDXNwYW1AYWNtZS5vcmcxEzARBgNVBAcT -Ck1ldHJvcG9saXMxETAPBgNVBAgTCE5ldyBZb3JrMQswCQYDVQQGEwJVUzENMAsG -A1UEAxMEdGVzdDAeFw0xNDA3MTExOTU3MjRaFw0xNzA0MDYxOTU3MjRaME0xCzAJ -BgNVBAYTAlVTMREwDwYDVQQIEwhOZXcgWW9yazENMAsGA1UEChMEQWNtZTELMAkG -A1UECxMCUkQxDzANBgNVBAMTBmxhdHZpYTCBnzANBgkqhkiG9w0BAQEFAAOBjQAw -gYkCgYEAyG+kytdRj3TFbRmHDYp3TXugVQ81chew0qeOxZWOz80IjtWpgdOaCvKW -NCuc8wUR9BWrEQW+39SaRMLiQfQtyFSQZijc3nsEBu/Lo4uWZ0W/FHDRVSvkJA/V -Ex5NL5ikI+wbUeCV5KajGNDalZ8F1pk32+CBs8h1xNx5DyxuEHUCAwEAATANBgkq -hkiG9w0BAQQFAAOBgQCVQF9Y//Q4Psy+umEM38pIlbZ2hxC5xNz/MbVPwuCkNcGn -KYNpQJP+JyVTsPpO8RLZsAQDzRueMI3S7fbbwTzAflN0z19wvblvu93xkaBytVok -9VBAH28olVhy9b1MMeg2WOt5sUEQaFNPnwwsyiY9+HsRpvpRnPSQF+kyYVsshQ== ------END CERTIFICATE----- - """.strip() - - # RSA public key as dumped by openssl - exponent = 65537 - modulus_str = """ -00:c8:6f:a4:ca:d7:51:8f:74:c5:6d:19:87:0d:8a: -77:4d:7b:a0:55:0f:35:72:17:b0:d2:a7:8e:c5:95: -8e:cf:cd:08:8e:d5:a9:81:d3:9a:0a:f2:96:34:2b: -9c:f3:05:11:f4:15:ab:11:05:be:df:d4:9a:44:c2: -e2:41:f4:2d:c8:54:90:66:28:dc:de:7b:04:06:ef: -cb:a3:8b:96:67:45:bf:14:70:d1:55:2b:e4:24:0f: -d5:13:1e:4d:2f:98:a4:23:ec:1b:51:e0:95:e4:a6: -a3:18:d0:da:95:9f:05:d6:99:37:db:e0:81:b3:c8: -75:c4:dc:79:0f:2c:6e:10:75 - """ - modulus = int(re.sub("[^0-9a-f]","", modulus_str), 16) - - key = RSA.importKey(x509_v1_cert) - self.assertEqual(key.e, exponent) - self.assertEqual(key.n, modulus) - self.failIf(key.has_private()) - - def test_x509v3(self): - - # Sample V3 certificate with a 1024 bit RSA key - x509_v3_cert = """ ------BEGIN CERTIFICATE----- -MIIEcjCCAlqgAwIBAgIBATANBgkqhkiG9w0BAQsFADBhMQswCQYDVQQGEwJVUzEL -MAkGA1UECAwCTUQxEjAQBgNVBAcMCUJhbHRpbW9yZTEQMA4GA1UEAwwHVGVzdCBD -QTEfMB0GCSqGSIb3DQEJARYQdGVzdEBleGFtcGxlLmNvbTAeFw0xNDA3MTIwOTM1 -MTJaFw0xNzA0MDcwOTM1MTJaMEQxCzAJBgNVBAYTAlVTMQswCQYDVQQIDAJNRDES -MBAGA1UEBwwJQmFsdGltb3JlMRQwEgYDVQQDDAtUZXN0IFNlcnZlcjCBnzANBgkq -hkiG9w0BAQEFAAOBjQAwgYkCgYEA/S7GJV2OcFdyNMQ4K75KrYFtMEn3VnEFdPHa -jyS37XlMxSh0oS4GeTGVUCJInl5Cpsv8WQdh03FfeOdvzp5IZ46OcjeOPiWnmjgl -2G5j7e2bDH7RSchGV+OD6Fb1Agvuu2/9iy8fdf3rPQ/7eAddzKUrzwacVbnW+tg2 -QtSXKRcCAwEAAaOB1TCB0jAdBgNVHQ4EFgQU/WwCX7FfWMIPDFfJ+I8a2COG+l8w -HwYDVR0jBBgwFoAUa0hkif3RMaraiWtsOOZZlLu9wJwwCQYDVR0TBAIwADALBgNV -HQ8EBAMCBeAwSgYDVR0RBEMwQYILZXhhbXBsZS5jb22CD3d3dy5leGFtcGxlLmNv -bYIQbWFpbC5leGFtcGxlLmNvbYIPZnRwLmV4YW1wbGUuY29tMCwGCWCGSAGG+EIB -DQQfFh1PcGVuU1NMIEdlbmVyYXRlZCBDZXJ0aWZpY2F0ZTANBgkqhkiG9w0BAQsF -AAOCAgEAvO6xfdsGbnoK4My3eJthodTAjMjPwFVY133LH04QLcCv54TxKhtUg1fi -PgdjVe1HpTytPBfXy2bSZbXAN0abZCtw1rYrnn7o1g2pN8iypVq3zVn0iMTzQzxs -zEPO3bpR/UhNSf90PmCsS5rqZpAAnXSaAy1ClwHWk/0eG2pYkhE1m1ABVMN2lsAW -e9WxGk6IFqaI9O37NYQwmEypMs4DC+ECJEvbPFiqi3n0gbXCZJJ6omDA5xJldaYK -Oa7KR3s/qjBsu9UAiWpLBuFoSTHIF2aeRKRFmUdmzwo43eVPep65pY6eQ4AdL2RF -rqEuINbGlzI5oQyYhu71IwB+iPZXaZZPlwjLgOsuad/p2hOgDb5WxUi8FnDPursQ -ujfpIpmrOP/zpvvQWnwePI3lI+5n41kTBSbefXEdv6rXpHk3QRzB90uPxnXPdxSC -16ASA8bQT5an/1AgoE3k9CrcD2K0EmgaX0YI0HUhkyzbkg34EhpWJ6vvRUbRiNRo -9cIbt/ya9Y9u0Ja8GLXv6dwX0l0IdJMkL8KifXUFAVCujp1FBrr/gdmwQn8itANy -+qbnWSxmOvtaY0zcaFAcONuHva0h51/WqXOMO1eb8PhR4HIIYU8p1oBwQp7dSni8 -THDi1F+GG5PsymMDj5cWK42f+QzjVw5PrVmFqqrrEoMlx8DWh5Y= ------END CERTIFICATE----- -""".strip() - - # RSA public key as dumped by openssl - exponent = 65537 - modulus_str = """ -00:fd:2e:c6:25:5d:8e:70:57:72:34:c4:38:2b:be: -4a:ad:81:6d:30:49:f7:56:71:05:74:f1:da:8f:24: -b7:ed:79:4c:c5:28:74:a1:2e:06:79:31:95:50:22: -48:9e:5e:42:a6:cb:fc:59:07:61:d3:71:5f:78:e7: -6f:ce:9e:48:67:8e:8e:72:37:8e:3e:25:a7:9a:38: -25:d8:6e:63:ed:ed:9b:0c:7e:d1:49:c8:46:57:e3: -83:e8:56:f5:02:0b:ee:bb:6f:fd:8b:2f:1f:75:fd: -eb:3d:0f:fb:78:07:5d:cc:a5:2b:cf:06:9c:55:b9: -d6:fa:d8:36:42:d4:97:29:17 - """ - modulus = int(re.sub("[^0-9a-f]","", modulus_str), 16) - - key = RSA.importKey(x509_v3_cert) - self.assertEqual(key.e, exponent) - self.assertEqual(key.n, modulus) - self.failIf(key.has_private()) - - -class TestImport_2048(unittest.TestCase): - - def test_import_openssh_public(self): - key_file_ref = load_file("rsa2048_private.pem") - key_file = load_file("rsa2048_public_openssh.txt") - - # Skip test if test vectors are not installed - if None in (key_file_ref, key_file): - return - - key_ref = RSA.import_key(key_file_ref).public_key() - key = RSA.import_key(key_file) - self.assertEqual(key_ref, key) - - def test_import_openssh_private_clear(self): - key_file = load_file("rsa2048_private_openssh.pem") - key_file_old = load_file("rsa2048_private_openssh_old.pem") - - # Skip test if test vectors are not installed - if None in (key_file_old, key_file): - return - - key = RSA.import_key(key_file) - key_old = RSA.import_key(key_file_old) - - self.assertEqual(key, key_old) - - def test_import_openssh_private_password(self): - key_file = load_file("rsa2048_private_openssh_pwd.pem") - key_file_old = load_file("rsa2048_private_openssh_pwd_old.pem") - - # Skip test if test vectors are not installed - if None in (key_file_old, key_file): - return - - key = RSA.import_key(key_file, b"password") - key_old = RSA.import_key(key_file_old) - self.assertEqual(key, key_old) - - -if __name__ == '__main__': - unittest.main() - - -def get_tests(config={}): - tests = [] - tests += list_test_cases(ImportKeyTests) - tests += list_test_cases(ImportKeyFromX509Cert) - tests += list_test_cases(TestImport_2048) - return tests - - -if __name__ == '__main__': - suite = lambda: unittest.TestSuite(get_tests()) - unittest.main(defaultTest='suite') - -# vim:set ts=4 sw=4 sts=4 expandtab: diff --git a/Crypto/SelfTest/Random/__init__.py b/Crypto/SelfTest/Random/__init__.py deleted file mode 100644 index 53061cc..0000000 --- a/Crypto/SelfTest/Random/__init__.py +++ /dev/null @@ -1,39 +0,0 @@ -# -*- coding: utf-8 -*- -# -# SelfTest/Random/__init__.py: Self-test for random number generation modules -# -# Written in 2008 by Dwayne C. Litzenberger -# -# =================================================================== -# The contents of this file are dedicated to the public domain. To -# the extent that dedication to the public domain is not available, -# everyone is granted a worldwide, perpetual, royalty-free, -# non-exclusive license to exercise all rights associated with the -# contents of this file for any purpose whatsoever. -# No rights are reserved. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS -# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN -# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# =================================================================== - -"""Self-test for random number generators""" - -__revision__ = "$Id$" - -def get_tests(config={}): - tests = [] - from Crypto.SelfTest.Random import test_random; tests += test_random.get_tests(config=config) - return tests - -if __name__ == '__main__': - import unittest - suite = lambda: unittest.TestSuite(get_tests()) - unittest.main(defaultTest='suite') - -# vim:set ts=4 sw=4 sts=4 expandtab: diff --git a/Crypto/SelfTest/Random/__pycache__/__init__.cpython-36.pyc b/Crypto/SelfTest/Random/__pycache__/__init__.cpython-36.pyc deleted file mode 100644 index 236df2247680377f24b35ce5c0f078a3ca1dd66b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 676 zcmYjNy>8n;3?`+sEdK=PRG>ov4@LnEv4#Lmhaf1Bsf$t6U8?19_MKHZ`Z4a#0US6} zvgSehN?JSh6*`raYrs5^AbBLekG#6L7+(LFswe{Z4QCRP|C!X?kkOEV#taKsqYiZV zf>~ffE$##RN%wSAicILfj$a__8L^44qx$_{tifJ zV*ZCpA;EUUfbs}NVYF)Mb&)4w_V&*1x4xM%tM61Z`_>V%0rj za<<)DUi3Ywi^%{A9K##zvTZD7rHWcg%a@t2xZosAxx3Gp91k1x!81Jb9dMq6ZM-7@ zrk@RX(Z!Bvbwj%~&P<=$+xVtb)l#clKDHwTJLG)NabJSjNSn3Vm7ZrM{kAWqZdOue zW8!8W3Rg7Dl2>8UwW3vRKXTRRU1@ILQOfZyA`rp27bCxa0#~2> diff --git a/Crypto/SelfTest/Random/__pycache__/test_random.cpython-36.pyc b/Crypto/SelfTest/Random/__pycache__/test_random.cpython-36.pyc deleted file mode 100644 index 72f7210de3fa0c2abc1b5b351e6fcaafc138db4f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3289 zcma)9&1>976rYi_TJ4v;**N}+p(d0hhQ^C+nm{QbkcLtyKE!E41+9>Gw6@l}tKE^D z+D1zY%CQ9>O3yvy(Ec<119a`lJ@-_4=Sus{f)Rd;NidrUF0?kcxq551hPU38tv3U?{#2g! zqG0p6+Z91)v+I3#f8zqdu-y%w^8E&pqn`%i2}Zbp$zzC;sR%Xfrwbi>7-@0O@ATT< z3vANhP@`WNBaiVEBmB`srj#Y?@Bw0rc}q*!K#R2&d?b9Jk0~Q&EhE-rBhi#zPRVma zZccGY!-y3PuSVPK*Q@zAWReO zGxp6dg91Di<9uwzg+xbe)2msJtW|=ZZZMr4@!+r6I$~WzV?f^;MoMxclb`dTe65Ba z=a*SrSOi96D`S?||Lqk!xr-?C2}g{pgCYgA(?0j#}WMw6wkF_ z8z}L2;HU*JE^Azi%{*cQE<p{PJ4%sj62esLD-Zhv~O0cSL{>; zkL;A*xT>${jwNIL(O)!VOxTK>_-3u0-Mr=-DCy&cPoSB77%!^BrBvU^3k%B&Qn@H% zdT~LY#*}ZReA}WZ60Ur)U!F$_y+L-))wb zphZgieiWuTPzPRGAVx-(GN;O8TFw^FT|e}~wD{6(AA8TF3}jk(aoQV_c{299QEE00 z1Ha*=dUzV9<=37J{h;gk-DZ#$C>~cz_f#sJi(hnwcapg>+I|?N`S9?#*=)nQ?R8T# zbg2i~D5pk9(Z9r1FcT27BxZj=c-`p)O8Kv-RzyF zd3oF=@j7-0|G>obGPigUPg#v}iQZUg7B{%58JMel4o{h{^E-TjFN0p?HBgHf>e0%O zmLa_}meqI-9x}gGtj*}K0rxS?dHqm9rp%Tm_auZ-EjCxFZ(@;GoU8;yB?11Bbb9Aywmu_<-=r;X>OPRb#d7Vz$}b9QI9aC24(j@VPyyOcm;Z44U>UNvQUw=@0nIsmGd9r CJKhEW diff --git a/Crypto/SelfTest/Random/test_random.py b/Crypto/SelfTest/Random/test_random.py deleted file mode 100644 index 8fadc53..0000000 --- a/Crypto/SelfTest/Random/test_random.py +++ /dev/null @@ -1,167 +0,0 @@ -# -*- coding: utf-8 -*- -# -# SelfTest/Util/test_generic.py: Self-test for the Crypto.Random.new() function -# -# Written in 2008 by Dwayne C. Litzenberger -# -# =================================================================== -# The contents of this file are dedicated to the public domain. To -# the extent that dedication to the public domain is not available, -# everyone is granted a worldwide, perpetual, royalty-free, -# non-exclusive license to exercise all rights associated with the -# contents of this file for any purpose whatsoever. -# No rights are reserved. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS -# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN -# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# =================================================================== - -"""Self-test suite for Crypto.Random.new()""" - -import sys -import unittest -from Crypto.Util.py3compat import b - -class SimpleTest(unittest.TestCase): - def runTest(self): - """Crypto.Random.new()""" - # Import the Random module and try to use it - from Crypto import Random - randobj = Random.new() - x = randobj.read(16) - y = randobj.read(16) - self.assertNotEqual(x, y) - z = Random.get_random_bytes(16) - self.assertNotEqual(x, z) - self.assertNotEqual(y, z) - # Test the Random.random module, which - # implements a subset of Python's random API - # Not implemented: - # seed(), getstate(), setstate(), jumpahead() - # random(), uniform(), triangular(), betavariate() - # expovariate(), gammavariate(), gauss(), - # longnormvariate(), normalvariate(), - # vonmisesvariate(), paretovariate() - # weibullvariate() - # WichmannHill(), whseed(), SystemRandom() - from Crypto.Random import random - x = random.getrandbits(16*8) - y = random.getrandbits(16*8) - self.assertNotEqual(x, y) - # Test randrange - if x>y: - start = y - stop = x - else: - start = x - stop = y - for step in range(1,10): - x = random.randrange(start,stop,step) - y = random.randrange(start,stop,step) - self.assertNotEqual(x, y) - self.assertEqual(start <= x < stop, True) - self.assertEqual(start <= y < stop, True) - self.assertEqual((x - start) % step, 0) - self.assertEqual((y - start) % step, 0) - for i in range(10): - self.assertEqual(random.randrange(1,2), 1) - self.assertRaises(ValueError, random.randrange, start, start) - self.assertRaises(ValueError, random.randrange, stop, start, step) - self.assertRaises(TypeError, random.randrange, start, stop, step, step) - self.assertRaises(TypeError, random.randrange, start, stop, "1") - self.assertRaises(TypeError, random.randrange, "1", stop, step) - self.assertRaises(TypeError, random.randrange, 1, "2", step) - self.assertRaises(ValueError, random.randrange, start, stop, 0) - # Test randint - x = random.randint(start,stop) - y = random.randint(start,stop) - self.assertNotEqual(x, y) - self.assertEqual(start <= x <= stop, True) - self.assertEqual(start <= y <= stop, True) - for i in range(10): - self.assertEqual(random.randint(1,1), 1) - self.assertRaises(ValueError, random.randint, stop, start) - self.assertRaises(TypeError, random.randint, start, stop, step) - self.assertRaises(TypeError, random.randint, "1", stop) - self.assertRaises(TypeError, random.randint, 1, "2") - # Test choice - seq = range(10000) - x = random.choice(seq) - y = random.choice(seq) - self.assertNotEqual(x, y) - self.assertEqual(x in seq, True) - self.assertEqual(y in seq, True) - for i in range(10): - self.assertEqual(random.choice((1,2,3)) in (1,2,3), True) - self.assertEqual(random.choice([1,2,3]) in [1,2,3], True) - if sys.version_info[0] == 3: - self.assertEqual(random.choice(bytearray(b('123'))) in bytearray(b('123')), True) - self.assertEqual(1, random.choice([1])) - self.assertRaises(IndexError, random.choice, []) - self.assertRaises(TypeError, random.choice, 1) - # Test shuffle. Lacks random parameter to specify function. - # Make copies of seq - seq = range(500) - x = list(seq) - y = list(seq) - random.shuffle(x) - random.shuffle(y) - self.assertNotEqual(x, y) - self.assertEqual(len(seq), len(x)) - self.assertEqual(len(seq), len(y)) - for i in range(len(seq)): - self.assertEqual(x[i] in seq, True) - self.assertEqual(y[i] in seq, True) - self.assertEqual(seq[i] in x, True) - self.assertEqual(seq[i] in y, True) - z = [1] - random.shuffle(z) - self.assertEqual(z, [1]) - if sys.version_info[0] == 3: - z = bytearray(b('12')) - random.shuffle(z) - self.assertEqual(b('1') in z, True) - self.assertRaises(TypeError, random.shuffle, b('12')) - self.assertRaises(TypeError, random.shuffle, 1) - self.assertRaises(TypeError, random.shuffle, "11") - self.assertRaises(TypeError, random.shuffle, (1,2)) - # 2to3 wraps a list() around it, alas - but I want to shoot - # myself in the foot here! :D - # if sys.version_info[0] == 3: - # self.assertRaises(TypeError, random.shuffle, range(3)) - # Test sample - x = random.sample(seq, 20) - y = random.sample(seq, 20) - self.assertNotEqual(x, y) - for i in range(20): - self.assertEqual(x[i] in seq, True) - self.assertEqual(y[i] in seq, True) - z = random.sample([1], 1) - self.assertEqual(z, [1]) - z = random.sample((1,2,3), 1) - self.assertEqual(z[0] in (1,2,3), True) - z = random.sample("123", 1) - self.assertEqual(z[0] in "123", True) - z = random.sample(range(3), 1) - self.assertEqual(z[0] in range(3), True) - if sys.version_info[0] == 3: - z = random.sample(b("123"), 1) - self.assertEqual(z[0] in b("123"), True) - z = random.sample(bytearray(b("123")), 1) - self.assertEqual(z[0] in bytearray(b("123")), True) - self.assertRaises(TypeError, random.sample, 1) - -def get_tests(config={}): - return [SimpleTest()] - -if __name__ == '__main__': - suite = lambda: unittest.TestSuite(get_tests()) - unittest.main(defaultTest='suite') - -# vim:set ts=4 sw=4 sts=4 expandtab: diff --git a/Crypto/SelfTest/Signature/__init__.py b/Crypto/SelfTest/Signature/__init__.py deleted file mode 100644 index 88c7f34..0000000 --- a/Crypto/SelfTest/Signature/__init__.py +++ /dev/null @@ -1,39 +0,0 @@ -# -*- coding: utf-8 -*- -# -# SelfTest/Signature/__init__.py: Self-test for signature modules -# -# =================================================================== -# The contents of this file are dedicated to the public domain. To -# the extent that dedication to the public domain is not available, -# everyone is granted a worldwide, perpetual, royalty-free, -# non-exclusive license to exercise all rights associated with the -# contents of this file for any purpose whatsoever. -# No rights are reserved. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS -# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN -# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# =================================================================== - -"""Self-test for signature modules""" - -import os - -def get_tests(config={}): - tests = [] - from . import test_pkcs1_15; tests += test_pkcs1_15.get_tests(config=config) - from . import test_pss; tests += test_pss.get_tests(config=config) - from . import test_dss; tests += test_dss.get_tests(config=config) - return tests - -if __name__ == '__main__': - import unittest - suite = lambda: unittest.TestSuite(get_tests()) - unittest.main(defaultTest='suite') - -# vim:set ts=4 sw=4 sts=4 expandtab: diff --git a/Crypto/SelfTest/Signature/__pycache__/__init__.cpython-36.pyc b/Crypto/SelfTest/Signature/__pycache__/__init__.cpython-36.pyc deleted file mode 100644 index 78283df6ac1c0d570ef6b2482f4c17930c69868c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 748 zcmZ8fJ#X7E5Is_qEjxCbtwRgcLlzB*5CmRk`u7aW}c<4vEcLeU+5O{XV|h=u392(eH zln)*C#VkG1X0BGHr@P{Q+m})|nUpPW++oOCRYpoXrta6&Eokf`DpJw@<=g#Dw{I}z NXam6`KI%t|osyzSz diff --git a/Crypto/SelfTest/Signature/__pycache__/test_dss.cpython-36.pyc b/Crypto/SelfTest/Signature/__pycache__/test_dss.cpython-36.pyc deleted file mode 100644 index ddb2eb35625b3a875c608af11065c2dbeabe96c0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 39159 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 E2V+?U?EnA( diff --git a/Crypto/SelfTest/Signature/test_dss.py b/Crypto/SelfTest/Signature/test_dss.py deleted file mode 100644 index 1d23e09..0000000 --- a/Crypto/SelfTest/Signature/test_dss.py +++ /dev/null @@ -1,1132 +0,0 @@ -# -# SelfTest/Signature/test_dss.py: Self-test for DSS signatures -# -# =================================================================== -# -# Copyright (c) 2014, Legrandin -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# =================================================================== - -import re -import unittest -from binascii import hexlify, unhexlify - -from Crypto.Util.py3compat import tobytes, bord, bchr - -from Crypto.Hash import (SHA1, SHA224, SHA256, SHA384, SHA512, SHA3_256, - SHA3_384, SHA3_512) -from Crypto.Signature import DSS -from Crypto.PublicKey import DSA, ECC -from Crypto.SelfTest.st_common import list_test_cases -from Crypto.SelfTest.loader import load_test_vectors, load_test_vectors_wycheproof -from Crypto.Util.number import bytes_to_long, long_to_bytes - - -def t2b(hexstring): - ws = hexstring.replace(" ", "").replace("\n", "") - return unhexlify(tobytes(ws)) - - -def t2l(hexstring): - ws = hexstring.replace(" ", "").replace("\n", "") - return int(ws, 16) - - -def load_hash_by_name(hash_name): - return __import__("Crypto.Hash." + hash_name, globals(), locals(), ["new"]) - - -class StrRNG: - - def __init__(self, randomness): - length = len(randomness) - self._idx = 0 - # Fix required to get the right K (see how randint() works!) - self._randomness = long_to_bytes(bytes_to_long(randomness) - 1, length) - - def __call__(self, n): - out = self._randomness[self._idx:self._idx + n] - self._idx += n - return out - - -class FIPS_DSA_Tests(unittest.TestCase): - - # 1st 1024 bit key from SigGen.txt - P = 0xa8f9cd201e5e35d892f85f80e4db2599a5676a3b1d4f190330ed3256b26d0e80a0e49a8fffaaad2a24f472d2573241d4d6d6c7480c80b4c67bb4479c15ada7ea8424d2502fa01472e760241713dab025ae1b02e1703a1435f62ddf4ee4c1b664066eb22f2e3bf28bb70a2a76e4fd5ebe2d1229681b5b06439ac9c7e9d8bde283 - Q = 0xf85f0f83ac4df7ea0cdf8f469bfeeaea14156495 - G = 0x2b3152ff6c62f14622b8f48e59f8af46883b38e79b8c74deeae9df131f8b856e3ad6c8455dab87cc0da8ac973417ce4f7878557d6cdf40b35b4a0ca3eb310c6a95d68ce284ad4e25ea28591611ee08b8444bd64b25f3f7c572410ddfb39cc728b9c936f85f419129869929cdb909a6a3a99bbe089216368171bd0ba81de4fe33 - X = 0xc53eae6d45323164c7d07af5715703744a63fc3a - Y = 0x313fd9ebca91574e1c2eebe1517c57e0c21b0209872140c5328761bbb2450b33f1b18b409ce9ab7c4cd8fda3391e8e34868357c199e16a6b2eba06d6749def791d79e95d3a4d09b24c392ad89dbf100995ae19c01062056bb14bce005e8731efde175f95b975089bdcdaea562b32786d96f5a31aedf75364008ad4fffebb970b - - key_pub = DSA.construct((Y, G, P, Q)) - key_priv = DSA.construct((Y, G, P, Q, X)) - - def shortDescription(self): - return "FIPS DSA Tests" - - def test_loopback(self): - hashed_msg = SHA512.new(b"test") - signer = DSS.new(self.key_priv, 'fips-186-3') - signature = signer.sign(hashed_msg) - - verifier = DSS.new(self.key_pub, 'fips-186-3') - verifier.verify(hashed_msg, signature) - - def test_negative_unapproved_hashes(self): - """Verify that unapproved hashes are rejected""" - - from Crypto.Hash import RIPEMD160 - - self.description = "Unapproved hash (RIPEMD160) test" - hash_obj = RIPEMD160.new() - signer = DSS.new(self.key_priv, 'fips-186-3') - self.assertRaises(ValueError, signer.sign, hash_obj) - self.assertRaises(ValueError, signer.verify, hash_obj, b"\x00" * 40) - - def test_negative_unknown_modes_encodings(self): - """Verify that unknown modes/encodings are rejected""" - - self.description = "Unknown mode test" - self.assertRaises(ValueError, DSS.new, self.key_priv, 'fips-186-0') - - self.description = "Unknown encoding test" - self.assertRaises(ValueError, DSS.new, self.key_priv, 'fips-186-3', 'xml') - - def test_asn1_encoding(self): - """Verify ASN.1 encoding""" - - self.description = "ASN.1 encoding test" - hash_obj = SHA1.new() - signer = DSS.new(self.key_priv, 'fips-186-3', 'der') - signature = signer.sign(hash_obj) - - # Verify that output looks like a DER SEQUENCE - self.assertEqual(bord(signature[0]), 48) - signer.verify(hash_obj, signature) - - # Verify that ASN.1 parsing fails as expected - signature = bchr(7) + signature[1:] - self.assertRaises(ValueError, signer.verify, hash_obj, signature) - - def test_sign_verify(self): - """Verify public/private method""" - - self.description = "can_sign() test" - signer = DSS.new(self.key_priv, 'fips-186-3') - self.failUnless(signer.can_sign()) - - signer = DSS.new(self.key_pub, 'fips-186-3') - self.failIf(signer.can_sign()) - - -class FIPS_DSA_Tests_KAT(unittest.TestCase): - pass - - -test_vectors_verify = load_test_vectors(("Signature", "DSA"), - "FIPS_186_3_SigVer.rsp", - "Signature Verification 186-3", - {'result': lambda x: x}) or [] - -for idx, tv in enumerate(test_vectors_verify): - - if isinstance(tv, str): - res = re.match(r"\[mod = L=([0-9]+), N=([0-9]+), ([a-zA-Z0-9-]+)\]", tv) - assert(res) - hash_name = res.group(3).replace("-", "") - hash_module = load_hash_by_name(hash_name) - continue - - if hasattr(tv, "p"): - modulus = tv.p - generator = tv.g - suborder = tv.q - continue - - hash_obj = hash_module.new(tv.msg) - - comps = [bytes_to_long(x) for x in (tv.y, generator, modulus, suborder)] - key = DSA.construct(comps, False) # type: ignore - verifier = DSS.new(key, 'fips-186-3') - - def positive_test(self, verifier=verifier, hash_obj=hash_obj, signature=tv.r+tv.s): - verifier.verify(hash_obj, signature) - - def negative_test(self, verifier=verifier, hash_obj=hash_obj, signature=tv.r+tv.s): - self.assertRaises(ValueError, verifier.verify, hash_obj, signature) - - if tv.result == 'p': - setattr(FIPS_DSA_Tests_KAT, "test_verify_positive_%d" % idx, positive_test) - else: - setattr(FIPS_DSA_Tests_KAT, "test_verify_negative_%d" % idx, negative_test) - - -test_vectors_sign = load_test_vectors(("Signature", "DSA"), - "FIPS_186_3_SigGen.txt", - "Signature Creation 186-3", - {}) or [] - -for idx, tv in enumerate(test_vectors_sign): - - if isinstance(tv, str): - res = re.match(r"\[mod = L=([0-9]+), N=([0-9]+), ([a-zA-Z0-9-]+)\]", tv) - assert(res) - hash_name = res.group(3).replace("-", "") - hash_module = load_hash_by_name(hash_name) - continue - - if hasattr(tv, "p"): - modulus = tv.p - generator = tv.g - suborder = tv.q - continue - - hash_obj = hash_module.new(tv.msg) - comps_dsa = [bytes_to_long(x) for x in (tv.y, generator, modulus, suborder, tv.x)] - key = DSA.construct(comps_dsa, False) # type: ignore - signer = DSS.new(key, 'fips-186-3', randfunc=StrRNG(tv.k)) - - def new_test(self, signer=signer, hash_obj=hash_obj, signature=tv.r+tv.s): - self.assertEqual(signer.sign(hash_obj), signature) - setattr(FIPS_DSA_Tests_KAT, "test_sign_%d" % idx, new_test) - - -class FIPS_ECDSA_Tests(unittest.TestCase): - - key_priv = ECC.generate(curve="P-256") - key_pub = key_priv.public_key() - - def shortDescription(self): - return "FIPS ECDSA Tests" - - def test_loopback(self): - hashed_msg = SHA512.new(b"test") - signer = DSS.new(self.key_priv, 'fips-186-3') - signature = signer.sign(hashed_msg) - - verifier = DSS.new(self.key_pub, 'fips-186-3') - verifier.verify(hashed_msg, signature) - - def test_negative_unapproved_hashes(self): - """Verify that unapproved hashes are rejected""" - - from Crypto.Hash import SHA1 - - self.description = "Unapproved hash (SHA-1) test" - hash_obj = SHA1.new() - signer = DSS.new(self.key_priv, 'fips-186-3') - self.assertRaises(ValueError, signer.sign, hash_obj) - self.assertRaises(ValueError, signer.verify, hash_obj, b"\x00" * 40) - - def test_sign_verify(self): - """Verify public/private method""" - - self.description = "can_sign() test" - signer = DSS.new(self.key_priv, 'fips-186-3') - self.failUnless(signer.can_sign()) - - signer = DSS.new(self.key_pub, 'fips-186-3') - self.failIf(signer.can_sign()) - - def test_negative_unknown_modes_encodings(self): - """Verify that unknown modes/encodings are rejected""" - - self.description = "Unknown mode test" - self.assertRaises(ValueError, DSS.new, self.key_priv, 'fips-186-0') - - self.description = "Unknown encoding test" - self.assertRaises(ValueError, DSS.new, self.key_priv, 'fips-186-3', 'xml') - - def test_asn1_encoding(self): - """Verify ASN.1 encoding""" - - self.description = "ASN.1 encoding test" - hash_obj = SHA256.new() - signer = DSS.new(self.key_priv, 'fips-186-3', 'der') - signature = signer.sign(hash_obj) - - # Verify that output looks like a DER SEQUENCE - self.assertEqual(bord(signature[0]), 48) - signer.verify(hash_obj, signature) - - # Verify that ASN.1 parsing fails as expected - signature = bchr(7) + signature[1:] - self.assertRaises(ValueError, signer.verify, hash_obj, signature) - - -class FIPS_ECDSA_Tests_KAT(unittest.TestCase): - pass - - -test_vectors_verify = load_test_vectors(("Signature", "ECDSA"), - "SigVer.rsp", - "ECDSA Signature Verification 186-3", - {'result': lambda x: x, - 'qx': lambda x: int(x, 16), - 'qy': lambda x: int(x, 16), - }) or [] - -for idx, tv in enumerate(test_vectors_verify): - - if isinstance(tv, str): - res = re.match(r"\[(P-[0-9]+),(SHA-[0-9]+)\]", tv) - assert res - curve_name = res.group(1) - hash_name = res.group(2).replace("-", "") - hash_module = load_hash_by_name(hash_name) - continue - - hash_obj = hash_module.new(tv.msg) - ecc_key = ECC.construct(curve=curve_name, point_x=tv.qx, point_y=tv.qy) - verifier = DSS.new(ecc_key, 'fips-186-3') - - def positive_test(self, verifier=verifier, hash_obj=hash_obj, signature=tv.r+tv.s): - verifier.verify(hash_obj, signature) - - def negative_test(self, verifier=verifier, hash_obj=hash_obj, signature=tv.r+tv.s): - self.assertRaises(ValueError, verifier.verify, hash_obj, signature) - - if tv.result.startswith('p'): - setattr(FIPS_ECDSA_Tests_KAT, "test_verify_positive_%d" % idx, positive_test) - else: - setattr(FIPS_ECDSA_Tests_KAT, "test_verify_negative_%d" % idx, negative_test) - - -test_vectors_sign = load_test_vectors(("Signature", "ECDSA"), - "SigGen.txt", - "ECDSA Signature Verification 186-3", - {'d': lambda x: int(x, 16)}) or [] - -for idx, tv in enumerate(test_vectors_sign): - - if isinstance(tv, str): - res = re.match(r"\[(P-[0-9]+),(SHA-[0-9]+)\]", tv) - assert res - curve_name = res.group(1) - hash_name = res.group(2).replace("-", "") - hash_module = load_hash_by_name(hash_name) - continue - - hash_obj = hash_module.new(tv.msg) - ecc_key = ECC.construct(curve=curve_name, d=tv.d) - signer = DSS.new(ecc_key, 'fips-186-3', randfunc=StrRNG(tv.k)) - - def sign_test(self, signer=signer, hash_obj=hash_obj, signature=tv.r+tv.s): - self.assertEqual(signer.sign(hash_obj), signature) - setattr(FIPS_ECDSA_Tests_KAT, "test_sign_%d" % idx, sign_test) - - -class Det_DSA_Tests(unittest.TestCase): - """Tests from rfc6979""" - - # Each key is (p, q, g, x, y, desc) - keys = [ - ( - """ - 86F5CA03DCFEB225063FF830A0C769B9DD9D6153AD91D7CE27F787C43278B447 - E6533B86B18BED6E8A48B784A14C252C5BE0DBF60B86D6385BD2F12FB763ED88 - 73ABFD3F5BA2E0A8C0A59082EAC056935E529DAF7C610467899C77ADEDFC846C - 881870B7B19B2B58F9BE0521A17002E3BDD6B86685EE90B3D9A1B02B782B1779""", - "996F967F6C8E388D9E28D01E205FBA957A5698B1", - """ - 07B0F92546150B62514BB771E2A0C0CE387F03BDA6C56B505209FF25FD3C133D - 89BBCD97E904E09114D9A7DEFDEADFC9078EA544D2E401AEECC40BB9FBBF78FD - 87995A10A1C27CB7789B594BA7EFB5C4326A9FE59A070E136DB77175464ADCA4 - 17BE5DCE2F40D10A46A3A3943F26AB7FD9C0398FF8C76EE0A56826A8A88F1DBD""", - "411602CB19A6CCC34494D79D98EF1E7ED5AF25F7", - """ - 5DF5E01DED31D0297E274E1691C192FE5868FEF9E19A84776454B100CF16F653 - 92195A38B90523E2542EE61871C0440CB87C322FC4B4D2EC5E1E7EC766E1BE8D - 4CE935437DC11C3C8FD426338933EBFE739CB3465F4D3668C5E473508253B1E6 - 82F65CBDC4FAE93C2EA212390E54905A86E2223170B44EAA7DA5DD9FFCFB7F3B""", - "DSA1024" - ), - ( - """ - 9DB6FB5951B66BB6FE1E140F1D2CE5502374161FD6538DF1648218642F0B5C48 - C8F7A41AADFA187324B87674FA1822B00F1ECF8136943D7C55757264E5A1A44F - FE012E9936E00C1D3E9310B01C7D179805D3058B2A9F4BB6F9716BFE6117C6B5 - B3CC4D9BE341104AD4A80AD6C94E005F4B993E14F091EB51743BF33050C38DE2 - 35567E1B34C3D6A5C0CEAA1A0F368213C3D19843D0B4B09DCB9FC72D39C8DE41 - F1BF14D4BB4563CA28371621CAD3324B6A2D392145BEBFAC748805236F5CA2FE - 92B871CD8F9C36D3292B5509CA8CAA77A2ADFC7BFD77DDA6F71125A7456FEA15 - 3E433256A2261C6A06ED3693797E7995FAD5AABBCFBE3EDA2741E375404AE25B""", - "F2C3119374CE76C9356990B465374A17F23F9ED35089BD969F61C6DDE9998C1F", - """ - 5C7FF6B06F8F143FE8288433493E4769C4D988ACE5BE25A0E24809670716C613 - D7B0CEE6932F8FAA7C44D2CB24523DA53FBE4F6EC3595892D1AA58C4328A06C4 - 6A15662E7EAA703A1DECF8BBB2D05DBE2EB956C142A338661D10461C0D135472 - 085057F3494309FFA73C611F78B32ADBB5740C361C9F35BE90997DB2014E2EF5 - AA61782F52ABEB8BD6432C4DD097BC5423B285DAFB60DC364E8161F4A2A35ACA - 3A10B1C4D203CC76A470A33AFDCBDD92959859ABD8B56E1725252D78EAC66E71 - BA9AE3F1DD2487199874393CD4D832186800654760E1E34C09E4D155179F9EC0 - DC4473F996BDCE6EED1CABED8B6F116F7AD9CF505DF0F998E34AB27514B0FFE7""", - "69C7548C21D0DFEA6B9A51C9EAD4E27C33D3B3F180316E5BCAB92C933F0E4DBC", - """ - 667098C654426C78D7F8201EAC6C203EF030D43605032C2F1FA937E5237DBD94 - 9F34A0A2564FE126DC8B715C5141802CE0979C8246463C40E6B6BDAA2513FA61 - 1728716C2E4FD53BC95B89E69949D96512E873B9C8F8DFD499CC312882561ADE - CB31F658E934C0C197F2C4D96B05CBAD67381E7B768891E4DA3843D24D94CDFB - 5126E9B8BF21E8358EE0E0A30EF13FD6A664C0DCE3731F7FB49A4845A4FD8254 - 687972A2D382599C9BAC4E0ED7998193078913032558134976410B89D2C171D1 - 23AC35FD977219597AA7D15C1A9A428E59194F75C721EBCBCFAE44696A499AFA - 74E04299F132026601638CB87AB79190D4A0986315DA8EEC6561C938996BEADF""", - "DSA2048" - ), - ] - - # This is a sequence of items: - # message, k, r, s, hash module - signatures = [ - ( - "sample", - "7BDB6B0FF756E1BB5D53583EF979082F9AD5BD5B", - "2E1A0C2562B2912CAAF89186FB0F42001585DA55", - "29EFB6B0AFF2D7A68EB70CA313022253B9A88DF5", - SHA1, - 'DSA1024' - ), - ( - "sample", - "562097C06782D60C3037BA7BE104774344687649", - "4BC3B686AEA70145856814A6F1BB53346F02101E", - "410697B92295D994D21EDD2F4ADA85566F6F94C1", - SHA224, - 'DSA1024' - ), - ( - "sample", - "519BA0546D0C39202A7D34D7DFA5E760B318BCFB", - "81F2F5850BE5BC123C43F71A3033E9384611C545", - "4CDD914B65EB6C66A8AAAD27299BEE6B035F5E89", - SHA256, - 'DSA1024' - ), - ( - "sample", - "95897CD7BBB944AA932DBC579C1C09EB6FCFC595", - "07F2108557EE0E3921BC1774F1CA9B410B4CE65A", - "54DF70456C86FAC10FAB47C1949AB83F2C6F7595", - SHA384, - 'DSA1024' - ), - ( - "sample", - "09ECE7CA27D0F5A4DD4E556C9DF1D21D28104F8B", - "16C3491F9B8C3FBBDD5E7A7B667057F0D8EE8E1B", - "02C36A127A7B89EDBB72E4FFBC71DABC7D4FC69C", - SHA512, - 'DSA1024' - ), - ( - "test", - "5C842DF4F9E344EE09F056838B42C7A17F4A6433", - "42AB2052FD43E123F0607F115052A67DCD9C5C77", - "183916B0230D45B9931491D4C6B0BD2FB4AAF088", - SHA1, - 'DSA1024' - ), - ( - "test", - "4598B8EFC1A53BC8AECD58D1ABBB0C0C71E67297", - "6868E9964E36C1689F6037F91F28D5F2C30610F2", - "49CEC3ACDC83018C5BD2674ECAAD35B8CD22940F", - SHA224, - 'DSA1024' - ), - ( - "test", - "5A67592E8128E03A417B0484410FB72C0B630E1A", - "22518C127299B0F6FDC9872B282B9E70D0790812", - "6837EC18F150D55DE95B5E29BE7AF5D01E4FE160", - SHA256, - 'DSA1024' - ), - ( - "test", - "220156B761F6CA5E6C9F1B9CF9C24BE25F98CD89", - "854CF929B58D73C3CBFDC421E8D5430CD6DB5E66", - "91D0E0F53E22F898D158380676A871A157CDA622", - SHA384, - 'DSA1024' - ), - ( - "test", - "65D2C2EEB175E370F28C75BFCDC028D22C7DBE9C", - "8EA47E475BA8AC6F2D821DA3BD212D11A3DEB9A0", - "7C670C7AD72B6C050C109E1790008097125433E8", - SHA512, - 'DSA1024' - ), - ( - "sample", - "888FA6F7738A41BDC9846466ABDB8174C0338250AE50CE955CA16230F9CBD53E", - "3A1B2DBD7489D6ED7E608FD036C83AF396E290DBD602408E8677DAABD6E7445A", - "D26FCBA19FA3E3058FFC02CA1596CDBB6E0D20CB37B06054F7E36DED0CDBBCCF", - SHA1, - 'DSA2048' - ), - ( - "sample", - "BC372967702082E1AA4FCE892209F71AE4AD25A6DFD869334E6F153BD0C4D806", - "DC9F4DEADA8D8FF588E98FED0AB690FFCE858DC8C79376450EB6B76C24537E2C", - "A65A9C3BC7BABE286B195D5DA68616DA8D47FA0097F36DD19F517327DC848CEC", - SHA224, - 'DSA2048' - ), - ( - "sample", - "8926A27C40484216F052F4427CFD5647338B7B3939BC6573AF4333569D597C52", - "EACE8BDBBE353C432A795D9EC556C6D021F7A03F42C36E9BC87E4AC7932CC809", - "7081E175455F9247B812B74583E9E94F9EA79BD640DC962533B0680793A38D53", - SHA256, - 'DSA2048' - ), - ( - "sample", - "C345D5AB3DA0A5BCB7EC8F8FB7A7E96069E03B206371EF7D83E39068EC564920", - "B2DA945E91858834FD9BF616EBAC151EDBC4B45D27D0DD4A7F6A22739F45C00B", - "19048B63D9FD6BCA1D9BAE3664E1BCB97F7276C306130969F63F38FA8319021B", - SHA384, - 'DSA2048' - ), - ( - "sample", - "5A12994431785485B3F5F067221517791B85A597B7A9436995C89ED0374668FC", - "2016ED092DC5FB669B8EFB3D1F31A91EECB199879BE0CF78F02BA062CB4C942E", - "D0C76F84B5F091E141572A639A4FB8C230807EEA7D55C8A154A224400AFF2351", - SHA512, - 'DSA2048' - ), - ( - "test", - "6EEA486F9D41A037B2C640BC5645694FF8FF4B98D066A25F76BE641CCB24BA4F", - "C18270A93CFC6063F57A4DFA86024F700D980E4CF4E2CB65A504397273D98EA0", - "414F22E5F31A8B6D33295C7539C1C1BA3A6160D7D68D50AC0D3A5BEAC2884FAA", - SHA1, - 'DSA2048' - ), - ( - "test", - "06BD4C05ED74719106223BE33F2D95DA6B3B541DAD7BFBD7AC508213B6DA6670", - "272ABA31572F6CC55E30BF616B7A265312018DD325BE031BE0CC82AA17870EA3", - "E9CC286A52CCE201586722D36D1E917EB96A4EBDB47932F9576AC645B3A60806", - SHA224, - 'DSA2048' - ), - ( - "test", - "1D6CE6DDA1C5D37307839CD03AB0A5CBB18E60D800937D67DFB4479AAC8DEAD7", - "8190012A1969F9957D56FCCAAD223186F423398D58EF5B3CEFD5A4146A4476F0", - "7452A53F7075D417B4B013B278D1BB8BBD21863F5E7B1CEE679CF2188E1AB19E", - SHA256, - 'DSA2048' - ), - ( - "test", - "206E61F73DBE1B2DC8BE736B22B079E9DACD974DB00EEBBC5B64CAD39CF9F91C", - "239E66DDBE8F8C230A3D071D601B6FFBDFB5901F94D444C6AF56F732BEB954BE", - "6BD737513D5E72FE85D1C750E0F73921FE299B945AAD1C802F15C26A43D34961", - SHA384, - 'DSA2048' - ), - ( - "test", - "AFF1651E4CD6036D57AA8B2A05CCF1A9D5A40166340ECBBDC55BE10B568AA0AA", - "89EC4BB1400ECCFF8E7D9AA515CD1DE7803F2DAFF09693EE7FD1353E90A68307", - "C9F0BDABCC0D880BB137A994CC7F3980CE91CC10FAF529FC46565B15CEA854E1", - SHA512, - 'DSA2048' - ) - ] - - def setUp(self): - # Convert DSA key components from hex strings to integers - # Each key is (p, q, g, x, y, desc) - - from collections import namedtuple - - TestKey = namedtuple('TestKey', 'p q g x y') - new_keys = {} - for k in self.keys: - tk = TestKey(*[t2l(y) for y in k[:-1]]) - new_keys[k[-1]] = tk - self.keys = new_keys - - # Convert signature encoding - TestSig = namedtuple('TestSig', 'message nonce result module test_key') - new_signatures = [] - for message, nonce, r, s, module, test_key in self.signatures: - tsig = TestSig( - tobytes(message), - t2l(nonce), - t2b(r) + t2b(s), - module, - self.keys[test_key] - ) - new_signatures.append(tsig) - self.signatures = new_signatures - - def test1(self): - q = 0x4000000000000000000020108A2E0CC0D99F8A5EF - x = 0x09A4D6792295A7F730FC3F2B49CBC0F62E862272F - p = 2 * q + 1 - y = pow(2, x, p) - key = DSA.construct([pow(y, 2, p), 2, p, q, x], False) - signer = DSS.new(key, 'deterministic-rfc6979') - - # Test _int2octets - self.assertEqual(hexlify(signer._int2octets(x)), - b'009a4d6792295a7f730fc3f2b49cbc0f62e862272f') - - # Test _bits2octets - h1 = SHA256.new(b"sample").digest() - self.assertEqual(hexlify(signer._bits2octets(h1)), - b'01795edf0d54db760f156d0dac04c0322b3a204224') - - def test2(self): - - for sig in self.signatures: - tk = sig.test_key - key = DSA.construct([tk.y, tk.g, tk.p, tk.q, tk.x], False) - signer = DSS.new(key, 'deterministic-rfc6979') - - hash_obj = sig.module.new(sig.message) - result = signer.sign(hash_obj) - self.assertEqual(sig.result, result) - - -class Det_ECDSA_Tests(unittest.TestCase): - - key_priv_p256 = ECC.construct(curve="P-256", d=0xC9AFA9D845BA75166B5C215767B1D6934E50C3DB36E89B127B8A622B120F6721) - key_pub_p256 = key_priv_p256.public_key() - - key_priv_p384 = ECC.construct(curve="P-384", d=0x6B9D3DAD2E1B8C1C05B19875B6659F4DE23C3B667BF297BA9AA47740787137D896D5724E4C70A825F872C9EA60D2EDF5) - key_pub_p384 = key_priv_p384.public_key() - - key_priv_p521 = ECC.construct(curve="P-521", d=0x0FAD06DAA62BA3B25D2FB40133DA757205DE67F5BB0018FEE8C86E1B68C7E75CAA896EB32F1F47C70855836A6D16FCC1466F6D8FBEC67DB89EC0C08B0E996B83538) - key_pub_p521 = key_priv_p521.public_key() - - # This is a sequence of items: - # message, k, r, s, hash module - # taken from RFC6979 - signatures_p256_ = ( - ( - "sample", - "882905F1227FD620FBF2ABF21244F0BA83D0DC3A9103DBBEE43A1FB858109DB4", - "61340C88C3AAEBEB4F6D667F672CA9759A6CCAA9FA8811313039EE4A35471D32", - "6D7F147DAC089441BB2E2FE8F7A3FA264B9C475098FDCF6E00D7C996E1B8B7EB", - SHA1 - ), - ( - "sample", - "103F90EE9DC52E5E7FB5132B7033C63066D194321491862059967C715985D473", - "53B2FFF5D1752B2C689DF257C04C40A587FABABB3F6FC2702F1343AF7CA9AA3F", - "B9AFB64FDC03DC1A131C7D2386D11E349F070AA432A4ACC918BEA988BF75C74C", - SHA224 - ), - ( - "sample", - "A6E3C57DD01ABE90086538398355DD4C3B17AA873382B0F24D6129493D8AAD60", - "EFD48B2AACB6A8FD1140DD9CD45E81D69D2C877B56AAF991C34D0EA84EAF3716", - "F7CB1C942D657C41D436C7A1B6E29F65F3E900DBB9AFF4064DC4AB2F843ACDA8", - SHA256 - ), - ( - "sample", - "09F634B188CEFD98E7EC88B1AA9852D734D0BC272F7D2A47DECC6EBEB375AAD4", - "0EAFEA039B20E9B42309FB1D89E213057CBF973DC0CFC8F129EDDDC800EF7719", - "4861F0491E6998B9455193E34E7B0D284DDD7149A74B95B9261F13ABDE940954", - SHA384 - ), - ( - "sample", - "5FA81C63109BADB88C1F367B47DA606DA28CAD69AA22C4FE6AD7DF73A7173AA5", - "8496A60B5E9B47C825488827E0495B0E3FA109EC4568FD3F8D1097678EB97F00", - "2362AB1ADBE2B8ADF9CB9EDAB740EA6049C028114F2460F96554F61FAE3302FE", - SHA512 - ), - ( - "test", - "8C9520267C55D6B980DF741E56B4ADEE114D84FBFA2E62137954164028632A2E", - "0CBCC86FD6ABD1D99E703E1EC50069EE5C0B4BA4B9AC60E409E8EC5910D81A89", - "01B9D7B73DFAA60D5651EC4591A0136F87653E0FD780C3B1BC872FFDEAE479B1", - SHA1 - ), - ( - "test", - "669F4426F2688B8BE0DB3A6BD1989BDAEFFF84B649EEB84F3DD26080F667FAA7", - "C37EDB6F0AE79D47C3C27E962FA269BB4F441770357E114EE511F662EC34A692", - "C820053A05791E521FCAAD6042D40AEA1D6B1A540138558F47D0719800E18F2D", - SHA224 - ), - ( - "test", - "D16B6AE827F17175E040871A1C7EC3500192C4C92677336EC2537ACAEE0008E0", - "F1ABB023518351CD71D881567B1EA663ED3EFCF6C5132B354F28D3B0B7D38367", - "019F4113742A2B14BD25926B49C649155F267E60D3814B4C0CC84250E46F0083", - SHA256 - ), - ( - "test", - "16AEFFA357260B04B1DD199693960740066C1A8F3E8EDD79070AA914D361B3B8", - "83910E8B48BB0C74244EBDF7F07A1C5413D61472BD941EF3920E623FBCCEBEB6", - "8DDBEC54CF8CD5874883841D712142A56A8D0F218F5003CB0296B6B509619F2C", - SHA384 - ), - ( - "test", - "6915D11632ACA3C40D5D51C08DAF9C555933819548784480E93499000D9F0B7F", - "461D93F31B6540894788FD206C07CFA0CC35F46FA3C91816FFF1040AD1581A04", - "39AF9F15DE0DB8D97E72719C74820D304CE5226E32DEDAE67519E840D1194E55", - SHA512 - ) - ) - - signatures_p384_ = ( - ( - "sample", - "4471EF7518BB2C7C20F62EAE1C387AD0C5E8E470995DB4ACF694466E6AB096630F29E5938D25106C3C340045A2DB01A7", - "EC748D839243D6FBEF4FC5C4859A7DFFD7F3ABDDF72014540C16D73309834FA37B9BA002899F6FDA3A4A9386790D4EB2", - "A3BCFA947BEEF4732BF247AC17F71676CB31A847B9FF0CBC9C9ED4C1A5B3FACF26F49CA031D4857570CCB5CA4424A443", - SHA1 - ), - ( - "sample", - "A4E4D2F0E729EB786B31FC20AD5D849E304450E0AE8E3E341134A5C1AFA03CAB8083EE4E3C45B06A5899EA56C51B5879", - "42356E76B55A6D9B4631C865445DBE54E056D3B3431766D0509244793C3F9366450F76EE3DE43F5A125333A6BE060122", - "9DA0C81787064021E78DF658F2FBB0B042BF304665DB721F077A4298B095E4834C082C03D83028EFBF93A3C23940CA8D", - SHA224 - ), - ( - "sample", - "180AE9F9AEC5438A44BC159A1FCB277C7BE54FA20E7CF404B490650A8ACC414E375572342863C899F9F2EDF9747A9B60", - "21B13D1E013C7FA1392D03C5F99AF8B30C570C6F98D4EA8E354B63A21D3DAA33BDE1E888E63355D92FA2B3C36D8FB2CD", - "F3AA443FB107745BF4BD77CB3891674632068A10CA67E3D45DB2266FA7D1FEEBEFDC63ECCD1AC42EC0CB8668A4FA0AB0", - SHA256 - ), - ( - "sample", - "94ED910D1A099DAD3254E9242AE85ABDE4BA15168EAF0CA87A555FD56D10FBCA2907E3E83BA95368623B8C4686915CF9", - "94EDBB92A5ECB8AAD4736E56C691916B3F88140666CE9FA73D64C4EA95AD133C81A648152E44ACF96E36DD1E80FABE46", - "99EF4AEB15F178CEA1FE40DB2603138F130E740A19624526203B6351D0A3A94FA329C145786E679E7B82C71A38628AC8", - SHA384 - ), - ( - "sample", - "92FC3C7183A883E24216D1141F1A8976C5B0DD797DFA597E3D7B32198BD35331A4E966532593A52980D0E3AAA5E10EC3", - "ED0959D5880AB2D869AE7F6C2915C6D60F96507F9CB3E047C0046861DA4A799CFE30F35CC900056D7C99CD7882433709", - "512C8CCEEE3890A84058CE1E22DBC2198F42323CE8ACA9135329F03C068E5112DC7CC3EF3446DEFCEB01A45C2667FDD5", - SHA512 - ), - ( - "test", - "66CC2C8F4D303FC962E5FF6A27BD79F84EC812DDAE58CF5243B64A4AD8094D47EC3727F3A3C186C15054492E30698497", - "4BC35D3A50EF4E30576F58CD96CE6BF638025EE624004A1F7789A8B8E43D0678ACD9D29876DAF46638645F7F404B11C7", - "D5A6326C494ED3FF614703878961C0FDE7B2C278F9A65FD8C4B7186201A2991695BA1C84541327E966FA7B50F7382282", - SHA1 - ), - ( - "test", - "18FA39DB95AA5F561F30FA3591DC59C0FA3653A80DAFFA0B48D1A4C6DFCBFF6E3D33BE4DC5EB8886A8ECD093F2935726", - "E8C9D0B6EA72A0E7837FEA1D14A1A9557F29FAA45D3E7EE888FC5BF954B5E62464A9A817C47FF78B8C11066B24080E72", - "07041D4A7A0379AC7232FF72E6F77B6DDB8F09B16CCE0EC3286B2BD43FA8C6141C53EA5ABEF0D8231077A04540A96B66", - SHA224 - ), - ( - "test", - "0CFAC37587532347DC3389FDC98286BBA8C73807285B184C83E62E26C401C0FAA48DD070BA79921A3457ABFF2D630AD7", - "6D6DEFAC9AB64DABAFE36C6BF510352A4CC27001263638E5B16D9BB51D451559F918EEDAF2293BE5B475CC8F0188636B", - "2D46F3BECBCC523D5F1A1256BF0C9B024D879BA9E838144C8BA6BAEB4B53B47D51AB373F9845C0514EEFB14024787265", - SHA256 - ), - ( - "test", - "015EE46A5BF88773ED9123A5AB0807962D193719503C527B031B4C2D225092ADA71F4A459BC0DA98ADB95837DB8312EA", - "8203B63D3C853E8D77227FB377BCF7B7B772E97892A80F36AB775D509D7A5FEB0542A7F0812998DA8F1DD3CA3CF023DB", - "DDD0760448D42D8A43AF45AF836FCE4DE8BE06B485E9B61B827C2F13173923E06A739F040649A667BF3B828246BAA5A5", - SHA384 - ), - ( - "test", - "3780C4F67CB15518B6ACAE34C9F83568D2E12E47DEAB6C50A4E4EE5319D1E8CE0E2CC8A136036DC4B9C00E6888F66B6C", - "A0D5D090C9980FAF3C2CE57B7AE951D31977DD11C775D314AF55F76C676447D06FB6495CD21B4B6E340FC236584FB277", - "976984E59B4C77B0E8E4460DCA3D9F20E07B9BB1F63BEEFAF576F6B2E8B224634A2092CD3792E0159AD9CEE37659C736", - SHA512 - ), - ) - - signatures_p521_ = ( - ( - "sample", - "0089C071B419E1C2820962321787258469511958E80582E95D8378E0C2CCDB3CB42BEDE42F50E3FA3C71F5A76724281D31D9C89F0F91FC1BE4918DB1C03A5838D0F9", - "00343B6EC45728975EA5CBA6659BBB6062A5FF89EEA58BE3C80B619F322C87910FE092F7D45BB0F8EEE01ED3F20BABEC079D202AE677B243AB40B5431D497C55D75D", - "00E7B0E675A9B24413D448B8CC119D2BF7B2D2DF032741C096634D6D65D0DBE3D5694625FB9E8104D3B842C1B0E2D0B98BEA19341E8676AEF66AE4EBA3D5475D5D16", - SHA1 - ), - ( - "sample", - "0121415EC2CD7726330A61F7F3FA5DE14BE9436019C4DB8CB4041F3B54CF31BE0493EE3F427FB906393D895A19C9523F3A1D54BB8702BD4AA9C99DAB2597B92113F3", - "01776331CFCDF927D666E032E00CF776187BC9FDD8E69D0DABB4109FFE1B5E2A30715F4CC923A4A5E94D2503E9ACFED92857B7F31D7152E0F8C00C15FF3D87E2ED2E", - "0050CB5265417FE2320BBB5A122B8E1A32BD699089851128E360E620A30C7E17BA41A666AF126CE100E5799B153B60528D5300D08489CA9178FB610A2006C254B41F", - SHA224 - ), - ( - "sample", - "00EDF38AFCAAECAB4383358B34D67C9F2216C8382AAEA44A3DAD5FDC9C32575761793FEF24EB0FC276DFC4F6E3EC476752F043CF01415387470BCBD8678ED2C7E1A0", - "01511BB4D675114FE266FC4372B87682BAECC01D3CC62CF2303C92B3526012659D16876E25C7C1E57648F23B73564D67F61C6F14D527D54972810421E7D87589E1A7", - "004A171143A83163D6DF460AAF61522695F207A58B95C0644D87E52AA1A347916E4F7A72930B1BC06DBE22CE3F58264AFD23704CBB63B29B931F7DE6C9D949A7ECFC", - SHA256 - ), - ( - "sample", - "01546A108BC23A15D6F21872F7DED661FA8431DDBD922D0DCDB77CC878C8553FFAD064C95A920A750AC9137E527390D2D92F153E66196966EA554D9ADFCB109C4211", - "01EA842A0E17D2DE4F92C15315C63DDF72685C18195C2BB95E572B9C5136CA4B4B576AD712A52BE9730627D16054BA40CC0B8D3FF035B12AE75168397F5D50C67451", - "01F21A3CEE066E1961025FB048BD5FE2B7924D0CD797BABE0A83B66F1E35EEAF5FDE143FA85DC394A7DEE766523393784484BDF3E00114A1C857CDE1AA203DB65D61", - SHA384 - ), - ( - "sample", - "01DAE2EA071F8110DC26882D4D5EAE0621A3256FC8847FB9022E2B7D28E6F10198B1574FDD03A9053C08A1854A168AA5A57470EC97DD5CE090124EF52A2F7ECBFFD3", - "00C328FAFCBD79DD77850370C46325D987CB525569FB63C5D3BC53950E6D4C5F174E25A1EE9017B5D450606ADD152B534931D7D4E8455CC91F9B15BF05EC36E377FA", - "00617CCE7CF5064806C467F678D3B4080D6F1CC50AF26CA209417308281B68AF282623EAA63E5B5C0723D8B8C37FF0777B1A20F8CCB1DCCC43997F1EE0E44DA4A67A", - SHA512 - ), - ( - "test", - "00BB9F2BF4FE1038CCF4DABD7139A56F6FD8BB1386561BD3C6A4FC818B20DF5DDBA80795A947107A1AB9D12DAA615B1ADE4F7A9DC05E8E6311150F47F5C57CE8B222", - "013BAD9F29ABE20DE37EBEB823C252CA0F63361284015A3BF430A46AAA80B87B0693F0694BD88AFE4E661FC33B094CD3B7963BED5A727ED8BD6A3A202ABE009D0367", - "01E9BB81FF7944CA409AD138DBBEE228E1AFCC0C890FC78EC8604639CB0DBDC90F717A99EAD9D272855D00162EE9527567DD6A92CBD629805C0445282BBC916797FF", - SHA1 - ), - ( - "test", - "0040D09FCF3C8A5F62CF4FB223CBBB2B9937F6B0577C27020A99602C25A01136987E452988781484EDBBCF1C47E554E7FC901BC3085E5206D9F619CFF07E73D6F706", - "01C7ED902E123E6815546065A2C4AF977B22AA8EADDB68B2C1110E7EA44D42086BFE4A34B67DDC0E17E96536E358219B23A706C6A6E16BA77B65E1C595D43CAE17FB", - "0177336676304FCB343CE028B38E7B4FBA76C1C1B277DA18CAD2A8478B2A9A9F5BEC0F3BA04F35DB3E4263569EC6AADE8C92746E4C82F8299AE1B8F1739F8FD519A4", - SHA224 - ), - ( - "test", - "001DE74955EFAABC4C4F17F8E84D881D1310B5392D7700275F82F145C61E843841AF09035BF7A6210F5A431A6A9E81C9323354A9E69135D44EBD2FCAA7731B909258", - "000E871C4A14F993C6C7369501900C4BC1E9C7B0B4BA44E04868B30B41D8071042EB28C4C250411D0CE08CD197E4188EA4876F279F90B3D8D74A3C76E6F1E4656AA8", - "00CD52DBAA33B063C3A6CD8058A1FB0A46A4754B034FCC644766CA14DA8CA5CA9FDE00E88C1AD60CCBA759025299079D7A427EC3CC5B619BFBC828E7769BCD694E86", - SHA256 - ), - ( - "test", - "01F1FC4A349A7DA9A9E116BFDD055DC08E78252FF8E23AC276AC88B1770AE0B5DCEB1ED14A4916B769A523CE1E90BA22846AF11DF8B300C38818F713DADD85DE0C88", - "014BEE21A18B6D8B3C93FAB08D43E739707953244FDBE924FA926D76669E7AC8C89DF62ED8975C2D8397A65A49DCC09F6B0AC62272741924D479354D74FF6075578C", - "0133330865C067A0EAF72362A65E2D7BC4E461E8C8995C3B6226A21BD1AA78F0ED94FE536A0DCA35534F0CD1510C41525D163FE9D74D134881E35141ED5E8E95B979", - SHA384 - ), - ( - "test", - "016200813020EC986863BEDFC1B121F605C1215645018AEA1A7B215A564DE9EB1B38A67AA1128B80CE391C4FB71187654AAA3431027BFC7F395766CA988C964DC56D", - "013E99020ABF5CEE7525D16B69B229652AB6BDF2AFFCAEF38773B4B7D08725F10CDB93482FDCC54EDCEE91ECA4166B2A7C6265EF0CE2BD7051B7CEF945BABD47EE6D", - "01FBD0013C674AA79CB39849527916CE301C66EA7CE8B80682786AD60F98F7E78A19CA69EFF5C57400E3B3A0AD66CE0978214D13BAF4E9AC60752F7B155E2DE4DCE3", - SHA512 - ), - ) - - signatures_p256 = [] - for a, b, c, d, e in signatures_p256_: - new_tv = (tobytes(a), unhexlify(b), unhexlify(c), unhexlify(d), e) - signatures_p256.append(new_tv) - - signatures_p384 = [] - for a, b, c, d, e in signatures_p384_: - new_tv = (tobytes(a), unhexlify(b), unhexlify(c), unhexlify(d), e) - signatures_p384.append(new_tv) - - signatures_p521 = [] - for a, b, c, d, e in signatures_p521_: - new_tv = (tobytes(a), unhexlify(b), unhexlify(c), unhexlify(d), e) - signatures_p521.append(new_tv) - - def shortDescription(self): - return "Deterministic ECDSA Tests" - - def test_loopback_p256(self): - hashed_msg = SHA512.new(b"test") - signer = DSS.new(self.key_priv_p256, 'deterministic-rfc6979') - signature = signer.sign(hashed_msg) - - verifier = DSS.new(self.key_pub_p256, 'deterministic-rfc6979') - verifier.verify(hashed_msg, signature) - - def test_loopback_p384(self): - hashed_msg = SHA512.new(b"test") - signer = DSS.new(self.key_priv_p384, 'deterministic-rfc6979') - signature = signer.sign(hashed_msg) - - verifier = DSS.new(self.key_pub_p384, 'deterministic-rfc6979') - verifier.verify(hashed_msg, signature) - - def test_loopback_p521(self): - hashed_msg = SHA512.new(b"test") - signer = DSS.new(self.key_priv_p521, 'deterministic-rfc6979') - signature = signer.sign(hashed_msg) - - verifier = DSS.new(self.key_pub_p521, 'deterministic-rfc6979') - verifier.verify(hashed_msg, signature) - - def test_data_rfc6979_p256(self): - signer = DSS.new(self.key_priv_p256, 'deterministic-rfc6979') - for message, k, r, s, module in self.signatures_p256: - hash_obj = module.new(message) - result = signer.sign(hash_obj) - self.assertEqual(r + s, result) - - def test_data_rfc6979_p384(self): - signer = DSS.new(self.key_priv_p384, 'deterministic-rfc6979') - for message, k, r, s, module in self.signatures_p384: - hash_obj = module.new(message) - result = signer.sign(hash_obj) - self.assertEqual(r + s, result) - - def test_data_rfc6979_p521(self): - signer = DSS.new(self.key_priv_p521, 'deterministic-rfc6979') - for message, k, r, s, module in self.signatures_p521: - hash_obj = module.new(message) - result = signer.sign(hash_obj) - self.assertEqual(r + s, result) - - -def get_hash_module(hash_name): - if hash_name == "SHA-512": - hash_module = SHA512 - elif hash_name == "SHA-512/224": - hash_module = SHA512.new(truncate="224") - elif hash_name == "SHA-512/256": - hash_module = SHA512.new(truncate="256") - elif hash_name == "SHA-384": - hash_module = SHA384 - elif hash_name == "SHA-256": - hash_module = SHA256 - elif hash_name == "SHA-224": - hash_module = SHA224 - elif hash_name == "SHA-1": - hash_module = SHA1 - else: - raise ValueError("Unknown hash algorithm: " + hash_name) - return hash_module - - -class TestVectorsDSAWycheproof(unittest.TestCase): - - def __init__(self, wycheproof_warnings, slow_tests): - unittest.TestCase.__init__(self) - self._wycheproof_warnings = wycheproof_warnings - self._slow_tests = slow_tests - self._id = "None" - self.tv = [] - - def setUp(self): - - def filter_dsa(group): - return DSA.import_key(group['keyPem']) - - def filter_sha(group): - return get_hash_module(group['sha']) - - def filter_type(group): - sig_type = group['type'] - if sig_type != 'DsaVerify': - raise ValueError("Unknown signature type " + sig_type) - return sig_type - - result = load_test_vectors_wycheproof(("Signature", "wycheproof"), - "dsa_test.json", - "Wycheproof DSA signature", - group_tag={'key': filter_dsa, - 'hash_module': filter_sha, - 'sig_type': filter_type}) - self.tv += result - - def shortDescription(self): - return self._id - - def warn(self, tv): - if tv.warning and self._wycheproof_warnings: - import warnings - warnings.warn("Wycheproof warning: %s (%s)" % (self._id, tv.comment)) - - def test_verify(self, tv): - self._id = "Wycheproof DSA Test #" + str(tv.id) - - hashed_msg = tv.hash_module.new(tv.msg) - signer = DSS.new(tv.key, 'fips-186-3', encoding='der') - try: - signature = signer.verify(hashed_msg, tv.sig) - except ValueError as e: - if tv.warning: - return - assert not tv.valid - else: - assert tv.valid - self.warn(tv) - - def runTest(self): - for tv in self.tv: - self.test_verify(tv) - - -class TestVectorsECDSAWycheproof(unittest.TestCase): - - def __init__(self, wycheproof_warnings, slow_tests): - unittest.TestCase.__init__(self) - self._wycheproof_warnings = wycheproof_warnings - self._slow_tests = slow_tests - self._id = "None" - - def add_tests(self, filename): - - def filter_ecc(group): - # These are the only curves we accept to skip - if group['key']['curve'] in ('secp224r1', 'secp224k1', 'secp256k1', - 'brainpoolP224r1', 'brainpoolP224t1', - 'brainpoolP256r1', 'brainpoolP256t1', - 'brainpoolP320r1', 'brainpoolP320t1', - 'brainpoolP384r1', 'brainpoolP384t1', - 'brainpoolP512r1', 'brainpoolP512t1', - ): - return None - return ECC.import_key(group['keyPem']) - - def filter_sha(group): - return get_hash_module(group['sha']) - - def filter_encoding(group): - encoding_name = group['type'] - if encoding_name == "EcdsaVerify": - return "der" - elif encoding_name == "EcdsaP1363Verify": - return "binary" - else: - raise ValueError("Unknown signature type " + encoding_name) - - result = load_test_vectors_wycheproof(("Signature", "wycheproof"), - filename, - "Wycheproof ECDSA signature (%s)" % filename, - group_tag={'key': filter_ecc, - 'hash_module': filter_sha, - 'encoding': filter_encoding, - }) - self.tv += result - - def setUp(self): - self.tv = [] - self.add_tests("ecdsa_secp224r1_sha224_p1363_test.json") - self.add_tests("ecdsa_secp224r1_sha224_test.json") - if self._slow_tests: - self.add_tests("ecdsa_secp224r1_sha256_p1363_test.json") - self.add_tests("ecdsa_secp224r1_sha256_test.json") - self.add_tests("ecdsa_secp224r1_sha3_224_test.json") - self.add_tests("ecdsa_secp224r1_sha3_256_test.json") - self.add_tests("ecdsa_secp224r1_sha3_512_test.json") - self.add_tests("ecdsa_secp224r1_sha512_p1363_test.json") - self.add_tests("ecdsa_secp224r1_sha512_test.json") - self.add_tests("ecdsa_secp256r1_sha256_p1363_test.json") - self.add_tests("ecdsa_secp256r1_sha256_test.json") - self.add_tests("ecdsa_secp256r1_sha3_256_test.json") - self.add_tests("ecdsa_secp256r1_sha3_512_test.json") - self.add_tests("ecdsa_secp256r1_sha512_p1363_test.json") - self.add_tests("ecdsa_secp256r1_sha512_test.json") - if self._slow_tests: - self.add_tests("ecdsa_secp384r1_sha3_384_test.json") - self.add_tests("ecdsa_secp384r1_sha3_512_test.json") - self.add_tests("ecdsa_secp384r1_sha384_p1363_test.json") - self.add_tests("ecdsa_secp384r1_sha384_test.json") - self.add_tests("ecdsa_secp384r1_sha512_p1363_test.json") - self.add_tests("ecdsa_secp384r1_sha512_test.json") - if self._slow_tests: - self.add_tests("ecdsa_secp521r1_sha3_512_test.json") - self.add_tests("ecdsa_secp521r1_sha512_p1363_test.json") - self.add_tests("ecdsa_secp521r1_sha512_test.json") - self.add_tests("ecdsa_test.json") - self.add_tests("ecdsa_webcrypto_test.json") - - def shortDescription(self): - return self._id - - def warn(self, tv): - if tv.warning and self._wycheproof_warnings: - import warnings - warnings.warn("Wycheproof warning: %s (%s)" % (self._id, tv.comment)) - - def test_verify(self, tv): - self._id = "Wycheproof ECDSA Test #%d (%s, %s)" % (tv.id, tv.comment, tv.filename) - - # Skip tests with unsupported curves - if tv.key is None: - return - - hashed_msg = tv.hash_module.new(tv.msg) - signer = DSS.new(tv.key, 'fips-186-3', encoding=tv.encoding) - try: - signature = signer.verify(hashed_msg, tv.sig) - except ValueError as e: - if tv.warning: - return - if tv.comment == "k*G has a large x-coordinate": - return - assert not tv.valid - else: - assert tv.valid - self.warn(tv) - - def runTest(self): - for tv in self.tv: - self.test_verify(tv) - - -def get_tests(config={}): - wycheproof_warnings = config.get('wycheproof_warnings') - - tests = [] - tests += list_test_cases(FIPS_DSA_Tests) - tests += list_test_cases(FIPS_ECDSA_Tests) - tests += list_test_cases(Det_DSA_Tests) - tests += list_test_cases(Det_ECDSA_Tests) - - slow_tests = not config.get('slow_tests') - if slow_tests: - tests += list_test_cases(FIPS_DSA_Tests_KAT) - tests += list_test_cases(FIPS_ECDSA_Tests_KAT) - - tests += [TestVectorsDSAWycheproof(wycheproof_warnings, slow_tests)] - tests += [TestVectorsECDSAWycheproof(wycheproof_warnings, slow_tests)] - - return tests - - -if __name__ == '__main__': - def suite(): - return unittest.TestSuite(get_tests()) - unittest.main(defaultTest='suite') diff --git a/Crypto/SelfTest/Signature/test_pkcs1_15.py b/Crypto/SelfTest/Signature/test_pkcs1_15.py deleted file mode 100644 index 8e2c6ee..0000000 --- a/Crypto/SelfTest/Signature/test_pkcs1_15.py +++ /dev/null @@ -1,348 +0,0 @@ -# =================================================================== -# -# Copyright (c) 2014, Legrandin -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# =================================================================== - -import json -import unittest -from binascii import unhexlify - -from Crypto.Util.py3compat import bchr -from Crypto.Util.number import bytes_to_long -from Crypto.Util.strxor import strxor -from Crypto.SelfTest.st_common import list_test_cases -from Crypto.SelfTest.loader import load_test_vectors, load_test_vectors_wycheproof - -from Crypto.Hash import (SHA1, SHA224, SHA256, SHA384, SHA512, SHA3_384, - SHA3_224, SHA3_256, SHA3_512) -from Crypto.PublicKey import RSA -from Crypto.Signature import pkcs1_15 -from Crypto.Signature import PKCS1_v1_5 - -from Crypto.Util._file_system import pycryptodome_filename -from Crypto.Util.strxor import strxor - - -def load_hash_by_name(hash_name): - return __import__("Crypto.Hash." + hash_name, globals(), locals(), ["new"]) - - -class FIPS_PKCS1_Verify_Tests(unittest.TestCase): - - def shortDescription(self): - return "FIPS PKCS1 Tests (Verify)" - - def test_can_sign(self): - test_public_key = RSA.generate(1024).public_key() - verifier = pkcs1_15.new(test_public_key) - self.assertEqual(verifier.can_sign(), False) - - -class FIPS_PKCS1_Verify_Tests_KAT(unittest.TestCase): - pass - - -test_vectors_verify = load_test_vectors(("Signature", "PKCS1-v1.5"), - "SigVer15_186-3.rsp", - "Signature Verification 186-3", - {'shaalg': lambda x: x, - 'd': lambda x: int(x), - 'result': lambda x: x}) or [] - - -for count, tv in enumerate(test_vectors_verify): - if isinstance(tv, str): - continue - if hasattr(tv, "n"): - modulus = tv.n - continue - - hash_module = load_hash_by_name(tv.shaalg.upper()) - hash_obj = hash_module.new(tv.msg) - public_key = RSA.construct([bytes_to_long(x) for x in (modulus, tv.e)]) # type: ignore - verifier = pkcs1_15.new(public_key) - - def positive_test(self, hash_obj=hash_obj, verifier=verifier, signature=tv.s): - verifier.verify(hash_obj, signature) - - def negative_test(self, hash_obj=hash_obj, verifier=verifier, signature=tv.s): - self.assertRaises(ValueError, verifier.verify, hash_obj, signature) - - if tv.result == 'f': - setattr(FIPS_PKCS1_Verify_Tests_KAT, "test_negative_%d" % count, negative_test) - else: - setattr(FIPS_PKCS1_Verify_Tests_KAT, "test_positive_%d" % count, positive_test) - - -class FIPS_PKCS1_Sign_Tests(unittest.TestCase): - - def shortDescription(self): - return "FIPS PKCS1 Tests (Sign)" - - def test_can_sign(self): - test_private_key = RSA.generate(1024) - signer = pkcs1_15.new(test_private_key) - self.assertEqual(signer.can_sign(), True) - - -class FIPS_PKCS1_Sign_Tests_KAT(unittest.TestCase): - pass - - -test_vectors_sign = load_test_vectors(("Signature", "PKCS1-v1.5"), - "SigGen15_186-2.txt", - "Signature Generation 186-2", - {'shaalg': lambda x: x}) or [] - -test_vectors_sign += load_test_vectors(("Signature", "PKCS1-v1.5"), - "SigGen15_186-3.txt", - "Signature Generation 186-3", - {'shaalg': lambda x: x}) or [] - -for count, tv in enumerate(test_vectors_sign): - if isinstance(tv, str): - continue - if hasattr(tv, "n"): - modulus = tv.n - continue - if hasattr(tv, "e"): - private_key = RSA.construct([bytes_to_long(x) for x in (modulus, tv.e, tv.d)]) # type: ignore - signer = pkcs1_15.new(private_key) - continue - - hash_module = load_hash_by_name(tv.shaalg.upper()) - hash_obj = hash_module.new(tv.msg) - - def new_test(self, hash_obj=hash_obj, signer=signer, result=tv.s): - signature = signer.sign(hash_obj) - self.assertEqual(signature, result) - - setattr(FIPS_PKCS1_Sign_Tests_KAT, "test_%d" % count, new_test) - - -class PKCS1_15_NoParams(unittest.TestCase): - """Verify that PKCS#1 v1.5 signatures pass even without NULL parameters in - the algorithm identifier (PyCrypto/LP bug #1119552).""" - - rsakey = """-----BEGIN RSA PRIVATE KEY----- - MIIBOwIBAAJBAL8eJ5AKoIsjURpcEoGubZMxLD7+kT+TLr7UkvEtFrRhDDKMtuII - q19FrL4pUIMymPMSLBn3hJLe30Dw48GQM4UCAwEAAQJACUSDEp8RTe32ftq8IwG8 - Wojl5mAd1wFiIOrZ/Uv8b963WJOJiuQcVN29vxU5+My9GPZ7RA3hrDBEAoHUDPrI - OQIhAPIPLz4dphiD9imAkivY31Rc5AfHJiQRA7XixTcjEkojAiEAyh/pJHks/Mlr - +rdPNEpotBjfV4M4BkgGAA/ipcmaAjcCIQCHvhwwKVBLzzTscT2HeUdEeBMoiXXK - JACAr3sJQJGxIQIgarRp+m1WSKV1MciwMaTOnbU7wxFs9DP1pva76lYBzgUCIQC9 - n0CnZCJ6IZYqSt0H5N7+Q+2Ro64nuwV/OSQfM6sBwQ== - -----END RSA PRIVATE KEY-----""" - - msg = b"This is a test\x0a" - - # PKCS1 v1.5 signature of the message computed using SHA-1. - # The digestAlgorithm SEQUENCE does NOT contain the NULL parameter. - sig_str = "a287a13517f716e72fb14eea8e33a8db4a4643314607e7ca3e3e28"\ - "1893db74013dda8b855fd99f6fecedcb25fcb7a434f35cd0a101f8"\ - "b19348e0bd7b6f152dfc" - signature = unhexlify(sig_str) - - def runTest(self): - verifier = pkcs1_15.new(RSA.importKey(self.rsakey)) - hashed = SHA1.new(self.msg) - verifier.verify(hashed, self.signature) - - -class PKCS1_Legacy_Module_Tests(unittest.TestCase): - """Verify that the legacy module Crypto.Signature.PKCS1_v1_5 - behaves as expected. The only difference is that the verify() - method returns True/False and does not raise exceptions.""" - - def shortDescription(self): - return "Test legacy Crypto.Signature.PKCS1_v1_5" - - def runTest(self): - key = RSA.importKey(PKCS1_15_NoParams.rsakey) - hashed = SHA1.new(b"Test") - good_signature = PKCS1_v1_5.new(key).sign(hashed) - verifier = PKCS1_v1_5.new(key.public_key()) - - self.assertEqual(verifier.verify(hashed, good_signature), True) - - # Flip a few bits in the signature - bad_signature = strxor(good_signature, bchr(1) * len(good_signature)) - self.assertEqual(verifier.verify(hashed, bad_signature), False) - - -class PKCS1_All_Hashes_Tests(unittest.TestCase): - - def shortDescription(self): - return "Test PKCS#1v1.5 signature in combination with all hashes" - - def runTest(self): - - key = RSA.generate(1024) - signer = pkcs1_15.new(key) - hash_names = ("MD2", "MD4", "MD5", "RIPEMD160", "SHA1", - "SHA224", "SHA256", "SHA384", "SHA512", - "SHA3_224", "SHA3_256", "SHA3_384", "SHA3_512") - - for name in hash_names: - hashed = load_hash_by_name(name).new(b"Test") - signer.sign(hashed) - - from Crypto.Hash import BLAKE2b, BLAKE2s - for hash_size in (20, 32, 48, 64): - hashed_b = BLAKE2b.new(digest_bytes=hash_size, data=b"Test") - signer.sign(hashed_b) - for hash_size in (16, 20, 28, 32): - hashed_s = BLAKE2s.new(digest_bytes=hash_size, data=b"Test") - signer.sign(hashed_s) - - -class TestVectorsWycheproof(unittest.TestCase): - - def __init__(self, wycheproof_warnings): - unittest.TestCase.__init__(self) - self._wycheproof_warnings = wycheproof_warnings - self._id = "None" - - def setUp(self): - self.tv = [] - self.add_tests("rsa_sig_gen_misc_test.json") - self.add_tests("rsa_signature_2048_sha224_test.json") - self.add_tests("rsa_signature_2048_sha256_test.json") - self.add_tests("rsa_signature_2048_sha384_test.json") - self.add_tests("rsa_signature_2048_sha3_224_test.json") - self.add_tests("rsa_signature_2048_sha3_256_test.json") - self.add_tests("rsa_signature_2048_sha3_384_test.json") - self.add_tests("rsa_signature_2048_sha3_512_test.json") - self.add_tests("rsa_signature_2048_sha512_test.json") - self.add_tests("rsa_signature_2048_sha512_224_test.json") - self.add_tests("rsa_signature_2048_sha512_256_test.json") - self.add_tests("rsa_signature_3072_sha256_test.json") - self.add_tests("rsa_signature_3072_sha384_test.json") - self.add_tests("rsa_signature_3072_sha3_256_test.json") - self.add_tests("rsa_signature_3072_sha3_384_test.json") - self.add_tests("rsa_signature_3072_sha3_512_test.json") - self.add_tests("rsa_signature_3072_sha512_test.json") - self.add_tests("rsa_signature_3072_sha512_256_test.json") - self.add_tests("rsa_signature_4096_sha384_test.json") - self.add_tests("rsa_signature_4096_sha512_test.json") - self.add_tests("rsa_signature_4096_sha512_256_test.json") - self.add_tests("rsa_signature_test.json") - - def add_tests(self, filename): - - def filter_rsa(group): - return RSA.import_key(group['keyPem']) - - def filter_sha(group): - hash_name = group['sha'] - if hash_name == "SHA-512": - return SHA512 - elif hash_name == "SHA-512/224": - return SHA512.new(truncate="224") - elif hash_name == "SHA-512/256": - return SHA512.new(truncate="256") - elif hash_name == "SHA3-512": - return SHA3_512 - elif hash_name == "SHA-384": - return SHA384 - elif hash_name == "SHA3-384": - return SHA3_384 - elif hash_name == "SHA-256": - return SHA256 - elif hash_name == "SHA3-256": - return SHA3_256 - elif hash_name == "SHA-224": - return SHA224 - elif hash_name == "SHA3-224": - return SHA3_224 - elif hash_name == "SHA-1": - return SHA1 - else: - raise ValueError("Unknown hash algorithm: " + hash_name) - - def filter_type(group): - type_name = group['type'] - if type_name not in ("RsassaPkcs1Verify", "RsassaPkcs1Generate"): - raise ValueError("Unknown type name " + type_name) - - result = load_test_vectors_wycheproof(("Signature", "wycheproof"), - filename, - "Wycheproof PKCS#1v1.5 signature (%s)" % filename, - group_tag={'rsa_key': filter_rsa, - 'hash_mod': filter_sha, - 'type': filter_type}) - return result - - def shortDescription(self): - return self._id - - def warn(self, tv): - if tv.warning and self._wycheproof_warnings: - import warnings - warnings.warn("Wycheproof warning: %s (%s)" % (self._id, tv.comment)) - - def test_verify(self, tv): - self._id = "Wycheproof RSA PKCS$#1 Test #" + str(tv.id) - - hashed_msg = tv.hash_module.new(tv.msg) - signer = pkcs1_15.new(tv.key) - try: - signature = signer.verify(hashed_msg, tv.sig) - except ValueError as e: - if tv.warning: - return - assert not tv.valid - else: - assert tv.valid - self.warn(tv) - - def runTest(self): - for tv in self.tv: - self.test_verify(tv) - - -def get_tests(config={}): - wycheproof_warnings = config.get('wycheproof_warnings') - - tests = [] - tests += list_test_cases(FIPS_PKCS1_Verify_Tests) - tests += list_test_cases(FIPS_PKCS1_Sign_Tests) - tests += list_test_cases(PKCS1_15_NoParams) - tests += list_test_cases(PKCS1_Legacy_Module_Tests) - tests += list_test_cases(PKCS1_All_Hashes_Tests) - tests += [ TestVectorsWycheproof(wycheproof_warnings) ] - - if config.get('slow_tests'): - tests += list_test_cases(FIPS_PKCS1_Verify_Tests_KAT) - tests += list_test_cases(FIPS_PKCS1_Sign_Tests_KAT) - - return tests - -if __name__ == '__main__': - suite = lambda: unittest.TestSuite(get_tests()) - unittest.main(defaultTest='suite') diff --git a/Crypto/SelfTest/Signature/test_pss.py b/Crypto/SelfTest/Signature/test_pss.py deleted file mode 100644 index 535474b..0000000 --- a/Crypto/SelfTest/Signature/test_pss.py +++ /dev/null @@ -1,377 +0,0 @@ -# =================================================================== -# -# Copyright (c) 2014, Legrandin -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# =================================================================== - -import unittest - -from Crypto.Util.py3compat import b, bchr -from Crypto.Util.number import bytes_to_long -from Crypto.Util.strxor import strxor -from Crypto.SelfTest.st_common import list_test_cases -from Crypto.SelfTest.loader import load_test_vectors, load_test_vectors_wycheproof - -from Crypto.Hash import SHA1, SHA224, SHA256, SHA384, SHA512 -from Crypto.PublicKey import RSA -from Crypto.Signature import pss -from Crypto.Signature import PKCS1_PSS - -from Crypto.Signature.pss import MGF1 - - -def load_hash_by_name(hash_name): - return __import__("Crypto.Hash." + hash_name, globals(), locals(), ["new"]) - - -class PRNG(object): - - def __init__(self, stream): - self.stream = stream - self.idx = 0 - - def __call__(self, rnd_size): - result = self.stream[self.idx:self.idx + rnd_size] - self.idx += rnd_size - return result - - -class PSS_Tests(unittest.TestCase): - - rsa_key = b'-----BEGIN RSA PRIVATE KEY-----\nMIIEowIBAAKCAQEAsvI34FgiTK8+txBvmooNGpNwk23YTU51dwNZi5yha3W4lA/Q\nvcZrDalkmD7ekWQwnduxVKa6pRSI13KBgeUOIqJoGXSWhntEtY3FEwvWOHW5AE7Q\njUzTzCiYT6TVaCcpa/7YLai+p6ai2g5f5Zfh4jSawa9uYeuggFygQq4IVW796MgV\nyqxYMM/arEj+/sKz3Viua9Rp9fFosertCYCX4DUTgW0mX9bwEnEOgjSI3pLOPXz1\n8vx+DRZS5wMCmwCUa0sKonLn3cAUPq+sGix7+eo7T0Z12MU8ud7IYVX/75r3cXiF\nPaYE2q8Le0kgOApIXbb+x74x0rNgyIh1yGygkwIDAQABAoIBABz4t1A0pLT6qHI2\nEIOaNz3mwhK0dZEqkz0GB1Dhtoax5ATgvKCFB98J3lYB08IBURe1snOsnMpOVUtg\naBRSM+QqnCUG6bnzKjAkuFP5liDE+oNQv1YpKp9CsUovuzdmI8Au3ewihl+ZTIN2\nUVNYMEOR1b5m+z2SSwWNOYsiJwpBrT7zkpdlDyjat7FiiPhMMIMXjhQFVxURMIcB\njUBtPzGvV/PG90cVDWi1wRGeeP1dDqti/jsnvykQ15KW1MqGrpeNKRmDdTy/Ucl1\nWIoYklKw3U456lgZ/rDTDB818+Tlnk35z4yF7d5ANPM8CKfqOPcnO1BCKVFzf4eq\n54wvUtkCgYEA1Zv2lp06l7rXMsvNtyYQjbFChezRDRnPwZmN4NCdRtTgGG1G0Ryd\nYz6WWoPGqZp0b4LAaaHd3W2GTcpXF8WXMKfMX1W+tMAxMozfsXRKMcHoypwuS5wT\nfJRXJCG4pvd57AB0iVUEJW2we+uGKU5Zxcx//id2nXGCpoRyViIplQsCgYEA1nVC\neHupHChht0Fh4N09cGqZHZzuwXjOUMzR3Vsfz+4WzVS3NvIgN4g5YgmQFOeKwo5y\niRq5yvubcNdFvf85eHWClg0zPAyxJCVUWigCrrOanGEhJo6re4idJvNVzu4Ucg0v\n6B3SJ1HsCda+ZSNz24bSyqRep8A+RoAaoVSFx5kCgYEAn3RvXPs9s+obnqWYiPF3\nRe5etE6Vt2vfNKwFxx6zaR6bsmBQjuUHcABWiHb6I71S0bMPI0tbrWGG8ibrYKl1\nNTLtUvVVCOS3VP7oNTWT9RTFTAnOXU7DFSo+6o/poWn3r36ff6zhDXeWWMr2OXtt\ndEQ1/2lCGEGVv+v61eVmmQUCgYABFHITPTwqwiFL1O5zPWnzyPWgaovhOYSAb6eW\n38CXQXGn8wdBJZL39J2lWrr4//l45VK6UgIhfYbY2JynSkO10ZGow8RARygVMILu\nOUlaK9lZdDvAf/NpGdUAvzTtZ9F+iYZ2OsA2JnlzyzsGM1l//3vMPWukmJk3ral0\nqoJJ8QKBgGRG3eVHnIegBbFVuMDp2NTcfuSuDVUQ1fGAwtPiFa8u81IodJnMk2pq\niXu2+0ytNA/M+SVrAnE2AgIzcaJbtr0p2srkuVM7KMWnG1vWFNjtXN8fAhf/joOv\nD+NmPL/N4uE57e40tbiU/H7KdyZaDt+5QiTmdhuyAe6CBjKsF2jy\n-----END RSA PRIVATE KEY-----' - msg = b'AAA' - tag = b'\x00[c5\xd8\xb0\x8b!D\x81\x83\x07\xc0\xdd\xb9\xb4\xb2`\x92\xe7\x02\xf1\xe1P\xea\xc3\xf0\xe3>\xddX5\xdd\x8e\xc5\x89\xef\xf3\xc2\xdc\xfeP\x02\x7f\x12+\xc9\xaf\xbb\xec\xfe\xb0\xa5\xb9\x08\x11P\x8fL\xee5\x9b\xb0k{=_\xd2\x14\xfb\x01R\xb7\xfe\x14}b\x03\x8d5Y\x89~}\xfc\xf2l\xd01-\xbd\xeb\x11\xcdV\x11\xe9l\x19k/o5\xa2\x0f\x15\xe7Q$\t=\xec\x1dAB\x19\xa5P\x9a\xaf\xa3G\x86"\xd6~\xf0j\xfcqkbs\x13\x84b\xe4\xbdm(\xed`\xa4F\xfb\x8f.\xe1\x8c)/_\x9eS\x98\xa4v\xb8\xdc\xfe\xf7/D\x18\x19\xb3T\x97:\xe2\x96s\xe8<\xa2\xb4\xb9\xf8/' - - def test_positive_1(self): - key = RSA.import_key(self.rsa_key) - h = SHA256.new(self.msg) - verifier = pss.new(key) - verifier.verify(h, self.tag) - - def test_negative_1(self): - key = RSA.import_key(self.rsa_key) - h = SHA256.new(self.msg + b'A') - verifier = pss.new(key) - tag = bytearray(self.tag) - self.assertRaises(ValueError, verifier.verify, h, tag) - - def test_negative_2(self): - key = RSA.import_key(self.rsa_key) - h = SHA256.new(self.msg) - verifier = pss.new(key, salt_bytes=1000) - tag = bytearray(self.tag) - self.assertRaises(ValueError, verifier.verify, h, tag) - - -class FIPS_PKCS1_Verify_Tests(unittest.TestCase): - - def shortDescription(self): - return "FIPS PKCS1 Tests (Verify)" - - def verify_positive(self, hashmod, message, public_key, salt, signature): - prng = PRNG(salt) - hashed = hashmod.new(message) - verifier = pss.new(public_key, salt_bytes=len(salt), rand_func=prng) - verifier.verify(hashed, signature) - - def verify_negative(self, hashmod, message, public_key, salt, signature): - prng = PRNG(salt) - hashed = hashmod.new(message) - verifier = pss.new(public_key, salt_bytes=len(salt), rand_func=prng) - self.assertRaises(ValueError, verifier.verify, hashed, signature) - - def test_can_sign(self): - test_public_key = RSA.generate(1024).public_key() - verifier = pss.new(test_public_key) - self.assertEqual(verifier.can_sign(), False) - - -class FIPS_PKCS1_Verify_Tests_KAT(unittest.TestCase): - pass - - -test_vectors_verify = load_test_vectors(("Signature", "PKCS1-PSS"), - "SigVerPSS_186-3.rsp", - "Signature Verification 186-3", - {'shaalg': lambda x: x, - 'result': lambda x: x}) or [] - - -for count, tv in enumerate(test_vectors_verify): - if isinstance(tv, str): - continue - if hasattr(tv, "n"): - modulus = tv.n - continue - if hasattr(tv, "p"): - continue - - hash_module = load_hash_by_name(tv.shaalg.upper()) - hash_obj = hash_module.new(tv.msg) - public_key = RSA.construct([bytes_to_long(x) for x in (modulus, tv.e)]) # type: ignore - if tv.saltval != b("\x00"): - prng = PRNG(tv.saltval) - verifier = pss.new(public_key, salt_bytes=len(tv.saltval), rand_func=prng) - else: - verifier = pss.new(public_key, salt_bytes=0) - - def positive_test(self, hash_obj=hash_obj, verifier=verifier, signature=tv.s): - verifier.verify(hash_obj, signature) - - def negative_test(self, hash_obj=hash_obj, verifier=verifier, signature=tv.s): - self.assertRaises(ValueError, verifier.verify, hash_obj, signature) - - if tv.result == 'p': - setattr(FIPS_PKCS1_Verify_Tests_KAT, "test_positive_%d" % count, positive_test) - else: - setattr(FIPS_PKCS1_Verify_Tests_KAT, "test_negative_%d" % count, negative_test) - - -class FIPS_PKCS1_Sign_Tests(unittest.TestCase): - - def shortDescription(self): - return "FIPS PKCS1 Tests (Sign)" - - def test_can_sign(self): - test_private_key = RSA.generate(1024) - signer = pss.new(test_private_key) - self.assertEqual(signer.can_sign(), True) - - -class FIPS_PKCS1_Sign_Tests_KAT(unittest.TestCase): - pass - - -test_vectors_sign = load_test_vectors(("Signature", "PKCS1-PSS"), - "SigGenPSS_186-2.txt", - "Signature Generation 186-2", - {'shaalg': lambda x: x}) or [] - -test_vectors_sign += load_test_vectors(("Signature", "PKCS1-PSS"), - "SigGenPSS_186-3.txt", - "Signature Generation 186-3", - {'shaalg': lambda x: x}) or [] - -for count, tv in enumerate(test_vectors_sign): - if isinstance(tv, str): - continue - if hasattr(tv, "n"): - modulus = tv.n - continue - if hasattr(tv, "e"): - private_key = RSA.construct([bytes_to_long(x) for x in (modulus, tv.e, tv.d)]) # type: ignore - continue - - hash_module = load_hash_by_name(tv.shaalg.upper()) - hash_obj = hash_module.new(tv.msg) - if tv.saltval != b("\x00"): - prng = PRNG(tv.saltval) - signer = pss.new(private_key, salt_bytes=len(tv.saltval), rand_func=prng) - else: - signer = pss.new(private_key, salt_bytes=0) - - def new_test(self, hash_obj=hash_obj, signer=signer, result=tv.s): - signature = signer.sign(hash_obj) - self.assertEqual(signature, result) - - setattr(FIPS_PKCS1_Sign_Tests_KAT, "test_%d" % count, new_test) - - -class PKCS1_Legacy_Module_Tests(unittest.TestCase): - """Verify that the legacy module Crypto.Signature.PKCS1_PSS - behaves as expected. The only difference is that the verify() - method returns True/False and does not raise exceptions.""" - - def shortDescription(self): - return "Test legacy Crypto.Signature.PKCS1_PSS" - - def runTest(self): - key = RSA.generate(1024) - hashed = SHA1.new(b("Test")) - good_signature = PKCS1_PSS.new(key).sign(hashed) - verifier = PKCS1_PSS.new(key.public_key()) - - self.assertEqual(verifier.verify(hashed, good_signature), True) - - # Flip a few bits in the signature - bad_signature = strxor(good_signature, bchr(1) * len(good_signature)) - self.assertEqual(verifier.verify(hashed, bad_signature), False) - - -class PKCS1_All_Hashes_Tests(unittest.TestCase): - - def shortDescription(self): - return "Test PKCS#1 PSS signature in combination with all hashes" - - def runTest(self): - - key = RSA.generate(1280) - signer = pss.new(key) - hash_names = ("MD2", "MD4", "MD5", "RIPEMD160", "SHA1", - "SHA224", "SHA256", "SHA384", "SHA512", - "SHA3_224", "SHA3_256", "SHA3_384", "SHA3_512") - - for name in hash_names: - hashed = load_hash_by_name(name).new(b("Test")) - signer.sign(hashed) - - from Crypto.Hash import BLAKE2b, BLAKE2s - for hash_size in (20, 32, 48, 64): - hashed_b = BLAKE2b.new(digest_bytes=hash_size, data=b("Test")) - signer.sign(hashed_b) - for hash_size in (16, 20, 28, 32): - hashed_s = BLAKE2s.new(digest_bytes=hash_size, data=b("Test")) - signer.sign(hashed_s) - - -def get_hash_module(hash_name): - if hash_name == "SHA-512": - hash_module = SHA512 - elif hash_name == "SHA-512/224": - hash_module = SHA512.new(truncate="224") - elif hash_name == "SHA-512/256": - hash_module = SHA512.new(truncate="256") - elif hash_name == "SHA-384": - hash_module = SHA384 - elif hash_name == "SHA-256": - hash_module = SHA256 - elif hash_name == "SHA-224": - hash_module = SHA224 - elif hash_name == "SHA-1": - hash_module = SHA1 - else: - raise ValueError("Unknown hash algorithm: " + hash_name) - return hash_module - - -class TestVectorsPSSWycheproof(unittest.TestCase): - - def __init__(self, wycheproof_warnings): - unittest.TestCase.__init__(self) - self._wycheproof_warnings = wycheproof_warnings - self._id = "None" - - def add_tests(self, filename): - - def filter_rsa(group): - return RSA.import_key(group['keyPem']) - - def filter_sha(group): - return get_hash_module(group['sha']) - - def filter_type(group): - type_name = group['type'] - if type_name not in ("RsassaPssVerify", ): - raise ValueError("Unknown type name " + type_name) - - def filter_slen(group): - return group['sLen'] - - def filter_mgf(group): - mgf = group['mgf'] - if mgf not in ("MGF1", ): - raise ValueError("Unknown MGF " + mgf) - mgf1_hash = get_hash_module(group['mgfSha']) - - def mgf(x, y, mh=mgf1_hash): - return MGF1(x, y, mh) - - return mgf - - result = load_test_vectors_wycheproof(("Signature", "wycheproof"), - filename, - "Wycheproof PSS signature (%s)" % filename, - group_tag={'key': filter_rsa, - 'hash_module': filter_sha, - 'sLen': filter_slen, - 'mgf': filter_mgf, - 'type': filter_type}) - return result - - def setUp(self): - self.tv = [] - self.add_tests("rsa_pss_2048_sha1_mgf1_20_test.json") - self.add_tests("rsa_pss_2048_sha256_mgf1_0_test.json") - self.add_tests("rsa_pss_2048_sha256_mgf1_32_test.json") - self.add_tests("rsa_pss_2048_sha512_256_mgf1_28_test.json") - self.add_tests("rsa_pss_2048_sha512_256_mgf1_32_test.json") - self.add_tests("rsa_pss_3072_sha256_mgf1_32_test.json") - self.add_tests("rsa_pss_4096_sha256_mgf1_32_test.json") - self.add_tests("rsa_pss_4096_sha512_mgf1_32_test.json") - self.add_tests("rsa_pss_misc_test.json") - - def shortDescription(self): - return self._id - - def warn(self, tv): - if tv.warning and self._wycheproof_warnings: - import warnings - warnings.warn("Wycheproof warning: %s (%s)" % (self._id, tv.comment)) - - def test_verify(self, tv): - self._id = "Wycheproof RSA PSS Test #%d (%s)" % (tv.id, tv.comment) - - hashed_msg = tv.hash_module.new(tv.msg) - signer = pss.new(tv.key, mask_func=tv.mgf, salt_bytes=tv.sLen) - try: - signature = signer.verify(hashed_msg, tv.sig) - except ValueError as e: - if tv.warning: - return - assert not tv.valid - else: - assert tv.valid - self.warn(tv) - - def runTest(self): - for tv in self.tv: - self.test_verify(tv) - - -def get_tests(config={}): - wycheproof_warnings = config.get('wycheproof_warnings') - - tests = [] - tests += list_test_cases(PSS_Tests) - tests += list_test_cases(FIPS_PKCS1_Verify_Tests) - tests += list_test_cases(FIPS_PKCS1_Sign_Tests) - tests += list_test_cases(PKCS1_Legacy_Module_Tests) - tests += list_test_cases(PKCS1_All_Hashes_Tests) - - if config.get('slow_tests'): - tests += list_test_cases(FIPS_PKCS1_Verify_Tests_KAT) - tests += list_test_cases(FIPS_PKCS1_Sign_Tests_KAT) - - tests += [TestVectorsPSSWycheproof(wycheproof_warnings)] - - return tests - - -if __name__ == '__main__': - def suite(): - return unittest.TestSuite(get_tests()) - unittest.main(defaultTest='suite') diff --git a/Crypto/SelfTest/Util/__init__.py b/Crypto/SelfTest/Util/__init__.py deleted file mode 100644 index ee993db..0000000 --- a/Crypto/SelfTest/Util/__init__.py +++ /dev/null @@ -1,46 +0,0 @@ -# -*- coding: utf-8 -*- -# -# SelfTest/Util/__init__.py: Self-test for utility modules -# -# Written in 2008 by Dwayne C. Litzenberger -# -# =================================================================== -# The contents of this file are dedicated to the public domain. To -# the extent that dedication to the public domain is not available, -# everyone is granted a worldwide, perpetual, royalty-free, -# non-exclusive license to exercise all rights associated with the -# contents of this file for any purpose whatsoever. -# No rights are reserved. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS -# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN -# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# =================================================================== - -"""Self-test for utility modules""" - -__revision__ = "$Id$" - -import os - -def get_tests(config={}): - tests = [] - from Crypto.SelfTest.Util import test_number; tests += test_number.get_tests(config=config) - from Crypto.SelfTest.Util import test_Counter; tests += test_Counter.get_tests(config=config) - from Crypto.SelfTest.Util import test_Padding; tests += test_Padding.get_tests(config=config) - from Crypto.SelfTest.Util import test_strxor; tests += test_strxor.get_tests(config=config) - from Crypto.SelfTest.Util import test_asn1; tests += test_asn1.get_tests(config=config) - from Crypto.SelfTest.Util import test_rfc1751; tests += test_rfc1751.get_tests(config=config) - return tests - -if __name__ == '__main__': - import unittest - suite = lambda: unittest.TestSuite(get_tests()) - unittest.main(defaultTest='suite') - -# vim:set ts=4 sw=4 sts=4 expandtab: diff --git a/Crypto/SelfTest/Util/__pycache__/__init__.cpython-36.pyc b/Crypto/SelfTest/Util/__pycache__/__init__.cpython-36.pyc deleted file mode 100644 index 2a9a2ad254219f5db7660f53c157a4233a62dc08..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 963 zcmZ{jKX21O6u|G!|C1CtupoiRki|lc6;&k*sw#zrB|-`ecsV&aCpdNN=6G3At zn6Ppdvy9BCu!VC^V=J|Vd(GsPVNUD_Px$vFc2j5Ri9oa-C?&$0kg$FGa+2orGo32k zotLs(=`7Fmrn@Rdm8a^~?!6biUyzQBXB1zsd=MLC1fsr!T9BFwC?qE#~od{s{T{pJ2+8K?O~)NHs@aC2^$ELFJ-?%O?^?9r_Y4zHxSD==NXR zZ$!3%{~kv-iH!23SVZfM{!$j_QJzir`~I6qWjZ}uC$sBhk*a7{U$n0;!ulf4vm(=+ z_tzU4K+snp>IEo5ZQ3EH{}f}{_?)kjtl)fx=KF<}o8L?aHkvG{W_RQc?}Ls*tMMyH zhdsst4rx+Bi6)$B=|G`-OXhl5Wsi$&i46V+J-`@R3JbpI;7Y_LG%GsMGb+M$PY=1#J!w0-nH5Ed}nso zA+Z_>l)UDH@RjZfi6?&rUdqhg+1S(siL-8Y?{0SXH?uS2op!tN^oPg%_kfT;$kOG* zd>3wW2ttsE2r5`Yk8$)87P0S$@I~dCh>B#V-jx^miVUczirO`eDzYkqmrVCWT{Nyq zR0EwrG)3!%QX;$~61Jxw9m!;{ZKbhhYmn)!J$*5@S?7gSNoOycq*m$~>`g+N)6aT+ zoX#%>lU=yYHy|X5C;&19gsnW`2_Hs)6IB>1q9y_ut8)~@fagH8#RiOZaR+ej=B;wi zV+86`FpL+DxZ57w<}L^q1~Q@?9U-vN>uFR1%35h5WKna;8I7TY&%ObFe^CLgswUy;S}T^9pF?wC@})L=E569QX76$M9f~fUpLg-d{m2 zRo269!jiR!?E{BXQtCSB9fwpmV4Sn*COnjEx&`y~bO-w(e4B@H4co!~dbTZCHfOtm zP`)Ck%zEw()JT~!e$TN%04wQJO`M!xG_@OL#~W8dE;mEp5^1gEwRAwAQ=u&cX%D1iONAcUgeBUV`WB{2bt`V=V{jJoJ{p>B((` zO-EQP`y3Hnp3>>NZvqxd|CdnT$A|)=nGF7csL{XwhAb9-aXVz8v;v9M?MmtiOy-$T zgm5VrusL}*ewh!|A|GZL4Xi4aDyw)BpW(63uOU+>?!D# z>9Dc3)YMroY~(>4r+g&iIB&%9C=(MX?Kp46@lO+;6kjy_PY~Tkv4P?(6c125MDZR9 z48fAXqSqdX58yVqDxiTMRN(dlFYw&Al^9|iTnzCP=MDD~8tyA#q1cPqBkmc2WmJZagc=tE6>rwTgER343V8x=6^vCdo zVH$Cj#&I8>7S{qAy9ypWpb`g5d!d&H6F5}FjOxcAk0#LHow=n*IS99Z@O8pRCxSoQ z1!D&H(3nrq;&EL_qo$ApK1nRv3hQ|-jz!jw_R*(*fhls~86L4aK%WKh+kDjW;V9`}0p`aJ diff --git a/Crypto/SelfTest/Util/__pycache__/test_Padding.cpython-36.pyc b/Crypto/SelfTest/Util/__pycache__/test_Padding.cpython-36.pyc deleted file mode 100644 index 46f7c577eea84fa8d78bb32449f9fc57f3eda8e7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5348 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 Fe*sq<(02d; diff --git a/Crypto/SelfTest/Util/__pycache__/test_number.cpython-36.pyc b/Crypto/SelfTest/Util/__pycache__/test_number.cpython-36.pyc deleted file mode 100644 index d1250bab45d144a79202b9f136811135505c786b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4887 zcmeHLU2I%O6`r|&d-u=l*meAq*lb)88r`LSZTuxN`K z2t^XKO82L7nDieCiR17&-9T)Tp&+@!XhvlU^r2P*XVzzgD2d9*bh%JikK31W_L|E} z#dz7Vne0{ykVVHUAt3h#&J>tzm8ndFKP(qB;IFd)GvRNrAPd1iz``&& zk!tV^cXB9#lf!w$2mjdgN%))rAW{oRfm*n3FuQrhQW(LxO$lU%H8DJ~6KW>hv~VH} zrB$t9x#xjLb6~Xhrc4B}PiOL!u2tXR71@9od3c*3+3%uh)!uZD}ohy5s}?rn-K6S`+5C*N$nd z8T0zkJ77i&=JgwB!Tf&p4*j-cpbl+(dJE>sVsyX)9Wb*6^W+P*V7`1tTfYix$FvR@ zC~#X{qXqM14s^iG4p^`Q7HYw~afE%0ML^fPD)%+*MPoUe=d+AosL}^(Xamv^YG^h! zwA&gga}9O1W*`Y5!QG;UTA!-jg(qQDBbMXX!hOo(j_p)~v+HZN+^VGEWXwhR79cK?Y0$_8;ak^0pM_^fDomJ!mHj#lof8q1P`4D>9d;h-!1-pjZHm9I~95-*V0~SH*q(HA&Lz3dSw{wa_rW8me0%8ct zs-d%1zTB*QU9IhBx;%YLm0YQEVi;;=)W=UwCp4*iRc(>GPL*D&QhU21_DV%*ZEz0i zJGk!?rJHtBjfQ~k1_je-gbp;Ncgu8Tc$?a_w$@NSv_P~4=^|c*gr|Hf3LD)*7vXL7 z;4}cazYWpa5ET$#4ZT{Rq}vdqt=8T)o_#*grBQZxn#>PvQeQGxMaB2apMB|R!uG&& zPgZ)Hmzz6sokb6f>6Ev;xTv$D7bw3AMpr`%uU$s+8ze`OTnEB$JPPFDi$I1ysS|$W zD@)IWO~nJo>kb3T$%k!6sMx7m)l}sPN%=x``C{ z?&S~58}kJI{|tX%D+V+C3i|91tb_NvWial!KCu7TS9cKp?){MZ!*_;Bt)IQV>kgW4 zdEs{7?}t)ML33FiuZRNId=dp-)`>^wZHh z=;D8}_=|Hx=blUf8)o0GT<abnP9F|SS#TXYrE@-NY_)ZvkI*^ zyMfe0APj@NR|UTyUz1jLZu2zt$_*ET;U3PAbTLIp_!~LHO`Nv47^MwChXS#`9|eIM z(g6v!Am~s6bwqVF>8wIBQo>VLIOT2s=m}~!frx$}{P+)VlKc#$zMXh)_dAmdYVl)V zH(<8CwCR~A=0eZvdGWc?aQfnN zrMKd54o;rl)zh*xjO!Z{vREBBlfEL>ppNYI8R;xg6Bv9_YEYW-&;&L67q^I z0}!zX%R0xgLAi#=`W!Gh5g^20IQUn3w=EcQrV^&WMG~l&0%LH|g=7TDUL=no!Faey zW#oAtBXki0f@}^ZOls=pesibUEAfUVpdn$vAvK}-q`V0y6yqXkGRR_ZUX5R9xcA607Rig3}~AN?i>?R3zJW zo`S_rqL91YnF@L#ojW(S)l1M zS{XLi)Olmxs^(*PtFXwdscXRDU>5>)63+QpFF`Y5W-nRgyo+rm!U7LQnZBkw1GxDZ zM{BlRF^v_2GyZjrya36VSn(vxoSYU<5V_E&kQ?qAc=107=3VDZp%TigB26*j?KXNA JBRZ@w{Wn_f27>?q diff --git a/Crypto/SelfTest/Util/__pycache__/test_rfc1751.cpython-36.pyc b/Crypto/SelfTest/Util/__pycache__/test_rfc1751.cpython-36.pyc deleted file mode 100644 index 609f792ea5debb59519e01164f223001c65bcde3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1617 zcmZ`(OH<=U5S|&ywlIc}<&aRdl}uih@*#fU7o<{KE6XytFm_4^C{#&Q!V*Rx+w4fr zE?edV*Zh$DC0%pcb8ei{EdfPdQ#GwtPftI-?w;DpO1^dSwR0j9@&|dg;GevP9sUBu zB`yt!m42y3;hzO;B3aTzwq#0nh%34B9dTukTx4z~E9;Xp>So;R9kp_v;^r=yuw2Dm zx+B&S=;YnJyZjraVE2F&3m?D-85CK(dg)!;(aiRyHk<}k>ybVJ{@ z7qmlu{{AO+!)~OAT+ju(r8jcK7BYM@3vwYXG7IUJQ4-1Ur8n6`mW6YWy;(a3xWIXS z5U=U&TCLk^>3XZysaG1c``lB*Sp=VYInQcZEMX&tx?(DtZ1E1t6pt(^sP!|`@UrwpuB%*>fBU& zeSWMO`&`>q4Zb%V?C@Px-Qil#JmKx3q4Oa(b+ymc<9?Be3_vKdK!8VVg_811$mfyI z#LB5Zb;6PF$2n*7)IRs#39Mwi?1Z5wBK^(W350~YxmXUp;4GG1CvvPDwgza&nYT0H zhUq`pve?^Ai(PL1PQ=G>>)t5;>WFgSOvmM`>*#zot(61+^pP($%b_26-(5MQOK0qb zWldaPMYHk&IKtj2A4Yyqj)1ep*$7*vbafqPP*BAz!WTdYW0cXXv`X_#p#|9Q*Z znLkcsX@$do#2YV-z0`L28C(ppvk5Iwg^JICLqH~uKeg=<9z3q63<@B@hXdj!xA@M{ z0k~D>Q$NCZttAua!5rE#G55@Qf?ZNY<%htToVw1dZ@^fHF2t8W;!KG5iqu+my)$PX zL};tHEWSXEWgyo20}9yCrH3jf{gMoqrQih(5KG`l1Hi@*U!i#!^ZK8F(#pR={6lO! Ps3TpIUVKu>DuB#iY=3sV diff --git a/Crypto/SelfTest/Util/__pycache__/test_strxor.cpython-36.pyc b/Crypto/SelfTest/Util/__pycache__/test_strxor.cpython-36.pyc deleted file mode 100644 index c17b687b778a66fd6bb6de46be8f88ca05cc016b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 9187 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 B)kgpT diff --git a/Crypto/SelfTest/Util/test_Counter.py b/Crypto/SelfTest/Util/test_Counter.py deleted file mode 100644 index 8837a32..0000000 --- a/Crypto/SelfTest/Util/test_Counter.py +++ /dev/null @@ -1,67 +0,0 @@ -# -*- coding: utf-8 -*- -# -# SelfTest/Util/test_Counter: Self-test for the Crypto.Util.Counter module -# -# Written in 2009 by Dwayne C. Litzenberger -# -# =================================================================== -# The contents of this file are dedicated to the public domain. To -# the extent that dedication to the public domain is not available, -# everyone is granted a worldwide, perpetual, royalty-free, -# non-exclusive license to exercise all rights associated with the -# contents of this file for any purpose whatsoever. -# No rights are reserved. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS -# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN -# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# =================================================================== - -"""Self-tests for Crypto.Util.Counter""" - -from Crypto.Util.py3compat import * - -import unittest - -class CounterTests(unittest.TestCase): - def setUp(self): - global Counter - from Crypto.Util import Counter - - def test_BE(self): - """Big endian""" - c = Counter.new(128) - c = Counter.new(128, little_endian=False) - - def test_LE(self): - """Little endian""" - c = Counter.new(128, little_endian=True) - - def test_nbits(self): - c = Counter.new(nbits=128) - self.assertRaises(ValueError, Counter.new, 129) - - def test_prefix(self): - c = Counter.new(128, prefix=b("xx")) - - def test_suffix(self): - c = Counter.new(128, suffix=b("xx")) - - def test_iv(self): - c = Counter.new(128, initial_value=2) - self.assertRaises(ValueError, Counter.new, 16, initial_value=0x1FFFF) - -def get_tests(config={}): - from Crypto.SelfTest.st_common import list_test_cases - return list_test_cases(CounterTests) - -if __name__ == '__main__': - suite = lambda: unittest.TestSuite(get_tests()) - unittest.main(defaultTest='suite') - -# vim:set ts=4 sw=4 sts=4 expandtab: diff --git a/Crypto/SelfTest/Util/test_Padding.py b/Crypto/SelfTest/Util/test_Padding.py deleted file mode 100644 index 4634659..0000000 --- a/Crypto/SelfTest/Util/test_Padding.py +++ /dev/null @@ -1,154 +0,0 @@ -# -# SelfTest/Util/test_Padding.py: Self-test for padding functions -# -# =================================================================== -# -# Copyright (c) 2014, Legrandin -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# =================================================================== - -import unittest -from binascii import unhexlify as uh - -from Crypto.Util.py3compat import * -from Crypto.SelfTest.st_common import list_test_cases -from Crypto.Util.Padding import pad, unpad - -class PKCS7_Tests(unittest.TestCase): - - def test1(self): - padded = pad(b(""), 4) - self.failUnless(padded == uh(b("04040404"))) - padded = pad(b(""), 4, 'pkcs7') - self.failUnless(padded == uh(b("04040404"))) - back = unpad(padded, 4) - self.failUnless(back == b("")) - - def test2(self): - padded = pad(uh(b("12345678")), 4) - self.failUnless(padded == uh(b("1234567804040404"))) - back = unpad(padded, 4) - self.failUnless(back == uh(b("12345678"))) - - def test3(self): - padded = pad(uh(b("123456")), 4) - self.failUnless(padded == uh(b("12345601"))) - back = unpad(padded, 4) - self.failUnless(back == uh(b("123456"))) - - def test4(self): - padded = pad(uh(b("1234567890")), 4) - self.failUnless(padded == uh(b("1234567890030303"))) - back = unpad(padded, 4) - self.failUnless(back == uh(b("1234567890"))) - - def testn1(self): - self.assertRaises(ValueError, pad, uh(b("12")), 4, 'pkcs8') - - def testn2(self): - self.assertRaises(ValueError, unpad, b("\0\0\0"), 4) - self.assertRaises(ValueError, unpad, b(""), 4) - - def testn3(self): - self.assertRaises(ValueError, unpad, b("123456\x02"), 4) - self.assertRaises(ValueError, unpad, b("123456\x00"), 4) - self.assertRaises(ValueError, unpad, b("123456\x05\x05\x05\x05\x05"), 4) - -class X923_Tests(unittest.TestCase): - - def test1(self): - padded = pad(b(""), 4, 'x923') - self.failUnless(padded == uh(b("00000004"))) - back = unpad(padded, 4, 'x923') - self.failUnless(back == b("")) - - def test2(self): - padded = pad(uh(b("12345678")), 4, 'x923') - self.failUnless(padded == uh(b("1234567800000004"))) - back = unpad(padded, 4, 'x923') - self.failUnless(back == uh(b("12345678"))) - - def test3(self): - padded = pad(uh(b("123456")), 4, 'x923') - self.failUnless(padded == uh(b("12345601"))) - back = unpad(padded, 4, 'x923') - self.failUnless(back == uh(b("123456"))) - - def test4(self): - padded = pad(uh(b("1234567890")), 4, 'x923') - self.failUnless(padded == uh(b("1234567890000003"))) - back = unpad(padded, 4, 'x923') - self.failUnless(back == uh(b("1234567890"))) - - def testn1(self): - self.assertRaises(ValueError, unpad, b("123456\x02"), 4, 'x923') - self.assertRaises(ValueError, unpad, b("123456\x00"), 4, 'x923') - self.assertRaises(ValueError, unpad, b("123456\x00\x00\x00\x00\x05"), 4, 'x923') - self.assertRaises(ValueError, unpad, b(""), 4, 'x923') - -class ISO7816_Tests(unittest.TestCase): - - def test1(self): - padded = pad(b(""), 4, 'iso7816') - self.failUnless(padded == uh(b("80000000"))) - back = unpad(padded, 4, 'iso7816') - self.failUnless(back == b("")) - - def test2(self): - padded = pad(uh(b("12345678")), 4, 'iso7816') - self.failUnless(padded == uh(b("1234567880000000"))) - back = unpad(padded, 4, 'iso7816') - self.failUnless(back == uh(b("12345678"))) - - def test3(self): - padded = pad(uh(b("123456")), 4, 'iso7816') - self.failUnless(padded == uh(b("12345680"))) - #import pdb; pdb.set_trace() - back = unpad(padded, 4, 'iso7816') - self.failUnless(back == uh(b("123456"))) - - def test4(self): - padded = pad(uh(b("1234567890")), 4, 'iso7816') - self.failUnless(padded == uh(b("1234567890800000"))) - back = unpad(padded, 4, 'iso7816') - self.failUnless(back == uh(b("1234567890"))) - - def testn1(self): - self.assertRaises(ValueError, unpad, b("123456\x81"), 4, 'iso7816') - self.assertRaises(ValueError, unpad, b(""), 4, 'iso7816') - -def get_tests(config={}): - tests = [] - tests += list_test_cases(PKCS7_Tests) - tests += list_test_cases(X923_Tests) - tests += list_test_cases(ISO7816_Tests) - return tests - -if __name__ == '__main__': - suite = lambda: unittest.TestSuite(get_tests()) - unittest.main(defaultTest='suite') - diff --git a/Crypto/SelfTest/Util/test_asn1.py b/Crypto/SelfTest/Util/test_asn1.py deleted file mode 100644 index 368e47d..0000000 --- a/Crypto/SelfTest/Util/test_asn1.py +++ /dev/null @@ -1,784 +0,0 @@ -# -# SelfTest/Util/test_asn.py: Self-test for the Crypto.Util.asn1 module -# -# =================================================================== -# -# Copyright (c) 2014, Legrandin -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# =================================================================== - -"""Self-tests for Crypto.Util.asn1""" - -import unittest - -from Crypto.Util.py3compat import * -from Crypto.Util.asn1 import (DerObject, DerSetOf, DerInteger, - DerBitString, - DerObjectId, DerNull, DerOctetString, - DerSequence) - -class DerObjectTests(unittest.TestCase): - - def testObjInit1(self): - # Fail with invalid tag format (must be 1 byte) - self.assertRaises(ValueError, DerObject, b('\x00\x99')) - # Fail with invalid implicit tag (must be <0x1F) - self.assertRaises(ValueError, DerObject, 0x1F) - - # ------ - - def testObjEncode1(self): - # No payload - der = DerObject(b('\x02')) - self.assertEquals(der.encode(), b('\x02\x00')) - # Small payload (primitive) - der.payload = b('\x45') - self.assertEquals(der.encode(), b('\x02\x01\x45')) - # Invariant - self.assertEquals(der.encode(), b('\x02\x01\x45')) - # Initialize with numerical tag - der = DerObject(0x04) - der.payload = b('\x45') - self.assertEquals(der.encode(), b('\x04\x01\x45')) - # Initialize with constructed type - der = DerObject(b('\x10'), constructed=True) - self.assertEquals(der.encode(), b('\x30\x00')) - - def testObjEncode2(self): - # Initialize with payload - der = DerObject(0x03, b('\x12\x12')) - self.assertEquals(der.encode(), b('\x03\x02\x12\x12')) - - def testObjEncode3(self): - # Long payload - der = DerObject(b('\x10')) - der.payload = b("0")*128 - self.assertEquals(der.encode(), b('\x10\x81\x80' + "0"*128)) - - def testObjEncode4(self): - # Implicit tags (constructed) - der = DerObject(0x10, implicit=1, constructed=True) - der.payload = b('ppll') - self.assertEquals(der.encode(), b('\xa1\x04ppll')) - # Implicit tags (primitive) - der = DerObject(0x02, implicit=0x1E, constructed=False) - der.payload = b('ppll') - self.assertEquals(der.encode(), b('\x9E\x04ppll')) - - def testObjEncode5(self): - # Encode type with explicit tag - der = DerObject(0x10, explicit=5) - der.payload = b("xxll") - self.assertEqual(der.encode(), b("\xa5\x06\x10\x04xxll")) - - # ----- - - def testObjDecode1(self): - # Decode short payload - der = DerObject(0x02) - der.decode(b('\x02\x02\x01\x02')) - self.assertEquals(der.payload, b("\x01\x02")) - self.assertEquals(der._tag_octet, 0x02) - - def testObjDecode2(self): - # Decode long payload - der = DerObject(0x02) - der.decode(b('\x02\x81\x80' + "1"*128)) - self.assertEquals(der.payload, b("1")*128) - self.assertEquals(der._tag_octet, 0x02) - - def testObjDecode3(self): - # Decode payload with too much data gives error - der = DerObject(0x02) - self.assertRaises(ValueError, der.decode, b('\x02\x02\x01\x02\xFF')) - # Decode payload with too little data gives error - der = DerObject(0x02) - self.assertRaises(ValueError, der.decode, b('\x02\x02\x01')) - - def testObjDecode4(self): - # Decode implicit tag (primitive) - der = DerObject(0x02, constructed=False, implicit=0xF) - self.assertRaises(ValueError, der.decode, b('\x02\x02\x01\x02')) - der.decode(b('\x8F\x01\x00')) - self.assertEquals(der.payload, b('\x00')) - # Decode implicit tag (constructed) - der = DerObject(0x02, constructed=True, implicit=0xF) - self.assertRaises(ValueError, der.decode, b('\x02\x02\x01\x02')) - der.decode(b('\xAF\x01\x00')) - self.assertEquals(der.payload, b('\x00')) - - def testObjDecode5(self): - # Decode payload with unexpected tag gives error - der = DerObject(0x02) - self.assertRaises(ValueError, der.decode, b('\x03\x02\x01\x02')) - - def testObjDecode6(self): - # Arbitrary DER object - der = DerObject() - der.decode(b('\x65\x01\x88')) - self.assertEquals(der._tag_octet, 0x65) - self.assertEquals(der.payload, b('\x88')) - - def testObjDecode7(self): - # Decode explicit tag - der = DerObject(0x10, explicit=5) - der.decode(b("\xa5\x06\x10\x04xxll")) - self.assertEquals(der._inner_tag_octet, 0x10) - self.assertEquals(der.payload, b('xxll')) - - # Explicit tag may be 0 - der = DerObject(0x10, explicit=0) - der.decode(b("\xa0\x06\x10\x04xxll")) - self.assertEquals(der._inner_tag_octet, 0x10) - self.assertEquals(der.payload, b('xxll')) - - def testObjDecode8(self): - # Verify that decode returns the object - der = DerObject(0x02) - self.assertEqual(der, der.decode(b('\x02\x02\x01\x02'))) - -class DerIntegerTests(unittest.TestCase): - - def testInit1(self): - der = DerInteger(1) - self.assertEquals(der.encode(), b('\x02\x01\x01')) - - def testEncode1(self): - # Single-byte integers - # Value 0 - der = DerInteger(0) - self.assertEquals(der.encode(), b('\x02\x01\x00')) - # Value 1 - der = DerInteger(1) - self.assertEquals(der.encode(), b('\x02\x01\x01')) - # Value 127 - der = DerInteger(127) - self.assertEquals(der.encode(), b('\x02\x01\x7F')) - - def testEncode2(self): - # Multi-byte integers - # Value 128 - der = DerInteger(128) - self.assertEquals(der.encode(), b('\x02\x02\x00\x80')) - # Value 0x180 - der = DerInteger(0x180) - self.assertEquals(der.encode(), b('\x02\x02\x01\x80')) - # One very long integer - der = DerInteger(2**2048) - self.assertEquals(der.encode(), - b('\x02\x82\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ - b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ - b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ - b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ - b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ - b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ - b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ - b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ - b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ - b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ - b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ - b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ - b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ - b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ - b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ - b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ - b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ - b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ - b('\x00\x00\x00\x00\x00\x00\x00\x00\x00')) - - def testEncode3(self): - # Negative integers - # Value -1 - der = DerInteger(-1) - self.assertEquals(der.encode(), b('\x02\x01\xFF')) - # Value -128 - der = DerInteger(-128) - self.assertEquals(der.encode(), b('\x02\x01\x80')) - # Value - der = DerInteger(-87873) - self.assertEquals(der.encode(), b('\x02\x03\xFE\xA8\xBF')) - - def testEncode4(self): - # Explicit encoding - number = DerInteger(0x34, explicit=3) - self.assertEquals(number.encode(), b('\xa3\x03\x02\x01\x34')) - - # ----- - - def testDecode1(self): - # Single-byte integer - der = DerInteger() - # Value 0 - der.decode(b('\x02\x01\x00')) - self.assertEquals(der.value, 0) - # Value 1 - der.decode(b('\x02\x01\x01')) - self.assertEquals(der.value, 1) - # Value 127 - der.decode(b('\x02\x01\x7F')) - self.assertEquals(der.value, 127) - - def testDecode2(self): - # Multi-byte integer - der = DerInteger() - # Value 0x180L - der.decode(b('\x02\x02\x01\x80')) - self.assertEquals(der.value,0x180) - # One very long integer - der.decode( - b('\x02\x82\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ - b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ - b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ - b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ - b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ - b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ - b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ - b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ - b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ - b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ - b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ - b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ - b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ - b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ - b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ - b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ - b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ - b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ - b('\x00\x00\x00\x00\x00\x00\x00\x00\x00')) - self.assertEquals(der.value,2**2048) - - def testDecode3(self): - # Negative integer - der = DerInteger() - # Value -1 - der.decode(b('\x02\x01\xFF')) - self.assertEquals(der.value, -1) - # Value -32768 - der.decode(b('\x02\x02\x80\x00')) - self.assertEquals(der.value, -32768) - - def testDecode5(self): - # We still accept BER integer format - der = DerInteger() - # Redundant leading zeroes - der.decode(b('\x02\x02\x00\x01')) - self.assertEquals(der.value, 1) - # Redundant leading 0xFF - der.decode(b('\x02\x02\xFF\xFF')) - self.assertEquals(der.value, -1) - # Empty payload - der.decode(b('\x02\x00')) - self.assertEquals(der.value, 0) - - def testDecode6(self): - # Explicit encoding - number = DerInteger(explicit=3) - number.decode(b('\xa3\x03\x02\x01\x34')) - self.assertEquals(number.value, 0x34) - - def testDecode7(self): - # Verify decode returns the DerInteger - der = DerInteger() - self.assertEquals(der, der.decode(b('\x02\x01\x7F'))) - - ### - - def testStrict1(self): - number = DerInteger() - - number.decode(b'\x02\x02\x00\x01') - number.decode(b'\x02\x02\x00\x7F') - self.assertRaises(ValueError, number.decode, b'\x02\x02\x00\x01', strict=True) - self.assertRaises(ValueError, number.decode, b'\x02\x02\x00\x7F', strict=True) - - ### - - def testErrDecode1(self): - # Wide length field - der = DerInteger() - self.assertRaises(ValueError, der.decode, b('\x02\x81\x01\x01')) - - -class DerSequenceTests(unittest.TestCase): - - def testInit1(self): - der = DerSequence([1, DerInteger(2), b('0\x00')]) - self.assertEquals(der.encode(), b('0\x08\x02\x01\x01\x02\x01\x020\x00')) - - def testEncode1(self): - # Empty sequence - der = DerSequence() - self.assertEquals(der.encode(), b('0\x00')) - self.failIf(der.hasOnlyInts()) - # One single-byte integer (zero) - der.append(0) - self.assertEquals(der.encode(), b('0\x03\x02\x01\x00')) - self.assertEquals(der.hasInts(),1) - self.assertEquals(der.hasInts(False),1) - self.failUnless(der.hasOnlyInts()) - self.failUnless(der.hasOnlyInts(False)) - # Invariant - self.assertEquals(der.encode(), b('0\x03\x02\x01\x00')) - - def testEncode2(self): - # Indexing - der = DerSequence() - der.append(0) - der[0] = 1 - self.assertEquals(len(der),1) - self.assertEquals(der[0],1) - self.assertEquals(der[-1],1) - self.assertEquals(der.encode(), b('0\x03\x02\x01\x01')) - # - der[:] = [1] - self.assertEquals(len(der),1) - self.assertEquals(der[0],1) - self.assertEquals(der.encode(), b('0\x03\x02\x01\x01')) - - def testEncode3(self): - # One multi-byte integer (non-zero) - der = DerSequence() - der.append(0x180) - self.assertEquals(der.encode(), b('0\x04\x02\x02\x01\x80')) - - def testEncode4(self): - # One very long integer - der = DerSequence() - der.append(2**2048) - self.assertEquals(der.encode(), b('0\x82\x01\x05')+ - b('\x02\x82\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ - b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ - b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ - b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ - b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ - b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ - b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ - b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ - b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ - b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ - b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ - b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ - b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ - b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ - b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ - b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ - b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ - b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ - b('\x00\x00\x00\x00\x00\x00\x00\x00\x00')) - - def testEncode5(self): - der = DerSequence() - der += 1 - der += b('\x30\x00') - self.assertEquals(der.encode(), b('\x30\x05\x02\x01\x01\x30\x00')) - - def testEncode6(self): - # Two positive integers - der = DerSequence() - der.append(0x180) - der.append(0xFF) - self.assertEquals(der.encode(), b('0\x08\x02\x02\x01\x80\x02\x02\x00\xff')) - self.failUnless(der.hasOnlyInts()) - self.failUnless(der.hasOnlyInts(False)) - # Two mixed integers - der = DerSequence() - der.append(2) - der.append(-2) - self.assertEquals(der.encode(), b('0\x06\x02\x01\x02\x02\x01\xFE')) - self.assertEquals(der.hasInts(), 1) - self.assertEquals(der.hasInts(False), 2) - self.failIf(der.hasOnlyInts()) - self.failUnless(der.hasOnlyInts(False)) - # - der.append(0x01) - der[1:] = [9,8] - self.assertEquals(len(der),3) - self.assertEqual(der[1:],[9,8]) - self.assertEqual(der[1:-1],[9]) - self.assertEquals(der.encode(), b('0\x09\x02\x01\x02\x02\x01\x09\x02\x01\x08')) - - def testEncode7(self): - # One integer and another type (already encoded) - der = DerSequence() - der.append(0x180) - der.append(b('0\x03\x02\x01\x05')) - self.assertEquals(der.encode(), b('0\x09\x02\x02\x01\x800\x03\x02\x01\x05')) - self.failIf(der.hasOnlyInts()) - - def testEncode8(self): - # One integer and another type (yet to encode) - der = DerSequence() - der.append(0x180) - der.append(DerSequence([5])) - self.assertEquals(der.encode(), b('0\x09\x02\x02\x01\x800\x03\x02\x01\x05')) - self.failIf(der.hasOnlyInts()) - - #### - - def testDecode1(self): - # Empty sequence - der = DerSequence() - der.decode(b('0\x00')) - self.assertEquals(len(der),0) - # One single-byte integer (zero) - der.decode(b('0\x03\x02\x01\x00')) - self.assertEquals(len(der),1) - self.assertEquals(der[0],0) - # Invariant - der.decode(b('0\x03\x02\x01\x00')) - self.assertEquals(len(der),1) - self.assertEquals(der[0],0) - - def testDecode2(self): - # One single-byte integer (non-zero) - der = DerSequence() - der.decode(b('0\x03\x02\x01\x7f')) - self.assertEquals(len(der),1) - self.assertEquals(der[0],127) - - def testDecode4(self): - # One very long integer - der = DerSequence() - der.decode(b('0\x82\x01\x05')+ - b('\x02\x82\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ - b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ - b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ - b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ - b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ - b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ - b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ - b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ - b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ - b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ - b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ - b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ - b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ - b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ - b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ - b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ - b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ - b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ - b('\x00\x00\x00\x00\x00\x00\x00\x00\x00')) - self.assertEquals(len(der),1) - self.assertEquals(der[0],2**2048) - - def testDecode6(self): - # Two integers - der = DerSequence() - der.decode(b('0\x08\x02\x02\x01\x80\x02\x02\x00\xff')) - self.assertEquals(len(der),2) - self.assertEquals(der[0],0x180) - self.assertEquals(der[1],0xFF) - - def testDecode7(self): - # One integer and 2 other types - der = DerSequence() - der.decode(b('0\x0A\x02\x02\x01\x80\x24\x02\xb6\x63\x12\x00')) - self.assertEquals(len(der),3) - self.assertEquals(der[0],0x180) - self.assertEquals(der[1],b('\x24\x02\xb6\x63')) - self.assertEquals(der[2],b('\x12\x00')) - - def testDecode8(self): - # Only 2 other types - der = DerSequence() - der.decode(b('0\x06\x24\x02\xb6\x63\x12\x00')) - self.assertEquals(len(der),2) - self.assertEquals(der[0],b('\x24\x02\xb6\x63')) - self.assertEquals(der[1],b('\x12\x00')) - self.assertEquals(der.hasInts(), 0) - self.assertEquals(der.hasInts(False), 0) - self.failIf(der.hasOnlyInts()) - self.failIf(der.hasOnlyInts(False)) - - def testDecode9(self): - # Verify that decode returns itself - der = DerSequence() - self.assertEqual(der, der.decode(b('0\x06\x24\x02\xb6\x63\x12\x00'))) - - ### - - def testErrDecode1(self): - # Not a sequence - der = DerSequence() - self.assertRaises(ValueError, der.decode, b('')) - self.assertRaises(ValueError, der.decode, b('\x00')) - self.assertRaises(ValueError, der.decode, b('\x30')) - - def testErrDecode2(self): - der = DerSequence() - # Too much data - self.assertRaises(ValueError, der.decode, b('\x30\x00\x00')) - - def testErrDecode3(self): - # Wrong length format - der = DerSequence() - # Missing length in sub-item - self.assertRaises(ValueError, der.decode, b('\x30\x04\x02\x01\x01\x00')) - # Valid BER, but invalid DER length - self.assertRaises(ValueError, der.decode, b('\x30\x81\x03\x02\x01\x01')) - self.assertRaises(ValueError, der.decode, b('\x30\x04\x02\x81\x01\x01')) - - def test_expected_nr_elements(self): - der_bin = DerSequence([1, 2, 3]).encode() - - DerSequence().decode(der_bin, nr_elements=3) - DerSequence().decode(der_bin, nr_elements=(2,3)) - self.assertRaises(ValueError, DerSequence().decode, der_bin, nr_elements=1) - self.assertRaises(ValueError, DerSequence().decode, der_bin, nr_elements=(4,5)) - - def test_expected_only_integers(self): - - der_bin1 = DerSequence([1, 2, 3]).encode() - der_bin2 = DerSequence([1, 2, DerSequence([3, 4])]).encode() - - DerSequence().decode(der_bin1, only_ints_expected=True) - DerSequence().decode(der_bin1, only_ints_expected=False) - DerSequence().decode(der_bin2, only_ints_expected=False) - self.assertRaises(ValueError, DerSequence().decode, der_bin2, only_ints_expected=True) - - -class DerOctetStringTests(unittest.TestCase): - - def testInit1(self): - der = DerOctetString(b('\xFF')) - self.assertEquals(der.encode(), b('\x04\x01\xFF')) - - def testEncode1(self): - # Empty sequence - der = DerOctetString() - self.assertEquals(der.encode(), b('\x04\x00')) - # Small payload - der.payload = b('\x01\x02') - self.assertEquals(der.encode(), b('\x04\x02\x01\x02')) - - #### - - def testDecode1(self): - # Empty sequence - der = DerOctetString() - der.decode(b('\x04\x00')) - self.assertEquals(der.payload, b('')) - # Small payload - der.decode(b('\x04\x02\x01\x02')) - self.assertEquals(der.payload, b('\x01\x02')) - - def testDecode2(self): - # Verify that decode returns the object - der = DerOctetString() - self.assertEqual(der, der.decode(b('\x04\x00'))) - - def testErrDecode1(self): - # No leftovers allowed - der = DerOctetString() - self.assertRaises(ValueError, der.decode, b('\x04\x01\x01\xff')) - -class DerNullTests(unittest.TestCase): - - def testEncode1(self): - der = DerNull() - self.assertEquals(der.encode(), b('\x05\x00')) - - #### - - def testDecode1(self): - # Empty sequence - der = DerNull() - self.assertEquals(der, der.decode(b('\x05\x00'))) - -class DerObjectIdTests(unittest.TestCase): - - def testInit1(self): - der = DerObjectId("1.1") - self.assertEquals(der.encode(), b('\x06\x01)')) - - def testEncode1(self): - der = DerObjectId('1.2.840.113549.1.1.1') - self.assertEquals(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.assertEquals(der.encode(), b('\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x01\x01')) - - #### - - def testDecode1(self): - # Empty sequence - der = DerObjectId() - der.decode(b('\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x01\x01')) - self.assertEquals(der.value, '1.2.840.113549.1.1.1') - - def testDecode2(self): - # Verify that decode returns the object - der = DerObjectId() - self.assertEquals(der, - 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')) - self.assertEquals(der.value, '1.2.840.113549.1.0.1') - - -class DerBitStringTests(unittest.TestCase): - - def testInit1(self): - der = DerBitString(b("\xFF")) - self.assertEquals(der.encode(), b('\x03\x02\x00\xFF')) - - def testInit2(self): - der = DerBitString(DerInteger(1)) - self.assertEquals(der.encode(), b('\x03\x04\x00\x02\x01\x01')) - - def testEncode1(self): - # Empty sequence - der = DerBitString() - self.assertEquals(der.encode(), b('\x03\x01\x00')) - # Small payload - der = DerBitString(b('\x01\x02')) - self.assertEquals(der.encode(), b('\x03\x03\x00\x01\x02')) - # Small payload - der = DerBitString() - der.value = b('\x01\x02') - self.assertEquals(der.encode(), b('\x03\x03\x00\x01\x02')) - - #### - - def testDecode1(self): - # Empty sequence - der = DerBitString() - der.decode(b('\x03\x00')) - self.assertEquals(der.value, b('')) - # Small payload - der.decode(b('\x03\x03\x00\x01\x02')) - self.assertEquals(der.value, b('\x01\x02')) - - def testDecode2(self): - # Verify that decode returns the object - der = DerBitString() - self.assertEquals(der, der.decode(b('\x03\x00'))) - - -class DerSetOfTests(unittest.TestCase): - - def testInit1(self): - der = DerSetOf([DerInteger(1), DerInteger(2)]) - self.assertEquals(der.encode(), b('1\x06\x02\x01\x01\x02\x01\x02')) - - def testEncode1(self): - # Empty set - der = DerSetOf() - self.assertEquals(der.encode(), b('1\x00')) - # One single-byte integer (zero) - der.add(0) - self.assertEquals(der.encode(), b('1\x03\x02\x01\x00')) - # Invariant - self.assertEquals(der.encode(), b('1\x03\x02\x01\x00')) - - def testEncode2(self): - # Two integers - der = DerSetOf() - der.add(0x180) - der.add(0xFF) - self.assertEquals(der.encode(), b('1\x08\x02\x02\x00\xff\x02\x02\x01\x80')) - # Initialize with integers - der = DerSetOf([0x180, 0xFF]) - self.assertEquals(der.encode(), b('1\x08\x02\x02\x00\xff\x02\x02\x01\x80')) - - def testEncode3(self): - # One integer and another type (no matter what it is) - der = DerSetOf() - der.add(0x180) - self.assertRaises(ValueError, der.add, b('\x00\x02\x00\x00')) - - def testEncode4(self): - # Only non integers - der = DerSetOf() - der.add(b('\x01\x00')) - der.add(b('\x01\x01\x01')) - self.assertEquals(der.encode(), b('1\x05\x01\x00\x01\x01\x01')) - - #### - - def testDecode1(self): - # Empty sequence - der = DerSetOf() - der.decode(b('1\x00')) - self.assertEquals(len(der),0) - # One single-byte integer (zero) - der.decode(b('1\x03\x02\x01\x00')) - self.assertEquals(len(der),1) - self.assertEquals(list(der),[0]) - - def testDecode2(self): - # Two integers - der = DerSetOf() - der.decode(b('1\x08\x02\x02\x01\x80\x02\x02\x00\xff')) - self.assertEquals(len(der),2) - l = list(der) - self.failUnless(0x180 in l) - self.failUnless(0xFF in l) - - def testDecode3(self): - # One integer and 2 other types - der = DerSetOf() - #import pdb; pdb.set_trace() - self.assertRaises(ValueError, der.decode, - b('0\x0A\x02\x02\x01\x80\x24\x02\xb6\x63\x12\x00')) - - def testDecode4(self): - # Verify that decode returns the object - der = DerSetOf() - self.assertEquals(der, - der.decode(b('1\x08\x02\x02\x01\x80\x02\x02\x00\xff'))) - - ### - - def testErrDecode1(self): - # No leftovers allowed - der = DerSetOf() - self.assertRaises(ValueError, der.decode, - b('1\x08\x02\x02\x01\x80\x02\x02\x00\xff\xAA')) - -def get_tests(config={}): - from Crypto.SelfTest.st_common import list_test_cases - listTests = [] - listTests += list_test_cases(DerObjectTests) - listTests += list_test_cases(DerIntegerTests) - listTests += list_test_cases(DerSequenceTests) - listTests += list_test_cases(DerOctetStringTests) - listTests += list_test_cases(DerNullTests) - listTests += list_test_cases(DerObjectIdTests) - listTests += list_test_cases(DerBitStringTests) - listTests += list_test_cases(DerSetOfTests) - return listTests - -if __name__ == '__main__': - suite = lambda: unittest.TestSuite(get_tests()) - unittest.main(defaultTest='suite') - -# vim:set ts=4 sw=4 sts=4 expandtab: diff --git a/Crypto/SelfTest/Util/test_number.py b/Crypto/SelfTest/Util/test_number.py deleted file mode 100644 index 13f9d19..0000000 --- a/Crypto/SelfTest/Util/test_number.py +++ /dev/null @@ -1,144 +0,0 @@ -# -*- coding: utf-8 -*- -# -# SelfTest/Util/test_number.py: Self-test for parts of the Crypto.Util.number module -# -# Written in 2008 by Dwayne C. Litzenberger -# -# =================================================================== -# The contents of this file are dedicated to the public domain. To -# the extent that dedication to the public domain is not available, -# everyone is granted a worldwide, perpetual, royalty-free, -# non-exclusive license to exercise all rights associated with the -# contents of this file for any purpose whatsoever. -# No rights are reserved. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS -# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN -# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# =================================================================== - -"""Self-tests for (some of) Crypto.Util.number""" - -from Crypto.Util.py3compat import * - -import unittest - -class MyError(Exception): - """Dummy exception used for tests""" - -# NB: In some places, we compare tuples instead of just output values so that -# if any inputs cause a test failure, we'll be able to tell which ones. - -class MiscTests(unittest.TestCase): - def setUp(self): - global number, math - from Crypto.Util import number - import math - - def test_ceil_div(self): - """Util.number.ceil_div""" - self.assertRaises(TypeError, number.ceil_div, "1", 1) - self.assertRaises(ZeroDivisionError, number.ceil_div, 1, 0) - self.assertRaises(ZeroDivisionError, number.ceil_div, -1, 0) - - # b = 1 - self.assertEqual(0, number.ceil_div(0, 1)) - self.assertEqual(1, number.ceil_div(1, 1)) - self.assertEqual(2, number.ceil_div(2, 1)) - self.assertEqual(3, number.ceil_div(3, 1)) - - # b = 2 - self.assertEqual(0, number.ceil_div(0, 2)) - self.assertEqual(1, number.ceil_div(1, 2)) - self.assertEqual(1, number.ceil_div(2, 2)) - self.assertEqual(2, number.ceil_div(3, 2)) - self.assertEqual(2, number.ceil_div(4, 2)) - self.assertEqual(3, number.ceil_div(5, 2)) - - # b = 3 - self.assertEqual(0, number.ceil_div(0, 3)) - self.assertEqual(1, number.ceil_div(1, 3)) - self.assertEqual(1, number.ceil_div(2, 3)) - self.assertEqual(1, number.ceil_div(3, 3)) - self.assertEqual(2, number.ceil_div(4, 3)) - self.assertEqual(2, number.ceil_div(5, 3)) - self.assertEqual(2, number.ceil_div(6, 3)) - self.assertEqual(3, number.ceil_div(7, 3)) - - # b = 4 - self.assertEqual(0, number.ceil_div(0, 4)) - self.assertEqual(1, number.ceil_div(1, 4)) - self.assertEqual(1, number.ceil_div(2, 4)) - self.assertEqual(1, number.ceil_div(3, 4)) - self.assertEqual(1, number.ceil_div(4, 4)) - self.assertEqual(2, number.ceil_div(5, 4)) - self.assertEqual(2, number.ceil_div(6, 4)) - self.assertEqual(2, number.ceil_div(7, 4)) - self.assertEqual(2, number.ceil_div(8, 4)) - self.assertEqual(3, number.ceil_div(9, 4)) - - def test_getStrongPrime(self): - """Util.number.getStrongPrime""" - self.assertRaises(ValueError, number.getStrongPrime, 256) - self.assertRaises(ValueError, number.getStrongPrime, 513) - bits = 512 - x = number.getStrongPrime(bits) - self.assertNotEqual(x % 2, 0) - self.assertEqual(x > (1 << bits-1)-1, 1) - self.assertEqual(x < (1 << bits), 1) - e = 2**16+1 - x = number.getStrongPrime(bits, e) - self.assertEqual(number.GCD(x-1, e), 1) - self.assertNotEqual(x % 2, 0) - self.assertEqual(x > (1 << bits-1)-1, 1) - self.assertEqual(x < (1 << bits), 1) - e = 2**16+2 - x = number.getStrongPrime(bits, e) - self.assertEqual(number.GCD((x-1)>>1, e), 1) - self.assertNotEqual(x % 2, 0) - self.assertEqual(x > (1 << bits-1)-1, 1) - self.assertEqual(x < (1 << bits), 1) - - def test_isPrime(self): - """Util.number.isPrime""" - self.assertEqual(number.isPrime(-3), False) # Regression test: negative numbers should not be prime - self.assertEqual(number.isPrime(-2), False) # Regression test: negative numbers should not be prime - self.assertEqual(number.isPrime(1), False) # Regression test: isPrime(1) caused some versions of PyCrypto to crash. - self.assertEqual(number.isPrime(2), True) - self.assertEqual(number.isPrime(3), True) - self.assertEqual(number.isPrime(4), False) - self.assertEqual(number.isPrime(2**1279-1), True) - self.assertEqual(number.isPrime(-(2**1279-1)), False) # Regression test: negative numbers should not be prime - # test some known gmp pseudo-primes taken from - # http://www.trnicely.net/misc/mpzspsp.html - for composite in (43 * 127 * 211, 61 * 151 * 211, 15259 * 30517, - 346141 * 692281, 1007119 * 2014237, 3589477 * 7178953, - 4859419 * 9718837, 2730439 * 5460877, - 245127919 * 490255837, 963939391 * 1927878781, - 4186358431 * 8372716861, 1576820467 * 3153640933): - self.assertEqual(number.isPrime(int(composite)), False) - - def test_size(self): - self.assertEqual(number.size(2),2) - self.assertEqual(number.size(3),2) - self.assertEqual(number.size(0xa2),8) - self.assertEqual(number.size(0xa2ba40),8*3) - self.assertEqual(number.size(0xa2ba40ee07e3b2bd2f02ce227f36a195024486e49c19cb41bbbdfbba98b22b0e577c2eeaffa20d883a76e65e394c69d4b3c05a1e8fadda27edb2a42bc000fe888b9b32c22d15add0cd76b3e7936e19955b220dd17d4ea904b1ec102b2e4de7751222aa99151024c7cb41cc5ea21d00eeb41f7c800834d2c6e06bce3bce7ea9a5), 1024) - self.assertRaises(ValueError, number.size, -1) - - -def get_tests(config={}): - from Crypto.SelfTest.st_common import list_test_cases - tests = list_test_cases(MiscTests) - return tests - -if __name__ == '__main__': - suite = lambda: unittest.TestSuite(get_tests()) - unittest.main(defaultTest='suite') - -# vim:set ts=4 sw=4 sts=4 expandtab: diff --git a/Crypto/SelfTest/Util/test_rfc1751.py b/Crypto/SelfTest/Util/test_rfc1751.py deleted file mode 100644 index af0aa2b..0000000 --- a/Crypto/SelfTest/Util/test_rfc1751.py +++ /dev/null @@ -1,38 +0,0 @@ -import unittest - -import binascii -from Crypto.Util.RFC1751 import key_to_english, english_to_key - - -class RFC1751_Tests(unittest.TestCase): - - def test1(self): - data = [ - ('EB33F77EE73D4053', 'TIDE ITCH SLOW REIN RULE MOT'), - ('CCAC2AED591056BE4F90FD441C534766', 'RASH BUSH MILK LOOK BAD BRIM AVID GAFF BAIT ROT POD LOVE'), - ('EFF81F9BFBC65350920CDD7416DE8009', 'TROD MUTE TAIL WARM CHAR KONG HAAG CITY BORE O TEAL AWL') - ] - - for key_hex, words in data: - key_bin = binascii.a2b_hex(key_hex) - - w2 = key_to_english(key_bin) - self.assertEqual(w2, words) - - k2 = english_to_key(words) - self.assertEqual(k2, key_bin) - - def test_error_key_to_english(self): - - self.assertRaises(ValueError, key_to_english, b'0' * 7) - - -def get_tests(config={}): - from Crypto.SelfTest.st_common import list_test_cases - tests = list_test_cases(RFC1751_Tests) - return tests - - -if __name__ == '__main__': - suite = lambda: unittest.TestSuite(get_tests()) - unittest.main(defaultTest='suite') diff --git a/Crypto/SelfTest/Util/test_strxor.py b/Crypto/SelfTest/Util/test_strxor.py deleted file mode 100644 index c91d38f..0000000 --- a/Crypto/SelfTest/Util/test_strxor.py +++ /dev/null @@ -1,280 +0,0 @@ -# -# SelfTest/Util/test_strxor.py: Self-test for XORing -# -# =================================================================== -# -# Copyright (c) 2014, Legrandin -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# =================================================================== - -import unittest -from binascii import unhexlify, hexlify - -from Crypto.SelfTest.st_common import list_test_cases -from Crypto.Util.strxor import strxor, strxor_c - - -class StrxorTests(unittest.TestCase): - - def test1(self): - term1 = unhexlify(b"ff339a83e5cd4cdf5649") - term2 = unhexlify(b"383d4ba020573314395b") - result = unhexlify(b"c70ed123c59a7fcb6f12") - self.assertEqual(strxor(term1, term2), result) - self.assertEqual(strxor(term2, term1), result) - - def test2(self): - es = b"" - self.assertEqual(strxor(es, es), es) - - def test3(self): - term1 = unhexlify(b"ff339a83e5cd4cdf5649") - all_zeros = b"\x00" * len(term1) - self.assertEqual(strxor(term1, term1), all_zeros) - - def test_wrong_length(self): - term1 = unhexlify(b"ff339a83e5cd4cdf5649") - term2 = unhexlify(b"ff339a83e5cd4cdf564990") - self.assertRaises(ValueError, strxor, term1, term2) - - def test_bytearray(self): - term1 = unhexlify(b"ff339a83e5cd4cdf5649") - term1_ba = bytearray(term1) - term2 = unhexlify(b"383d4ba020573314395b") - result = unhexlify(b"c70ed123c59a7fcb6f12") - - self.assertEqual(strxor(term1_ba, term2), result) - - def test_memoryview(self): - term1 = unhexlify(b"ff339a83e5cd4cdf5649") - term1_mv = memoryview(term1) - term2 = unhexlify(b"383d4ba020573314395b") - result = unhexlify(b"c70ed123c59a7fcb6f12") - - self.assertEqual(strxor(term1_mv, term2), result) - - def test_output_bytearray(self): - """Verify result can be stored in pre-allocated memory""" - - term1 = unhexlify(b"ff339a83e5cd4cdf5649") - term2 = unhexlify(b"383d4ba020573314395b") - original_term1 = term1[:] - original_term2 = term2[:] - expected_xor = unhexlify(b"c70ed123c59a7fcb6f12") - output = bytearray(len(term1)) - - result = strxor(term1, term2, output=output) - - self.assertEqual(result, None) - self.assertEqual(output, expected_xor) - self.assertEqual(term1, original_term1) - self.assertEqual(term2, original_term2) - - def test_output_memoryview(self): - """Verify result can be stored in pre-allocated memory""" - - term1 = unhexlify(b"ff339a83e5cd4cdf5649") - term2 = unhexlify(b"383d4ba020573314395b") - original_term1 = term1[:] - original_term2 = term2[:] - expected_xor = unhexlify(b"c70ed123c59a7fcb6f12") - output = memoryview(bytearray(len(term1))) - - result = strxor(term1, term2, output=output) - - self.assertEqual(result, None) - self.assertEqual(output, expected_xor) - self.assertEqual(term1, original_term1) - self.assertEqual(term2, original_term2) - - def test_output_overlapping_bytearray(self): - """Verify result can be stored in overlapping memory""" - - term1 = bytearray(unhexlify(b"ff339a83e5cd4cdf5649")) - term2 = unhexlify(b"383d4ba020573314395b") - original_term2 = term2[:] - expected_xor = unhexlify(b"c70ed123c59a7fcb6f12") - - result = strxor(term1, term2, output=term1) - - self.assertEqual(result, None) - self.assertEqual(term1, expected_xor) - self.assertEqual(term2, original_term2) - - def test_output_overlapping_memoryview(self): - """Verify result can be stored in overlapping memory""" - - term1 = memoryview(bytearray(unhexlify(b"ff339a83e5cd4cdf5649"))) - term2 = unhexlify(b"383d4ba020573314395b") - original_term2 = term2[:] - expected_xor = unhexlify(b"c70ed123c59a7fcb6f12") - - result = strxor(term1, term2, output=term1) - - self.assertEqual(result, None) - self.assertEqual(term1, expected_xor) - self.assertEqual(term2, original_term2) - - def test_output_ro_bytes(self): - """Verify result cannot be stored in read-only memory""" - - term1 = unhexlify(b"ff339a83e5cd4cdf5649") - term2 = unhexlify(b"383d4ba020573314395b") - - self.assertRaises(TypeError, strxor, term1, term2, output=term1) - - def test_output_ro_memoryview(self): - """Verify result cannot be stored in read-only memory""" - - term1 = memoryview(unhexlify(b"ff339a83e5cd4cdf5649")) - term2 = unhexlify(b"383d4ba020573314395b") - - self.assertRaises(TypeError, strxor, term1, term2, output=term1) - - def test_output_incorrect_length(self): - """Verify result cannot be stored in memory of incorrect length""" - - term1 = unhexlify(b"ff339a83e5cd4cdf5649") - term2 = unhexlify(b"383d4ba020573314395b") - output = bytearray(len(term1) - 1) - - self.assertRaises(ValueError, strxor, term1, term2, output=output) - - -class Strxor_cTests(unittest.TestCase): - - def test1(self): - term1 = unhexlify(b"ff339a83e5cd4cdf5649") - result = unhexlify(b"be72dbc2a48c0d9e1708") - self.assertEqual(strxor_c(term1, 65), result) - - def test2(self): - term1 = unhexlify(b"ff339a83e5cd4cdf5649") - self.assertEqual(strxor_c(term1, 0), term1) - - def test3(self): - self.assertEqual(strxor_c(b"", 90), b"") - - def test_wrong_range(self): - term1 = unhexlify(b"ff339a83e5cd4cdf5649") - self.assertRaises(ValueError, strxor_c, term1, -1) - self.assertRaises(ValueError, strxor_c, term1, 256) - - def test_bytearray(self): - term1 = unhexlify(b"ff339a83e5cd4cdf5649") - term1_ba = bytearray(term1) - result = unhexlify(b"be72dbc2a48c0d9e1708") - - self.assertEqual(strxor_c(term1_ba, 65), result) - - def test_memoryview(self): - term1 = unhexlify(b"ff339a83e5cd4cdf5649") - term1_mv = memoryview(term1) - result = unhexlify(b"be72dbc2a48c0d9e1708") - - self.assertEqual(strxor_c(term1_mv, 65), result) - - def test_output_bytearray(self): - term1 = unhexlify(b"ff339a83e5cd4cdf5649") - original_term1 = term1[:] - expected_result = unhexlify(b"be72dbc2a48c0d9e1708") - output = bytearray(len(term1)) - - result = strxor_c(term1, 65, output=output) - - self.assertEqual(result, None) - self.assertEqual(output, expected_result) - self.assertEqual(term1, original_term1) - - def test_output_memoryview(self): - term1 = unhexlify(b"ff339a83e5cd4cdf5649") - original_term1 = term1[:] - expected_result = unhexlify(b"be72dbc2a48c0d9e1708") - output = memoryview(bytearray(len(term1))) - - result = strxor_c(term1, 65, output=output) - - self.assertEqual(result, None) - self.assertEqual(output, expected_result) - self.assertEqual(term1, original_term1) - - def test_output_overlapping_bytearray(self): - """Verify result can be stored in overlapping memory""" - - term1 = bytearray(unhexlify(b"ff339a83e5cd4cdf5649")) - expected_xor = unhexlify(b"be72dbc2a48c0d9e1708") - - result = strxor_c(term1, 65, output=term1) - - self.assertEqual(result, None) - self.assertEqual(term1, expected_xor) - - def test_output_overlapping_memoryview(self): - """Verify result can be stored in overlapping memory""" - - term1 = memoryview(bytearray(unhexlify(b"ff339a83e5cd4cdf5649"))) - expected_xor = unhexlify(b"be72dbc2a48c0d9e1708") - - result = strxor_c(term1, 65, output=term1) - - self.assertEqual(result, None) - self.assertEqual(term1, expected_xor) - - def test_output_ro_bytes(self): - """Verify result cannot be stored in read-only memory""" - - term1 = unhexlify(b"ff339a83e5cd4cdf5649") - - self.assertRaises(TypeError, strxor_c, term1, 65, output=term1) - - def test_output_ro_memoryview(self): - """Verify result cannot be stored in read-only memory""" - - term1 = memoryview(unhexlify(b"ff339a83e5cd4cdf5649")) - term2 = unhexlify(b"383d4ba020573314395b") - - self.assertRaises(TypeError, strxor_c, term1, 65, output=term1) - - def test_output_incorrect_length(self): - """Verify result cannot be stored in memory of incorrect length""" - - term1 = unhexlify(b"ff339a83e5cd4cdf5649") - output = bytearray(len(term1) - 1) - - self.assertRaises(ValueError, strxor_c, term1, 65, output=output) - - -def get_tests(config={}): - tests = [] - tests += list_test_cases(StrxorTests) - tests += list_test_cases(Strxor_cTests) - return tests - - -if __name__ == '__main__': - suite = lambda: unittest.TestSuite(get_tests()) - unittest.main(defaultTest='suite') diff --git a/Crypto/SelfTest/__init__.py b/Crypto/SelfTest/__init__.py deleted file mode 100644 index bc34f4a..0000000 --- a/Crypto/SelfTest/__init__.py +++ /dev/null @@ -1,97 +0,0 @@ -# -*- coding: utf-8 -*- -# -# SelfTest/__init__.py: Self-test for PyCrypto -# -# Written in 2008 by Dwayne C. Litzenberger -# -# =================================================================== -# The contents of this file are dedicated to the public domain. To -# the extent that dedication to the public domain is not available, -# everyone is granted a worldwide, perpetual, royalty-free, -# non-exclusive license to exercise all rights associated with the -# contents of this file for any purpose whatsoever. -# No rights are reserved. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS -# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN -# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# =================================================================== - -"""Self tests - -These tests should perform quickly and can ideally be used every time an -application runs. -""" - -__revision__ = "$Id$" - -import sys -import unittest -from Crypto.Util.py3compat import BytesIO - -class SelfTestError(Exception): - def __init__(self, message, result): - Exception.__init__(self, message, result) - self.message = message - self.result = result - -def run(module=None, verbosity=0, stream=None, tests=None, config=None, **kwargs): - """Execute self-tests. - - This raises SelfTestError if any test is unsuccessful. - - You may optionally pass in a sub-module of SelfTest if you only want to - perform some of the tests. For example, the following would test only the - hash modules: - - Crypto.SelfTest.run(Crypto.SelfTest.Hash) - - """ - - if config is None: - config = {} - suite = unittest.TestSuite() - if module is None: - if tests is None: - tests = get_tests(config=config) - suite.addTests(tests) - else: - if tests is None: - suite.addTests(module.get_tests(config=config)) - else: - raise ValueError("'module' and 'tests' arguments are mutually exclusive") - if stream is None: - kwargs['stream'] = BytesIO() - else: - kwargs['stream'] = stream - runner = unittest.TextTestRunner(verbosity=verbosity, **kwargs) - result = runner.run(suite) - if not result.wasSuccessful(): - if stream is None: - sys.stderr.write(kwargs['stream'].getvalue()) - raise SelfTestError("Self-test failed", result) - return result - -def get_tests(config={}): - tests = [] - from Crypto.SelfTest import Cipher; tests += Cipher.get_tests(config=config) - from Crypto.SelfTest import Hash; tests += Hash.get_tests(config=config) - from Crypto.SelfTest import Protocol; tests += Protocol.get_tests(config=config) - from Crypto.SelfTest import PublicKey; tests += PublicKey.get_tests(config=config) - from Crypto.SelfTest import Random; tests += Random.get_tests(config=config) - from Crypto.SelfTest import Util; tests += Util.get_tests(config=config) - from Crypto.SelfTest import Signature; tests += Signature.get_tests(config=config) - from Crypto.SelfTest import IO; tests += IO.get_tests(config=config) - from Crypto.SelfTest import Math; tests += Math.get_tests(config=config) - return tests - -if __name__ == '__main__': - suite = lambda: unittest.TestSuite(get_tests()) - unittest.main(defaultTest='suite') - -# vim:set ts=4 sw=4 sts=4 expandtab: diff --git a/Crypto/SelfTest/__main__.py b/Crypto/SelfTest/__main__.py deleted file mode 100644 index 9ab0912..0000000 --- a/Crypto/SelfTest/__main__.py +++ /dev/null @@ -1,38 +0,0 @@ -#! /usr/bin/env python -# -# __main__.py : Stand-along loader for PyCryptodome test suite -# -# =================================================================== -# The contents of this file are dedicated to the public domain. To -# the extent that dedication to the public domain is not available, -# everyone is granted a worldwide, perpetual, royalty-free, -# non-exclusive license to exercise all rights associated with the -# contents of this file for any purpose whatsoever. -# No rights are reserved. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS -# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN -# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# =================================================================== - -from __future__ import print_function - -import sys - -from Crypto import SelfTest - -slow_tests = not "--skip-slow-tests" in sys.argv -if not slow_tests: - print("Skipping slow tests") - -wycheproof_warnings = "--wycheproof-warnings" in sys.argv -if wycheproof_warnings: - print("Printing Wycheproof warnings") - -config = {'slow_tests' : slow_tests, 'wycheproof_warnings' : wycheproof_warnings } -SelfTest.run(stream=sys.stdout, verbosity=1, config=config) diff --git a/Crypto/SelfTest/loader.py b/Crypto/SelfTest/loader.py deleted file mode 100644 index 18be270..0000000 --- a/Crypto/SelfTest/loader.py +++ /dev/null @@ -1,206 +0,0 @@ -# =================================================================== -# -# Copyright (c) 2016, Legrandin -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# =================================================================== - -import os -import re -import json -import errno -import binascii -import warnings -from binascii import unhexlify -from Crypto.Util.py3compat import FileNotFoundError - - -try: - import pycryptodome_test_vectors # type: ignore - test_vectors_available = True -except ImportError: - test_vectors_available = False - - -def _load_tests(dir_comps, file_in, description, conversions): - """Load and parse a test vector file - - Return a list of objects, one per group of adjacent - KV lines or for a single line in the form "[.*]". - - For a group of lines, the object has one attribute per line. - """ - - line_number = 0 - results = [] - - class TestVector(object): - def __init__(self, description, count): - self.desc = description - self.count = count - self.others = [] - - test_vector = None - count = 0 - new_group = True - - while True: - line_number += 1 - line = file_in.readline() - if not line: - if test_vector is not None: - results.append(test_vector) - break - line = line.strip() - - # Skip comments and empty lines - if line.startswith('#') or not line: - new_group = True - continue - - if line.startswith("["): - if test_vector is not None: - results.append(test_vector) - test_vector = None - results.append(line) - continue - - if new_group: - count += 1 - new_group = False - if test_vector is not None: - results.append(test_vector) - test_vector = TestVector("%s (#%d)" % (description, count), count) - - res = re.match("([A-Za-z0-9]+) = ?(.*)", line) - if not res: - test_vector.others += [line] - else: - token = res.group(1).lower() - data = res.group(2).lower() - - conversion = conversions.get(token, None) - if conversion is None: - if len(data) % 2 != 0: - data = "0" + data - setattr(test_vector, token, binascii.unhexlify(data)) - else: - setattr(test_vector, token, conversion(data)) - - # This line is ignored - return results - - -def load_test_vectors(dir_comps, file_name, description, conversions): - """Load and parse a test vector file - - This function returns a list of objects, one per group of adjacent - KV lines or for a single line in the form "[.*]". - - For a group of lines, the object has one attribute per line. - """ - - results = None - - try: - if not test_vectors_available: - raise FileNotFoundError(errno.ENOENT, - os.strerror(errno.ENOENT), - file_name) - - description = "%s test (%s)" % (description, file_name) - - init_dir = os.path.dirname(pycryptodome_test_vectors.__file__) - full_file_name = os.path.join(os.path.join(init_dir, *dir_comps), file_name) - with open(full_file_name) as file_in: - results = _load_tests(dir_comps, file_in, description, conversions) - - except FileNotFoundError: - warnings.warn("Warning: skipping extended tests for " + description, - UserWarning, - stacklevel=2) - - return results - - -def load_test_vectors_wycheproof(dir_comps, file_name, description, - root_tag={}, group_tag={}, unit_tag={}): - - result = [] - try: - if not test_vectors_available: - raise FileNotFoundError(errno.ENOENT, - os.strerror(errno.ENOENT), - file_name) - - init_dir = os.path.dirname(pycryptodome_test_vectors.__file__) - full_file_name = os.path.join(os.path.join(init_dir, *dir_comps), file_name) - with open(full_file_name) as file_in: - tv_tree = json.load(file_in) - - except FileNotFoundError: - warnings.warn("Warning: skipping extended tests for " + description, - UserWarning, - stacklevel=2) - return result - - class TestVector(object): - pass - - common_root = {} - for k, v in root_tag.items(): - common_root[k] = v(tv_tree) - - for group in tv_tree['testGroups']: - - common_group = {} - for k, v in group_tag.items(): - common_group[k] = v(group) - - for test in group['tests']: - tv = TestVector() - - for k, v in common_root.items(): - setattr(tv, k, v) - for k, v in common_group.items(): - setattr(tv, k, v) - - tv.id = test['tcId'] - tv.comment = test['comment'] - for attr in 'key', 'iv', 'aad', 'msg', 'ct', 'tag', 'label', 'ikm', 'salt', 'info', 'okm', 'sig': - if attr in test: - setattr(tv, attr, unhexlify(test[attr])) - tv.filename = file_name - - for k, v in unit_tag.items(): - setattr(tv, k, v(test)) - - tv.valid = test['result'] != "invalid" - tv.warning = test['result'] == "acceptable" - result.append(tv) - - return result - diff --git a/Crypto/SelfTest/st_common.py b/Crypto/SelfTest/st_common.py deleted file mode 100644 index e098d81..0000000 --- a/Crypto/SelfTest/st_common.py +++ /dev/null @@ -1,55 +0,0 @@ -# -*- coding: utf-8 -*- -# -# SelfTest/st_common.py: Common functions for SelfTest modules -# -# Written in 2008 by Dwayne C. Litzenberger -# -# =================================================================== -# The contents of this file are dedicated to the public domain. To -# the extent that dedication to the public domain is not available, -# everyone is granted a worldwide, perpetual, royalty-free, -# non-exclusive license to exercise all rights associated with the -# contents of this file for any purpose whatsoever. -# No rights are reserved. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS -# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN -# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# =================================================================== - -"""Common functions for SelfTest modules""" - -import unittest -import binascii -from Crypto.Util.py3compat import b - - -def list_test_cases(class_): - """Return a list of TestCase instances given a TestCase class - - This is useful when you have defined test* methods on your TestCase class. - """ - return unittest.TestLoader().loadTestsFromTestCase(class_) - -def strip_whitespace(s): - """Remove whitespace from a text or byte string""" - if isinstance(s,str): - return b("".join(s.split())) - else: - return b("").join(s.split()) - -def a2b_hex(s): - """Convert hexadecimal to binary, ignoring whitespace""" - return binascii.a2b_hex(strip_whitespace(s)) - -def b2a_hex(s): - """Convert binary to hexadecimal""" - # For completeness - return binascii.b2a_hex(s) - -# vim:set ts=4 sw=4 sts=4 expandtab: diff --git a/Crypto/Signature/DSS.py b/Crypto/Signature/DSS.py deleted file mode 100644 index 4092d42..0000000 --- a/Crypto/Signature/DSS.py +++ /dev/null @@ -1,416 +0,0 @@ -# -# Signature/DSS.py : DSS.py -# -# =================================================================== -# -# Copyright (c) 2014, Legrandin -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# =================================================================== - -__all__ = ['new'] - - -from Crypto.Util.asn1 import DerSequence -from Crypto.Util.number import long_to_bytes -from Crypto.Math.Numbers import Integer - -from Crypto.Hash import HMAC -from Crypto.PublicKey.ECC import EccKey -from Crypto.PublicKey.DSA import DsaKey - - -class DssSigScheme(object): - """A (EC)DSA signature object. - Do not instantiate directly. - Use :func:`Crypto.Signature.DSS.new`. - """ - - def __init__(self, key, encoding, order): - """Create a new Digital Signature Standard (DSS) object. - - Do not instantiate this object directly, - use `Crypto.Signature.DSS.new` instead. - """ - - self._key = key - self._encoding = encoding - self._order = order - - self._order_bits = self._order.size_in_bits() - self._order_bytes = (self._order_bits - 1) // 8 + 1 - - def can_sign(self): - """Return ``True`` if this signature object can be used - for signing messages.""" - - return self._key.has_private() - - def _compute_nonce(self, msg_hash): - raise NotImplementedError("To be provided by subclasses") - - def _valid_hash(self, msg_hash): - raise NotImplementedError("To be provided by subclasses") - - def sign(self, msg_hash): - """Produce the DSA/ECDSA signature of a message. - - :parameter msg_hash: - The hash that was carried out over the message. - The object belongs to the :mod:`Crypto.Hash` package. - - Under mode *'fips-186-3'*, the hash must be a FIPS - approved secure hash (SHA-1 or a member of the SHA-2 family), - of cryptographic strength appropriate for the DSA key. - For instance, a 3072/256 DSA key can only be used - in combination with SHA-512. - :type msg_hash: hash object - - :return: The signature as a *byte string* - :raise ValueError: if the hash algorithm is incompatible to the (EC)DSA key - :raise TypeError: if the (EC)DSA key has no private half - """ - - if not self._valid_hash(msg_hash): - raise ValueError("Hash is not sufficiently strong") - - # Generate the nonce k (critical!) - nonce = self._compute_nonce(msg_hash) - - # Perform signature using the raw API - z = Integer.from_bytes(msg_hash.digest()[:self._order_bytes]) - sig_pair = self._key._sign(z, nonce) - - # Encode the signature into a single byte string - if self._encoding == 'binary': - output = b"".join([long_to_bytes(x, self._order_bytes) - for x in sig_pair]) - else: - # Dss-sig ::= SEQUENCE { - # r INTEGER, - # s INTEGER - # } - # Ecdsa-Sig-Value ::= SEQUENCE { - # r INTEGER, - # s INTEGER - # } - output = DerSequence(sig_pair).encode() - - return output - - def verify(self, msg_hash, signature): - """Check if a certain (EC)DSA signature is authentic. - - :parameter msg_hash: - The hash that was carried out over the message. - This is an object belonging to the :mod:`Crypto.Hash` module. - - Under mode *'fips-186-3'*, the hash must be a FIPS - approved secure hash (SHA-1 or a member of the SHA-2 family), - of cryptographic strength appropriate for the DSA key. - For instance, a 3072/256 DSA key can only be used in - combination with SHA-512. - :type msg_hash: hash object - - :parameter signature: - The signature that needs to be validated - :type signature: byte string - - :raise ValueError: if the signature is not authentic - """ - - if not self._valid_hash(msg_hash): - raise ValueError("Hash is not sufficiently strong") - - if self._encoding == 'binary': - if len(signature) != (2 * self._order_bytes): - raise ValueError("The signature is not authentic (length)") - r_prime, s_prime = [Integer.from_bytes(x) - for x in (signature[:self._order_bytes], - signature[self._order_bytes:])] - else: - try: - der_seq = DerSequence().decode(signature, strict=True) - except (ValueError, IndexError): - raise ValueError("The signature is not authentic (DER)") - if len(der_seq) != 2 or not der_seq.hasOnlyInts(): - raise ValueError("The signature is not authentic (DER content)") - r_prime, s_prime = Integer(der_seq[0]), Integer(der_seq[1]) - - if not (0 < r_prime < self._order) or not (0 < s_prime < self._order): - raise ValueError("The signature is not authentic (d)") - - z = Integer.from_bytes(msg_hash.digest()[:self._order_bytes]) - result = self._key._verify(z, (r_prime, s_prime)) - if not result: - raise ValueError("The signature is not authentic") - # Make PyCrypto code to fail - return False - - -class DeterministicDsaSigScheme(DssSigScheme): - # Also applicable to ECDSA - - def __init__(self, key, encoding, order, private_key): - super(DeterministicDsaSigScheme, self).__init__(key, encoding, order) - self._private_key = private_key - - def _bits2int(self, bstr): - """See 2.3.2 in RFC6979""" - - result = Integer.from_bytes(bstr) - q_len = self._order.size_in_bits() - b_len = len(bstr) * 8 - if b_len > q_len: - # Only keep leftmost q_len bits - result >>= (b_len - q_len) - return result - - def _int2octets(self, int_mod_q): - """See 2.3.3 in RFC6979""" - - assert 0 < int_mod_q < self._order - return long_to_bytes(int_mod_q, self._order_bytes) - - def _bits2octets(self, bstr): - """See 2.3.4 in RFC6979""" - - z1 = self._bits2int(bstr) - if z1 < self._order: - z2 = z1 - else: - z2 = z1 - self._order - return self._int2octets(z2) - - def _compute_nonce(self, mhash): - """Generate k in a deterministic way""" - - # See section 3.2 in RFC6979.txt - # Step a - h1 = mhash.digest() - # Step b - mask_v = b'\x01' * mhash.digest_size - # Step c - nonce_k = b'\x00' * mhash.digest_size - - for int_oct in (b'\x00', b'\x01'): - # Step d/f - nonce_k = HMAC.new(nonce_k, - mask_v + int_oct + - self._int2octets(self._private_key) + - self._bits2octets(h1), mhash).digest() - # Step e/g - mask_v = HMAC.new(nonce_k, mask_v, mhash).digest() - - nonce = -1 - while not (0 < nonce < self._order): - # Step h.C (second part) - if nonce != -1: - nonce_k = HMAC.new(nonce_k, mask_v + b'\x00', - mhash).digest() - mask_v = HMAC.new(nonce_k, mask_v, mhash).digest() - - # Step h.A - mask_t = b"" - - # Step h.B - while len(mask_t) < self._order_bytes: - mask_v = HMAC.new(nonce_k, mask_v, mhash).digest() - mask_t += mask_v - - # Step h.C (first part) - nonce = self._bits2int(mask_t) - return nonce - - def _valid_hash(self, msg_hash): - return True - - -class FipsDsaSigScheme(DssSigScheme): - - #: List of L (bit length of p) and N (bit length of q) combinations - #: that are allowed by FIPS 186-3. The security level is provided in - #: Table 2 of FIPS 800-57 (rev3). - _fips_186_3_L_N = ( - (1024, 160), # 80 bits (SHA-1 or stronger) - (2048, 224), # 112 bits (SHA-224 or stronger) - (2048, 256), # 128 bits (SHA-256 or stronger) - (3072, 256) # 256 bits (SHA-512) - ) - - def __init__(self, key, encoding, order, randfunc): - super(FipsDsaSigScheme, self).__init__(key, encoding, order) - self._randfunc = randfunc - - L = Integer(key.p).size_in_bits() - if (L, self._order_bits) not in self._fips_186_3_L_N: - error = ("L/N (%d, %d) is not compliant to FIPS 186-3" - % (L, self._order_bits)) - raise ValueError(error) - - def _compute_nonce(self, msg_hash): - # hash is not used - return Integer.random_range(min_inclusive=1, - max_exclusive=self._order, - randfunc=self._randfunc) - - def _valid_hash(self, msg_hash): - """Verify that SHA-1, SHA-2 or SHA-3 are used""" - return (msg_hash.oid == "1.3.14.3.2.26" or - msg_hash.oid.startswith("2.16.840.1.101.3.4.2.")) - - -class FipsEcDsaSigScheme(DssSigScheme): - - def __init__(self, key, encoding, order, randfunc): - super(FipsEcDsaSigScheme, self).__init__(key, encoding, order) - self._randfunc = randfunc - - def _compute_nonce(self, msg_hash): - return Integer.random_range(min_inclusive=1, - max_exclusive=self._key._curve.order, - randfunc=self._randfunc) - - def _valid_hash(self, msg_hash): - """Verify that SHA-[23] (256|384|512) bits are used to - match the security of P-256 (128 bits), P-384 (192 bits) - or P-521 (256 bits)""" - - modulus_bits = self._key.pointQ.size_in_bits() - - sha256 = ( "2.16.840.1.101.3.4.2.1", "2.16.840.1.101.3.4.2.8" ) - sha384 = ( "2.16.840.1.101.3.4.2.2", "2.16.840.1.101.3.4.2.9" ) - sha512 = ( "2.16.840.1.101.3.4.2.3", "2.16.840.1.101.3.4.2.10") - - if msg_hash.oid in sha256: - return modulus_bits <= 256 - elif msg_hash.oid in sha384: - return modulus_bits <= 384 - else: - return msg_hash.oid in sha512 - - -def new(key, mode, encoding='binary', randfunc=None): - """Create a signature object :class:`DSS_SigScheme` that - can perform (EC)DSA signature or verification. - - .. note:: - Refer to `NIST SP 800 Part 1 Rev 4`_ (or newer release) for an - overview of the recommended key lengths. - - :parameter key: - The key to use for computing the signature (*private* keys only) - or verifying one: it must be either - :class:`Crypto.PublicKey.DSA` or :class:`Crypto.PublicKey.ECC`. - - For DSA keys, let ``L`` and ``N`` be the bit lengths of the modulus ``p`` - and of ``q``: the pair ``(L,N)`` must appear in the following list, - in compliance to section 4.2 of `FIPS 186-4`_: - - - (1024, 160) *legacy only; do not create new signatures with this* - - (2048, 224) *deprecated; do not create new signatures with this* - - (2048, 256) - - (3072, 256) - - For ECC, only keys over P-256, P384, and P-521 are accepted. - :type key: - a key object - - :parameter mode: - The parameter can take these values: - - - *'fips-186-3'*. The signature generation is randomized and carried out - according to `FIPS 186-3`_: the nonce ``k`` is taken from the RNG. - - *'deterministic-rfc6979'*. The signature generation is not - randomized. See RFC6979_. - :type mode: - string - - :parameter encoding: - How the signature is encoded. This value determines the output of - :meth:`sign` and the input to :meth:`verify`. - - The following values are accepted: - - - *'binary'* (default), the signature is the raw concatenation - of ``r`` and ``s``. It is defined in the IEEE P.1363 standard. - - For DSA, the size in bytes of the signature is ``N/4`` bytes - (e.g. 64 for ``N=256``). - - For ECDSA, the signature is always twice the length of a point - coordinate (e.g. 64 bytes for P-256). - - - *'der'*, the signature is a ASN.1 DER SEQUENCE - with two INTEGERs (``r`` and ``s``). It is defined in RFC3279_. - The size of the signature is variable. - :type encoding: string - - :parameter randfunc: - A function that returns random *byte strings*, of a given length. - If omitted, the internal RNG is used. - Only applicable for the *'fips-186-3'* mode. - :type randfunc: callable - - .. _FIPS 186-3: http://csrc.nist.gov/publications/fips/fips186-3/fips_186-3.pdf - .. _FIPS 186-4: http://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.186-4.pdf - .. _NIST SP 800 Part 1 Rev 4: http://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-57pt1r4.pdf - .. _RFC6979: http://tools.ietf.org/html/rfc6979 - .. _RFC3279: https://tools.ietf.org/html/rfc3279#section-2.2.2 - """ - - # The goal of the 'mode' parameter is to avoid to - # have the current version of the standard as default. - # - # Over time, such version will be superseded by (for instance) - # FIPS 186-4 and it will be odd to have -3 as default. - - if encoding not in ('binary', 'der'): - raise ValueError("Unknown encoding '%s'" % encoding) - - if isinstance(key, EccKey): - order = key._curve.order - private_key_attr = 'd' - elif isinstance(key, DsaKey): - order = Integer(key.q) - private_key_attr = 'x' - else: - raise ValueError("Unsupported key type " + str(type(key))) - - if key.has_private(): - private_key = getattr(key, private_key_attr) - else: - private_key = None - - if mode == 'deterministic-rfc6979': - return DeterministicDsaSigScheme(key, encoding, order, private_key) - elif mode == 'fips-186-3': - if isinstance(key, EccKey): - return FipsEcDsaSigScheme(key, encoding, order, randfunc) - else: - return FipsDsaSigScheme(key, encoding, order, randfunc) - else: - raise ValueError("Unknown DSS mode '%s'" % mode) diff --git a/Crypto/Signature/DSS.pyi b/Crypto/Signature/DSS.pyi deleted file mode 100644 index 08cad81..0000000 --- a/Crypto/Signature/DSS.pyi +++ /dev/null @@ -1,27 +0,0 @@ -from typing import Union, Optional, Callable -from typing_extensions import Protocol - -from Crypto.PublicKey.DSA import DsaKey -from Crypto.PublicKey.ECC import EccKey - -class Hash(Protocol): - def digest(self) -> bytes: ... - -__all__ = ['new'] - -class DssSigScheme: - def __init__(self, key: Union[DsaKey, EccKey], encoding: str, order: int) -> None: ... - def can_sign(self) -> bool: ... - def sign(self, msg_hash: Hash) -> bytes: ... - def verify(self, msg_hash: Hash, signature: bytes) -> bool: ... - -class DeterministicDsaSigScheme(DssSigScheme): - def __init__(self, key, encoding, order, private_key) -> None: ... - -class FipsDsaSigScheme(DssSigScheme): - def __init__(self, key: DsaKey, encoding: str, order: int, randfunc: Callable) -> None: ... - -class FipsEcDsaSigScheme(DssSigScheme): - def __init__(self, key: EccKey, encoding: str, order: int, randfunc: Callable) -> None: ... - -def new(key: Union[DsaKey, EccKey], mode: str, encoding: Optional[str]='binary', randfunc: Optional[Callable]=None) -> Union[DeterministicDsaSigScheme, FipsDsaSigScheme, FipsEcDsaSigScheme]: ... diff --git a/Crypto/Signature/PKCS1_PSS.py b/Crypto/Signature/PKCS1_PSS.py deleted file mode 100644 index c39d388..0000000 --- a/Crypto/Signature/PKCS1_PSS.py +++ /dev/null @@ -1,55 +0,0 @@ -# =================================================================== -# -# Copyright (c) 2014, Legrandin -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# =================================================================== - -""" -Legacy module for PKCS#1 PSS signatures. - -:undocumented: __package__ -""" - -import types - -from Crypto.Signature import pss - - -def _pycrypto_verify(self, hash_object, signature): - try: - self._verify(hash_object, signature) - except (ValueError, TypeError): - return False - return True - - -def new(rsa_key, mgfunc=None, saltLen=None, randfunc=None): - pkcs1 = pss.new(rsa_key, mask_func=mgfunc, - salt_bytes=saltLen, rand_func=randfunc) - pkcs1._verify = pkcs1.verify - pkcs1.verify = types.MethodType(_pycrypto_verify, pkcs1) - return pkcs1 diff --git a/Crypto/Signature/PKCS1_PSS.pyi b/Crypto/Signature/PKCS1_PSS.pyi deleted file mode 100644 index 882cc8f..0000000 --- a/Crypto/Signature/PKCS1_PSS.pyi +++ /dev/null @@ -1,7 +0,0 @@ -from typing import Optional, Callable - -from Crypto.PublicKey.RSA import RsaKey -from Crypto.Signature.pss import PSS_SigScheme - - -def new(rsa_key: RsaKey, mgfunc: Optional[Callable]=None, saltLen: Optional[int]=None, randfunc: Optional[Callable]=None) -> PSS_SigScheme: ... diff --git a/Crypto/Signature/PKCS1_v1_5.py b/Crypto/Signature/PKCS1_v1_5.py deleted file mode 100644 index ac888ed..0000000 --- a/Crypto/Signature/PKCS1_v1_5.py +++ /dev/null @@ -1,53 +0,0 @@ -# =================================================================== -# -# Copyright (c) 2014, Legrandin -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# =================================================================== - -""" -Legacy module for PKCS#1 v1.5 signatures. - -:undocumented: __package__ -""" - -import types - -from Crypto.Signature import pkcs1_15 - -def _pycrypto_verify(self, hash_object, signature): - try: - self._verify(hash_object, signature) - except (ValueError, TypeError): - return False - return True - -def new(rsa_key): - pkcs1 = pkcs1_15.new(rsa_key) - pkcs1._verify = pkcs1.verify - pkcs1.verify = types.MethodType(_pycrypto_verify, pkcs1) - return pkcs1 - diff --git a/Crypto/Signature/PKCS1_v1_5.pyi b/Crypto/Signature/PKCS1_v1_5.pyi deleted file mode 100644 index 55b9637..0000000 --- a/Crypto/Signature/PKCS1_v1_5.pyi +++ /dev/null @@ -1,6 +0,0 @@ -from Crypto.PublicKey.RSA import RsaKey - -from Crypto.Signature.pkcs1_15 import PKCS115_SigScheme - - -def new(rsa_key: RsaKey) -> PKCS115_SigScheme: ... \ No newline at end of file diff --git a/Crypto/Signature/__init__.py b/Crypto/Signature/__init__.py deleted file mode 100644 index da028a5..0000000 --- a/Crypto/Signature/__init__.py +++ /dev/null @@ -1,36 +0,0 @@ -# =================================================================== -# -# Copyright (c) 2014, Legrandin -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# =================================================================== - -"""Digital signature protocols - -A collection of standardized protocols to carry out digital signatures. -""" - -__all__ = ['PKCS1_v1_5', 'PKCS1_PSS', 'DSS', 'pkcs1_15', 'pss'] diff --git a/Crypto/Signature/pkcs1_15.py b/Crypto/Signature/pkcs1_15.py deleted file mode 100644 index 54a4bf7..0000000 --- a/Crypto/Signature/pkcs1_15.py +++ /dev/null @@ -1,222 +0,0 @@ -# =================================================================== -# -# Copyright (c) 2014, Legrandin -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# =================================================================== - -import Crypto.Util.number -from Crypto.Util.number import ceil_div, bytes_to_long, long_to_bytes -from Crypto.Util.asn1 import DerSequence, DerNull, DerOctetString, DerObjectId - -class PKCS115_SigScheme: - """A signature object for ``RSASSA-PKCS1-v1_5``. - Do not instantiate directly. - Use :func:`Crypto.Signature.pkcs1_15.new`. - """ - - def __init__(self, rsa_key): - """Initialize this PKCS#1 v1.5 signature scheme object. - - :Parameters: - rsa_key : an RSA key object - Creation of signatures is only possible if this is a *private* - RSA key. Verification of signatures is always possible. - """ - self._key = rsa_key - - def can_sign(self): - """Return ``True`` if this object can be used to sign messages.""" - return self._key.has_private() - - def sign(self, msg_hash): - """Create the PKCS#1 v1.5 signature of a message. - - This function is also called ``RSASSA-PKCS1-V1_5-SIGN`` and - it is specified in - `section 8.2.1 of RFC8017 `_. - - :parameter msg_hash: - This is an object from the :mod:`Crypto.Hash` package. - It has been used to digest the message to sign. - :type msg_hash: hash object - - :return: the signature encoded as a *byte string*. - :raise ValueError: if the RSA key is not long enough for the given hash algorithm. - :raise TypeError: if the RSA key has no private half. - """ - - # See 8.2.1 in RFC3447 - modBits = Crypto.Util.number.size(self._key.n) - k = ceil_div(modBits,8) # Convert from bits to bytes - - # Step 1 - em = _EMSA_PKCS1_V1_5_ENCODE(msg_hash, k) - # Step 2a (OS2IP) - em_int = bytes_to_long(em) - # Step 2b (RSASP1) - m_int = self._key._decrypt(em_int) - # Step 2c (I2OSP) - signature = long_to_bytes(m_int, k) - return signature - - def verify(self, msg_hash, signature): - """Check if the PKCS#1 v1.5 signature over a message is valid. - - This function is also called ``RSASSA-PKCS1-V1_5-VERIFY`` and - it is specified in - `section 8.2.2 of RFC8037 `_. - - :parameter msg_hash: - The hash that was carried out over the message. This is an object - belonging to the :mod:`Crypto.Hash` module. - :type parameter: hash object - - :parameter signature: - The signature that needs to be validated. - :type signature: byte string - - :raise ValueError: if the signature is not valid. - """ - - # See 8.2.2 in RFC3447 - modBits = Crypto.Util.number.size(self._key.n) - k = ceil_div(modBits, 8) # Convert from bits to bytes - - # Step 1 - if len(signature) != k: - raise ValueError("Invalid signature") - # Step 2a (O2SIP) - signature_int = bytes_to_long(signature) - # Step 2b (RSAVP1) - em_int = self._key._encrypt(signature_int) - # Step 2c (I2OSP) - em1 = long_to_bytes(em_int, k) - # Step 3 - try: - possible_em1 = [ _EMSA_PKCS1_V1_5_ENCODE(msg_hash, k, True) ] - # MD2/4/5 hashes always require NULL params in AlgorithmIdentifier. - # For all others, it is optional. - try: - algorithm_is_md = msg_hash.oid.startswith('1.2.840.113549.2.') - except AttributeError: - algorithm_is_md = False - if not algorithm_is_md: # MD2/MD4/MD5 - possible_em1.append(_EMSA_PKCS1_V1_5_ENCODE(msg_hash, k, False)) - except ValueError: - raise ValueError("Invalid signature") - # Step 4 - # By comparing the full encodings (as opposed to checking each - # of its components one at a time) we avoid attacks to the padding - # scheme like Bleichenbacher's (see http://www.mail-archive.com/cryptography@metzdowd.com/msg06537). - # - if em1 not in possible_em1: - raise ValueError("Invalid signature") - pass - - -def _EMSA_PKCS1_V1_5_ENCODE(msg_hash, emLen, with_hash_parameters=True): - """ - Implement the ``EMSA-PKCS1-V1_5-ENCODE`` function, as defined - in PKCS#1 v2.1 (RFC3447, 9.2). - - ``_EMSA-PKCS1-V1_5-ENCODE`` actually accepts the message ``M`` as input, - and hash it internally. Here, we expect that the message has already - been hashed instead. - - :Parameters: - msg_hash : hash object - The hash object that holds the digest of the message being signed. - emLen : int - The length the final encoding must have, in bytes. - with_hash_parameters : bool - If True (default), include NULL parameters for the hash - algorithm in the ``digestAlgorithm`` SEQUENCE. - - :attention: the early standard (RFC2313) stated that ``DigestInfo`` - had to be BER-encoded. This means that old signatures - might have length tags in indefinite form, which - is not supported in DER. Such encoding cannot be - reproduced by this function. - - :Return: An ``emLen`` byte long string that encodes the hash. - """ - - # First, build the ASN.1 DER object DigestInfo: - # - # DigestInfo ::= SEQUENCE { - # digestAlgorithm AlgorithmIdentifier, - # digest OCTET STRING - # } - # - # where digestAlgorithm identifies the hash function and shall be an - # algorithm ID with an OID in the set PKCS1-v1-5DigestAlgorithms. - # - # PKCS1-v1-5DigestAlgorithms ALGORITHM-IDENTIFIER ::= { - # { OID id-md2 PARAMETERS NULL }| - # { OID id-md5 PARAMETERS NULL }| - # { OID id-sha1 PARAMETERS NULL }| - # { OID id-sha256 PARAMETERS NULL }| - # { OID id-sha384 PARAMETERS NULL }| - # { OID id-sha512 PARAMETERS NULL } - # } - # - # Appendix B.1 also says that for SHA-1/-2 algorithms, the parameters - # should be omitted. They may be present, but when they are, they shall - # have NULL value. - - digestAlgo = DerSequence([ DerObjectId(msg_hash.oid).encode() ]) - - if with_hash_parameters: - digestAlgo.append(DerNull().encode()) - - digest = DerOctetString(msg_hash.digest()) - digestInfo = DerSequence([ - digestAlgo.encode(), - digest.encode() - ]).encode() - - # We need at least 11 bytes for the remaining data: 3 fixed bytes and - # at least 8 bytes of padding). - if emLen bytes: ... - -class PKCS115_SigScheme: - def __init__(self, rsa_key: RsaKey) -> None: ... - def can_sign(self) -> bool: ... - def sign(self, msg_hash: Hash) -> bytes: ... - def verify(self, msg_hash: Hash, signature: bytes) -> None: ... - -def _EMSA_PKCS1_V1_5_ENCODE(msg_hash: Hash, emLen: int, with_hash_parameters: Optional[bool]=True) -> bytes: ... - -def new(rsa_key: RsaKey) -> PKCS115_SigScheme: ... diff --git a/Crypto/Signature/pss.py b/Crypto/Signature/pss.py deleted file mode 100644 index 5f34ace..0000000 --- a/Crypto/Signature/pss.py +++ /dev/null @@ -1,386 +0,0 @@ -# =================================================================== -# -# Copyright (c) 2014, Legrandin -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# =================================================================== - -from Crypto.Util.py3compat import bchr, bord, iter_range -import Crypto.Util.number -from Crypto.Util.number import (ceil_div, - long_to_bytes, - bytes_to_long - ) -from Crypto.Util.strxor import strxor -from Crypto import Random - - -class PSS_SigScheme: - """A signature object for ``RSASSA-PSS``. - Do not instantiate directly. - Use :func:`Crypto.Signature.pss.new`. - """ - - def __init__(self, key, mgfunc, saltLen, randfunc): - """Initialize this PKCS#1 PSS signature scheme object. - - :Parameters: - key : an RSA key object - If a private half is given, both signature and - verification are possible. - If a public half is given, only verification is possible. - mgfunc : callable - A mask generation function that accepts two parameters: - a string to use as seed, and the lenth of the mask to - generate, in bytes. - saltLen : integer - Length of the salt, in bytes. - randfunc : callable - A function that returns random bytes. - """ - - self._key = key - self._saltLen = saltLen - self._mgfunc = mgfunc - self._randfunc = randfunc - - def can_sign(self): - """Return ``True`` if this object can be used to sign messages.""" - return self._key.has_private() - - def sign(self, msg_hash): - """Create the PKCS#1 PSS signature of a message. - - This function is also called ``RSASSA-PSS-SIGN`` and - it is specified in - `section 8.1.1 of RFC8017 `_. - - :parameter msg_hash: - This is an object from the :mod:`Crypto.Hash` package. - It has been used to digest the message to sign. - :type msg_hash: hash object - - :return: the signature encoded as a *byte string*. - :raise ValueError: if the RSA key is not long enough for the given hash algorithm. - :raise TypeError: if the RSA key has no private half. - """ - - # Set defaults for salt length and mask generation function - if self._saltLen is None: - sLen = msg_hash.digest_size - else: - sLen = self._saltLen - - if self._mgfunc is None: - mgf = lambda x, y: MGF1(x, y, msg_hash) - else: - mgf = self._mgfunc - - modBits = Crypto.Util.number.size(self._key.n) - - # See 8.1.1 in RFC3447 - k = ceil_div(modBits, 8) # k is length in bytes of the modulus - # Step 1 - em = _EMSA_PSS_ENCODE(msg_hash, modBits-1, self._randfunc, mgf, sLen) - # Step 2a (OS2IP) - em_int = bytes_to_long(em) - # Step 2b (RSASP1) - m_int = self._key._decrypt(em_int) - # Step 2c (I2OSP) - signature = long_to_bytes(m_int, k) - return signature - - def verify(self, msg_hash, signature): - """Check if the PKCS#1 PSS signature over a message is valid. - - This function is also called ``RSASSA-PSS-VERIFY`` and - it is specified in - `section 8.1.2 of RFC8037 `_. - - :parameter msg_hash: - The hash that was carried out over the message. This is an object - belonging to the :mod:`Crypto.Hash` module. - :type parameter: hash object - - :parameter signature: - The signature that needs to be validated. - :type signature: bytes - - :raise ValueError: if the signature is not valid. - """ - - # Set defaults for salt length and mask generation function - if self._saltLen is None: - sLen = msg_hash.digest_size - else: - sLen = self._saltLen - if self._mgfunc: - mgf = self._mgfunc - else: - mgf = lambda x, y: MGF1(x, y, msg_hash) - - modBits = Crypto.Util.number.size(self._key.n) - - # See 8.1.2 in RFC3447 - k = ceil_div(modBits, 8) # Convert from bits to bytes - # Step 1 - if len(signature) != k: - raise ValueError("Incorrect signature") - # Step 2a (O2SIP) - signature_int = bytes_to_long(signature) - # Step 2b (RSAVP1) - em_int = self._key._encrypt(signature_int) - # Step 2c (I2OSP) - emLen = ceil_div(modBits - 1, 8) - em = long_to_bytes(em_int, emLen) - # Step 3/4 - _EMSA_PSS_VERIFY(msg_hash, em, modBits-1, mgf, sLen) - - -def MGF1(mgfSeed, maskLen, hash_gen): - """Mask Generation Function, described in `B.2.1 of RFC8017 - `_. - - :param mfgSeed: - seed from which the mask is generated - :type mfgSeed: byte string - - :param maskLen: - intended length in bytes of the mask - :type maskLen: integer - - :param hash_gen: - A module or a hash object from :mod:`Crypto.Hash` - :type hash_object: - - :return: the mask, as a *byte string* - """ - - T = b"" - for counter in iter_range(ceil_div(maskLen, hash_gen.digest_size)): - c = long_to_bytes(counter, 4) - hobj = hash_gen.new() - hobj.update(mgfSeed + c) - T = T + hobj.digest() - assert(len(T) >= maskLen) - return T[:maskLen] - - -def _EMSA_PSS_ENCODE(mhash, emBits, randFunc, mgf, sLen): - r""" - Implement the ``EMSA-PSS-ENCODE`` function, as defined - in PKCS#1 v2.1 (RFC3447, 9.1.1). - - The original ``EMSA-PSS-ENCODE`` actually accepts the message ``M`` - as input, and hash it internally. Here, we expect that the message - has already been hashed instead. - - :Parameters: - mhash : hash object - The hash object that holds the digest of the message being signed. - emBits : int - Maximum length of the final encoding, in bits. - randFunc : callable - An RNG function that accepts as only parameter an int, and returns - a string of random bytes, to be used as salt. - mgf : callable - A mask generation function that accepts two parameters: a string to - use as seed, and the lenth of the mask to generate, in bytes. - sLen : int - Length of the salt, in bytes. - - :Return: An ``emLen`` byte long string that encodes the hash - (with ``emLen = \ceil(emBits/8)``). - - :Raise ValueError: - When digest or salt length are too big. - """ - - emLen = ceil_div(emBits, 8) - - # Bitmask of digits that fill up - lmask = 0 - for i in iter_range(8*emLen-emBits): - lmask = lmask >> 1 | 0x80 - - # Step 1 and 2 have been already done - # Step 3 - if emLen < mhash.digest_size+sLen+2: - raise ValueError("Digest or salt length are too long" - " for given key size.") - # Step 4 - salt = randFunc(sLen) - # Step 5 - m_prime = bchr(0)*8 + mhash.digest() + salt - # Step 6 - h = mhash.new() - h.update(m_prime) - # Step 7 - ps = bchr(0)*(emLen-sLen-mhash.digest_size-2) - # Step 8 - db = ps + bchr(1) + salt - # Step 9 - dbMask = mgf(h.digest(), emLen-mhash.digest_size-1) - # Step 10 - maskedDB = strxor(db, dbMask) - # Step 11 - maskedDB = bchr(bord(maskedDB[0]) & ~lmask) + maskedDB[1:] - # Step 12 - em = maskedDB + h.digest() + bchr(0xBC) - return em - - -def _EMSA_PSS_VERIFY(mhash, em, emBits, mgf, sLen): - """ - Implement the ``EMSA-PSS-VERIFY`` function, as defined - in PKCS#1 v2.1 (RFC3447, 9.1.2). - - ``EMSA-PSS-VERIFY`` actually accepts the message ``M`` as input, - and hash it internally. Here, we expect that the message has already - been hashed instead. - - :Parameters: - mhash : hash object - The hash object that holds the digest of the message to be verified. - em : string - The signature to verify, therefore proving that the sender really - signed the message that was received. - emBits : int - Length of the final encoding (em), in bits. - mgf : callable - A mask generation function that accepts two parameters: a string to - use as seed, and the lenth of the mask to generate, in bytes. - sLen : int - Length of the salt, in bytes. - - :Raise ValueError: - When the encoding is inconsistent, or the digest or salt lengths - are too big. - """ - - emLen = ceil_div(emBits, 8) - - # Bitmask of digits that fill up - lmask = 0 - for i in iter_range(8*emLen-emBits): - lmask = lmask >> 1 | 0x80 - - # Step 1 and 2 have been already done - # Step 3 - if emLen < mhash.digest_size+sLen+2: - raise ValueError("Incorrect signature") - # Step 4 - if ord(em[-1:]) != 0xBC: - raise ValueError("Incorrect signature") - # Step 5 - maskedDB = em[:emLen-mhash.digest_size-1] - h = em[emLen-mhash.digest_size-1:-1] - # Step 6 - if lmask & bord(em[0]): - raise ValueError("Incorrect signature") - # Step 7 - dbMask = mgf(h, emLen-mhash.digest_size-1) - # Step 8 - db = strxor(maskedDB, dbMask) - # Step 9 - db = bchr(bord(db[0]) & ~lmask) + db[1:] - # Step 10 - if not db.startswith(bchr(0)*(emLen-mhash.digest_size-sLen-2) + bchr(1)): - raise ValueError("Incorrect signature") - # Step 11 - if sLen > 0: - salt = db[-sLen:] - else: - salt = b"" - # Step 12 - m_prime = bchr(0)*8 + mhash.digest() + salt - # Step 13 - hobj = mhash.new() - hobj.update(m_prime) - hp = hobj.digest() - # Step 14 - if h != hp: - raise ValueError("Incorrect signature") - - -def new(rsa_key, **kwargs): - """Create an object for making or verifying PKCS#1 PSS signatures. - - :parameter rsa_key: - The RSA key to use for signing or verifying the message. - This is a :class:`Crypto.PublicKey.RSA` object. - Signing is only possible when ``rsa_key`` is a **private** RSA key. - :type rsa_key: RSA object - - :Keyword Arguments: - - * *mask_func* (``callable``) -- - A function that returns the mask (as `bytes`). - It must accept two parameters: a seed (as `bytes`) - and the length of the data to return. - - If not specified, it will be the function :func:`MGF1` defined in - `RFC8017 `_ and - combined with the same hash algorithm applied to the - message to sign or verify. - - If you want to use a different function, for instance still :func:`MGF1` - but together with another hash, you can do:: - - from Crypto.Hash import SHA256 - from Crypto.Signature.pss import MGF1 - mgf = lambda x, y: MGF1(x, y, SHA256) - - * *salt_bytes* (``integer``) -- - Length of the salt, in bytes. - It is a value between 0 and ``emLen - hLen - 2``, where ``emLen`` - is the size of the RSA modulus and ``hLen`` is the size of the digest - applied to the message to sign or verify. - - The salt is generated internally, you don't need to provide it. - - If not specified, the salt length will be ``hLen``. - If it is zero, the signature scheme becomes deterministic. - - Note that in some implementations such as OpenSSL the default - salt length is ``emLen - hLen - 2`` (even though it is not more - secure than ``hLen``). - - * *rand_func* (``callable``) -- - A function that returns random ``bytes``, of the desired length. - The default is :func:`Crypto.Random.get_random_bytes`. - - :return: a :class:`PSS_SigScheme` signature object - """ - - mask_func = kwargs.pop("mask_func", None) - salt_len = kwargs.pop("salt_bytes", None) - rand_func = kwargs.pop("rand_func", None) - if rand_func is None: - rand_func = Random.get_random_bytes - if kwargs: - raise ValueError("Unknown keywords: " + str(kwargs.keys())) - return PSS_SigScheme(rsa_key, mask_func, salt_len, rand_func) diff --git a/Crypto/Signature/pss.pyi b/Crypto/Signature/pss.pyi deleted file mode 100644 index 4d216ca..0000000 --- a/Crypto/Signature/pss.pyi +++ /dev/null @@ -1,30 +0,0 @@ -from typing import Union, Callable, Optional -from typing_extensions import Protocol - -from Crypto.PublicKey.RSA import RsaKey - - -class Hash(Protocol): - def digest(self) -> bytes: ... - def update(self, bytes) -> None: ... - - -class HashModule(Protocol): - @staticmethod - def new(data: Optional[bytes]) -> Hash: ... - - -MaskFunction = Callable[[bytes, int, Union[Hash, HashModule]], bytes] -RndFunction = Callable[[int], bytes] - -class PSS_SigScheme: - def __init__(self, key: RsaKey, mgfunc: RndFunction, saltLen: int, randfunc: RndFunction) -> None: ... - def can_sign(self) -> bool: ... - def sign(self, msg_hash: Hash) -> bytes: ... - def verify(self, msg_hash: Hash, signature: bytes) -> None: ... - - -MGF1 : MaskFunction -def _EMSA_PSS_ENCODE(mhash: Hash, emBits: int, randFunc: RndFunction, mgf:MaskFunction, sLen: int) -> str: ... -def _EMSA_PSS_VERIFY(mhash: Hash, em: str, emBits: int, mgf: MaskFunction, sLen: int) -> None: ... -def new(rsa_key: RsaKey, **kwargs: Union[MaskFunction, RndFunction, int]) -> PSS_SigScheme: ... diff --git a/Crypto/Util/Counter.py b/Crypto/Util/Counter.py deleted file mode 100644 index c67bc95..0000000 --- a/Crypto/Util/Counter.py +++ /dev/null @@ -1,77 +0,0 @@ -# -*- coding: ascii -*- -# -# Util/Counter.py : Fast counter for use with CTR-mode ciphers -# -# Written in 2008 by Dwayne C. Litzenberger -# -# =================================================================== -# The contents of this file are dedicated to the public domain. To -# the extent that dedication to the public domain is not available, -# everyone is granted a worldwide, perpetual, royalty-free, -# non-exclusive license to exercise all rights associated with the -# contents of this file for any purpose whatsoever. -# No rights are reserved. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS -# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN -# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# =================================================================== - -def new(nbits, prefix=b"", suffix=b"", initial_value=1, little_endian=False, allow_wraparound=False): - """Create a stateful counter block function suitable for CTR encryption modes. - - Each call to the function returns the next counter block. - Each counter block is made up by three parts: - - +------+--------------+-------+ - |prefix| counter value|postfix| - +------+--------------+-------+ - - The counter value is incremented by 1 at each call. - - Args: - nbits (integer): - Length of the desired counter value, in bits. It must be a multiple of 8. - prefix (byte string): - The constant prefix of the counter block. By default, no prefix is - used. - suffix (byte string): - The constant postfix of the counter block. By default, no suffix is - used. - initial_value (integer): - The initial value of the counter. Default value is 1. - Its length in bits must not exceed the argument ``nbits``. - little_endian (boolean): - If ``True``, the counter number will be encoded in little endian format. - If ``False`` (default), in big endian format. - allow_wraparound (boolean): - This parameter is ignored. - Returns: - An object that can be passed with the :data:`counter` parameter to a CTR mode - cipher. - - It must hold that *len(prefix) + nbits//8 + len(suffix)* matches the - block size of the underlying block cipher. - """ - - if (nbits % 8) != 0: - raise ValueError("'nbits' must be a multiple of 8") - - iv_bl = initial_value.bit_length() - if iv_bl > nbits: - raise ValueError("Initial value takes %d bits but it is longer than " - "the counter (%d bits)" % - (iv_bl, nbits)) - - # Ignore wraparound - return {"counter_len": nbits // 8, - "prefix": prefix, - "suffix": suffix, - "initial_value": initial_value, - "little_endian": little_endian - } diff --git a/Crypto/Util/Counter.pyi b/Crypto/Util/Counter.pyi deleted file mode 100644 index fa2ffdd..0000000 --- a/Crypto/Util/Counter.pyi +++ /dev/null @@ -1,5 +0,0 @@ -from typing import Optional, Union, Dict - -def new(nbits: int, prefix: Optional[bytes]=..., suffix: Optional[bytes]=..., initial_value: Optional[int]=1, - little_endian: Optional[bool]=False, allow_wraparound: Optional[bool]=False) -> \ - Dict[str, Union[int, bytes, bool]]: ... diff --git a/Crypto/Util/Padding.py b/Crypto/Util/Padding.py deleted file mode 100644 index da69e55..0000000 --- a/Crypto/Util/Padding.py +++ /dev/null @@ -1,108 +0,0 @@ -# -# Util/Padding.py : Functions to manage padding -# -# =================================================================== -# -# Copyright (c) 2014, Legrandin -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# =================================================================== - -__all__ = [ 'pad', 'unpad' ] - -from Crypto.Util.py3compat import * - - -def pad(data_to_pad, block_size, style='pkcs7'): - """Apply standard padding. - - Args: - data_to_pad (byte string): - The data that needs to be padded. - block_size (integer): - The block boundary to use for padding. The output length is guaranteed - to be a multiple of :data:`block_size`. - style (string): - Padding algorithm. It can be *'pkcs7'* (default), *'iso7816'* or *'x923'*. - - Return: - byte string : the original data with the appropriate padding added at the end. - """ - - padding_len = block_size-len(data_to_pad)%block_size - if style == 'pkcs7': - padding = bchr(padding_len)*padding_len - elif style == 'x923': - padding = bchr(0)*(padding_len-1) + bchr(padding_len) - elif style == 'iso7816': - padding = bchr(128) + bchr(0)*(padding_len-1) - else: - raise ValueError("Unknown padding style") - return data_to_pad + padding - - -def unpad(padded_data, block_size, style='pkcs7'): - """Remove standard padding. - - Args: - padded_data (byte string): - A piece of data with padding that needs to be stripped. - block_size (integer): - The block boundary to use for padding. The input length - must be a multiple of :data:`block_size`. - style (string): - Padding algorithm. It can be *'pkcs7'* (default), *'iso7816'* or *'x923'*. - Return: - byte string : data without padding. - Raises: - ValueError: if the padding is incorrect. - """ - - pdata_len = len(padded_data) - if pdata_len == 0: - raise ValueError("Zero-length input cannot be unpadded") - if pdata_len % block_size: - raise ValueError("Input data is not padded") - if style in ('pkcs7', 'x923'): - padding_len = bord(padded_data[-1]) - if padding_len<1 or padding_len>min(block_size, pdata_len): - raise ValueError("Padding is incorrect.") - if style == 'pkcs7': - if padded_data[-padding_len:]!=bchr(padding_len)*padding_len: - raise ValueError("PKCS#7 padding is incorrect.") - else: - if padded_data[-padding_len:-1]!=bchr(0)*(padding_len-1): - raise ValueError("ANSI X.923 padding is incorrect.") - elif style == 'iso7816': - padding_len = pdata_len - padded_data.rfind(bchr(128)) - if padding_len<1 or padding_len>min(block_size, pdata_len): - raise ValueError("Padding is incorrect.") - if padding_len>1 and padded_data[1-padding_len:]!=bchr(0)*(padding_len-1): - raise ValueError("ISO 7816-4 padding is incorrect.") - else: - raise ValueError("Unknown padding style") - return padded_data[:-padding_len] - diff --git a/Crypto/Util/Padding.pyi b/Crypto/Util/Padding.pyi deleted file mode 100644 index 4d8d30d..0000000 --- a/Crypto/Util/Padding.pyi +++ /dev/null @@ -1,6 +0,0 @@ -from typing import Optional - -__all__ = [ 'pad', 'unpad' ] - -def pad(data_to_pad: bytes, block_size: int, style: Optional[str]='pkcs7') -> bytes: ... -def unpad(padded_data: bytes, block_size: int, style: Optional[str]='pkcs7') -> bytes: ... \ No newline at end of file diff --git a/Crypto/Util/RFC1751.py b/Crypto/Util/RFC1751.py deleted file mode 100644 index 9ed52d2..0000000 --- a/Crypto/Util/RFC1751.py +++ /dev/null @@ -1,386 +0,0 @@ -# rfc1751.py : Converts between 128-bit strings and a human-readable -# sequence of words, as defined in RFC1751: "A Convention for -# Human-Readable 128-bit Keys", by Daniel L. McDonald. -# -# Part of the Python Cryptography Toolkit -# -# Written by Andrew M. Kuchling and others -# -# =================================================================== -# The contents of this file are dedicated to the public domain. To -# the extent that dedication to the public domain is not available, -# everyone is granted a worldwide, perpetual, royalty-free, -# non-exclusive license to exercise all rights associated with the -# contents of this file for any purpose whatsoever. -# No rights are reserved. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS -# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN -# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# =================================================================== - -from __future__ import print_function - -import binascii - -from Crypto.Util.py3compat import bord, bchr - -binary = {0: '0000', 1: '0001', 2: '0010', 3: '0011', 4: '0100', 5: '0101', - 6: '0110', 7: '0111', 8: '1000', 9: '1001', 10: '1010', 11: '1011', - 12: '1100', 13: '1101', 14: '1110', 15: '1111'} - - -def _key2bin(s): - "Convert a key into a string of binary digits" - kl = map(lambda x: bord(x), s) - kl = map(lambda x: binary[x >> 4] + binary[x & 15], kl) - return ''.join(kl) - - -def _extract(key, start, length): - """Extract a bitstring(2.x)/bytestring(2.x) from a string of binary digits, and return its - numeric value.""" - - result = 0 - for y in key[start:start+length]: - result = result * 2 + ord(y) - 48 - return result - - -def key_to_english(key): - """Transform an arbitrary key into a string containing English words. - - Example:: - - >>> from Crypto.Util.RFC1751 import key_to_english - >>> key_to_english(b'66666666') - 'RAM LOIS GOAD CREW CARE HIT' - - Args: - key (byte string): - The key to convert. Its length must be a multiple of 8. - Return: - A string of English words. - """ - - if len(key) % 8 != 0: - raise ValueError('The length of the key must be a multiple of 8.') - - english = '' - for index in range(0, len(key), 8): # Loop over 8-byte subkeys - subkey = key[index:index + 8] - # Compute the parity of the key - skbin = _key2bin(subkey) - p = 0 - for i in range(0, 64, 2): - p = p + _extract(skbin, i, 2) - # Append parity bits to the subkey - skbin = _key2bin(subkey + bchr((p << 6) & 255)) - for i in range(0, 64, 11): - english = english + wordlist[_extract(skbin, i, 11)] + ' ' - - return english.strip() - - -def english_to_key(s): - """Transform a string into a corresponding key. - - Example:: - - >>> from Crypto.Util.RFC1751 import english_to_key - >>> english_to_key('RAM LOIS GOAD CREW CARE HIT') - b'66666666' - - Args: - s (string): the string with the words separated by whitespace; - the number of words must be a multiple of 6. - Return: - A byte string. - """ - - L = s.upper().split() - key = b'' - for index in range(0, len(L), 6): - sublist = L[index:index + 6] - char = 9 * [0] - bits = 0 - for i in sublist: - index = wordlist.index(i) - shift = (8 - (bits + 11) % 8) % 8 - y = index << shift - cl, cc, cr = (y >> 16), (y >> 8) & 0xff, y & 0xff - if (shift > 5): - char[bits >> 3] = char[bits >> 3] | cl - char[(bits >> 3) + 1] = char[(bits >> 3) + 1] | cc - char[(bits >> 3) + 2] = char[(bits >> 3) + 2] | cr - elif shift > -3: - char[bits >> 3] = char[bits >> 3] | cc - char[(bits >> 3) + 1] = char[(bits >> 3) + 1] | cr - else: - char[bits >> 3] = char[bits >> 3] | cr - bits = bits + 11 - - subkey = b'' - for y in char: - subkey = subkey + bchr(y) - - # Check the parity of the resulting key - skbin = _key2bin(subkey) - p = 0 - for i in range(0, 64, 2): - p = p + _extract(skbin, i, 2) - if (p & 3) != _extract(skbin, 64, 2): - raise ValueError("Parity error in resulting key") - key = key + subkey[0:8] - return key - - -wordlist = [ - "A", "ABE", "ACE", "ACT", "AD", "ADA", "ADD", - "AGO", "AID", "AIM", "AIR", "ALL", "ALP", "AM", "AMY", "AN", "ANA", - "AND", "ANN", "ANT", "ANY", "APE", "APS", "APT", "ARC", "ARE", "ARK", - "ARM", "ART", "AS", "ASH", "ASK", "AT", "ATE", "AUG", "AUK", "AVE", - "AWE", "AWK", "AWL", "AWN", "AX", "AYE", "BAD", "BAG", "BAH", "BAM", - "BAN", "BAR", "BAT", "BAY", "BE", "BED", "BEE", "BEG", "BEN", "BET", - "BEY", "BIB", "BID", "BIG", "BIN", "BIT", "BOB", "BOG", "BON", "BOO", - "BOP", "BOW", "BOY", "BUB", "BUD", "BUG", "BUM", "BUN", "BUS", "BUT", - "BUY", "BY", "BYE", "CAB", "CAL", "CAM", "CAN", "CAP", "CAR", "CAT", - "CAW", "COD", "COG", "COL", "CON", "COO", "COP", "COT", "COW", "COY", - "CRY", "CUB", "CUE", "CUP", "CUR", "CUT", "DAB", "DAD", "DAM", "DAN", - "DAR", "DAY", "DEE", "DEL", "DEN", "DES", "DEW", "DID", "DIE", "DIG", - "DIN", "DIP", "DO", "DOE", "DOG", "DON", "DOT", "DOW", "DRY", "DUB", - "DUD", "DUE", "DUG", "DUN", "EAR", "EAT", "ED", "EEL", "EGG", "EGO", - "ELI", "ELK", "ELM", "ELY", "EM", "END", "EST", "ETC", "EVA", "EVE", - "EWE", "EYE", "FAD", "FAN", "FAR", "FAT", "FAY", "FED", "FEE", "FEW", - "FIB", "FIG", "FIN", "FIR", "FIT", "FLO", "FLY", "FOE", "FOG", "FOR", - "FRY", "FUM", "FUN", "FUR", "GAB", "GAD", "GAG", "GAL", "GAM", "GAP", - "GAS", "GAY", "GEE", "GEL", "GEM", "GET", "GIG", "GIL", "GIN", "GO", - "GOT", "GUM", "GUN", "GUS", "GUT", "GUY", "GYM", "GYP", "HA", "HAD", - "HAL", "HAM", "HAN", "HAP", "HAS", "HAT", "HAW", "HAY", "HE", "HEM", - "HEN", "HER", "HEW", "HEY", "HI", "HID", "HIM", "HIP", "HIS", "HIT", - "HO", "HOB", "HOC", "HOE", "HOG", "HOP", "HOT", "HOW", "HUB", "HUE", - "HUG", "HUH", "HUM", "HUT", "I", "ICY", "IDA", "IF", "IKE", "ILL", - "INK", "INN", "IO", "ION", "IQ", "IRA", "IRE", "IRK", "IS", "IT", - "ITS", "IVY", "JAB", "JAG", "JAM", "JAN", "JAR", "JAW", "JAY", "JET", - "JIG", "JIM", "JO", "JOB", "JOE", "JOG", "JOT", "JOY", "JUG", "JUT", - "KAY", "KEG", "KEN", "KEY", "KID", "KIM", "KIN", "KIT", "LA", "LAB", - "LAC", "LAD", "LAG", "LAM", "LAP", "LAW", "LAY", "LEA", "LED", "LEE", - "LEG", "LEN", "LEO", "LET", "LEW", "LID", "LIE", "LIN", "LIP", "LIT", - "LO", "LOB", "LOG", "LOP", "LOS", "LOT", "LOU", "LOW", "LOY", "LUG", - "LYE", "MA", "MAC", "MAD", "MAE", "MAN", "MAO", "MAP", "MAT", "MAW", - "MAY", "ME", "MEG", "MEL", "MEN", "MET", "MEW", "MID", "MIN", "MIT", - "MOB", "MOD", "MOE", "MOO", "MOP", "MOS", "MOT", "MOW", "MUD", "MUG", - "MUM", "MY", "NAB", "NAG", "NAN", "NAP", "NAT", "NAY", "NE", "NED", - "NEE", "NET", "NEW", "NIB", "NIL", "NIP", "NIT", "NO", "NOB", "NOD", - "NON", "NOR", "NOT", "NOV", "NOW", "NU", "NUN", "NUT", "O", "OAF", - "OAK", "OAR", "OAT", "ODD", "ODE", "OF", "OFF", "OFT", "OH", "OIL", - "OK", "OLD", "ON", "ONE", "OR", "ORB", "ORE", "ORR", "OS", "OTT", - "OUR", "OUT", "OVA", "OW", "OWE", "OWL", "OWN", "OX", "PA", "PAD", - "PAL", "PAM", "PAN", "PAP", "PAR", "PAT", "PAW", "PAY", "PEA", "PEG", - "PEN", "PEP", "PER", "PET", "PEW", "PHI", "PI", "PIE", "PIN", "PIT", - "PLY", "PO", "POD", "POE", "POP", "POT", "POW", "PRO", "PRY", "PUB", - "PUG", "PUN", "PUP", "PUT", "QUO", "RAG", "RAM", "RAN", "RAP", "RAT", - "RAW", "RAY", "REB", "RED", "REP", "RET", "RIB", "RID", "RIG", "RIM", - "RIO", "RIP", "ROB", "ROD", "ROE", "RON", "ROT", "ROW", "ROY", "RUB", - "RUE", "RUG", "RUM", "RUN", "RYE", "SAC", "SAD", "SAG", "SAL", "SAM", - "SAN", "SAP", "SAT", "SAW", "SAY", "SEA", "SEC", "SEE", "SEN", "SET", - "SEW", "SHE", "SHY", "SIN", "SIP", "SIR", "SIS", "SIT", "SKI", "SKY", - "SLY", "SO", "SOB", "SOD", "SON", "SOP", "SOW", "SOY", "SPA", "SPY", - "SUB", "SUD", "SUE", "SUM", "SUN", "SUP", "TAB", "TAD", "TAG", "TAN", - "TAP", "TAR", "TEA", "TED", "TEE", "TEN", "THE", "THY", "TIC", "TIE", - "TIM", "TIN", "TIP", "TO", "TOE", "TOG", "TOM", "TON", "TOO", "TOP", - "TOW", "TOY", "TRY", "TUB", "TUG", "TUM", "TUN", "TWO", "UN", "UP", - "US", "USE", "VAN", "VAT", "VET", "VIE", "WAD", "WAG", "WAR", "WAS", - "WAY", "WE", "WEB", "WED", "WEE", "WET", "WHO", "WHY", "WIN", "WIT", - "WOK", "WON", "WOO", "WOW", "WRY", "WU", "YAM", "YAP", "YAW", "YE", - "YEA", "YES", "YET", "YOU", "ABED", "ABEL", "ABET", "ABLE", "ABUT", - "ACHE", "ACID", "ACME", "ACRE", "ACTA", "ACTS", "ADAM", "ADDS", - "ADEN", "AFAR", "AFRO", "AGEE", "AHEM", "AHOY", "AIDA", "AIDE", - "AIDS", "AIRY", "AJAR", "AKIN", "ALAN", "ALEC", "ALGA", "ALIA", - "ALLY", "ALMA", "ALOE", "ALSO", "ALTO", "ALUM", "ALVA", "AMEN", - "AMES", "AMID", "AMMO", "AMOK", "AMOS", "AMRA", "ANDY", "ANEW", - "ANNA", "ANNE", "ANTE", "ANTI", "AQUA", "ARAB", "ARCH", "AREA", - "ARGO", "ARID", "ARMY", "ARTS", "ARTY", "ASIA", "ASKS", "ATOM", - "AUNT", "AURA", "AUTO", "AVER", "AVID", "AVIS", "AVON", "AVOW", - "AWAY", "AWRY", "BABE", "BABY", "BACH", "BACK", "BADE", "BAIL", - "BAIT", "BAKE", "BALD", "BALE", "BALI", "BALK", "BALL", "BALM", - "BAND", "BANE", "BANG", "BANK", "BARB", "BARD", "BARE", "BARK", - "BARN", "BARR", "BASE", "BASH", "BASK", "BASS", "BATE", "BATH", - "BAWD", "BAWL", "BEAD", "BEAK", "BEAM", "BEAN", "BEAR", "BEAT", - "BEAU", "BECK", "BEEF", "BEEN", "BEER", - "BEET", "BELA", "BELL", "BELT", "BEND", "BENT", "BERG", "BERN", - "BERT", "BESS", "BEST", "BETA", "BETH", "BHOY", "BIAS", "BIDE", - "BIEN", "BILE", "BILK", "BILL", "BIND", "BING", "BIRD", "BITE", - "BITS", "BLAB", "BLAT", "BLED", "BLEW", "BLOB", "BLOC", "BLOT", - "BLOW", "BLUE", "BLUM", "BLUR", "BOAR", "BOAT", "BOCA", "BOCK", - "BODE", "BODY", "BOGY", "BOHR", "BOIL", "BOLD", "BOLO", "BOLT", - "BOMB", "BONA", "BOND", "BONE", "BONG", "BONN", "BONY", "BOOK", - "BOOM", "BOON", "BOOT", "BORE", "BORG", "BORN", "BOSE", "BOSS", - "BOTH", "BOUT", "BOWL", "BOYD", "BRAD", "BRAE", "BRAG", "BRAN", - "BRAY", "BRED", "BREW", "BRIG", "BRIM", "BROW", "BUCK", "BUDD", - "BUFF", "BULB", "BULK", "BULL", "BUNK", "BUNT", "BUOY", "BURG", - "BURL", "BURN", "BURR", "BURT", "BURY", "BUSH", "BUSS", "BUST", - "BUSY", "BYTE", "CADY", "CAFE", "CAGE", "CAIN", "CAKE", "CALF", - "CALL", "CALM", "CAME", "CANE", "CANT", "CARD", "CARE", "CARL", - "CARR", "CART", "CASE", "CASH", "CASK", "CAST", "CAVE", "CEIL", - "CELL", "CENT", "CERN", "CHAD", "CHAR", "CHAT", "CHAW", "CHEF", - "CHEN", "CHEW", "CHIC", "CHIN", "CHOU", "CHOW", "CHUB", "CHUG", - "CHUM", "CITE", "CITY", "CLAD", "CLAM", "CLAN", "CLAW", "CLAY", - "CLOD", "CLOG", "CLOT", "CLUB", "CLUE", "COAL", "COAT", "COCA", - "COCK", "COCO", "CODA", "CODE", "CODY", "COED", "COIL", "COIN", - "COKE", "COLA", "COLD", "COLT", "COMA", "COMB", "COME", "COOK", - "COOL", "COON", "COOT", "CORD", "CORE", "CORK", "CORN", "COST", - "COVE", "COWL", "CRAB", "CRAG", "CRAM", "CRAY", "CREW", "CRIB", - "CROW", "CRUD", "CUBA", "CUBE", "CUFF", "CULL", "CULT", "CUNY", - "CURB", "CURD", "CURE", "CURL", "CURT", "CUTS", "DADE", "DALE", - "DAME", "DANA", "DANE", "DANG", "DANK", "DARE", "DARK", "DARN", - "DART", "DASH", "DATA", "DATE", "DAVE", "DAVY", "DAWN", "DAYS", - "DEAD", "DEAF", "DEAL", "DEAN", "DEAR", "DEBT", "DECK", "DEED", - "DEEM", "DEER", "DEFT", "DEFY", "DELL", "DENT", "DENY", "DESK", - "DIAL", "DICE", "DIED", "DIET", "DIME", "DINE", "DING", "DINT", - "DIRE", "DIRT", "DISC", "DISH", "DISK", "DIVE", "DOCK", "DOES", - "DOLE", "DOLL", "DOLT", "DOME", "DONE", "DOOM", "DOOR", "DORA", - "DOSE", "DOTE", "DOUG", "DOUR", "DOVE", "DOWN", "DRAB", "DRAG", - "DRAM", "DRAW", "DREW", "DRUB", "DRUG", "DRUM", "DUAL", "DUCK", - "DUCT", "DUEL", "DUET", "DUKE", "DULL", "DUMB", "DUNE", "DUNK", - "DUSK", "DUST", "DUTY", "EACH", "EARL", "EARN", "EASE", "EAST", - "EASY", "EBEN", "ECHO", "EDDY", "EDEN", "EDGE", "EDGY", "EDIT", - "EDNA", "EGAN", "ELAN", "ELBA", "ELLA", "ELSE", "EMIL", "EMIT", - "EMMA", "ENDS", "ERIC", "EROS", "EVEN", "EVER", "EVIL", "EYED", - "FACE", "FACT", "FADE", "FAIL", "FAIN", "FAIR", "FAKE", "FALL", - "FAME", "FANG", "FARM", "FAST", "FATE", "FAWN", "FEAR", "FEAT", - "FEED", "FEEL", "FEET", "FELL", "FELT", "FEND", "FERN", "FEST", - "FEUD", "FIEF", "FIGS", "FILE", "FILL", "FILM", "FIND", "FINE", - "FINK", "FIRE", "FIRM", "FISH", "FISK", "FIST", "FITS", "FIVE", - "FLAG", "FLAK", "FLAM", "FLAT", "FLAW", "FLEA", "FLED", "FLEW", - "FLIT", "FLOC", "FLOG", "FLOW", "FLUB", "FLUE", "FOAL", "FOAM", - "FOGY", "FOIL", "FOLD", "FOLK", "FOND", "FONT", "FOOD", "FOOL", - "FOOT", "FORD", "FORE", "FORK", "FORM", "FORT", "FOSS", "FOUL", - "FOUR", "FOWL", "FRAU", "FRAY", "FRED", "FREE", "FRET", "FREY", - "FROG", "FROM", "FUEL", "FULL", "FUME", "FUND", "FUNK", "FURY", - "FUSE", "FUSS", "GAFF", "GAGE", "GAIL", "GAIN", "GAIT", "GALA", - "GALE", "GALL", "GALT", "GAME", "GANG", "GARB", "GARY", "GASH", - "GATE", "GAUL", "GAUR", "GAVE", "GAWK", "GEAR", "GELD", "GENE", - "GENT", "GERM", "GETS", "GIBE", "GIFT", "GILD", "GILL", "GILT", - "GINA", "GIRD", "GIRL", "GIST", "GIVE", "GLAD", "GLEE", "GLEN", - "GLIB", "GLOB", "GLOM", "GLOW", "GLUE", "GLUM", "GLUT", "GOAD", - "GOAL", "GOAT", "GOER", "GOES", "GOLD", "GOLF", "GONE", "GONG", - "GOOD", "GOOF", "GORE", "GORY", "GOSH", "GOUT", "GOWN", "GRAB", - "GRAD", "GRAY", "GREG", "GREW", "GREY", "GRID", "GRIM", "GRIN", - "GRIT", "GROW", "GRUB", "GULF", "GULL", "GUNK", "GURU", "GUSH", - "GUST", "GWEN", "GWYN", "HAAG", "HAAS", "HACK", "HAIL", "HAIR", - "HALE", "HALF", "HALL", "HALO", "HALT", "HAND", "HANG", "HANK", - "HANS", "HARD", "HARK", "HARM", "HART", "HASH", "HAST", "HATE", - "HATH", "HAUL", "HAVE", "HAWK", "HAYS", "HEAD", "HEAL", "HEAR", - "HEAT", "HEBE", "HECK", "HEED", "HEEL", "HEFT", "HELD", "HELL", - "HELM", "HERB", "HERD", "HERE", "HERO", "HERS", "HESS", "HEWN", - "HICK", "HIDE", "HIGH", "HIKE", "HILL", "HILT", "HIND", "HINT", - "HIRE", "HISS", "HIVE", "HOBO", "HOCK", "HOFF", "HOLD", "HOLE", - "HOLM", "HOLT", "HOME", "HONE", "HONK", "HOOD", "HOOF", "HOOK", - "HOOT", "HORN", "HOSE", "HOST", "HOUR", "HOVE", "HOWE", "HOWL", - "HOYT", "HUCK", "HUED", "HUFF", "HUGE", "HUGH", "HUGO", "HULK", - "HULL", "HUNK", "HUNT", "HURD", "HURL", "HURT", "HUSH", "HYDE", - "HYMN", "IBIS", "ICON", "IDEA", "IDLE", "IFFY", "INCA", "INCH", - "INTO", "IONS", "IOTA", "IOWA", "IRIS", "IRMA", "IRON", "ISLE", - "ITCH", "ITEM", "IVAN", "JACK", "JADE", "JAIL", "JAKE", "JANE", - "JAVA", "JEAN", "JEFF", "JERK", "JESS", "JEST", "JIBE", "JILL", - "JILT", "JIVE", "JOAN", "JOBS", "JOCK", "JOEL", "JOEY", "JOHN", - "JOIN", "JOKE", "JOLT", "JOVE", "JUDD", "JUDE", "JUDO", "JUDY", - "JUJU", "JUKE", "JULY", "JUNE", "JUNK", "JUNO", "JURY", "JUST", - "JUTE", "KAHN", "KALE", "KANE", "KANT", "KARL", "KATE", "KEEL", - "KEEN", "KENO", "KENT", "KERN", "KERR", "KEYS", "KICK", "KILL", - "KIND", "KING", "KIRK", "KISS", "KITE", "KLAN", "KNEE", "KNEW", - "KNIT", "KNOB", "KNOT", "KNOW", "KOCH", "KONG", "KUDO", "KURD", - "KURT", "KYLE", "LACE", "LACK", "LACY", "LADY", "LAID", "LAIN", - "LAIR", "LAKE", "LAMB", "LAME", "LAND", "LANE", "LANG", "LARD", - "LARK", "LASS", "LAST", "LATE", "LAUD", "LAVA", "LAWN", "LAWS", - "LAYS", "LEAD", "LEAF", "LEAK", "LEAN", "LEAR", "LEEK", "LEER", - "LEFT", "LEND", "LENS", "LENT", "LEON", "LESK", "LESS", "LEST", - "LETS", "LIAR", "LICE", "LICK", "LIED", "LIEN", "LIES", "LIEU", - "LIFE", "LIFT", "LIKE", "LILA", "LILT", "LILY", "LIMA", "LIMB", - "LIME", "LIND", "LINE", "LINK", "LINT", "LION", "LISA", "LIST", - "LIVE", "LOAD", "LOAF", "LOAM", "LOAN", "LOCK", "LOFT", "LOGE", - "LOIS", "LOLA", "LONE", "LONG", "LOOK", "LOON", "LOOT", "LORD", - "LORE", "LOSE", "LOSS", "LOST", "LOUD", "LOVE", "LOWE", "LUCK", - "LUCY", "LUGE", "LUKE", "LULU", "LUND", "LUNG", "LURA", "LURE", - "LURK", "LUSH", "LUST", "LYLE", "LYNN", "LYON", "LYRA", "MACE", - "MADE", "MAGI", "MAID", "MAIL", "MAIN", "MAKE", "MALE", "MALI", - "MALL", "MALT", "MANA", "MANN", "MANY", "MARC", "MARE", "MARK", - "MARS", "MART", "MARY", "MASH", "MASK", "MASS", "MAST", "MATE", - "MATH", "MAUL", "MAYO", "MEAD", "MEAL", "MEAN", "MEAT", "MEEK", - "MEET", "MELD", "MELT", "MEMO", "MEND", "MENU", "MERT", "MESH", - "MESS", "MICE", "MIKE", "MILD", "MILE", "MILK", "MILL", "MILT", - "MIMI", "MIND", "MINE", "MINI", "MINK", "MINT", "MIRE", "MISS", - "MIST", "MITE", "MITT", "MOAN", "MOAT", "MOCK", "MODE", "MOLD", - "MOLE", "MOLL", "MOLT", "MONA", "MONK", "MONT", "MOOD", "MOON", - "MOOR", "MOOT", "MORE", "MORN", "MORT", "MOSS", "MOST", "MOTH", - "MOVE", "MUCH", "MUCK", "MUDD", "MUFF", "MULE", "MULL", "MURK", - "MUSH", "MUST", "MUTE", "MUTT", "MYRA", "MYTH", "NAGY", "NAIL", - "NAIR", "NAME", "NARY", "NASH", "NAVE", "NAVY", "NEAL", "NEAR", - "NEAT", "NECK", "NEED", "NEIL", "NELL", "NEON", "NERO", "NESS", - "NEST", "NEWS", "NEWT", "NIBS", "NICE", "NICK", "NILE", "NINA", - "NINE", "NOAH", "NODE", "NOEL", "NOLL", "NONE", "NOOK", "NOON", - "NORM", "NOSE", "NOTE", "NOUN", "NOVA", "NUDE", "NULL", "NUMB", - "OATH", "OBEY", "OBOE", "ODIN", "OHIO", "OILY", "OINT", "OKAY", - "OLAF", "OLDY", "OLGA", "OLIN", "OMAN", "OMEN", "OMIT", "ONCE", - "ONES", "ONLY", "ONTO", "ONUS", "ORAL", "ORGY", "OSLO", "OTIS", - "OTTO", "OUCH", "OUST", "OUTS", "OVAL", "OVEN", "OVER", "OWLY", - "OWNS", "QUAD", "QUIT", "QUOD", "RACE", "RACK", "RACY", "RAFT", - "RAGE", "RAID", "RAIL", "RAIN", "RAKE", "RANK", "RANT", "RARE", - "RASH", "RATE", "RAVE", "RAYS", "READ", "REAL", "REAM", "REAR", - "RECK", "REED", "REEF", "REEK", "REEL", "REID", "REIN", "RENA", - "REND", "RENT", "REST", "RICE", "RICH", "RICK", "RIDE", "RIFT", - "RILL", "RIME", "RING", "RINK", "RISE", "RISK", "RITE", "ROAD", - "ROAM", "ROAR", "ROBE", "ROCK", "RODE", "ROIL", "ROLL", "ROME", - "ROOD", "ROOF", "ROOK", "ROOM", "ROOT", "ROSA", "ROSE", "ROSS", - "ROSY", "ROTH", "ROUT", "ROVE", "ROWE", "ROWS", "RUBE", "RUBY", - "RUDE", "RUDY", "RUIN", "RULE", "RUNG", "RUNS", "RUNT", "RUSE", - "RUSH", "RUSK", "RUSS", "RUST", "RUTH", "SACK", "SAFE", "SAGE", - "SAID", "SAIL", "SALE", "SALK", "SALT", "SAME", "SAND", "SANE", - "SANG", "SANK", "SARA", "SAUL", "SAVE", "SAYS", "SCAN", "SCAR", - "SCAT", "SCOT", "SEAL", "SEAM", "SEAR", "SEAT", "SEED", "SEEK", - "SEEM", "SEEN", "SEES", "SELF", "SELL", "SEND", "SENT", "SETS", - "SEWN", "SHAG", "SHAM", "SHAW", "SHAY", "SHED", "SHIM", "SHIN", - "SHOD", "SHOE", "SHOT", "SHOW", "SHUN", "SHUT", "SICK", "SIDE", - "SIFT", "SIGH", "SIGN", "SILK", "SILL", "SILO", "SILT", "SINE", - "SING", "SINK", "SIRE", "SITE", "SITS", "SITU", "SKAT", "SKEW", - "SKID", "SKIM", "SKIN", "SKIT", "SLAB", "SLAM", "SLAT", "SLAY", - "SLED", "SLEW", "SLID", "SLIM", "SLIT", "SLOB", "SLOG", "SLOT", - "SLOW", "SLUG", "SLUM", "SLUR", "SMOG", "SMUG", "SNAG", "SNOB", - "SNOW", "SNUB", "SNUG", "SOAK", "SOAR", "SOCK", "SODA", "SOFA", - "SOFT", "SOIL", "SOLD", "SOME", "SONG", "SOON", "SOOT", "SORE", - "SORT", "SOUL", "SOUR", "SOWN", "STAB", "STAG", "STAN", "STAR", - "STAY", "STEM", "STEW", "STIR", "STOW", "STUB", "STUN", "SUCH", - "SUDS", "SUIT", "SULK", "SUMS", "SUNG", "SUNK", "SURE", "SURF", - "SWAB", "SWAG", "SWAM", "SWAN", "SWAT", "SWAY", "SWIM", "SWUM", - "TACK", "TACT", "TAIL", "TAKE", "TALE", "TALK", "TALL", "TANK", - "TASK", "TATE", "TAUT", "TEAL", "TEAM", "TEAR", "TECH", "TEEM", - "TEEN", "TEET", "TELL", "TEND", "TENT", "TERM", "TERN", "TESS", - "TEST", "THAN", "THAT", "THEE", "THEM", "THEN", "THEY", "THIN", - "THIS", "THUD", "THUG", "TICK", "TIDE", "TIDY", "TIED", "TIER", - "TILE", "TILL", "TILT", "TIME", "TINA", "TINE", "TINT", "TINY", - "TIRE", "TOAD", "TOGO", "TOIL", "TOLD", "TOLL", "TONE", "TONG", - "TONY", "TOOK", "TOOL", "TOOT", "TORE", "TORN", "TOTE", "TOUR", - "TOUT", "TOWN", "TRAG", "TRAM", "TRAY", "TREE", "TREK", "TRIG", - "TRIM", "TRIO", "TROD", "TROT", "TROY", "TRUE", "TUBA", "TUBE", - "TUCK", "TUFT", "TUNA", "TUNE", "TUNG", "TURF", "TURN", "TUSK", - "TWIG", "TWIN", "TWIT", "ULAN", "UNIT", "URGE", "USED", "USER", - "USES", "UTAH", "VAIL", "VAIN", "VALE", "VARY", "VASE", "VAST", - "VEAL", "VEDA", "VEIL", "VEIN", "VEND", "VENT", "VERB", "VERY", - "VETO", "VICE", "VIEW", "VINE", "VISE", "VOID", "VOLT", "VOTE", - "WACK", "WADE", "WAGE", "WAIL", "WAIT", "WAKE", "WALE", "WALK", - "WALL", "WALT", "WAND", "WANE", "WANG", "WANT", "WARD", "WARM", - "WARN", "WART", "WASH", "WAST", "WATS", "WATT", "WAVE", "WAVY", - "WAYS", "WEAK", "WEAL", "WEAN", "WEAR", "WEED", "WEEK", "WEIR", - "WELD", "WELL", "WELT", "WENT", "WERE", "WERT", "WEST", "WHAM", - "WHAT", "WHEE", "WHEN", "WHET", "WHOA", "WHOM", "WICK", "WIFE", - "WILD", "WILL", "WIND", "WINE", "WING", "WINK", "WINO", "WIRE", - "WISE", "WISH", "WITH", "WOLF", "WONT", "WOOD", "WOOL", "WORD", - "WORE", "WORK", "WORM", "WORN", "WOVE", "WRIT", "WYNN", "YALE", - "YANG", "YANK", "YARD", "YARN", "YAWL", "YAWN", "YEAH", "YEAR", - "YELL", "YOGA", "YOKE" ] diff --git a/Crypto/Util/RFC1751.pyi b/Crypto/Util/RFC1751.pyi deleted file mode 100644 index 6ad07ff..0000000 --- a/Crypto/Util/RFC1751.pyi +++ /dev/null @@ -1,7 +0,0 @@ -from typing import Dict, List - -binary: Dict[int, str] -wordlist: List[str] - -def key_to_english(key: bytes) -> str: ... -def english_to_key(s: str) -> bytes: ... diff --git a/Crypto/Util/__init__.py b/Crypto/Util/__init__.py deleted file mode 100644 index f12214d..0000000 --- a/Crypto/Util/__init__.py +++ /dev/null @@ -1,41 +0,0 @@ -# -*- coding: utf-8 -*- -# -# =================================================================== -# The contents of this file are dedicated to the public domain. To -# the extent that dedication to the public domain is not available, -# everyone is granted a worldwide, perpetual, royalty-free, -# non-exclusive license to exercise all rights associated with the -# contents of this file for any purpose whatsoever. -# No rights are reserved. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS -# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN -# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# =================================================================== - -"""Miscellaneous modules - -Contains useful modules that don't belong into any of the -other Crypto.* subpackages. - -======================== ============================================= -Module Description -======================== ============================================= -`Crypto.Util.number` Number-theoretic functions (primality testing, etc.) -`Crypto.Util.Counter` Fast counter functions for CTR cipher modes. -`Crypto.Util.RFC1751` Converts between 128-bit keys and human-readable - strings of words. -`Crypto.Util.asn1` Minimal support for ASN.1 DER encoding -`Crypto.Util.Padding` Set of functions for adding and removing padding. -======================== ============================================= - -:undocumented: _galois, _number_new, cpuid, py3compat, _raw_api -""" - -__all__ = ['RFC1751', 'number', 'strxor', 'asn1', 'Counter', 'Padding'] - diff --git a/Crypto/Util/__pycache__/__init__.cpython-36.pyc b/Crypto/Util/__pycache__/__init__.cpython-36.pyc deleted file mode 100644 index 4df4eefd24d9ef7954204d292f2a089007d1ff6f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1116 zcmb_c&2AGh5Z)6iL#A{prNeC~%v+zo} z@)lgc&L;hV_STVh);nX*&-ab@@Zcc(b9RbMME&9c6d4s&V2TQ>D#>i~C!9Z)5oIhZh^ zWC>h41z0XYO@o(ZDkuYev(!%IFTnbV#$<*|X7en2^MF8*2VD1?vx{}5@!bD%#w;;h zJFes-X1v_=^x1KdOJ7Zxx!mR+tUtSH97K};g zy?ouBa0fHCw1GDYSH8lsYZ#_@B3QO<>AtshCe&{u)eB|lzp1g6*LlP73oc{lVFa{R z#z8Fp{b-Q);OxT?m?VmZXm_jsh-ox#s~<5Jlii>hW7J#LwHsEcdDsuSHs+7WcXr|> zRm4{;5JOJ@l~^clJAi8Pkz|Vw5bZhbfLl;Hq2Aj*ni=zAlP^lB}?X6!rWTaefPg0yz$$TrXGqr}ede`!xPD8bLK1e*ugV BO+Eks diff --git a/Crypto/Util/__pycache__/_cpu_features.cpython-36.pyc b/Crypto/Util/__pycache__/_cpu_features.cpython-36.pyc deleted file mode 100644 index f4240fd99b8c8b6384e807136c5ebdf0b25f6366..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 695 zcmbVKy-ve05Vn)_heDZHnCM85S`P>qKnSVKT@VuLVj0_Q-8ymP#I4%3ybKdh!AoRi z;uToHc2!X%hN>ss`TY0!yYGD7Y&O2{Z^(NMfDf=?q0R5C=VvxBz@P*P>_Z4RWC078 zK|f#-tGs}I$f~Sn$B5M*K)m;9&x072$5Ii7vpLoCtWZoP9BVSeQamq?x_+(mSP0p{ zG&6!>x_E1}wl|R$tr3}WOn8n{aXM9k#n(F_P?;FH0|0e}t_|9xYdx>qP=GO90xJgW z#X))K>t0o9t1tIAc)tQ&u@`*!dO{}GNGeJsni7o$CZ&Z?X^u$N9vYGk7b9hmBuP7& zTwPpF#xvAYDMz`cXeB9fk|HN59&l0^&GSw+*O7fAcI*Nh0QB=M>1+29%7*9cmHH*T z%Bpr>+usA)*4GcXc`vS%e>?5^Pcoq$3yfgM7`C0X4P_e~#>Y-ry^J2#91tK)6G9qX3*u9%kRms6JGYJ<+0G!Ny->LF z6S(u2a^+B76Ay|4V{c|V@_N%CNOyZ`6e5&Ik=^b1`%1ny74>@K(rWmuvK z%19P`MH8Ii*Jv1?1A@k>&-AAQ7J?mv*(tacRP8~{GBCRiWx)o2!4AXIFzb9HduW4K zc#iL&HF9JTEW*ZjTz7*v_ybv!bEaOkl;jL<9YN~5Sd z;WX8GA-UspCM2hd<#5xcfpVRdlK1-*P9{v^Q!PEDQdmdzj9O=enm4ddc>~=pAV}w_ z)23=VS}NLMFRNoy6;5Xw#uO}FvN<39(_khHH0P4%TsfMT5KK88v}J=)OU6@em>&L* z!zFrOs8p5~I8y$}ab<;8!wV{onK^fUua;;_!+`2g{ymPYMVGp63;hD z>Tscj8g}Yymr~c!#VV7ibV4RlOlzD>BBQnQ!B1p%VD9htacNB~b;@LX%1k^fRq9|_ z8?)kIUNSX5JJDqc&A3uDwTzrhjTJhMLG;TMD-@<^nsvS?x5-_+L(ENxhs5}gy16&huDBZj)X`C^-;;X~S^pzM!CzWX^Kt+H diff --git a/Crypto/Util/__pycache__/_raw_api.cpython-36.pyc b/Crypto/Util/__pycache__/_raw_api.cpython-36.pyc deleted file mode 100644 index 7e9cb236dff6dd822cda31ecfef2de3548588860..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8300 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 phX@oVRfwd2w*rR<86e>Q=6?4X3P diff --git a/Crypto/Util/__pycache__/py3compat.cpython-36.pyc b/Crypto/Util/__pycache__/py3compat.cpython-36.pyc deleted file mode 100644 index 11e57715b5ee99a94352fec8233d44b5a6b1384f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4712 zcmb7IO>Y~=8RjlYky?HDOO`D=PA6$nlBq<(b^3ueC>q-}>H<}Y%D&Jjh~dsqT4}k< z&I~2d5Q+jy4+VPcrPtp2m-gCI{z5M8^Uf^Er7Aj!4DQU%?z|t*^Sm>&ezLI<{P+21 z{Lxma^q*4UuZsS!@Y7ANR1&3bNqEAKy{>0lzw1lyxGcP#k|>|}>R+NFs$Z766|o{} zXseG@bs$NXonNTDmc%4KxBqPraYs&Uvo4tPZV((|IHe;`jB-3)l6*qEfeeB+EG}uuZ3(bo2 z+cRrORVp59#uZGAWEc%1DcEVmnSs%9qup*d*htAibPh)^6CuwjD&V5yC`31q5#ChJ zEsxLmMC1Kbj6M5(2lN6G7CV<_;L>E^+s4*t%rUek38N%ELzH5i2%Z=q z@;OW7nM=MI@;C-ljfRy7aeG8*rmPPnHDDz<6=-J7In6woFc4^>a2#_58|3Qm>^;41Sha$>RqIRnD!NG3oxN&;IPL)6PI zDb!BPxo{NOyv`ymp`HVPFHxh<)MNzIcr=984AbM$C@)JsJTv!)+jjl`vpZhuB#>mDFv!;0aBsV>x(@h>QJFho5{LAXkpr{QR` zvU!(t0wN*jw60m*`wL0EL+aP9Yl@ZyO+TmfZ?Q0J&K3bk4u@;cC1jJOMdDNNRLK_( zJaeGhbOCJD6$hcKZqtPp0!N^$dUclu2u63I#n%?}7@b+M+d`+3Urhd6$t7D6l1?Nb z`QFTpb!dH2ssEXL<$w^N^hfQC-KACk4%tw3{{_F?Fsicl6zhPtbzVcA>*%dq;PRW@ zy$5^9;*5QcAelm{2k{)P8f ze+N6urQ1n-V_kDEkdEJ<~L4 zah;ua?2X-GcG*x4Q#Cn_d|tXCKT6fdG_~q% zQ67cdNe6B_t$&8ko^dRH`3nqbl0?O?d-d`r_GV-dm1MuFA zi;0rl$XFYd7W?sD)$K}EukA}?nWxVyNnE9c`7jm5 zCe5}`+xMm7BT7h{Ew~QLR4~W1k(7lt%&9l*YFb?1TqrZI=9J9#*)lT=Wo0&*TRzKV z5q`YT+?;>#3SYdbtFqUB4g`s}|V#tIXQK0mQ z_I-8PPyw?a=)@CVzooW}=Qxh&6Ti4I@t*j`pLj=9e{KS(Lg1WffVZGw4>Sbs-5a18 zzBdk~Vlk&##{P@a0r z2F8-l)V{twjgyfozs@$0Q%6X-g5ryEnU`vGn95;z%*oiJo@CurLCK*ME4$3V8#Go9 zq~azm3ulE{hV7S7t0mN>I9o4dcu*Oq_zX|8GO;ePVNWV)T~$(7nPGVaOW2bPJJHC3 zney0e#=h#Z-QAtCkh{B^^D?PsN}5U)QaI+@5A5SfbgZQFZ+Djg|A`*X3OR&l8)f+D zQo@F*>CM?VapFG2RSi=uXFA-s@z(t!8$Fj+%!2%`;u-eiKIlt$folT{kz!|jV;ZpI zC37omBgaa`xQ&5DBX*MV@kjGgJ$~q-r+F@qt#EA}PYcWj+jv)4y*dorwGWQe?Z-T; zG^BS5{HR^J{tkgPXVd2g3+69BGwA4tpcS z-pF~eH5jRLpf`e{-vL6_*J;aZ(KSB++Va+EK+kz?+JxVlePj8Pg_!Xx$O}550r5$n zmgfN_ND+915{MvihydLj0CwCm)OgtUr?BH5U`NAZgZ&O%4m%D&L(|Fp7ds{=xG~i^ z#SOId^9(m&*Rwm{6903G8?Hj0D^U)mKftXHHXf)oStJt6F6nW_6UY!?%PCxO5b$ES zg6RAb*uq#cMV2{iI@Vz!&-6HSIqyr&s(~%k7sVIGrlr4u6@o2t1}36i==`EIvtD($ z@&E7x(4Y;rCxdeVK#z^xD?k$k87I%663O^dG6Ti5Uu1b%LMGmp*OzrSgH~0a@cHekGuvABa=SEjV`tLbY&+D z?4m4wIN-x2hrU{cn_5G%U>Wt=^pqHjRLR8r2z=TDLOgW|Xh?VPzfxa(?qrE4SUyM< zaynxcnGtGTEN!GQ$j%=Omen^GMH^2HW!<`ym!it#CvU@(#{94#SZ@05_u8BP0xx_V AG5`Po diff --git a/Crypto/Util/_cpu_features.py b/Crypto/Util/_cpu_features.py deleted file mode 100644 index b3039b5..0000000 --- a/Crypto/Util/_cpu_features.py +++ /dev/null @@ -1,46 +0,0 @@ -# =================================================================== -# -# Copyright (c) 2018, Helder Eijs -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# =================================================================== - -from Crypto.Util._raw_api import load_pycryptodome_raw_lib - - -_raw_cpuid_lib = load_pycryptodome_raw_lib("Crypto.Util._cpuid_c", - """ - int have_aes_ni(void); - int have_clmul(void); - """) - - -def have_aes_ni(): - return _raw_cpuid_lib.have_aes_ni() - - -def have_clmul(): - return _raw_cpuid_lib.have_clmul() diff --git a/Crypto/Util/_cpu_features.pyi b/Crypto/Util/_cpu_features.pyi deleted file mode 100644 index 10e669e..0000000 --- a/Crypto/Util/_cpu_features.pyi +++ /dev/null @@ -1,2 +0,0 @@ -def have_aes_ni() -> int: ... -def have_clmul() -> int: ... diff --git a/Crypto/Util/_cpuid_c.abi3.so b/Crypto/Util/_cpuid_c.abi3.so deleted file mode 100644 index 2a7ec30858aa8ef83393abb3095c4da5bcde0a0b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 12776 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 CgCK+e diff --git a/Crypto/Util/_file_system.py b/Crypto/Util/_file_system.py deleted file mode 100644 index 1cb0c4b..0000000 --- a/Crypto/Util/_file_system.py +++ /dev/null @@ -1,54 +0,0 @@ -# =================================================================== -# -# Copyright (c) 2016, Legrandin -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# =================================================================== - -import os - - -def pycryptodome_filename(dir_comps, filename): - """Return the complete file name for the module - - dir_comps : list of string - The list of directory names in the PyCryptodome package. - The first element must be "Crypto". - - filename : string - The filename (inclusing extension) in the target directory. - """ - - if dir_comps[0] != "Crypto": - raise ValueError("Only available for modules under 'Crypto'") - - dir_comps = list(dir_comps[1:]) + [filename] - - util_lib, _ = os.path.split(os.path.abspath(__file__)) - root_lib = os.path.join(util_lib, "..") - - return os.path.join(root_lib, *dir_comps) - diff --git a/Crypto/Util/_file_system.pyi b/Crypto/Util/_file_system.pyi deleted file mode 100644 index d54a126..0000000 --- a/Crypto/Util/_file_system.pyi +++ /dev/null @@ -1,4 +0,0 @@ -from typing import List - - -def pycryptodome_filename(dir_comps: List[str], filename: str) -> str: ... \ No newline at end of file diff --git a/Crypto/Util/_raw_api.py b/Crypto/Util/_raw_api.py deleted file mode 100644 index 44c37c2..0000000 --- a/Crypto/Util/_raw_api.py +++ /dev/null @@ -1,307 +0,0 @@ -# =================================================================== -# -# Copyright (c) 2014, Legrandin -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# =================================================================== - -import abc -import sys -from Crypto.Util.py3compat import byte_string -from Crypto.Util._file_system import pycryptodome_filename - -# -# List of file suffixes for Python extensions -# -if sys.version_info[0] < 3: - - import imp - extension_suffixes = [] - for ext, mod, typ in imp.get_suffixes(): - if typ == imp.C_EXTENSION: - extension_suffixes.append(ext) - -else: - - from importlib import machinery - extension_suffixes = machinery.EXTENSION_SUFFIXES - -# Which types with buffer interface we support (apart from byte strings) -_buffer_type = (bytearray, memoryview) - - -class _VoidPointer(object): - @abc.abstractmethod - def get(self): - """Return the memory location we point to""" - return - - @abc.abstractmethod - def address_of(self): - """Return a raw pointer to this pointer""" - return - - -try: - # Starting from v2.18, pycparser (used by cffi for in-line ABI mode) - # stops working correctly when PYOPTIMIZE==2 or the parameter -OO is - # passed. In that case, we fall back to ctypes. - # Note that PyPy ships with an old version of pycparser so we can keep - # using cffi there. - # See https://github.com/Legrandin/pycryptodome/issues/228 - if '__pypy__' not in sys.builtin_module_names and sys.flags.optimize == 2: - raise ImportError("CFFI with optimize=2 fails due to pycparser bug.") - - from cffi import FFI - - ffi = FFI() - null_pointer = ffi.NULL - uint8_t_type = ffi.typeof(ffi.new("const uint8_t*")) - - _Array = ffi.new("uint8_t[1]").__class__.__bases__ - - def load_lib(name, cdecl): - """Load a shared library and return a handle to it. - - @name, either an absolute path or the name of a library - in the system search path. - - @cdecl, the C function declarations. - """ - - lib = ffi.dlopen(name) - ffi.cdef(cdecl) - return lib - - def c_ulong(x): - """Convert a Python integer to unsigned long""" - return x - - c_ulonglong = c_ulong - c_uint = c_ulong - - def c_size_t(x): - """Convert a Python integer to size_t""" - return x - - def create_string_buffer(init_or_size, size=None): - """Allocate the given amount of bytes (initially set to 0)""" - - if isinstance(init_or_size, bytes): - size = max(len(init_or_size) + 1, size) - result = ffi.new("uint8_t[]", size) - result[:] = init_or_size - else: - if size: - raise ValueError("Size must be specified once only") - result = ffi.new("uint8_t[]", init_or_size) - return result - - def get_c_string(c_string): - """Convert a C string into a Python byte sequence""" - return ffi.string(c_string) - - def get_raw_buffer(buf): - """Convert a C buffer into a Python byte sequence""" - return ffi.buffer(buf)[:] - - def c_uint8_ptr(data): - if isinstance(data, _buffer_type): - # This only works for cffi >= 1.7 - return ffi.cast(uint8_t_type, ffi.from_buffer(data)) - elif byte_string(data) or isinstance(data, _Array): - return data - else: - raise TypeError("Object type %s cannot be passed to C code" % type(data)) - - class VoidPointer_cffi(_VoidPointer): - """Model a newly allocated pointer to void""" - - def __init__(self): - self._pp = ffi.new("void *[1]") - - def get(self): - return self._pp[0] - - def address_of(self): - return self._pp - - def VoidPointer(): - return VoidPointer_cffi() - - backend = "cffi" - -except ImportError: - - import ctypes - from ctypes import (CDLL, c_void_p, byref, c_ulong, c_ulonglong, c_size_t, - create_string_buffer, c_ubyte, c_uint) - from ctypes.util import find_library - from ctypes import Array as _Array - - null_pointer = None - cached_architecture = [] - - def load_lib(name, cdecl): - if not cached_architecture: - # platform.architecture() creates a subprocess, so caching the - # result makes successive imports faster. - import platform - cached_architecture[:] = platform.architecture() - bits, linkage = cached_architecture - if "." not in name and not linkage.startswith("Win"): - full_name = find_library(name) - if full_name is None: - raise OSError("Cannot load library '%s'" % name) - name = full_name - return CDLL(name) - - def get_c_string(c_string): - return c_string.value - - def get_raw_buffer(buf): - return buf.raw - - # ---- Get raw pointer --- - - _c_ssize_t = ctypes.c_ssize_t - - _PyBUF_SIMPLE = 0 - _PyObject_GetBuffer = ctypes.pythonapi.PyObject_GetBuffer - _PyBuffer_Release = ctypes.pythonapi.PyBuffer_Release - _py_object = ctypes.py_object - _c_ssize_p = ctypes.POINTER(_c_ssize_t) - - # See Include/object.h for CPython - # and https://github.com/pallets/click/blob/master/click/_winconsole.py - class _Py_buffer(ctypes.Structure): - _fields_ = [ - ('buf', c_void_p), - ('obj', ctypes.py_object), - ('len', _c_ssize_t), - ('itemsize', _c_ssize_t), - ('readonly', ctypes.c_int), - ('ndim', ctypes.c_int), - ('format', ctypes.c_char_p), - ('shape', _c_ssize_p), - ('strides', _c_ssize_p), - ('suboffsets', _c_ssize_p), - ('internal', c_void_p) - ] - - # Extra field for CPython 2.6/2.7 - if sys.version_info[0] == 2: - _fields_.insert(-1, ('smalltable', _c_ssize_t * 2)) - - def c_uint8_ptr(data): - if byte_string(data) or isinstance(data, _Array): - return data - elif isinstance(data, _buffer_type): - obj = _py_object(data) - buf = _Py_buffer() - _PyObject_GetBuffer(obj, byref(buf), _PyBUF_SIMPLE) - try: - buffer_type = c_ubyte * buf.len - return buffer_type.from_address(buf.buf) - finally: - _PyBuffer_Release(byref(buf)) - else: - raise TypeError("Object type %s cannot be passed to C code" % type(data)) - - # --- - - class VoidPointer_ctypes(_VoidPointer): - """Model a newly allocated pointer to void""" - - def __init__(self): - self._p = c_void_p() - - def get(self): - return self._p - - def address_of(self): - return byref(self._p) - - def VoidPointer(): - return VoidPointer_ctypes() - - backend = "ctypes" - del ctypes - - -class SmartPointer(object): - """Class to hold a non-managed piece of memory""" - - def __init__(self, raw_pointer, destructor): - self._raw_pointer = raw_pointer - self._destructor = destructor - - def get(self): - return self._raw_pointer - - def release(self): - rp, self._raw_pointer = self._raw_pointer, None - return rp - - def __del__(self): - try: - if self._raw_pointer is not None: - self._destructor(self._raw_pointer) - self._raw_pointer = None - except AttributeError: - pass - - -def load_pycryptodome_raw_lib(name, cdecl): - """Load a shared library and return a handle to it. - - @name, the name of the library expressed as a PyCryptodome module, - for instance Crypto.Cipher._raw_cbc. - - @cdecl, the C function declarations. - """ - - split = name.split(".") - dir_comps, basename = split[:-1], split[-1] - attempts = [] - for ext in extension_suffixes: - try: - filename = basename + ext - return load_lib(pycryptodome_filename(dir_comps, filename), - cdecl) - except OSError as exp: - attempts.append("Trying '%s': %s" % (filename, str(exp))) - raise OSError("Cannot load native module '%s': %s" % (name, ", ".join(attempts))) - - -def is_buffer(x): - """Return True if object x supports the buffer interface""" - return isinstance(x, (bytes, bytearray, memoryview)) - - -def is_writeable_buffer(x): - return (isinstance(x, bytearray) or - (isinstance(x, memoryview) and not x.readonly)) diff --git a/Crypto/Util/_raw_api.pyi b/Crypto/Util/_raw_api.pyi deleted file mode 100644 index 2bc5301..0000000 --- a/Crypto/Util/_raw_api.pyi +++ /dev/null @@ -1,27 +0,0 @@ -from typing import Any, Optional, Union - -def load_lib(name: str, cdecl: str) -> Any : ... -def c_ulong(x: int ) -> Any : ... -def c_ulonglong(x: int ) -> Any : ... -def c_size_t(x: int) -> Any : ... -def create_string_buffer(init_or_size: Union[bytes,int], size: Optional[int]) -> Any : ... -def get_c_string(c_string: Any) -> bytes : ... -def get_raw_buffer(buf: Any) -> bytes : ... -def c_uint8_ptr(data: Union[bytes, memoryview, bytearray]) -> Any : ... - -class VoidPointer(object): - def get(self) -> Any : ... - def address_of(self) -> Any : ... - -class SmartPointer(object): - def __init__(self, raw_pointer: Any, destructor: Any) -> None : ... - def get(self) -> Any : ... - def release(self) -> Any : ... - -backend : str -null_pointer : Any -ffi: Any - -def load_pycryptodome_raw_lib(name: str, cdecl: str) -> Any : ... -def is_buffer(x: Any) -> bool : ... -def is_writeable_buffer(x: Any) -> bool : ... diff --git a/Crypto/Util/_strxor.abi3.so b/Crypto/Util/_strxor.abi3.so deleted file mode 100644 index efecda25eef1f88d40ae3438b47e4040b766bba1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 14960 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 0 - - -class BytesIO_EOF(object): - """This class differs from BytesIO in that a ValueError exception is - raised whenever EOF is reached.""" - - def __init__(self, initial_bytes): - self._buffer = initial_bytes - self._index = 0 - self._bookmark = None - - def set_bookmark(self): - self._bookmark = self._index - - def data_since_bookmark(self): - assert self._bookmark is not None - return self._buffer[self._bookmark:self._index] - - def remaining_data(self): - return len(self._buffer) - self._index - - def read(self, length): - new_index = self._index + length - if new_index > len(self._buffer): - raise ValueError("Not enough data for DER decoding: expected %d bytes and found %d" % (new_index, len(self._buffer))) - - result = self._buffer[self._index:new_index] - self._index = new_index - return result - - def read_byte(self): - return bord(self.read(1)[0]) - - -class DerObject(object): - """Base class for defining a single DER object. - - This class should never be directly instantiated. - """ - - def __init__(self, asn1Id=None, payload=b'', implicit=None, - constructed=False, explicit=None): - """Initialize the DER object according to a specific ASN.1 type. - - :Parameters: - asn1Id : integer - The universal DER tag number for this object - (e.g. 0x10 for a SEQUENCE). - If None, the tag is not known yet. - - payload : byte string - The initial payload of the object (that it, - the content octets). - If not specified, the payload is empty. - - implicit : integer - The IMPLICIT tag number to use for the encoded object. - It overrides the universal tag *asn1Id*. - - constructed : bool - True when the ASN.1 type is *constructed*. - False when it is *primitive*. - - explicit : integer - The EXPLICIT tag number to use for the encoded object. - """ - - if asn1Id is None: - # The tag octet will be read in with ``decode`` - self._tag_octet = None - return - asn1Id = self._convertTag(asn1Id) - - self.payload = payload - - # In a BER/DER identifier octet: - # * bits 4-0 contain the tag value - # * bit 5 is set if the type is 'constructed' - # and unset if 'primitive' - # * bits 7-6 depend on the encoding class - # - # Class | Bit 7, Bit 6 - # ---------------------------------- - # universal | 0 0 - # application | 0 1 - # context-spec | 1 0 (default for IMPLICIT/EXPLICIT) - # private | 1 1 - # - if None not in (explicit, implicit): - raise ValueError("Explicit and implicit tags are" - " mutually exclusive") - - if implicit is not None: - self._tag_octet = 0x80 | 0x20 * constructed | self._convertTag(implicit) - return - - if explicit is not None: - self._tag_octet = 0xA0 | self._convertTag(explicit) - self._inner_tag_octet = 0x20 * constructed | asn1Id - return - - self._tag_octet = 0x20 * constructed | asn1Id - - def _convertTag(self, tag): - """Check if *tag* is a real DER tag. - Convert it from a character to number if necessary. - """ - if not _is_number(tag): - if len(tag) == 1: - tag = bord(tag[0]) - # Ensure that tag is a low tag - if not (_is_number(tag) and 0 <= tag < 0x1F): - raise ValueError("Wrong DER tag") - return tag - - @staticmethod - def _definite_form(length): - """Build length octets according to BER/DER - definite form. - """ - if length > 127: - encoding = long_to_bytes(length) - return bchr(len(encoding) + 128) + encoding - return bchr(length) - - def encode(self): - """Return this DER element, fully encoded as a binary byte string.""" - - # Concatenate identifier octets, length octets, - # and contents octets - - output_payload = self.payload - - # In case of an EXTERNAL tag, first encode the inner - # element. - if hasattr(self, "_inner_tag_octet"): - output_payload = (bchr(self._inner_tag_octet) + - self._definite_form(len(self.payload)) + - self.payload) - - return (bchr(self._tag_octet) + - self._definite_form(len(output_payload)) + - output_payload) - - def _decodeLen(self, s): - """Decode DER length octets from a file.""" - - length = s.read_byte() - - if length > 127: - encoded_length = s.read(length & 0x7F) - if bord(encoded_length[0]) == 0: - raise ValueError("Invalid DER: length has leading zero") - length = bytes_to_long(encoded_length) - if length <= 127: - raise ValueError("Invalid DER: length in long form but smaller than 128") - - return length - - def decode(self, der_encoded, strict=False): - """Decode a complete DER element, and re-initializes this - object with it. - - Args: - der_encoded (byte string): A complete DER element. - - Raises: - ValueError: in case of parsing errors. - """ - - if not byte_string(der_encoded): - raise ValueError("Input is not a byte string") - - s = BytesIO_EOF(der_encoded) - self._decodeFromStream(s, strict) - - # There shouldn't be other bytes left - if s.remaining_data() > 0: - raise ValueError("Unexpected extra data after the DER structure") - - return self - - def _decodeFromStream(self, s, strict): - """Decode a complete DER element from a file.""" - - idOctet = s.read_byte() - if self._tag_octet is not None: - if idOctet != self._tag_octet: - raise ValueError("Unexpected DER tag") - else: - self._tag_octet = idOctet - length = self._decodeLen(s) - self.payload = s.read(length) - - # In case of an EXTERNAL tag, further decode the inner - # element. - if hasattr(self, "_inner_tag_octet"): - p = BytesIO_EOF(self.payload) - inner_octet = p.read_byte() - if inner_octet != self._inner_tag_octet: - raise ValueError("Unexpected internal DER tag") - length = self._decodeLen(p) - self.payload = p.read(length) - - # There shouldn't be other bytes left - if p.remaining_data() > 0: - raise ValueError("Unexpected extra data after the DER structure") - - -class DerInteger(DerObject): - """Class to model a DER INTEGER. - - An example of encoding is:: - - >>> from Crypto.Util.asn1 import DerInteger - >>> from binascii import hexlify, unhexlify - >>> int_der = DerInteger(9) - >>> print hexlify(int_der.encode()) - - which will show ``020109``, the DER encoding of 9. - - And for decoding:: - - >>> s = unhexlify(b'020109') - >>> try: - >>> int_der = DerInteger() - >>> int_der.decode(s) - >>> print int_der.value - >>> except ValueError: - >>> print "Not a valid DER INTEGER" - - the output will be ``9``. - - :ivar value: The integer value - :vartype value: integer - """ - - def __init__(self, value=0, implicit=None, explicit=None): - """Initialize the DER object as an INTEGER. - - :Parameters: - value : integer - The value of the integer. - - implicit : integer - The IMPLICIT tag to use for the encoded object. - It overrides the universal tag for INTEGER (2). - """ - - DerObject.__init__(self, 0x02, b'', implicit, - False, explicit) - self.value = value # The integer value - - def encode(self): - """Return the DER INTEGER, fully encoded as a - binary string.""" - - number = self.value - self.payload = b'' - while True: - self.payload = bchr(int(number & 255)) + self.payload - if 128 <= number <= 255: - self.payload = bchr(0x00) + self.payload - if -128 <= number <= 255: - break - number >>= 8 - return DerObject.encode(self) - - def decode(self, der_encoded, strict=False): - """Decode a complete DER INTEGER DER, and re-initializes this - object with it. - - Args: - der_encoded (byte string): A complete INTEGER DER element. - - Raises: - ValueError: in case of parsing errors. - """ - - return DerObject.decode(self, der_encoded, strict=strict) - - def _decodeFromStream(self, s, strict): - """Decode a complete DER INTEGER from a file.""" - - # Fill up self.payload - DerObject._decodeFromStream(self, s, strict) - - if strict: - if len(self.payload) == 0: - raise ValueError("Invalid encoding for DER INTEGER: empty payload") - if len(self.payload) >= 2 and struct.unpack('>H', self.payload[:2])[0] < 0x80: - raise ValueError("Invalid encoding for DER INTEGER: leading zero") - - # Derive self.value from self.payload - self.value = 0 - bits = 1 - for i in self.payload: - self.value *= 256 - self.value += bord(i) - bits <<= 8 - if self.payload and bord(self.payload[0]) & 0x80: - self.value -= bits - - -class DerSequence(DerObject): - """Class to model a DER SEQUENCE. - - This object behaves like a dynamic Python sequence. - - Sub-elements that are INTEGERs behave like Python integers. - - Any other sub-element is a binary string encoded as a complete DER - sub-element (TLV). - - An example of encoding is: - - >>> from Crypto.Util.asn1 import DerSequence, DerInteger - >>> from binascii import hexlify, unhexlify - >>> obj_der = unhexlify('070102') - >>> seq_der = DerSequence([4]) - >>> seq_der.append(9) - >>> seq_der.append(obj_der.encode()) - >>> print hexlify(seq_der.encode()) - - which will show ``3009020104020109070102``, the DER encoding of the - sequence containing ``4``, ``9``, and the object with payload ``02``. - - For decoding: - - >>> s = unhexlify(b'3009020104020109070102') - >>> try: - >>> seq_der = DerSequence() - >>> seq_der.decode(s) - >>> print len(seq_der) - >>> print seq_der[0] - >>> print seq_der[:] - >>> except ValueError: - >>> print "Not a valid DER SEQUENCE" - - the output will be:: - - 3 - 4 - [4, 9, b'\x07\x01\x02'] - - """ - - def __init__(self, startSeq=None, implicit=None): - """Initialize the DER object as a SEQUENCE. - - :Parameters: - startSeq : Python sequence - A sequence whose element are either integers or - other DER objects. - - implicit : integer - The IMPLICIT tag to use for the encoded object. - It overrides the universal tag for SEQUENCE (16). - """ - - DerObject.__init__(self, 0x10, b'', implicit, True) - if startSeq is None: - self._seq = [] - else: - self._seq = startSeq - - # A few methods to make it behave like a python sequence - - def __delitem__(self, n): - del self._seq[n] - - def __getitem__(self, n): - return self._seq[n] - - def __setitem__(self, key, value): - self._seq[key] = value - - def __setslice__(self, i, j, sequence): - self._seq[i:j] = sequence - - def __delslice__(self, i, j): - del self._seq[i:j] - - def __getslice__(self, i, j): - return self._seq[max(0, i):max(0, j)] - - def __len__(self): - return len(self._seq) - - def __iadd__(self, item): - self._seq.append(item) - return self - - def append(self, item): - self._seq.append(item) - return self - - def hasInts(self, only_non_negative=True): - """Return the number of items in this sequence that are - integers. - - Args: - only_non_negative (boolean): - If ``True``, negative integers are not counted in. - """ - - items = [x for x in self._seq if _is_number(x, only_non_negative)] - return len(items) - - def hasOnlyInts(self, only_non_negative=True): - """Return ``True`` if all items in this sequence are integers - or non-negative integers. - - This function returns False is the sequence is empty, - or at least one member is not an integer. - - Args: - only_non_negative (boolean): - If ``True``, the presence of negative integers - causes the method to return ``False``.""" - return self._seq and self.hasInts(only_non_negative) == len(self._seq) - - def encode(self): - """Return this DER SEQUENCE, fully encoded as a - binary string. - - Raises: - ValueError: if some elements in the sequence are neither integers - nor byte strings. - """ - self.payload = b'' - for item in self._seq: - if byte_string(item): - self.payload += item - elif _is_number(item): - self.payload += DerInteger(item).encode() - else: - self.payload += item.encode() - return DerObject.encode(self) - - def decode(self, der_encoded, strict=False, nr_elements=None, only_ints_expected=False): - """Decode a complete DER SEQUENCE, and re-initializes this - object with it. - - Args: - der_encoded (byte string): - A complete SEQUENCE DER element. - nr_elements (None or integer or list of integers): - The number of members the SEQUENCE can have - only_ints_expected (boolean): - Whether the SEQUENCE is expected to contain only integers. - strict (boolean): - Whether decoding must check for strict DER compliancy. - - Raises: - ValueError: in case of parsing errors. - - DER INTEGERs are decoded into Python integers. Any other DER - element is not decoded. Its validity is not checked. - """ - - self._nr_elements = nr_elements - result = DerObject.decode(self, der_encoded, strict=strict) - - if only_ints_expected and not self.hasOnlyInts(): - raise ValueError("Some members are not INTEGERs") - - return result - - def _decodeFromStream(self, s, strict): - """Decode a complete DER SEQUENCE from a file.""" - - self._seq = [] - - # Fill up self.payload - DerObject._decodeFromStream(self, s, strict) - - # Add one item at a time to self.seq, by scanning self.payload - p = BytesIO_EOF(self.payload) - while p.remaining_data() > 0: - p.set_bookmark() - - der = DerObject() - der._decodeFromStream(p, strict) - - # Parse INTEGERs differently - if der._tag_octet != 0x02: - self._seq.append(p.data_since_bookmark()) - else: - derInt = DerInteger() - #import pdb; pdb.set_trace() - data = p.data_since_bookmark() - derInt.decode(data, strict=strict) - self._seq.append(derInt.value) - - ok = True - if self._nr_elements is not None: - try: - ok = len(self._seq) in self._nr_elements - except TypeError: - ok = len(self._seq) == self._nr_elements - - if not ok: - raise ValueError("Unexpected number of members (%d)" - " in the sequence" % len(self._seq)) - - -class DerOctetString(DerObject): - """Class to model a DER OCTET STRING. - - An example of encoding is: - - >>> from Crypto.Util.asn1 import DerOctetString - >>> from binascii import hexlify, unhexlify - >>> os_der = DerOctetString(b'\\xaa') - >>> os_der.payload += b'\\xbb' - >>> print hexlify(os_der.encode()) - - which will show ``0402aabb``, the DER encoding for the byte string - ``b'\\xAA\\xBB'``. - - For decoding: - - >>> s = unhexlify(b'0402aabb') - >>> try: - >>> os_der = DerOctetString() - >>> os_der.decode(s) - >>> print hexlify(os_der.payload) - >>> except ValueError: - >>> print "Not a valid DER OCTET STRING" - - the output will be ``aabb``. - - :ivar payload: The content of the string - :vartype payload: byte string - """ - - def __init__(self, value=b'', implicit=None): - """Initialize the DER object as an OCTET STRING. - - :Parameters: - value : byte string - The initial payload of the object. - If not specified, the payload is empty. - - implicit : integer - The IMPLICIT tag to use for the encoded object. - It overrides the universal tag for OCTET STRING (4). - """ - DerObject.__init__(self, 0x04, value, implicit, False) - - -class DerNull(DerObject): - """Class to model a DER NULL element.""" - - def __init__(self): - """Initialize the DER object as a NULL.""" - - DerObject.__init__(self, 0x05, b'', None, False) - - -class DerObjectId(DerObject): - """Class to model a DER OBJECT ID. - - An example of encoding is: - - >>> from Crypto.Util.asn1 import DerObjectId - >>> from binascii import hexlify, unhexlify - >>> oid_der = DerObjectId("1.2") - >>> oid_der.value += ".840.113549.1.1.1" - >>> print hexlify(oid_der.encode()) - - which will show ``06092a864886f70d010101``, the DER encoding for the - RSA Object Identifier ``1.2.840.113549.1.1.1``. - - For decoding: - - >>> s = unhexlify(b'06092a864886f70d010101') - >>> try: - >>> oid_der = DerObjectId() - >>> oid_der.decode(s) - >>> print oid_der.value - >>> except ValueError: - >>> print "Not a valid DER OBJECT ID" - - the output will be ``1.2.840.113549.1.1.1``. - - :ivar value: The Object ID (OID), a dot separated list of integers - :vartype value: string - """ - - def __init__(self, value='', implicit=None, explicit=None): - """Initialize the DER object as an OBJECT ID. - - :Parameters: - value : string - The initial Object Identifier (e.g. "1.2.0.0.6.2"). - implicit : integer - The IMPLICIT tag to use for the encoded object. - It overrides the universal tag for OBJECT ID (6). - explicit : integer - The EXPLICIT tag to use for the encoded object. - """ - DerObject.__init__(self, 0x06, b'', implicit, False, explicit) - self.value = value - - def encode(self): - """Return the DER OBJECT ID, fully encoded as a - 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]) - return DerObject.encode(self) - - def decode(self, der_encoded, strict=False): - """Decode a complete DER OBJECT ID, and re-initializes this - object with it. - - Args: - der_encoded (byte string): - A complete DER OBJECT ID. - strict (boolean): - Whether decoding must check for strict DER compliancy. - - Raises: - ValueError: in case of parsing errors. - """ - - return DerObject.decode(self, der_encoded, strict) - - def _decodeFromStream(self, s, strict): - """Decode a complete DER OBJECT ID from a file.""" - - # Fill up self.payload - DerObject._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)] - v = 0 - while p.remaining_data(): - c = p.read_byte() - v = v*128 + (c & 0x7F) - if not (c & 0x80): - comps.append(str(v)) - v = 0 - self.value = '.'.join(comps) - - -class DerBitString(DerObject): - """Class to model a DER BIT STRING. - - An example of encoding is: - - >>> from Crypto.Util.asn1 import DerBitString - >>> from binascii import hexlify, unhexlify - >>> bs_der = DerBitString(b'\\xaa') - >>> bs_der.value += b'\\xbb' - >>> print hexlify(bs_der.encode()) - - which will show ``040300aabb``, the DER encoding for the bit string - ``b'\\xAA\\xBB'``. - - For decoding: - - >>> s = unhexlify(b'040300aabb') - >>> try: - >>> bs_der = DerBitString() - >>> bs_der.decode(s) - >>> print hexlify(bs_der.value) - >>> except ValueError: - >>> print "Not a valid DER BIT STRING" - - the output will be ``aabb``. - - :ivar value: The content of the string - :vartype value: byte string - """ - - def __init__(self, value=b'', implicit=None, explicit=None): - """Initialize the DER object as a BIT STRING. - - :Parameters: - value : byte string or DER object - The initial, packed bit string. - If not specified, the bit string is empty. - implicit : integer - The IMPLICIT tag to use for the encoded object. - It overrides the universal tag for OCTET STRING (3). - explicit : integer - The EXPLICIT tag to use for the encoded object. - """ - DerObject.__init__(self, 0x03, b'', implicit, False, explicit) - - # The bitstring value (packed) - if isinstance(value, DerObject): - self.value = value.encode() - else: - self.value = value - - def encode(self): - """Return the DER BIT STRING, fully encoded as a - binary string.""" - - # Add padding count byte - self.payload = b'\x00' + self.value - return DerObject.encode(self) - - def decode(self, der_encoded, strict=False): - """Decode a complete DER BIT STRING, and re-initializes this - object with it. - - Args: - der_encoded (byte string): a complete DER BIT STRING. - strict (boolean): - Whether decoding must check for strict DER compliancy. - - Raises: - ValueError: in case of parsing errors. - """ - - return DerObject.decode(self, der_encoded, strict) - - def _decodeFromStream(self, s, strict): - """Decode a complete DER BIT STRING DER from a file.""" - - # Fill-up self.payload - DerObject._decodeFromStream(self, s, strict) - - if self.payload and bord(self.payload[0]) != 0: - raise ValueError("Not a valid BIT STRING") - - # Fill-up self.value - self.value = b'' - # Remove padding count byte - if self.payload: - self.value = self.payload[1:] - - -class DerSetOf(DerObject): - """Class to model a DER SET OF. - - An example of encoding is: - - >>> from Crypto.Util.asn1 import DerBitString - >>> from binascii import hexlify, unhexlify - >>> so_der = DerSetOf([4,5]) - >>> so_der.add(6) - >>> print hexlify(so_der.encode()) - - which will show ``3109020104020105020106``, the DER encoding - of a SET OF with items 4,5, and 6. - - For decoding: - - >>> s = unhexlify(b'3109020104020105020106') - >>> try: - >>> so_der = DerSetOf() - >>> so_der.decode(s) - >>> print [x for x in so_der] - >>> except ValueError: - >>> print "Not a valid DER SET OF" - - the output will be ``[4, 5, 6]``. - """ - - def __init__(self, startSet=None, implicit=None): - """Initialize the DER object as a SET OF. - - :Parameters: - startSet : container - The initial set of integers or DER encoded objects. - implicit : integer - The IMPLICIT tag to use for the encoded object. - It overrides the universal tag for SET OF (17). - """ - DerObject.__init__(self, 0x11, b'', implicit, True) - self._seq = [] - - # All elements must be of the same type (and therefore have the - # same leading octet) - self._elemOctet = None - - if startSet: - for e in startSet: - self.add(e) - - def __getitem__(self, n): - return self._seq[n] - - def __iter__(self): - return iter(self._seq) - - def __len__(self): - return len(self._seq) - - def add(self, elem): - """Add an element to the set. - - Args: - elem (byte string or integer): - An element of the same type of objects already in the set. - It can be an integer or a DER encoded object. - """ - - if _is_number(elem): - eo = 0x02 - elif isinstance(elem, DerObject): - eo = self._tag_octet - else: - eo = bord(elem[0]) - - if self._elemOctet != eo: - if self._elemOctet is not None: - raise ValueError("New element does not belong to the set") - self._elemOctet = eo - - if elem not in self._seq: - self._seq.append(elem) - - def decode(self, der_encoded, strict=False): - """Decode a complete SET OF DER element, and re-initializes this - object with it. - - DER INTEGERs are decoded into Python integers. Any other DER - element is left undecoded; its validity is not checked. - - Args: - der_encoded (byte string): a complete DER BIT SET OF. - strict (boolean): - Whether decoding must check for strict DER compliancy. - - Raises: - ValueError: in case of parsing errors. - """ - - return DerObject.decode(self, der_encoded, strict) - - def _decodeFromStream(self, s, strict): - """Decode a complete DER SET OF from a file.""" - - self._seq = [] - - # Fill up self.payload - DerObject._decodeFromStream(self, s, strict) - - # Add one item at a time to self.seq, by scanning self.payload - p = BytesIO_EOF(self.payload) - setIdOctet = -1 - while p.remaining_data() > 0: - p.set_bookmark() - - der = DerObject() - der._decodeFromStream(p, strict) - - # Verify that all members are of the same type - if setIdOctet < 0: - setIdOctet = der._tag_octet - else: - if setIdOctet != der._tag_octet: - raise ValueError("Not all elements are of the same DER type") - - # Parse INTEGERs differently - if setIdOctet != 0x02: - self._seq.append(p.data_since_bookmark()) - else: - derInt = DerInteger() - derInt.decode(p.data_since_bookmark(), strict) - self._seq.append(derInt.value) - # end - - def encode(self): - """Return this SET OF DER element, fully encoded as a - binary string. - """ - - # Elements in the set must be ordered in lexicographic order - ordered = [] - for item in self._seq: - if _is_number(item): - bys = DerInteger(item).encode() - elif isinstance(item, DerObject): - bys = item.encode() - else: - bys = item - ordered.append(bys) - ordered.sort() - self.payload = b''.join(ordered) - return DerObject.encode(self) diff --git a/Crypto/Util/asn1.pyi b/Crypto/Util/asn1.pyi deleted file mode 100644 index dac023b..0000000 --- a/Crypto/Util/asn1.pyi +++ /dev/null @@ -1,74 +0,0 @@ -from typing import Optional, Sequence, Union, Set, Iterable - -__all__ = ['DerObject', 'DerInteger', 'DerOctetString', 'DerNull', - 'DerSequence', 'DerObjectId', 'DerBitString', 'DerSetOf'] - -# TODO: Make the encoded DerObjects their own type, so that DerSequence and -# DerSetOf can check their contents better - -class BytesIO_EOF: - def __init__(self, initial_bytes: bytes) -> None: ... - def set_bookmark(self) -> None: ... - def data_since_bookmark(self) -> bytes: ... - def remaining_data(self) -> int: ... - def read(self, length: int) -> bytes: ... - def read_byte(self) -> bytes: ... - -class DerObject: - payload: bytes - def __init__(self, asn1Id: Optional[int]=None, payload: Optional[bytes]=..., implicit: Optional[int]=None, - constructed: Optional[bool]=False, explicit: Optional[int]=None) -> None: ... - def encode(self) -> bytes: ... - def decode(self, der_encoded: bytes, strict: Optional[bool]=False) -> DerObject: ... - -class DerInteger(DerObject): - value: int - def __init__(self, value: Optional[int]= 0, implicit: Optional[int]=None, explicit: Optional[int]=None) -> None: ... - def encode(self) -> bytes: ... - def decode(self, der_encoded: bytes, strict: Optional[bool]=False) -> DerInteger: ... - -class DerSequence(DerObject): - def __init__(self, startSeq: Optional[Sequence[Union[int, DerInteger, DerObject]]]=None, implicit: Optional[int]=None) -> None: ... - def __delitem__(self, n: int) -> None: ... - def __getitem__(self, n: int) -> None: ... - def __setitem__(self, key: int, value: DerObject) -> None: ... - def __setslice__(self, i: int, j: int, sequence: Sequence) -> None: ... - def __delslice__(self, i: int, j: int) -> None: ... - def __getslice__(self, i: int, j: int) -> DerSequence: ... - def __len__(self) -> int: ... - def __iadd__(self, item: DerObject) -> DerSequence: ... - def append(self, item: DerObject) -> DerSequence: ... - def hasInts(self, only_non_negative: Optional[bool]=True) -> int: ... - def hasOnlyInts(self, only_non_negative: Optional[bool]=True) -> bool: ... - def encode(self) -> bytes: ... - def decode(self, der_encoded: bytes, strict: Optional[bool]=False, nr_elements: Optional[int]=None, only_ints_expected: Optional[bool]=False) -> DerSequence: ... - -class DerOctetString(DerObject): - payload: bytes - def __init__(self, value: Optional[bytes]=..., implicit: Optional[int]=None) -> None: ... - -class DerNull(DerObject): - def __init__(self) -> None: ... - -class DerObjectId(DerObject): - value: str - def __init__(self, value: Optional[str]=..., implicit: Optional[int]=None, explicit: Optional[int]=None) -> None: ... - def encode(self) -> bytes: ... - def decode(self, der_encoded: bytes, strict: Optional[bool]=False) -> DerObjectId: ... - -class DerBitString(DerObject): - value: bytes - def __init__(self, value: Optional[bytes]=..., implicit: Optional[int]=None, explicit: Optional[int]=None) -> None: ... - def encode(self) -> bytes: ... - def decode(self, der_encoded: bytes, strict: Optional[bool]=False) -> DerBitString: ... - -DerSetElement = Union[bytes, int] - -class DerSetOf(DerObject): - def __init__(self, startSet: Optional[Set[DerSetElement]]=None, implicit: Optional[int]=None) -> None: ... - def __getitem__(self, n: int) -> DerSetElement: ... - def __iter__(self) -> Iterable: ... - def __len__(self) -> int: ... - def add(self, elem: DerSetElement) -> None: ... - def decode(self, der_encoded: bytes, strict: Optional[bool]=False) -> DerObject: ... - def encode(self) -> bytes: ... diff --git a/Crypto/Util/number.py b/Crypto/Util/number.py deleted file mode 100644 index 56df021..0000000 --- a/Crypto/Util/number.py +++ /dev/null @@ -1,1469 +0,0 @@ -# -# number.py : Number-theoretic functions -# -# Part of the Python Cryptography Toolkit -# -# Written by Andrew M. Kuchling, Barry A. Warsaw, and others -# -# =================================================================== -# The contents of this file are dedicated to the public domain. To -# the extent that dedication to the public domain is not available, -# everyone is granted a worldwide, perpetual, royalty-free, -# non-exclusive license to exercise all rights associated with the -# contents of this file for any purpose whatsoever. -# No rights are reserved. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS -# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN -# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# =================================================================== -# - -import math -import sys -import struct -from Crypto import Random -from Crypto.Util.py3compat import iter_range - -# Backward compatibility -_fastmath = None - - -def ceil_div(n, d): - """Return ceil(n/d), that is, the smallest integer r such that r*d >= n""" - - if d == 0: - raise ZeroDivisionError() - if (n < 0) or (d < 0): - raise ValueError("Non positive values") - r, q = divmod(n, d) - if (n != 0) and (q != 0): - r += 1 - return r - - -def size (N): - """Returns the size of the number N in bits.""" - - if N < 0: - raise ValueError("Size in bits only avialable for non-negative numbers") - - bits = 0 - while N >> bits: - bits += 1 - return bits - - -def getRandomInteger(N, randfunc=None): - """Return a random number at most N bits long. - - If :data:`randfunc` is omitted, then :meth:`Random.get_random_bytes` is used. - - .. deprecated:: 3.0 - This function is for internal use only and may be renamed or removed in - the future. Use :func:`Crypto.Random.random.getrandbits` instead. - """ - - if randfunc is None: - randfunc = Random.get_random_bytes - - S = randfunc(N>>3) - odd_bits = N % 8 - if odd_bits != 0: - rand_bits = ord(randfunc(1)) >> (8-odd_bits) - S = struct.pack('B', rand_bits) + S - value = bytes_to_long(S) - return value - -def getRandomRange(a, b, randfunc=None): - """Return a random number *n* so that *a <= n < b*. - - If :data:`randfunc` is omitted, then :meth:`Random.get_random_bytes` is used. - - .. deprecated:: 3.0 - This function is for internal use only and may be renamed or removed in - the future. Use :func:`Crypto.Random.random.randrange` instead. - """ - - range_ = b - a - 1 - bits = size(range_) - value = getRandomInteger(bits, randfunc) - while value > range_: - value = getRandomInteger(bits, randfunc) - return a + value - -def getRandomNBitInteger(N, randfunc=None): - """Return a random number with exactly N-bits, - i.e. a random number between 2**(N-1) and (2**N)-1. - - If :data:`randfunc` is omitted, then :meth:`Random.get_random_bytes` is used. - - .. deprecated:: 3.0 - This function is for internal use only and may be renamed or removed in - the future. - """ - - value = getRandomInteger (N-1, randfunc) - value |= 2 ** (N-1) # Ensure high bit is set - assert size(value) >= N - return value - -def GCD(x,y): - """Greatest Common Denominator of :data:`x` and :data:`y`. - """ - - x = abs(x) ; y = abs(y) - while x > 0: - x, y = y % x, x - return y - -def inverse(u, v): - """The inverse of :data:`u` *mod* :data:`v`.""" - - u3, v3 = u, v - u1, v1 = 1, 0 - while v3 > 0: - q = u3 // v3 - u1, v1 = v1, u1 - v1*q - u3, v3 = v3, u3 - v3*q - while u1<0: - u1 = u1 + v - return u1 - -# Given a number of bits to generate and a random generation function, -# find a prime number of the appropriate size. - -def getPrime(N, randfunc=None): - """Return a random N-bit prime number. - - If randfunc is omitted, then :meth:`Random.get_random_bytes` is used. - """ - if randfunc is None: - randfunc = Random.get_random_bytes - - number=getRandomNBitInteger(N, randfunc) | 1 - while (not isPrime(number, randfunc=randfunc)): - number=number+2 - return number - - -def _rabinMillerTest(n, rounds, randfunc=None): - """_rabinMillerTest(n:long, rounds:int, randfunc:callable):int - Tests if n is prime. - Returns 0 when n is definitely composite. - Returns 1 when n is probably prime. - Returns 2 when n is definitely prime. - - If randfunc is omitted, then Random.new().read is used. - - This function is for internal use only and may be renamed or removed in - the future. - """ - # check special cases (n==2, n even, n < 2) - if n < 3 or (n & 1) == 0: - return n == 2 - # n might be very large so it might be beneficial to precalculate n-1 - n_1 = n - 1 - # determine m and b so that 2**b * m = n - 1 and b maximal - b = 0 - m = n_1 - while (m & 1) == 0: - b += 1 - m >>= 1 - - tested = [] - # we need to do at most n-2 rounds. - for i in iter_range (min (rounds, n-2)): - # randomly choose a < n and make sure it hasn't been tested yet - a = getRandomRange (2, n, randfunc) - while a in tested: - a = getRandomRange (2, n, randfunc) - tested.append (a) - # do the rabin-miller test - z = pow (a, m, n) # (a**m) % n - if z == 1 or z == n_1: - continue - composite = 1 - for r in iter_range(b): - z = (z * z) % n - if z == 1: - return 0 - elif z == n_1: - composite = 0 - break - if composite: - return 0 - return 1 - -def getStrongPrime(N, e=0, false_positive_prob=1e-6, randfunc=None): - r""" - Return a random strong *N*-bit prime number. - In this context, *p* is a strong prime if *p-1* and *p+1* have at - least one large prime factor. - - Args: - N (integer): the exact length of the strong prime. - It must be a multiple of 128 and > 512. - e (integer): if provided, the returned prime (minus 1) - will be coprime to *e* and thus suitable for RSA where - *e* is the public exponent. - false_positive_prob (float): - The statistical probability for the result not to be actually a - prime. It defaults to 10\ :sup:`-6`. - Note that the real probability of a false-positive is far less. This is - just the mathematically provable limit. - randfunc (callable): - A function that takes a parameter *N* and that returns - a random byte string of such length. - If omitted, :func:`Crypto.Random.get_random_bytes` is used. - Return: - The new strong prime. - - .. deprecated:: 3.0 - This function is for internal use only and may be renamed or removed in - the future. - """ - - # This function was implemented following the - # instructions found in the paper: - # "FAST GENERATION OF RANDOM, STRONG RSA PRIMES" - # by Robert D. Silverman - # RSA Laboratories - # May 17, 1997 - # which by the time of writing could be freely downloaded here: - # http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.17.2713&rep=rep1&type=pdf - - if randfunc is None: - randfunc = Random.get_random_bytes - - # Use the accelerator if available - if _fastmath is not None: - return _fastmath.getStrongPrime(long(N), long(e), false_positive_prob, - randfunc) - - if (N < 512) or ((N % 128) != 0): - raise ValueError ("bits must be multiple of 128 and > 512") - - rabin_miller_rounds = int(math.ceil(-math.log(false_positive_prob)/math.log(4))) - - # calculate range for X - # lower_bound = sqrt(2) * 2^{511 + 128*x} - # upper_bound = 2^{512 + 128*x} - 1 - x = (N - 512) >> 7; - # We need to approximate the sqrt(2) in the lower_bound by an integer - # expression because floating point math overflows with these numbers - lower_bound = (14142135623730950489 * (2 ** (511 + 128*x))) // 10000000000000000000 - upper_bound = (1 << (512 + 128*x)) - 1 - # Randomly choose X in calculated range - X = getRandomRange (lower_bound, upper_bound, randfunc) - - # generate p1 and p2 - p = [0, 0] - for i in (0, 1): - # randomly choose 101-bit y - y = getRandomNBitInteger (101, randfunc) - # initialize the field for sieving - field = [0] * 5 * len (sieve_base) - # sieve the field - for prime in sieve_base: - offset = y % prime - for j in iter_range((prime - offset) % prime, len (field), prime): - field[j] = 1 - - # look for suitable p[i] starting at y - result = 0 - for j in range(len(field)): - composite = field[j] - # look for next canidate - if composite: - continue - tmp = y + j - result = _rabinMillerTest (tmp, rabin_miller_rounds) - if result > 0: - p[i] = tmp - break - if result == 0: - raise RuntimeError ("Couln't find prime in field. " - "Developer: Increase field_size") - - # Calculate R - # R = (p2^{-1} mod p1) * p2 - (p1^{-1} mod p2) * p1 - tmp1 = inverse (p[1], p[0]) * p[1] # (p2^-1 mod p1)*p2 - tmp2 = inverse (p[0], p[1]) * p[0] # (p1^-1 mod p2)*p1 - R = tmp1 - tmp2 # (p2^-1 mod p1)*p2 - (p1^-1 mod p2)*p1 - - # search for final prime number starting by Y0 - # Y0 = X + (R - X mod p1p2) - increment = p[0] * p[1] - X = X + (R - (X % increment)) - while 1: - is_possible_prime = 1 - # first check candidate against sieve_base - for prime in sieve_base: - if (X % prime) == 0: - is_possible_prime = 0 - break - # if e is given make sure that e and X-1 are coprime - # this is not necessarily a strong prime criterion but useful when - # creating them for RSA where the p-1 and q-1 should be coprime to - # the public exponent e - if e and is_possible_prime: - if e & 1: - if GCD(e, X-1) != 1: - is_possible_prime = 0 - else: - if GCD(e, (X-1) // 2) != 1: - is_possible_prime = 0 - - # do some Rabin-Miller-Tests - if is_possible_prime: - result = _rabinMillerTest (X, rabin_miller_rounds) - if result > 0: - break - X += increment - # abort when X has more bits than requested - # TODO: maybe we shouldn't abort but rather start over. - if X >= 1 << N: - raise RuntimeError ("Couln't find prime in field. " - "Developer: Increase field_size") - return X - -def isPrime(N, false_positive_prob=1e-6, randfunc=None): - r"""Test if a number *N* is a prime. - - Args: - false_positive_prob (float): - The statistical probability for the result not to be actually a - prime. It defaults to 10\ :sup:`-6`. - Note that the real probability of a false-positive is far less. - This is just the mathematically provable limit. - randfunc (callable): - A function that takes a parameter *N* and that returns - a random byte string of such length. - If omitted, :func:`Crypto.Random.get_random_bytes` is used. - - Return: - `True` is the input is indeed prime. - """ - - if randfunc is None: - randfunc = Random.get_random_bytes - - if _fastmath is not None: - return _fastmath.isPrime(long(N), false_positive_prob, randfunc) - - if N < 3 or N & 1 == 0: - return N == 2 - for p in sieve_base: - if N == p: - return 1 - if N % p == 0: - return 0 - - rounds = int(math.ceil(-math.log(false_positive_prob)/math.log(4))) - return _rabinMillerTest(N, rounds, randfunc) - - -# Improved conversion functions contributed by Barry Warsaw, after -# careful benchmarking - -import struct - -def long_to_bytes(n, blocksize=0): - """Convert an integer to a byte string. - - In Python 3.2+, use the native method instead:: - - >>> n.to_bytes(blocksize, 'big') - - For instance:: - - >>> n = 80 - >>> n.to_bytes(2, 'big') - b'\x00P' - - If the optional :data:`blocksize` is provided and greater than zero, - the byte string is padded with binary zeros (on the front) so that - the total length of the output is a multiple of blocksize. - - If :data:`blocksize` is zero or not provided, the byte string will - be of minimal length. - """ - # after much testing, this algorithm was deemed to be the fastest - s = b'' - n = int(n) - pack = struct.pack - while n > 0: - s = pack('>I', n & 0xffffffff) + s - n = n >> 32 - # strip off leading zeros - for i in range(len(s)): - if s[i] != b'\x00'[0]: - break - else: - # only happens when n == 0 - s = b'\x00' - i = 0 - s = s[i:] - # add back some pad bytes. this could be done more efficiently w.r.t. the - # de-padding being done above, but sigh... - if blocksize > 0 and len(s) % blocksize: - s = (blocksize - len(s) % blocksize) * b'\x00' + s - return s - -def bytes_to_long(s): - """Convert a byte string to a long integer (big endian). - - In Python 3.2+, use the native method instead:: - - >>> int.from_bytes(s, 'big') - - For instance:: - - >>> int.from_bytes(b'\x00P', 'big') - 80 - - This is (essentially) the inverse of :func:`long_to_bytes`. - """ - acc = 0 - - unpack = struct.unpack - - # Up to Python 2.7.4, struct.unpack can't work with bytearrays nor - # memoryviews - if sys.version_info[0:3] < (2, 7, 4): - if isinstance(s, bytearray): - s = bytes(s) - elif isinstance(s, memoryview): - s = s.tobytes() - - length = len(s) - if length % 4: - extra = (4 - length % 4) - s = b'\x00' * extra + s - length = length + extra - for i in range(0, length, 4): - acc = (acc << 32) + unpack('>I', s[i:i+4])[0] - return acc - - -# For backwards compatibility... -import warnings -def long2str(n, blocksize=0): - warnings.warn("long2str() has been replaced by long_to_bytes()") - return long_to_bytes(n, blocksize) -def str2long(s): - warnings.warn("str2long() has been replaced by bytes_to_long()") - return bytes_to_long(s) - - -# The first 10000 primes used for checking primality. -# This should be enough to eliminate most of the odd -# numbers before needing to do a Rabin-Miller test at all. -sieve_base = ( - 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, - 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, - 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, - 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, - 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, - 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, - 283, 293, 307, 311, 313, 317, 331, 337, 347, 349, - 353, 359, 367, 373, 379, 383, 389, 397, 401, 409, - 419, 421, 431, 433, 439, 443, 449, 457, 461, 463, - 467, 479, 487, 491, 499, 503, 509, 521, 523, 541, - 547, 557, 563, 569, 571, 577, 587, 593, 599, 601, - 607, 613, 617, 619, 631, 641, 643, 647, 653, 659, - 661, 673, 677, 683, 691, 701, 709, 719, 727, 733, - 739, 743, 751, 757, 761, 769, 773, 787, 797, 809, - 811, 821, 823, 827, 829, 839, 853, 857, 859, 863, - 877, 881, 883, 887, 907, 911, 919, 929, 937, 941, - 947, 953, 967, 971, 977, 983, 991, 997, 1009, 1013, - 1019, 1021, 1031, 1033, 1039, 1049, 1051, 1061, 1063, 1069, - 1087, 1091, 1093, 1097, 1103, 1109, 1117, 1123, 1129, 1151, - 1153, 1163, 1171, 1181, 1187, 1193, 1201, 1213, 1217, 1223, - 1229, 1231, 1237, 1249, 1259, 1277, 1279, 1283, 1289, 1291, - 1297, 1301, 1303, 1307, 1319, 1321, 1327, 1361, 1367, 1373, - 1381, 1399, 1409, 1423, 1427, 1429, 1433, 1439, 1447, 1451, - 1453, 1459, 1471, 1481, 1483, 1487, 1489, 1493, 1499, 1511, - 1523, 1531, 1543, 1549, 1553, 1559, 1567, 1571, 1579, 1583, - 1597, 1601, 1607, 1609, 1613, 1619, 1621, 1627, 1637, 1657, - 1663, 1667, 1669, 1693, 1697, 1699, 1709, 1721, 1723, 1733, - 1741, 1747, 1753, 1759, 1777, 1783, 1787, 1789, 1801, 1811, - 1823, 1831, 1847, 1861, 1867, 1871, 1873, 1877, 1879, 1889, - 1901, 1907, 1913, 1931, 1933, 1949, 1951, 1973, 1979, 1987, - 1993, 1997, 1999, 2003, 2011, 2017, 2027, 2029, 2039, 2053, - 2063, 2069, 2081, 2083, 2087, 2089, 2099, 2111, 2113, 2129, - 2131, 2137, 2141, 2143, 2153, 2161, 2179, 2203, 2207, 2213, - 2221, 2237, 2239, 2243, 2251, 2267, 2269, 2273, 2281, 2287, - 2293, 2297, 2309, 2311, 2333, 2339, 2341, 2347, 2351, 2357, - 2371, 2377, 2381, 2383, 2389, 2393, 2399, 2411, 2417, 2423, - 2437, 2441, 2447, 2459, 2467, 2473, 2477, 2503, 2521, 2531, - 2539, 2543, 2549, 2551, 2557, 2579, 2591, 2593, 2609, 2617, - 2621, 2633, 2647, 2657, 2659, 2663, 2671, 2677, 2683, 2687, - 2689, 2693, 2699, 2707, 2711, 2713, 2719, 2729, 2731, 2741, - 2749, 2753, 2767, 2777, 2789, 2791, 2797, 2801, 2803, 2819, - 2833, 2837, 2843, 2851, 2857, 2861, 2879, 2887, 2897, 2903, - 2909, 2917, 2927, 2939, 2953, 2957, 2963, 2969, 2971, 2999, - 3001, 3011, 3019, 3023, 3037, 3041, 3049, 3061, 3067, 3079, - 3083, 3089, 3109, 3119, 3121, 3137, 3163, 3167, 3169, 3181, - 3187, 3191, 3203, 3209, 3217, 3221, 3229, 3251, 3253, 3257, - 3259, 3271, 3299, 3301, 3307, 3313, 3319, 3323, 3329, 3331, - 3343, 3347, 3359, 3361, 3371, 3373, 3389, 3391, 3407, 3413, - 3433, 3449, 3457, 3461, 3463, 3467, 3469, 3491, 3499, 3511, - 3517, 3527, 3529, 3533, 3539, 3541, 3547, 3557, 3559, 3571, - 3581, 3583, 3593, 3607, 3613, 3617, 3623, 3631, 3637, 3643, - 3659, 3671, 3673, 3677, 3691, 3697, 3701, 3709, 3719, 3727, - 3733, 3739, 3761, 3767, 3769, 3779, 3793, 3797, 3803, 3821, - 3823, 3833, 3847, 3851, 3853, 3863, 3877, 3881, 3889, 3907, - 3911, 3917, 3919, 3923, 3929, 3931, 3943, 3947, 3967, 3989, - 4001, 4003, 4007, 4013, 4019, 4021, 4027, 4049, 4051, 4057, - 4073, 4079, 4091, 4093, 4099, 4111, 4127, 4129, 4133, 4139, - 4153, 4157, 4159, 4177, 4201, 4211, 4217, 4219, 4229, 4231, - 4241, 4243, 4253, 4259, 4261, 4271, 4273, 4283, 4289, 4297, - 4327, 4337, 4339, 4349, 4357, 4363, 4373, 4391, 4397, 4409, - 4421, 4423, 4441, 4447, 4451, 4457, 4463, 4481, 4483, 4493, - 4507, 4513, 4517, 4519, 4523, 4547, 4549, 4561, 4567, 4583, - 4591, 4597, 4603, 4621, 4637, 4639, 4643, 4649, 4651, 4657, - 4663, 4673, 4679, 4691, 4703, 4721, 4723, 4729, 4733, 4751, - 4759, 4783, 4787, 4789, 4793, 4799, 4801, 4813, 4817, 4831, - 4861, 4871, 4877, 4889, 4903, 4909, 4919, 4931, 4933, 4937, - 4943, 4951, 4957, 4967, 4969, 4973, 4987, 4993, 4999, 5003, - 5009, 5011, 5021, 5023, 5039, 5051, 5059, 5077, 5081, 5087, - 5099, 5101, 5107, 5113, 5119, 5147, 5153, 5167, 5171, 5179, - 5189, 5197, 5209, 5227, 5231, 5233, 5237, 5261, 5273, 5279, - 5281, 5297, 5303, 5309, 5323, 5333, 5347, 5351, 5381, 5387, - 5393, 5399, 5407, 5413, 5417, 5419, 5431, 5437, 5441, 5443, - 5449, 5471, 5477, 5479, 5483, 5501, 5503, 5507, 5519, 5521, - 5527, 5531, 5557, 5563, 5569, 5573, 5581, 5591, 5623, 5639, - 5641, 5647, 5651, 5653, 5657, 5659, 5669, 5683, 5689, 5693, - 5701, 5711, 5717, 5737, 5741, 5743, 5749, 5779, 5783, 5791, - 5801, 5807, 5813, 5821, 5827, 5839, 5843, 5849, 5851, 5857, - 5861, 5867, 5869, 5879, 5881, 5897, 5903, 5923, 5927, 5939, - 5953, 5981, 5987, 6007, 6011, 6029, 6037, 6043, 6047, 6053, - 6067, 6073, 6079, 6089, 6091, 6101, 6113, 6121, 6131, 6133, - 6143, 6151, 6163, 6173, 6197, 6199, 6203, 6211, 6217, 6221, - 6229, 6247, 6257, 6263, 6269, 6271, 6277, 6287, 6299, 6301, - 6311, 6317, 6323, 6329, 6337, 6343, 6353, 6359, 6361, 6367, - 6373, 6379, 6389, 6397, 6421, 6427, 6449, 6451, 6469, 6473, - 6481, 6491, 6521, 6529, 6547, 6551, 6553, 6563, 6569, 6571, - 6577, 6581, 6599, 6607, 6619, 6637, 6653, 6659, 6661, 6673, - 6679, 6689, 6691, 6701, 6703, 6709, 6719, 6733, 6737, 6761, - 6763, 6779, 6781, 6791, 6793, 6803, 6823, 6827, 6829, 6833, - 6841, 6857, 6863, 6869, 6871, 6883, 6899, 6907, 6911, 6917, - 6947, 6949, 6959, 6961, 6967, 6971, 6977, 6983, 6991, 6997, - 7001, 7013, 7019, 7027, 7039, 7043, 7057, 7069, 7079, 7103, - 7109, 7121, 7127, 7129, 7151, 7159, 7177, 7187, 7193, 7207, - 7211, 7213, 7219, 7229, 7237, 7243, 7247, 7253, 7283, 7297, - 7307, 7309, 7321, 7331, 7333, 7349, 7351, 7369, 7393, 7411, - 7417, 7433, 7451, 7457, 7459, 7477, 7481, 7487, 7489, 7499, - 7507, 7517, 7523, 7529, 7537, 7541, 7547, 7549, 7559, 7561, - 7573, 7577, 7583, 7589, 7591, 7603, 7607, 7621, 7639, 7643, - 7649, 7669, 7673, 7681, 7687, 7691, 7699, 7703, 7717, 7723, - 7727, 7741, 7753, 7757, 7759, 7789, 7793, 7817, 7823, 7829, - 7841, 7853, 7867, 7873, 7877, 7879, 7883, 7901, 7907, 7919, - 7927, 7933, 7937, 7949, 7951, 7963, 7993, 8009, 8011, 8017, - 8039, 8053, 8059, 8069, 8081, 8087, 8089, 8093, 8101, 8111, - 8117, 8123, 8147, 8161, 8167, 8171, 8179, 8191, 8209, 8219, - 8221, 8231, 8233, 8237, 8243, 8263, 8269, 8273, 8287, 8291, - 8293, 8297, 8311, 8317, 8329, 8353, 8363, 8369, 8377, 8387, - 8389, 8419, 8423, 8429, 8431, 8443, 8447, 8461, 8467, 8501, - 8513, 8521, 8527, 8537, 8539, 8543, 8563, 8573, 8581, 8597, - 8599, 8609, 8623, 8627, 8629, 8641, 8647, 8663, 8669, 8677, - 8681, 8689, 8693, 8699, 8707, 8713, 8719, 8731, 8737, 8741, - 8747, 8753, 8761, 8779, 8783, 8803, 8807, 8819, 8821, 8831, - 8837, 8839, 8849, 8861, 8863, 8867, 8887, 8893, 8923, 8929, - 8933, 8941, 8951, 8963, 8969, 8971, 8999, 9001, 9007, 9011, - 9013, 9029, 9041, 9043, 9049, 9059, 9067, 9091, 9103, 9109, - 9127, 9133, 9137, 9151, 9157, 9161, 9173, 9181, 9187, 9199, - 9203, 9209, 9221, 9227, 9239, 9241, 9257, 9277, 9281, 9283, - 9293, 9311, 9319, 9323, 9337, 9341, 9343, 9349, 9371, 9377, - 9391, 9397, 9403, 9413, 9419, 9421, 9431, 9433, 9437, 9439, - 9461, 9463, 9467, 9473, 9479, 9491, 9497, 9511, 9521, 9533, - 9539, 9547, 9551, 9587, 9601, 9613, 9619, 9623, 9629, 9631, - 9643, 9649, 9661, 9677, 9679, 9689, 9697, 9719, 9721, 9733, - 9739, 9743, 9749, 9767, 9769, 9781, 9787, 9791, 9803, 9811, - 9817, 9829, 9833, 9839, 9851, 9857, 9859, 9871, 9883, 9887, - 9901, 9907, 9923, 9929, 9931, 9941, 9949, 9967, 9973, 10007, - 10009, 10037, 10039, 10061, 10067, 10069, 10079, 10091, 10093, 10099, - 10103, 10111, 10133, 10139, 10141, 10151, 10159, 10163, 10169, 10177, - 10181, 10193, 10211, 10223, 10243, 10247, 10253, 10259, 10267, 10271, - 10273, 10289, 10301, 10303, 10313, 10321, 10331, 10333, 10337, 10343, - 10357, 10369, 10391, 10399, 10427, 10429, 10433, 10453, 10457, 10459, - 10463, 10477, 10487, 10499, 10501, 10513, 10529, 10531, 10559, 10567, - 10589, 10597, 10601, 10607, 10613, 10627, 10631, 10639, 10651, 10657, - 10663, 10667, 10687, 10691, 10709, 10711, 10723, 10729, 10733, 10739, - 10753, 10771, 10781, 10789, 10799, 10831, 10837, 10847, 10853, 10859, - 10861, 10867, 10883, 10889, 10891, 10903, 10909, 10937, 10939, 10949, - 10957, 10973, 10979, 10987, 10993, 11003, 11027, 11047, 11057, 11059, - 11069, 11071, 11083, 11087, 11093, 11113, 11117, 11119, 11131, 11149, - 11159, 11161, 11171, 11173, 11177, 11197, 11213, 11239, 11243, 11251, - 11257, 11261, 11273, 11279, 11287, 11299, 11311, 11317, 11321, 11329, - 11351, 11353, 11369, 11383, 11393, 11399, 11411, 11423, 11437, 11443, - 11447, 11467, 11471, 11483, 11489, 11491, 11497, 11503, 11519, 11527, - 11549, 11551, 11579, 11587, 11593, 11597, 11617, 11621, 11633, 11657, - 11677, 11681, 11689, 11699, 11701, 11717, 11719, 11731, 11743, 11777, - 11779, 11783, 11789, 11801, 11807, 11813, 11821, 11827, 11831, 11833, - 11839, 11863, 11867, 11887, 11897, 11903, 11909, 11923, 11927, 11933, - 11939, 11941, 11953, 11959, 11969, 11971, 11981, 11987, 12007, 12011, - 12037, 12041, 12043, 12049, 12071, 12073, 12097, 12101, 12107, 12109, - 12113, 12119, 12143, 12149, 12157, 12161, 12163, 12197, 12203, 12211, - 12227, 12239, 12241, 12251, 12253, 12263, 12269, 12277, 12281, 12289, - 12301, 12323, 12329, 12343, 12347, 12373, 12377, 12379, 12391, 12401, - 12409, 12413, 12421, 12433, 12437, 12451, 12457, 12473, 12479, 12487, - 12491, 12497, 12503, 12511, 12517, 12527, 12539, 12541, 12547, 12553, - 12569, 12577, 12583, 12589, 12601, 12611, 12613, 12619, 12637, 12641, - 12647, 12653, 12659, 12671, 12689, 12697, 12703, 12713, 12721, 12739, - 12743, 12757, 12763, 12781, 12791, 12799, 12809, 12821, 12823, 12829, - 12841, 12853, 12889, 12893, 12899, 12907, 12911, 12917, 12919, 12923, - 12941, 12953, 12959, 12967, 12973, 12979, 12983, 13001, 13003, 13007, - 13009, 13033, 13037, 13043, 13049, 13063, 13093, 13099, 13103, 13109, - 13121, 13127, 13147, 13151, 13159, 13163, 13171, 13177, 13183, 13187, - 13217, 13219, 13229, 13241, 13249, 13259, 13267, 13291, 13297, 13309, - 13313, 13327, 13331, 13337, 13339, 13367, 13381, 13397, 13399, 13411, - 13417, 13421, 13441, 13451, 13457, 13463, 13469, 13477, 13487, 13499, - 13513, 13523, 13537, 13553, 13567, 13577, 13591, 13597, 13613, 13619, - 13627, 13633, 13649, 13669, 13679, 13681, 13687, 13691, 13693, 13697, - 13709, 13711, 13721, 13723, 13729, 13751, 13757, 13759, 13763, 13781, - 13789, 13799, 13807, 13829, 13831, 13841, 13859, 13873, 13877, 13879, - 13883, 13901, 13903, 13907, 13913, 13921, 13931, 13933, 13963, 13967, - 13997, 13999, 14009, 14011, 14029, 14033, 14051, 14057, 14071, 14081, - 14083, 14087, 14107, 14143, 14149, 14153, 14159, 14173, 14177, 14197, - 14207, 14221, 14243, 14249, 14251, 14281, 14293, 14303, 14321, 14323, - 14327, 14341, 14347, 14369, 14387, 14389, 14401, 14407, 14411, 14419, - 14423, 14431, 14437, 14447, 14449, 14461, 14479, 14489, 14503, 14519, - 14533, 14537, 14543, 14549, 14551, 14557, 14561, 14563, 14591, 14593, - 14621, 14627, 14629, 14633, 14639, 14653, 14657, 14669, 14683, 14699, - 14713, 14717, 14723, 14731, 14737, 14741, 14747, 14753, 14759, 14767, - 14771, 14779, 14783, 14797, 14813, 14821, 14827, 14831, 14843, 14851, - 14867, 14869, 14879, 14887, 14891, 14897, 14923, 14929, 14939, 14947, - 14951, 14957, 14969, 14983, 15013, 15017, 15031, 15053, 15061, 15073, - 15077, 15083, 15091, 15101, 15107, 15121, 15131, 15137, 15139, 15149, - 15161, 15173, 15187, 15193, 15199, 15217, 15227, 15233, 15241, 15259, - 15263, 15269, 15271, 15277, 15287, 15289, 15299, 15307, 15313, 15319, - 15329, 15331, 15349, 15359, 15361, 15373, 15377, 15383, 15391, 15401, - 15413, 15427, 15439, 15443, 15451, 15461, 15467, 15473, 15493, 15497, - 15511, 15527, 15541, 15551, 15559, 15569, 15581, 15583, 15601, 15607, - 15619, 15629, 15641, 15643, 15647, 15649, 15661, 15667, 15671, 15679, - 15683, 15727, 15731, 15733, 15737, 15739, 15749, 15761, 15767, 15773, - 15787, 15791, 15797, 15803, 15809, 15817, 15823, 15859, 15877, 15881, - 15887, 15889, 15901, 15907, 15913, 15919, 15923, 15937, 15959, 15971, - 15973, 15991, 16001, 16007, 16033, 16057, 16061, 16063, 16067, 16069, - 16073, 16087, 16091, 16097, 16103, 16111, 16127, 16139, 16141, 16183, - 16187, 16189, 16193, 16217, 16223, 16229, 16231, 16249, 16253, 16267, - 16273, 16301, 16319, 16333, 16339, 16349, 16361, 16363, 16369, 16381, - 16411, 16417, 16421, 16427, 16433, 16447, 16451, 16453, 16477, 16481, - 16487, 16493, 16519, 16529, 16547, 16553, 16561, 16567, 16573, 16603, - 16607, 16619, 16631, 16633, 16649, 16651, 16657, 16661, 16673, 16691, - 16693, 16699, 16703, 16729, 16741, 16747, 16759, 16763, 16787, 16811, - 16823, 16829, 16831, 16843, 16871, 16879, 16883, 16889, 16901, 16903, - 16921, 16927, 16931, 16937, 16943, 16963, 16979, 16981, 16987, 16993, - 17011, 17021, 17027, 17029, 17033, 17041, 17047, 17053, 17077, 17093, - 17099, 17107, 17117, 17123, 17137, 17159, 17167, 17183, 17189, 17191, - 17203, 17207, 17209, 17231, 17239, 17257, 17291, 17293, 17299, 17317, - 17321, 17327, 17333, 17341, 17351, 17359, 17377, 17383, 17387, 17389, - 17393, 17401, 17417, 17419, 17431, 17443, 17449, 17467, 17471, 17477, - 17483, 17489, 17491, 17497, 17509, 17519, 17539, 17551, 17569, 17573, - 17579, 17581, 17597, 17599, 17609, 17623, 17627, 17657, 17659, 17669, - 17681, 17683, 17707, 17713, 17729, 17737, 17747, 17749, 17761, 17783, - 17789, 17791, 17807, 17827, 17837, 17839, 17851, 17863, 17881, 17891, - 17903, 17909, 17911, 17921, 17923, 17929, 17939, 17957, 17959, 17971, - 17977, 17981, 17987, 17989, 18013, 18041, 18043, 18047, 18049, 18059, - 18061, 18077, 18089, 18097, 18119, 18121, 18127, 18131, 18133, 18143, - 18149, 18169, 18181, 18191, 18199, 18211, 18217, 18223, 18229, 18233, - 18251, 18253, 18257, 18269, 18287, 18289, 18301, 18307, 18311, 18313, - 18329, 18341, 18353, 18367, 18371, 18379, 18397, 18401, 18413, 18427, - 18433, 18439, 18443, 18451, 18457, 18461, 18481, 18493, 18503, 18517, - 18521, 18523, 18539, 18541, 18553, 18583, 18587, 18593, 18617, 18637, - 18661, 18671, 18679, 18691, 18701, 18713, 18719, 18731, 18743, 18749, - 18757, 18773, 18787, 18793, 18797, 18803, 18839, 18859, 18869, 18899, - 18911, 18913, 18917, 18919, 18947, 18959, 18973, 18979, 19001, 19009, - 19013, 19031, 19037, 19051, 19069, 19073, 19079, 19081, 19087, 19121, - 19139, 19141, 19157, 19163, 19181, 19183, 19207, 19211, 19213, 19219, - 19231, 19237, 19249, 19259, 19267, 19273, 19289, 19301, 19309, 19319, - 19333, 19373, 19379, 19381, 19387, 19391, 19403, 19417, 19421, 19423, - 19427, 19429, 19433, 19441, 19447, 19457, 19463, 19469, 19471, 19477, - 19483, 19489, 19501, 19507, 19531, 19541, 19543, 19553, 19559, 19571, - 19577, 19583, 19597, 19603, 19609, 19661, 19681, 19687, 19697, 19699, - 19709, 19717, 19727, 19739, 19751, 19753, 19759, 19763, 19777, 19793, - 19801, 19813, 19819, 19841, 19843, 19853, 19861, 19867, 19889, 19891, - 19913, 19919, 19927, 19937, 19949, 19961, 19963, 19973, 19979, 19991, - 19993, 19997, 20011, 20021, 20023, 20029, 20047, 20051, 20063, 20071, - 20089, 20101, 20107, 20113, 20117, 20123, 20129, 20143, 20147, 20149, - 20161, 20173, 20177, 20183, 20201, 20219, 20231, 20233, 20249, 20261, - 20269, 20287, 20297, 20323, 20327, 20333, 20341, 20347, 20353, 20357, - 20359, 20369, 20389, 20393, 20399, 20407, 20411, 20431, 20441, 20443, - 20477, 20479, 20483, 20507, 20509, 20521, 20533, 20543, 20549, 20551, - 20563, 20593, 20599, 20611, 20627, 20639, 20641, 20663, 20681, 20693, - 20707, 20717, 20719, 20731, 20743, 20747, 20749, 20753, 20759, 20771, - 20773, 20789, 20807, 20809, 20849, 20857, 20873, 20879, 20887, 20897, - 20899, 20903, 20921, 20929, 20939, 20947, 20959, 20963, 20981, 20983, - 21001, 21011, 21013, 21017, 21019, 21023, 21031, 21059, 21061, 21067, - 21089, 21101, 21107, 21121, 21139, 21143, 21149, 21157, 21163, 21169, - 21179, 21187, 21191, 21193, 21211, 21221, 21227, 21247, 21269, 21277, - 21283, 21313, 21317, 21319, 21323, 21341, 21347, 21377, 21379, 21383, - 21391, 21397, 21401, 21407, 21419, 21433, 21467, 21481, 21487, 21491, - 21493, 21499, 21503, 21517, 21521, 21523, 21529, 21557, 21559, 21563, - 21569, 21577, 21587, 21589, 21599, 21601, 21611, 21613, 21617, 21647, - 21649, 21661, 21673, 21683, 21701, 21713, 21727, 21737, 21739, 21751, - 21757, 21767, 21773, 21787, 21799, 21803, 21817, 21821, 21839, 21841, - 21851, 21859, 21863, 21871, 21881, 21893, 21911, 21929, 21937, 21943, - 21961, 21977, 21991, 21997, 22003, 22013, 22027, 22031, 22037, 22039, - 22051, 22063, 22067, 22073, 22079, 22091, 22093, 22109, 22111, 22123, - 22129, 22133, 22147, 22153, 22157, 22159, 22171, 22189, 22193, 22229, - 22247, 22259, 22271, 22273, 22277, 22279, 22283, 22291, 22303, 22307, - 22343, 22349, 22367, 22369, 22381, 22391, 22397, 22409, 22433, 22441, - 22447, 22453, 22469, 22481, 22483, 22501, 22511, 22531, 22541, 22543, - 22549, 22567, 22571, 22573, 22613, 22619, 22621, 22637, 22639, 22643, - 22651, 22669, 22679, 22691, 22697, 22699, 22709, 22717, 22721, 22727, - 22739, 22741, 22751, 22769, 22777, 22783, 22787, 22807, 22811, 22817, - 22853, 22859, 22861, 22871, 22877, 22901, 22907, 22921, 22937, 22943, - 22961, 22963, 22973, 22993, 23003, 23011, 23017, 23021, 23027, 23029, - 23039, 23041, 23053, 23057, 23059, 23063, 23071, 23081, 23087, 23099, - 23117, 23131, 23143, 23159, 23167, 23173, 23189, 23197, 23201, 23203, - 23209, 23227, 23251, 23269, 23279, 23291, 23293, 23297, 23311, 23321, - 23327, 23333, 23339, 23357, 23369, 23371, 23399, 23417, 23431, 23447, - 23459, 23473, 23497, 23509, 23531, 23537, 23539, 23549, 23557, 23561, - 23563, 23567, 23581, 23593, 23599, 23603, 23609, 23623, 23627, 23629, - 23633, 23663, 23669, 23671, 23677, 23687, 23689, 23719, 23741, 23743, - 23747, 23753, 23761, 23767, 23773, 23789, 23801, 23813, 23819, 23827, - 23831, 23833, 23857, 23869, 23873, 23879, 23887, 23893, 23899, 23909, - 23911, 23917, 23929, 23957, 23971, 23977, 23981, 23993, 24001, 24007, - 24019, 24023, 24029, 24043, 24049, 24061, 24071, 24077, 24083, 24091, - 24097, 24103, 24107, 24109, 24113, 24121, 24133, 24137, 24151, 24169, - 24179, 24181, 24197, 24203, 24223, 24229, 24239, 24247, 24251, 24281, - 24317, 24329, 24337, 24359, 24371, 24373, 24379, 24391, 24407, 24413, - 24419, 24421, 24439, 24443, 24469, 24473, 24481, 24499, 24509, 24517, - 24527, 24533, 24547, 24551, 24571, 24593, 24611, 24623, 24631, 24659, - 24671, 24677, 24683, 24691, 24697, 24709, 24733, 24749, 24763, 24767, - 24781, 24793, 24799, 24809, 24821, 24841, 24847, 24851, 24859, 24877, - 24889, 24907, 24917, 24919, 24923, 24943, 24953, 24967, 24971, 24977, - 24979, 24989, 25013, 25031, 25033, 25037, 25057, 25073, 25087, 25097, - 25111, 25117, 25121, 25127, 25147, 25153, 25163, 25169, 25171, 25183, - 25189, 25219, 25229, 25237, 25243, 25247, 25253, 25261, 25301, 25303, - 25307, 25309, 25321, 25339, 25343, 25349, 25357, 25367, 25373, 25391, - 25409, 25411, 25423, 25439, 25447, 25453, 25457, 25463, 25469, 25471, - 25523, 25537, 25541, 25561, 25577, 25579, 25583, 25589, 25601, 25603, - 25609, 25621, 25633, 25639, 25643, 25657, 25667, 25673, 25679, 25693, - 25703, 25717, 25733, 25741, 25747, 25759, 25763, 25771, 25793, 25799, - 25801, 25819, 25841, 25847, 25849, 25867, 25873, 25889, 25903, 25913, - 25919, 25931, 25933, 25939, 25943, 25951, 25969, 25981, 25997, 25999, - 26003, 26017, 26021, 26029, 26041, 26053, 26083, 26099, 26107, 26111, - 26113, 26119, 26141, 26153, 26161, 26171, 26177, 26183, 26189, 26203, - 26209, 26227, 26237, 26249, 26251, 26261, 26263, 26267, 26293, 26297, - 26309, 26317, 26321, 26339, 26347, 26357, 26371, 26387, 26393, 26399, - 26407, 26417, 26423, 26431, 26437, 26449, 26459, 26479, 26489, 26497, - 26501, 26513, 26539, 26557, 26561, 26573, 26591, 26597, 26627, 26633, - 26641, 26647, 26669, 26681, 26683, 26687, 26693, 26699, 26701, 26711, - 26713, 26717, 26723, 26729, 26731, 26737, 26759, 26777, 26783, 26801, - 26813, 26821, 26833, 26839, 26849, 26861, 26863, 26879, 26881, 26891, - 26893, 26903, 26921, 26927, 26947, 26951, 26953, 26959, 26981, 26987, - 26993, 27011, 27017, 27031, 27043, 27059, 27061, 27067, 27073, 27077, - 27091, 27103, 27107, 27109, 27127, 27143, 27179, 27191, 27197, 27211, - 27239, 27241, 27253, 27259, 27271, 27277, 27281, 27283, 27299, 27329, - 27337, 27361, 27367, 27397, 27407, 27409, 27427, 27431, 27437, 27449, - 27457, 27479, 27481, 27487, 27509, 27527, 27529, 27539, 27541, 27551, - 27581, 27583, 27611, 27617, 27631, 27647, 27653, 27673, 27689, 27691, - 27697, 27701, 27733, 27737, 27739, 27743, 27749, 27751, 27763, 27767, - 27773, 27779, 27791, 27793, 27799, 27803, 27809, 27817, 27823, 27827, - 27847, 27851, 27883, 27893, 27901, 27917, 27919, 27941, 27943, 27947, - 27953, 27961, 27967, 27983, 27997, 28001, 28019, 28027, 28031, 28051, - 28057, 28069, 28081, 28087, 28097, 28099, 28109, 28111, 28123, 28151, - 28163, 28181, 28183, 28201, 28211, 28219, 28229, 28277, 28279, 28283, - 28289, 28297, 28307, 28309, 28319, 28349, 28351, 28387, 28393, 28403, - 28409, 28411, 28429, 28433, 28439, 28447, 28463, 28477, 28493, 28499, - 28513, 28517, 28537, 28541, 28547, 28549, 28559, 28571, 28573, 28579, - 28591, 28597, 28603, 28607, 28619, 28621, 28627, 28631, 28643, 28649, - 28657, 28661, 28663, 28669, 28687, 28697, 28703, 28711, 28723, 28729, - 28751, 28753, 28759, 28771, 28789, 28793, 28807, 28813, 28817, 28837, - 28843, 28859, 28867, 28871, 28879, 28901, 28909, 28921, 28927, 28933, - 28949, 28961, 28979, 29009, 29017, 29021, 29023, 29027, 29033, 29059, - 29063, 29077, 29101, 29123, 29129, 29131, 29137, 29147, 29153, 29167, - 29173, 29179, 29191, 29201, 29207, 29209, 29221, 29231, 29243, 29251, - 29269, 29287, 29297, 29303, 29311, 29327, 29333, 29339, 29347, 29363, - 29383, 29387, 29389, 29399, 29401, 29411, 29423, 29429, 29437, 29443, - 29453, 29473, 29483, 29501, 29527, 29531, 29537, 29567, 29569, 29573, - 29581, 29587, 29599, 29611, 29629, 29633, 29641, 29663, 29669, 29671, - 29683, 29717, 29723, 29741, 29753, 29759, 29761, 29789, 29803, 29819, - 29833, 29837, 29851, 29863, 29867, 29873, 29879, 29881, 29917, 29921, - 29927, 29947, 29959, 29983, 29989, 30011, 30013, 30029, 30047, 30059, - 30071, 30089, 30091, 30097, 30103, 30109, 30113, 30119, 30133, 30137, - 30139, 30161, 30169, 30181, 30187, 30197, 30203, 30211, 30223, 30241, - 30253, 30259, 30269, 30271, 30293, 30307, 30313, 30319, 30323, 30341, - 30347, 30367, 30389, 30391, 30403, 30427, 30431, 30449, 30467, 30469, - 30491, 30493, 30497, 30509, 30517, 30529, 30539, 30553, 30557, 30559, - 30577, 30593, 30631, 30637, 30643, 30649, 30661, 30671, 30677, 30689, - 30697, 30703, 30707, 30713, 30727, 30757, 30763, 30773, 30781, 30803, - 30809, 30817, 30829, 30839, 30841, 30851, 30853, 30859, 30869, 30871, - 30881, 30893, 30911, 30931, 30937, 30941, 30949, 30971, 30977, 30983, - 31013, 31019, 31033, 31039, 31051, 31063, 31069, 31079, 31081, 31091, - 31121, 31123, 31139, 31147, 31151, 31153, 31159, 31177, 31181, 31183, - 31189, 31193, 31219, 31223, 31231, 31237, 31247, 31249, 31253, 31259, - 31267, 31271, 31277, 31307, 31319, 31321, 31327, 31333, 31337, 31357, - 31379, 31387, 31391, 31393, 31397, 31469, 31477, 31481, 31489, 31511, - 31513, 31517, 31531, 31541, 31543, 31547, 31567, 31573, 31583, 31601, - 31607, 31627, 31643, 31649, 31657, 31663, 31667, 31687, 31699, 31721, - 31723, 31727, 31729, 31741, 31751, 31769, 31771, 31793, 31799, 31817, - 31847, 31849, 31859, 31873, 31883, 31891, 31907, 31957, 31963, 31973, - 31981, 31991, 32003, 32009, 32027, 32029, 32051, 32057, 32059, 32063, - 32069, 32077, 32083, 32089, 32099, 32117, 32119, 32141, 32143, 32159, - 32173, 32183, 32189, 32191, 32203, 32213, 32233, 32237, 32251, 32257, - 32261, 32297, 32299, 32303, 32309, 32321, 32323, 32327, 32341, 32353, - 32359, 32363, 32369, 32371, 32377, 32381, 32401, 32411, 32413, 32423, - 32429, 32441, 32443, 32467, 32479, 32491, 32497, 32503, 32507, 32531, - 32533, 32537, 32561, 32563, 32569, 32573, 32579, 32587, 32603, 32609, - 32611, 32621, 32633, 32647, 32653, 32687, 32693, 32707, 32713, 32717, - 32719, 32749, 32771, 32779, 32783, 32789, 32797, 32801, 32803, 32831, - 32833, 32839, 32843, 32869, 32887, 32909, 32911, 32917, 32933, 32939, - 32941, 32957, 32969, 32971, 32983, 32987, 32993, 32999, 33013, 33023, - 33029, 33037, 33049, 33053, 33071, 33073, 33083, 33091, 33107, 33113, - 33119, 33149, 33151, 33161, 33179, 33181, 33191, 33199, 33203, 33211, - 33223, 33247, 33287, 33289, 33301, 33311, 33317, 33329, 33331, 33343, - 33347, 33349, 33353, 33359, 33377, 33391, 33403, 33409, 33413, 33427, - 33457, 33461, 33469, 33479, 33487, 33493, 33503, 33521, 33529, 33533, - 33547, 33563, 33569, 33577, 33581, 33587, 33589, 33599, 33601, 33613, - 33617, 33619, 33623, 33629, 33637, 33641, 33647, 33679, 33703, 33713, - 33721, 33739, 33749, 33751, 33757, 33767, 33769, 33773, 33791, 33797, - 33809, 33811, 33827, 33829, 33851, 33857, 33863, 33871, 33889, 33893, - 33911, 33923, 33931, 33937, 33941, 33961, 33967, 33997, 34019, 34031, - 34033, 34039, 34057, 34061, 34123, 34127, 34129, 34141, 34147, 34157, - 34159, 34171, 34183, 34211, 34213, 34217, 34231, 34253, 34259, 34261, - 34267, 34273, 34283, 34297, 34301, 34303, 34313, 34319, 34327, 34337, - 34351, 34361, 34367, 34369, 34381, 34403, 34421, 34429, 34439, 34457, - 34469, 34471, 34483, 34487, 34499, 34501, 34511, 34513, 34519, 34537, - 34543, 34549, 34583, 34589, 34591, 34603, 34607, 34613, 34631, 34649, - 34651, 34667, 34673, 34679, 34687, 34693, 34703, 34721, 34729, 34739, - 34747, 34757, 34759, 34763, 34781, 34807, 34819, 34841, 34843, 34847, - 34849, 34871, 34877, 34883, 34897, 34913, 34919, 34939, 34949, 34961, - 34963, 34981, 35023, 35027, 35051, 35053, 35059, 35069, 35081, 35083, - 35089, 35099, 35107, 35111, 35117, 35129, 35141, 35149, 35153, 35159, - 35171, 35201, 35221, 35227, 35251, 35257, 35267, 35279, 35281, 35291, - 35311, 35317, 35323, 35327, 35339, 35353, 35363, 35381, 35393, 35401, - 35407, 35419, 35423, 35437, 35447, 35449, 35461, 35491, 35507, 35509, - 35521, 35527, 35531, 35533, 35537, 35543, 35569, 35573, 35591, 35593, - 35597, 35603, 35617, 35671, 35677, 35729, 35731, 35747, 35753, 35759, - 35771, 35797, 35801, 35803, 35809, 35831, 35837, 35839, 35851, 35863, - 35869, 35879, 35897, 35899, 35911, 35923, 35933, 35951, 35963, 35969, - 35977, 35983, 35993, 35999, 36007, 36011, 36013, 36017, 36037, 36061, - 36067, 36073, 36083, 36097, 36107, 36109, 36131, 36137, 36151, 36161, - 36187, 36191, 36209, 36217, 36229, 36241, 36251, 36263, 36269, 36277, - 36293, 36299, 36307, 36313, 36319, 36341, 36343, 36353, 36373, 36383, - 36389, 36433, 36451, 36457, 36467, 36469, 36473, 36479, 36493, 36497, - 36523, 36527, 36529, 36541, 36551, 36559, 36563, 36571, 36583, 36587, - 36599, 36607, 36629, 36637, 36643, 36653, 36671, 36677, 36683, 36691, - 36697, 36709, 36713, 36721, 36739, 36749, 36761, 36767, 36779, 36781, - 36787, 36791, 36793, 36809, 36821, 36833, 36847, 36857, 36871, 36877, - 36887, 36899, 36901, 36913, 36919, 36923, 36929, 36931, 36943, 36947, - 36973, 36979, 36997, 37003, 37013, 37019, 37021, 37039, 37049, 37057, - 37061, 37087, 37097, 37117, 37123, 37139, 37159, 37171, 37181, 37189, - 37199, 37201, 37217, 37223, 37243, 37253, 37273, 37277, 37307, 37309, - 37313, 37321, 37337, 37339, 37357, 37361, 37363, 37369, 37379, 37397, - 37409, 37423, 37441, 37447, 37463, 37483, 37489, 37493, 37501, 37507, - 37511, 37517, 37529, 37537, 37547, 37549, 37561, 37567, 37571, 37573, - 37579, 37589, 37591, 37607, 37619, 37633, 37643, 37649, 37657, 37663, - 37691, 37693, 37699, 37717, 37747, 37781, 37783, 37799, 37811, 37813, - 37831, 37847, 37853, 37861, 37871, 37879, 37889, 37897, 37907, 37951, - 37957, 37963, 37967, 37987, 37991, 37993, 37997, 38011, 38039, 38047, - 38053, 38069, 38083, 38113, 38119, 38149, 38153, 38167, 38177, 38183, - 38189, 38197, 38201, 38219, 38231, 38237, 38239, 38261, 38273, 38281, - 38287, 38299, 38303, 38317, 38321, 38327, 38329, 38333, 38351, 38371, - 38377, 38393, 38431, 38447, 38449, 38453, 38459, 38461, 38501, 38543, - 38557, 38561, 38567, 38569, 38593, 38603, 38609, 38611, 38629, 38639, - 38651, 38653, 38669, 38671, 38677, 38693, 38699, 38707, 38711, 38713, - 38723, 38729, 38737, 38747, 38749, 38767, 38783, 38791, 38803, 38821, - 38833, 38839, 38851, 38861, 38867, 38873, 38891, 38903, 38917, 38921, - 38923, 38933, 38953, 38959, 38971, 38977, 38993, 39019, 39023, 39041, - 39043, 39047, 39079, 39089, 39097, 39103, 39107, 39113, 39119, 39133, - 39139, 39157, 39161, 39163, 39181, 39191, 39199, 39209, 39217, 39227, - 39229, 39233, 39239, 39241, 39251, 39293, 39301, 39313, 39317, 39323, - 39341, 39343, 39359, 39367, 39371, 39373, 39383, 39397, 39409, 39419, - 39439, 39443, 39451, 39461, 39499, 39503, 39509, 39511, 39521, 39541, - 39551, 39563, 39569, 39581, 39607, 39619, 39623, 39631, 39659, 39667, - 39671, 39679, 39703, 39709, 39719, 39727, 39733, 39749, 39761, 39769, - 39779, 39791, 39799, 39821, 39827, 39829, 39839, 39841, 39847, 39857, - 39863, 39869, 39877, 39883, 39887, 39901, 39929, 39937, 39953, 39971, - 39979, 39983, 39989, 40009, 40013, 40031, 40037, 40039, 40063, 40087, - 40093, 40099, 40111, 40123, 40127, 40129, 40151, 40153, 40163, 40169, - 40177, 40189, 40193, 40213, 40231, 40237, 40241, 40253, 40277, 40283, - 40289, 40343, 40351, 40357, 40361, 40387, 40423, 40427, 40429, 40433, - 40459, 40471, 40483, 40487, 40493, 40499, 40507, 40519, 40529, 40531, - 40543, 40559, 40577, 40583, 40591, 40597, 40609, 40627, 40637, 40639, - 40693, 40697, 40699, 40709, 40739, 40751, 40759, 40763, 40771, 40787, - 40801, 40813, 40819, 40823, 40829, 40841, 40847, 40849, 40853, 40867, - 40879, 40883, 40897, 40903, 40927, 40933, 40939, 40949, 40961, 40973, - 40993, 41011, 41017, 41023, 41039, 41047, 41051, 41057, 41077, 41081, - 41113, 41117, 41131, 41141, 41143, 41149, 41161, 41177, 41179, 41183, - 41189, 41201, 41203, 41213, 41221, 41227, 41231, 41233, 41243, 41257, - 41263, 41269, 41281, 41299, 41333, 41341, 41351, 41357, 41381, 41387, - 41389, 41399, 41411, 41413, 41443, 41453, 41467, 41479, 41491, 41507, - 41513, 41519, 41521, 41539, 41543, 41549, 41579, 41593, 41597, 41603, - 41609, 41611, 41617, 41621, 41627, 41641, 41647, 41651, 41659, 41669, - 41681, 41687, 41719, 41729, 41737, 41759, 41761, 41771, 41777, 41801, - 41809, 41813, 41843, 41849, 41851, 41863, 41879, 41887, 41893, 41897, - 41903, 41911, 41927, 41941, 41947, 41953, 41957, 41959, 41969, 41981, - 41983, 41999, 42013, 42017, 42019, 42023, 42043, 42061, 42071, 42073, - 42083, 42089, 42101, 42131, 42139, 42157, 42169, 42179, 42181, 42187, - 42193, 42197, 42209, 42221, 42223, 42227, 42239, 42257, 42281, 42283, - 42293, 42299, 42307, 42323, 42331, 42337, 42349, 42359, 42373, 42379, - 42391, 42397, 42403, 42407, 42409, 42433, 42437, 42443, 42451, 42457, - 42461, 42463, 42467, 42473, 42487, 42491, 42499, 42509, 42533, 42557, - 42569, 42571, 42577, 42589, 42611, 42641, 42643, 42649, 42667, 42677, - 42683, 42689, 42697, 42701, 42703, 42709, 42719, 42727, 42737, 42743, - 42751, 42767, 42773, 42787, 42793, 42797, 42821, 42829, 42839, 42841, - 42853, 42859, 42863, 42899, 42901, 42923, 42929, 42937, 42943, 42953, - 42961, 42967, 42979, 42989, 43003, 43013, 43019, 43037, 43049, 43051, - 43063, 43067, 43093, 43103, 43117, 43133, 43151, 43159, 43177, 43189, - 43201, 43207, 43223, 43237, 43261, 43271, 43283, 43291, 43313, 43319, - 43321, 43331, 43391, 43397, 43399, 43403, 43411, 43427, 43441, 43451, - 43457, 43481, 43487, 43499, 43517, 43541, 43543, 43573, 43577, 43579, - 43591, 43597, 43607, 43609, 43613, 43627, 43633, 43649, 43651, 43661, - 43669, 43691, 43711, 43717, 43721, 43753, 43759, 43777, 43781, 43783, - 43787, 43789, 43793, 43801, 43853, 43867, 43889, 43891, 43913, 43933, - 43943, 43951, 43961, 43963, 43969, 43973, 43987, 43991, 43997, 44017, - 44021, 44027, 44029, 44041, 44053, 44059, 44071, 44087, 44089, 44101, - 44111, 44119, 44123, 44129, 44131, 44159, 44171, 44179, 44189, 44201, - 44203, 44207, 44221, 44249, 44257, 44263, 44267, 44269, 44273, 44279, - 44281, 44293, 44351, 44357, 44371, 44381, 44383, 44389, 44417, 44449, - 44453, 44483, 44491, 44497, 44501, 44507, 44519, 44531, 44533, 44537, - 44543, 44549, 44563, 44579, 44587, 44617, 44621, 44623, 44633, 44641, - 44647, 44651, 44657, 44683, 44687, 44699, 44701, 44711, 44729, 44741, - 44753, 44771, 44773, 44777, 44789, 44797, 44809, 44819, 44839, 44843, - 44851, 44867, 44879, 44887, 44893, 44909, 44917, 44927, 44939, 44953, - 44959, 44963, 44971, 44983, 44987, 45007, 45013, 45053, 45061, 45077, - 45083, 45119, 45121, 45127, 45131, 45137, 45139, 45161, 45179, 45181, - 45191, 45197, 45233, 45247, 45259, 45263, 45281, 45289, 45293, 45307, - 45317, 45319, 45329, 45337, 45341, 45343, 45361, 45377, 45389, 45403, - 45413, 45427, 45433, 45439, 45481, 45491, 45497, 45503, 45523, 45533, - 45541, 45553, 45557, 45569, 45587, 45589, 45599, 45613, 45631, 45641, - 45659, 45667, 45673, 45677, 45691, 45697, 45707, 45737, 45751, 45757, - 45763, 45767, 45779, 45817, 45821, 45823, 45827, 45833, 45841, 45853, - 45863, 45869, 45887, 45893, 45943, 45949, 45953, 45959, 45971, 45979, - 45989, 46021, 46027, 46049, 46051, 46061, 46073, 46091, 46093, 46099, - 46103, 46133, 46141, 46147, 46153, 46171, 46181, 46183, 46187, 46199, - 46219, 46229, 46237, 46261, 46271, 46273, 46279, 46301, 46307, 46309, - 46327, 46337, 46349, 46351, 46381, 46399, 46411, 46439, 46441, 46447, - 46451, 46457, 46471, 46477, 46489, 46499, 46507, 46511, 46523, 46549, - 46559, 46567, 46573, 46589, 46591, 46601, 46619, 46633, 46639, 46643, - 46649, 46663, 46679, 46681, 46687, 46691, 46703, 46723, 46727, 46747, - 46751, 46757, 46769, 46771, 46807, 46811, 46817, 46819, 46829, 46831, - 46853, 46861, 46867, 46877, 46889, 46901, 46919, 46933, 46957, 46993, - 46997, 47017, 47041, 47051, 47057, 47059, 47087, 47093, 47111, 47119, - 47123, 47129, 47137, 47143, 47147, 47149, 47161, 47189, 47207, 47221, - 47237, 47251, 47269, 47279, 47287, 47293, 47297, 47303, 47309, 47317, - 47339, 47351, 47353, 47363, 47381, 47387, 47389, 47407, 47417, 47419, - 47431, 47441, 47459, 47491, 47497, 47501, 47507, 47513, 47521, 47527, - 47533, 47543, 47563, 47569, 47581, 47591, 47599, 47609, 47623, 47629, - 47639, 47653, 47657, 47659, 47681, 47699, 47701, 47711, 47713, 47717, - 47737, 47741, 47743, 47777, 47779, 47791, 47797, 47807, 47809, 47819, - 47837, 47843, 47857, 47869, 47881, 47903, 47911, 47917, 47933, 47939, - 47947, 47951, 47963, 47969, 47977, 47981, 48017, 48023, 48029, 48049, - 48073, 48079, 48091, 48109, 48119, 48121, 48131, 48157, 48163, 48179, - 48187, 48193, 48197, 48221, 48239, 48247, 48259, 48271, 48281, 48299, - 48311, 48313, 48337, 48341, 48353, 48371, 48383, 48397, 48407, 48409, - 48413, 48437, 48449, 48463, 48473, 48479, 48481, 48487, 48491, 48497, - 48523, 48527, 48533, 48539, 48541, 48563, 48571, 48589, 48593, 48611, - 48619, 48623, 48647, 48649, 48661, 48673, 48677, 48679, 48731, 48733, - 48751, 48757, 48761, 48767, 48779, 48781, 48787, 48799, 48809, 48817, - 48821, 48823, 48847, 48857, 48859, 48869, 48871, 48883, 48889, 48907, - 48947, 48953, 48973, 48989, 48991, 49003, 49009, 49019, 49031, 49033, - 49037, 49043, 49057, 49069, 49081, 49103, 49109, 49117, 49121, 49123, - 49139, 49157, 49169, 49171, 49177, 49193, 49199, 49201, 49207, 49211, - 49223, 49253, 49261, 49277, 49279, 49297, 49307, 49331, 49333, 49339, - 49363, 49367, 49369, 49391, 49393, 49409, 49411, 49417, 49429, 49433, - 49451, 49459, 49463, 49477, 49481, 49499, 49523, 49529, 49531, 49537, - 49547, 49549, 49559, 49597, 49603, 49613, 49627, 49633, 49639, 49663, - 49667, 49669, 49681, 49697, 49711, 49727, 49739, 49741, 49747, 49757, - 49783, 49787, 49789, 49801, 49807, 49811, 49823, 49831, 49843, 49853, - 49871, 49877, 49891, 49919, 49921, 49927, 49937, 49939, 49943, 49957, - 49991, 49993, 49999, 50021, 50023, 50033, 50047, 50051, 50053, 50069, - 50077, 50087, 50093, 50101, 50111, 50119, 50123, 50129, 50131, 50147, - 50153, 50159, 50177, 50207, 50221, 50227, 50231, 50261, 50263, 50273, - 50287, 50291, 50311, 50321, 50329, 50333, 50341, 50359, 50363, 50377, - 50383, 50387, 50411, 50417, 50423, 50441, 50459, 50461, 50497, 50503, - 50513, 50527, 50539, 50543, 50549, 50551, 50581, 50587, 50591, 50593, - 50599, 50627, 50647, 50651, 50671, 50683, 50707, 50723, 50741, 50753, - 50767, 50773, 50777, 50789, 50821, 50833, 50839, 50849, 50857, 50867, - 50873, 50891, 50893, 50909, 50923, 50929, 50951, 50957, 50969, 50971, - 50989, 50993, 51001, 51031, 51043, 51047, 51059, 51061, 51071, 51109, - 51131, 51133, 51137, 51151, 51157, 51169, 51193, 51197, 51199, 51203, - 51217, 51229, 51239, 51241, 51257, 51263, 51283, 51287, 51307, 51329, - 51341, 51343, 51347, 51349, 51361, 51383, 51407, 51413, 51419, 51421, - 51427, 51431, 51437, 51439, 51449, 51461, 51473, 51479, 51481, 51487, - 51503, 51511, 51517, 51521, 51539, 51551, 51563, 51577, 51581, 51593, - 51599, 51607, 51613, 51631, 51637, 51647, 51659, 51673, 51679, 51683, - 51691, 51713, 51719, 51721, 51749, 51767, 51769, 51787, 51797, 51803, - 51817, 51827, 51829, 51839, 51853, 51859, 51869, 51871, 51893, 51899, - 51907, 51913, 51929, 51941, 51949, 51971, 51973, 51977, 51991, 52009, - 52021, 52027, 52051, 52057, 52067, 52069, 52081, 52103, 52121, 52127, - 52147, 52153, 52163, 52177, 52181, 52183, 52189, 52201, 52223, 52237, - 52249, 52253, 52259, 52267, 52289, 52291, 52301, 52313, 52321, 52361, - 52363, 52369, 52379, 52387, 52391, 52433, 52453, 52457, 52489, 52501, - 52511, 52517, 52529, 52541, 52543, 52553, 52561, 52567, 52571, 52579, - 52583, 52609, 52627, 52631, 52639, 52667, 52673, 52691, 52697, 52709, - 52711, 52721, 52727, 52733, 52747, 52757, 52769, 52783, 52807, 52813, - 52817, 52837, 52859, 52861, 52879, 52883, 52889, 52901, 52903, 52919, - 52937, 52951, 52957, 52963, 52967, 52973, 52981, 52999, 53003, 53017, - 53047, 53051, 53069, 53077, 53087, 53089, 53093, 53101, 53113, 53117, - 53129, 53147, 53149, 53161, 53171, 53173, 53189, 53197, 53201, 53231, - 53233, 53239, 53267, 53269, 53279, 53281, 53299, 53309, 53323, 53327, - 53353, 53359, 53377, 53381, 53401, 53407, 53411, 53419, 53437, 53441, - 53453, 53479, 53503, 53507, 53527, 53549, 53551, 53569, 53591, 53593, - 53597, 53609, 53611, 53617, 53623, 53629, 53633, 53639, 53653, 53657, - 53681, 53693, 53699, 53717, 53719, 53731, 53759, 53773, 53777, 53783, - 53791, 53813, 53819, 53831, 53849, 53857, 53861, 53881, 53887, 53891, - 53897, 53899, 53917, 53923, 53927, 53939, 53951, 53959, 53987, 53993, - 54001, 54011, 54013, 54037, 54049, 54059, 54083, 54091, 54101, 54121, - 54133, 54139, 54151, 54163, 54167, 54181, 54193, 54217, 54251, 54269, - 54277, 54287, 54293, 54311, 54319, 54323, 54331, 54347, 54361, 54367, - 54371, 54377, 54401, 54403, 54409, 54413, 54419, 54421, 54437, 54443, - 54449, 54469, 54493, 54497, 54499, 54503, 54517, 54521, 54539, 54541, - 54547, 54559, 54563, 54577, 54581, 54583, 54601, 54617, 54623, 54629, - 54631, 54647, 54667, 54673, 54679, 54709, 54713, 54721, 54727, 54751, - 54767, 54773, 54779, 54787, 54799, 54829, 54833, 54851, 54869, 54877, - 54881, 54907, 54917, 54919, 54941, 54949, 54959, 54973, 54979, 54983, - 55001, 55009, 55021, 55049, 55051, 55057, 55061, 55073, 55079, 55103, - 55109, 55117, 55127, 55147, 55163, 55171, 55201, 55207, 55213, 55217, - 55219, 55229, 55243, 55249, 55259, 55291, 55313, 55331, 55333, 55337, - 55339, 55343, 55351, 55373, 55381, 55399, 55411, 55439, 55441, 55457, - 55469, 55487, 55501, 55511, 55529, 55541, 55547, 55579, 55589, 55603, - 55609, 55619, 55621, 55631, 55633, 55639, 55661, 55663, 55667, 55673, - 55681, 55691, 55697, 55711, 55717, 55721, 55733, 55763, 55787, 55793, - 55799, 55807, 55813, 55817, 55819, 55823, 55829, 55837, 55843, 55849, - 55871, 55889, 55897, 55901, 55903, 55921, 55927, 55931, 55933, 55949, - 55967, 55987, 55997, 56003, 56009, 56039, 56041, 56053, 56081, 56087, - 56093, 56099, 56101, 56113, 56123, 56131, 56149, 56167, 56171, 56179, - 56197, 56207, 56209, 56237, 56239, 56249, 56263, 56267, 56269, 56299, - 56311, 56333, 56359, 56369, 56377, 56383, 56393, 56401, 56417, 56431, - 56437, 56443, 56453, 56467, 56473, 56477, 56479, 56489, 56501, 56503, - 56509, 56519, 56527, 56531, 56533, 56543, 56569, 56591, 56597, 56599, - 56611, 56629, 56633, 56659, 56663, 56671, 56681, 56687, 56701, 56711, - 56713, 56731, 56737, 56747, 56767, 56773, 56779, 56783, 56807, 56809, - 56813, 56821, 56827, 56843, 56857, 56873, 56891, 56893, 56897, 56909, - 56911, 56921, 56923, 56929, 56941, 56951, 56957, 56963, 56983, 56989, - 56993, 56999, 57037, 57041, 57047, 57059, 57073, 57077, 57089, 57097, - 57107, 57119, 57131, 57139, 57143, 57149, 57163, 57173, 57179, 57191, - 57193, 57203, 57221, 57223, 57241, 57251, 57259, 57269, 57271, 57283, - 57287, 57301, 57329, 57331, 57347, 57349, 57367, 57373, 57383, 57389, - 57397, 57413, 57427, 57457, 57467, 57487, 57493, 57503, 57527, 57529, - 57557, 57559, 57571, 57587, 57593, 57601, 57637, 57641, 57649, 57653, - 57667, 57679, 57689, 57697, 57709, 57713, 57719, 57727, 57731, 57737, - 57751, 57773, 57781, 57787, 57791, 57793, 57803, 57809, 57829, 57839, - 57847, 57853, 57859, 57881, 57899, 57901, 57917, 57923, 57943, 57947, - 57973, 57977, 57991, 58013, 58027, 58031, 58043, 58049, 58057, 58061, - 58067, 58073, 58099, 58109, 58111, 58129, 58147, 58151, 58153, 58169, - 58171, 58189, 58193, 58199, 58207, 58211, 58217, 58229, 58231, 58237, - 58243, 58271, 58309, 58313, 58321, 58337, 58363, 58367, 58369, 58379, - 58391, 58393, 58403, 58411, 58417, 58427, 58439, 58441, 58451, 58453, - 58477, 58481, 58511, 58537, 58543, 58549, 58567, 58573, 58579, 58601, - 58603, 58613, 58631, 58657, 58661, 58679, 58687, 58693, 58699, 58711, - 58727, 58733, 58741, 58757, 58763, 58771, 58787, 58789, 58831, 58889, - 58897, 58901, 58907, 58909, 58913, 58921, 58937, 58943, 58963, 58967, - 58979, 58991, 58997, 59009, 59011, 59021, 59023, 59029, 59051, 59053, - 59063, 59069, 59077, 59083, 59093, 59107, 59113, 59119, 59123, 59141, - 59149, 59159, 59167, 59183, 59197, 59207, 59209, 59219, 59221, 59233, - 59239, 59243, 59263, 59273, 59281, 59333, 59341, 59351, 59357, 59359, - 59369, 59377, 59387, 59393, 59399, 59407, 59417, 59419, 59441, 59443, - 59447, 59453, 59467, 59471, 59473, 59497, 59509, 59513, 59539, 59557, - 59561, 59567, 59581, 59611, 59617, 59621, 59627, 59629, 59651, 59659, - 59663, 59669, 59671, 59693, 59699, 59707, 59723, 59729, 59743, 59747, - 59753, 59771, 59779, 59791, 59797, 59809, 59833, 59863, 59879, 59887, - 59921, 59929, 59951, 59957, 59971, 59981, 59999, 60013, 60017, 60029, - 60037, 60041, 60077, 60083, 60089, 60091, 60101, 60103, 60107, 60127, - 60133, 60139, 60149, 60161, 60167, 60169, 60209, 60217, 60223, 60251, - 60257, 60259, 60271, 60289, 60293, 60317, 60331, 60337, 60343, 60353, - 60373, 60383, 60397, 60413, 60427, 60443, 60449, 60457, 60493, 60497, - 60509, 60521, 60527, 60539, 60589, 60601, 60607, 60611, 60617, 60623, - 60631, 60637, 60647, 60649, 60659, 60661, 60679, 60689, 60703, 60719, - 60727, 60733, 60737, 60757, 60761, 60763, 60773, 60779, 60793, 60811, - 60821, 60859, 60869, 60887, 60889, 60899, 60901, 60913, 60917, 60919, - 60923, 60937, 60943, 60953, 60961, 61001, 61007, 61027, 61031, 61043, - 61051, 61057, 61091, 61099, 61121, 61129, 61141, 61151, 61153, 61169, - 61211, 61223, 61231, 61253, 61261, 61283, 61291, 61297, 61331, 61333, - 61339, 61343, 61357, 61363, 61379, 61381, 61403, 61409, 61417, 61441, - 61463, 61469, 61471, 61483, 61487, 61493, 61507, 61511, 61519, 61543, - 61547, 61553, 61559, 61561, 61583, 61603, 61609, 61613, 61627, 61631, - 61637, 61643, 61651, 61657, 61667, 61673, 61681, 61687, 61703, 61717, - 61723, 61729, 61751, 61757, 61781, 61813, 61819, 61837, 61843, 61861, - 61871, 61879, 61909, 61927, 61933, 61949, 61961, 61967, 61979, 61981, - 61987, 61991, 62003, 62011, 62017, 62039, 62047, 62053, 62057, 62071, - 62081, 62099, 62119, 62129, 62131, 62137, 62141, 62143, 62171, 62189, - 62191, 62201, 62207, 62213, 62219, 62233, 62273, 62297, 62299, 62303, - 62311, 62323, 62327, 62347, 62351, 62383, 62401, 62417, 62423, 62459, - 62467, 62473, 62477, 62483, 62497, 62501, 62507, 62533, 62539, 62549, - 62563, 62581, 62591, 62597, 62603, 62617, 62627, 62633, 62639, 62653, - 62659, 62683, 62687, 62701, 62723, 62731, 62743, 62753, 62761, 62773, - 62791, 62801, 62819, 62827, 62851, 62861, 62869, 62873, 62897, 62903, - 62921, 62927, 62929, 62939, 62969, 62971, 62981, 62983, 62987, 62989, - 63029, 63031, 63059, 63067, 63073, 63079, 63097, 63103, 63113, 63127, - 63131, 63149, 63179, 63197, 63199, 63211, 63241, 63247, 63277, 63281, - 63299, 63311, 63313, 63317, 63331, 63337, 63347, 63353, 63361, 63367, - 63377, 63389, 63391, 63397, 63409, 63419, 63421, 63439, 63443, 63463, - 63467, 63473, 63487, 63493, 63499, 63521, 63527, 63533, 63541, 63559, - 63577, 63587, 63589, 63599, 63601, 63607, 63611, 63617, 63629, 63647, - 63649, 63659, 63667, 63671, 63689, 63691, 63697, 63703, 63709, 63719, - 63727, 63737, 63743, 63761, 63773, 63781, 63793, 63799, 63803, 63809, - 63823, 63839, 63841, 63853, 63857, 63863, 63901, 63907, 63913, 63929, - 63949, 63977, 63997, 64007, 64013, 64019, 64033, 64037, 64063, 64067, - 64081, 64091, 64109, 64123, 64151, 64153, 64157, 64171, 64187, 64189, - 64217, 64223, 64231, 64237, 64271, 64279, 64283, 64301, 64303, 64319, - 64327, 64333, 64373, 64381, 64399, 64403, 64433, 64439, 64451, 64453, - 64483, 64489, 64499, 64513, 64553, 64567, 64577, 64579, 64591, 64601, - 64609, 64613, 64621, 64627, 64633, 64661, 64663, 64667, 64679, 64693, - 64709, 64717, 64747, 64763, 64781, 64783, 64793, 64811, 64817, 64849, - 64853, 64871, 64877, 64879, 64891, 64901, 64919, 64921, 64927, 64937, - 64951, 64969, 64997, 65003, 65011, 65027, 65029, 65033, 65053, 65063, - 65071, 65089, 65099, 65101, 65111, 65119, 65123, 65129, 65141, 65147, - 65167, 65171, 65173, 65179, 65183, 65203, 65213, 65239, 65257, 65267, - 65269, 65287, 65293, 65309, 65323, 65327, 65353, 65357, 65371, 65381, - 65393, 65407, 65413, 65419, 65423, 65437, 65447, 65449, 65479, 65497, - 65519, 65521, 65537, 65539, 65543, 65551, 65557, 65563, 65579, 65581, - 65587, 65599, 65609, 65617, 65629, 65633, 65647, 65651, 65657, 65677, - 65687, 65699, 65701, 65707, 65713, 65717, 65719, 65729, 65731, 65761, - 65777, 65789, 65809, 65827, 65831, 65837, 65839, 65843, 65851, 65867, - 65881, 65899, 65921, 65927, 65929, 65951, 65957, 65963, 65981, 65983, - 65993, 66029, 66037, 66041, 66047, 66067, 66071, 66083, 66089, 66103, - 66107, 66109, 66137, 66161, 66169, 66173, 66179, 66191, 66221, 66239, - 66271, 66293, 66301, 66337, 66343, 66347, 66359, 66361, 66373, 66377, - 66383, 66403, 66413, 66431, 66449, 66457, 66463, 66467, 66491, 66499, - 66509, 66523, 66529, 66533, 66541, 66553, 66569, 66571, 66587, 66593, - 66601, 66617, 66629, 66643, 66653, 66683, 66697, 66701, 66713, 66721, - 66733, 66739, 66749, 66751, 66763, 66791, 66797, 66809, 66821, 66841, - 66851, 66853, 66863, 66877, 66883, 66889, 66919, 66923, 66931, 66943, - 66947, 66949, 66959, 66973, 66977, 67003, 67021, 67033, 67043, 67049, - 67057, 67061, 67073, 67079, 67103, 67121, 67129, 67139, 67141, 67153, - 67157, 67169, 67181, 67187, 67189, 67211, 67213, 67217, 67219, 67231, - 67247, 67261, 67271, 67273, 67289, 67307, 67339, 67343, 67349, 67369, - 67391, 67399, 67409, 67411, 67421, 67427, 67429, 67433, 67447, 67453, - 67477, 67481, 67489, 67493, 67499, 67511, 67523, 67531, 67537, 67547, - 67559, 67567, 67577, 67579, 67589, 67601, 67607, 67619, 67631, 67651, - 67679, 67699, 67709, 67723, 67733, 67741, 67751, 67757, 67759, 67763, - 67777, 67783, 67789, 67801, 67807, 67819, 67829, 67843, 67853, 67867, - 67883, 67891, 67901, 67927, 67931, 67933, 67939, 67943, 67957, 67961, - 67967, 67979, 67987, 67993, 68023, 68041, 68053, 68059, 68071, 68087, - 68099, 68111, 68113, 68141, 68147, 68161, 68171, 68207, 68209, 68213, - 68219, 68227, 68239, 68261, 68279, 68281, 68311, 68329, 68351, 68371, - 68389, 68399, 68437, 68443, 68447, 68449, 68473, 68477, 68483, 68489, - 68491, 68501, 68507, 68521, 68531, 68539, 68543, 68567, 68581, 68597, - 68611, 68633, 68639, 68659, 68669, 68683, 68687, 68699, 68711, 68713, - 68729, 68737, 68743, 68749, 68767, 68771, 68777, 68791, 68813, 68819, - 68821, 68863, 68879, 68881, 68891, 68897, 68899, 68903, 68909, 68917, - 68927, 68947, 68963, 68993, 69001, 69011, 69019, 69029, 69031, 69061, - 69067, 69073, 69109, 69119, 69127, 69143, 69149, 69151, 69163, 69191, - 69193, 69197, 69203, 69221, 69233, 69239, 69247, 69257, 69259, 69263, - 69313, 69317, 69337, 69341, 69371, 69379, 69383, 69389, 69401, 69403, - 69427, 69431, 69439, 69457, 69463, 69467, 69473, 69481, 69491, 69493, - 69497, 69499, 69539, 69557, 69593, 69623, 69653, 69661, 69677, 69691, - 69697, 69709, 69737, 69739, 69761, 69763, 69767, 69779, 69809, 69821, - 69827, 69829, 69833, 69847, 69857, 69859, 69877, 69899, 69911, 69929, - 69931, 69941, 69959, 69991, 69997, 70001, 70003, 70009, 70019, 70039, - 70051, 70061, 70067, 70079, 70099, 70111, 70117, 70121, 70123, 70139, - 70141, 70157, 70163, 70177, 70181, 70183, 70199, 70201, 70207, 70223, - 70229, 70237, 70241, 70249, 70271, 70289, 70297, 70309, 70313, 70321, - 70327, 70351, 70373, 70379, 70381, 70393, 70423, 70429, 70439, 70451, - 70457, 70459, 70481, 70487, 70489, 70501, 70507, 70529, 70537, 70549, - 70571, 70573, 70583, 70589, 70607, 70619, 70621, 70627, 70639, 70657, - 70663, 70667, 70687, 70709, 70717, 70729, 70753, 70769, 70783, 70793, - 70823, 70841, 70843, 70849, 70853, 70867, 70877, 70879, 70891, 70901, - 70913, 70919, 70921, 70937, 70949, 70951, 70957, 70969, 70979, 70981, - 70991, 70997, 70999, 71011, 71023, 71039, 71059, 71069, 71081, 71089, - 71119, 71129, 71143, 71147, 71153, 71161, 71167, 71171, 71191, 71209, - 71233, 71237, 71249, 71257, 71261, 71263, 71287, 71293, 71317, 71327, - 71329, 71333, 71339, 71341, 71347, 71353, 71359, 71363, 71387, 71389, - 71399, 71411, 71413, 71419, 71429, 71437, 71443, 71453, 71471, 71473, - 71479, 71483, 71503, 71527, 71537, 71549, 71551, 71563, 71569, 71593, - 71597, 71633, 71647, 71663, 71671, 71693, 71699, 71707, 71711, 71713, - 71719, 71741, 71761, 71777, 71789, 71807, 71809, 71821, 71837, 71843, - 71849, 71861, 71867, 71879, 71881, 71887, 71899, 71909, 71917, 71933, - 71941, 71947, 71963, 71971, 71983, 71987, 71993, 71999, 72019, 72031, - 72043, 72047, 72053, 72073, 72077, 72089, 72091, 72101, 72103, 72109, - 72139, 72161, 72167, 72169, 72173, 72211, 72221, 72223, 72227, 72229, - 72251, 72253, 72269, 72271, 72277, 72287, 72307, 72313, 72337, 72341, - 72353, 72367, 72379, 72383, 72421, 72431, 72461, 72467, 72469, 72481, - 72493, 72497, 72503, 72533, 72547, 72551, 72559, 72577, 72613, 72617, - 72623, 72643, 72647, 72649, 72661, 72671, 72673, 72679, 72689, 72701, - 72707, 72719, 72727, 72733, 72739, 72763, 72767, 72797, 72817, 72823, - 72859, 72869, 72871, 72883, 72889, 72893, 72901, 72907, 72911, 72923, - 72931, 72937, 72949, 72953, 72959, 72973, 72977, 72997, 73009, 73013, - 73019, 73037, 73039, 73043, 73061, 73063, 73079, 73091, 73121, 73127, - 73133, 73141, 73181, 73189, 73237, 73243, 73259, 73277, 73291, 73303, - 73309, 73327, 73331, 73351, 73361, 73363, 73369, 73379, 73387, 73417, - 73421, 73433, 73453, 73459, 73471, 73477, 73483, 73517, 73523, 73529, - 73547, 73553, 73561, 73571, 73583, 73589, 73597, 73607, 73609, 73613, - 73637, 73643, 73651, 73673, 73679, 73681, 73693, 73699, 73709, 73721, - 73727, 73751, 73757, 73771, 73783, 73819, 73823, 73847, 73849, 73859, - 73867, 73877, 73883, 73897, 73907, 73939, 73943, 73951, 73961, 73973, - 73999, 74017, 74021, 74027, 74047, 74051, 74071, 74077, 74093, 74099, - 74101, 74131, 74143, 74149, 74159, 74161, 74167, 74177, 74189, 74197, - 74201, 74203, 74209, 74219, 74231, 74257, 74279, 74287, 74293, 74297, - 74311, 74317, 74323, 74353, 74357, 74363, 74377, 74381, 74383, 74411, - 74413, 74419, 74441, 74449, 74453, 74471, 74489, 74507, 74509, 74521, - 74527, 74531, 74551, 74561, 74567, 74573, 74587, 74597, 74609, 74611, - 74623, 74653, 74687, 74699, 74707, 74713, 74717, 74719, 74729, 74731, - 74747, 74759, 74761, 74771, 74779, 74797, 74821, 74827, 74831, 74843, - 74857, 74861, 74869, 74873, 74887, 74891, 74897, 74903, 74923, 74929, - 74933, 74941, 74959, 75011, 75013, 75017, 75029, 75037, 75041, 75079, - 75083, 75109, 75133, 75149, 75161, 75167, 75169, 75181, 75193, 75209, - 75211, 75217, 75223, 75227, 75239, 75253, 75269, 75277, 75289, 75307, - 75323, 75329, 75337, 75347, 75353, 75367, 75377, 75389, 75391, 75401, - 75403, 75407, 75431, 75437, 75479, 75503, 75511, 75521, 75527, 75533, - 75539, 75541, 75553, 75557, 75571, 75577, 75583, 75611, 75617, 75619, - 75629, 75641, 75653, 75659, 75679, 75683, 75689, 75703, 75707, 75709, - 75721, 75731, 75743, 75767, 75773, 75781, 75787, 75793, 75797, 75821, - 75833, 75853, 75869, 75883, 75913, 75931, 75937, 75941, 75967, 75979, - 75983, 75989, 75991, 75997, 76001, 76003, 76031, 76039, 76079, 76081, - 76091, 76099, 76103, 76123, 76129, 76147, 76157, 76159, 76163, 76207, - 76213, 76231, 76243, 76249, 76253, 76259, 76261, 76283, 76289, 76303, - 76333, 76343, 76367, 76369, 76379, 76387, 76403, 76421, 76423, 76441, - 76463, 76471, 76481, 76487, 76493, 76507, 76511, 76519, 76537, 76541, - 76543, 76561, 76579, 76597, 76603, 76607, 76631, 76649, 76651, 76667, - 76673, 76679, 76697, 76717, 76733, 76753, 76757, 76771, 76777, 76781, - 76801, 76819, 76829, 76831, 76837, 76847, 76871, 76873, 76883, 76907, - 76913, 76919, 76943, 76949, 76961, 76963, 76991, 77003, 77017, 77023, - 77029, 77041, 77047, 77069, 77081, 77093, 77101, 77137, 77141, 77153, - 77167, 77171, 77191, 77201, 77213, 77237, 77239, 77243, 77249, 77261, - 77263, 77267, 77269, 77279, 77291, 77317, 77323, 77339, 77347, 77351, - 77359, 77369, 77377, 77383, 77417, 77419, 77431, 77447, 77471, 77477, - 77479, 77489, 77491, 77509, 77513, 77521, 77527, 77543, 77549, 77551, - 77557, 77563, 77569, 77573, 77587, 77591, 77611, 77617, 77621, 77641, - 77647, 77659, 77681, 77687, 77689, 77699, 77711, 77713, 77719, 77723, - 77731, 77743, 77747, 77761, 77773, 77783, 77797, 77801, 77813, 77839, - 77849, 77863, 77867, 77893, 77899, 77929, 77933, 77951, 77969, 77977, - 77983, 77999, 78007, 78017, 78031, 78041, 78049, 78059, 78079, 78101, - 78121, 78137, 78139, 78157, 78163, 78167, 78173, 78179, 78191, 78193, - 78203, 78229, 78233, 78241, 78259, 78277, 78283, 78301, 78307, 78311, - 78317, 78341, 78347, 78367, 78401, 78427, 78437, 78439, 78467, 78479, - 78487, 78497, 78509, 78511, 78517, 78539, 78541, 78553, 78569, 78571, - 78577, 78583, 78593, 78607, 78623, 78643, 78649, 78653, 78691, 78697, - 78707, 78713, 78721, 78737, 78779, 78781, 78787, 78791, 78797, 78803, - 78809, 78823, 78839, 78853, 78857, 78877, 78887, 78889, 78893, 78901, - 78919, 78929, 78941, 78977, 78979, 78989, 79031, 79039, 79043, 79063, - 79087, 79103, 79111, 79133, 79139, 79147, 79151, 79153, 79159, 79181, - 79187, 79193, 79201, 79229, 79231, 79241, 79259, 79273, 79279, 79283, - 79301, 79309, 79319, 79333, 79337, 79349, 79357, 79367, 79379, 79393, - 79397, 79399, 79411, 79423, 79427, 79433, 79451, 79481, 79493, 79531, - 79537, 79549, 79559, 79561, 79579, 79589, 79601, 79609, 79613, 79621, - 79627, 79631, 79633, 79657, 79669, 79687, 79691, 79693, 79697, 79699, - 79757, 79769, 79777, 79801, 79811, 79813, 79817, 79823, 79829, 79841, - 79843, 79847, 79861, 79867, 79873, 79889, 79901, 79903, 79907, 79939, - 79943, 79967, 79973, 79979, 79987, 79997, 79999, 80021, 80039, 80051, - 80071, 80077, 80107, 80111, 80141, 80147, 80149, 80153, 80167, 80173, - 80177, 80191, 80207, 80209, 80221, 80231, 80233, 80239, 80251, 80263, - 80273, 80279, 80287, 80309, 80317, 80329, 80341, 80347, 80363, 80369, - 80387, 80407, 80429, 80447, 80449, 80471, 80473, 80489, 80491, 80513, - 80527, 80537, 80557, 80567, 80599, 80603, 80611, 80621, 80627, 80629, - 80651, 80657, 80669, 80671, 80677, 80681, 80683, 80687, 80701, 80713, - 80737, 80747, 80749, 80761, 80777, 80779, 80783, 80789, 80803, 80809, - 80819, 80831, 80833, 80849, 80863, 80897, 80909, 80911, 80917, 80923, - 80929, 80933, 80953, 80963, 80989, 81001, 81013, 81017, 81019, 81023, - 81031, 81041, 81043, 81047, 81049, 81071, 81077, 81083, 81097, 81101, - 81119, 81131, 81157, 81163, 81173, 81181, 81197, 81199, 81203, 81223, - 81233, 81239, 81281, 81283, 81293, 81299, 81307, 81331, 81343, 81349, - 81353, 81359, 81371, 81373, 81401, 81409, 81421, 81439, 81457, 81463, - 81509, 81517, 81527, 81533, 81547, 81551, 81553, 81559, 81563, 81569, - 81611, 81619, 81629, 81637, 81647, 81649, 81667, 81671, 81677, 81689, - 81701, 81703, 81707, 81727, 81737, 81749, 81761, 81769, 81773, 81799, - 81817, 81839, 81847, 81853, 81869, 81883, 81899, 81901, 81919, 81929, - 81931, 81937, 81943, 81953, 81967, 81971, 81973, 82003, 82007, 82009, - 82013, 82021, 82031, 82037, 82039, 82051, 82067, 82073, 82129, 82139, - 82141, 82153, 82163, 82171, 82183, 82189, 82193, 82207, 82217, 82219, - 82223, 82231, 82237, 82241, 82261, 82267, 82279, 82301, 82307, 82339, - 82349, 82351, 82361, 82373, 82387, 82393, 82421, 82457, 82463, 82469, - 82471, 82483, 82487, 82493, 82499, 82507, 82529, 82531, 82549, 82559, - 82561, 82567, 82571, 82591, 82601, 82609, 82613, 82619, 82633, 82651, - 82657, 82699, 82721, 82723, 82727, 82729, 82757, 82759, 82763, 82781, - 82787, 82793, 82799, 82811, 82813, 82837, 82847, 82883, 82889, 82891, - 82903, 82913, 82939, 82963, 82981, 82997, 83003, 83009, 83023, 83047, - 83059, 83063, 83071, 83077, 83089, 83093, 83101, 83117, 83137, 83177, - 83203, 83207, 83219, 83221, 83227, 83231, 83233, 83243, 83257, 83267, - 83269, 83273, 83299, 83311, 83339, 83341, 83357, 83383, 83389, 83399, - 83401, 83407, 83417, 83423, 83431, 83437, 83443, 83449, 83459, 83471, - 83477, 83497, 83537, 83557, 83561, 83563, 83579, 83591, 83597, 83609, - 83617, 83621, 83639, 83641, 83653, 83663, 83689, 83701, 83717, 83719, - 83737, 83761, 83773, 83777, 83791, 83813, 83833, 83843, 83857, 83869, - 83873, 83891, 83903, 83911, 83921, 83933, 83939, 83969, 83983, 83987, - 84011, 84017, 84047, 84053, 84059, 84061, 84067, 84089, 84121, 84127, - 84131, 84137, 84143, 84163, 84179, 84181, 84191, 84199, 84211, 84221, - 84223, 84229, 84239, 84247, 84263, 84299, 84307, 84313, 84317, 84319, - 84347, 84349, 84377, 84389, 84391, 84401, 84407, 84421, 84431, 84437, - 84443, 84449, 84457, 84463, 84467, 84481, 84499, 84503, 84509, 84521, - 84523, 84533, 84551, 84559, 84589, 84629, 84631, 84649, 84653, 84659, - 84673, 84691, 84697, 84701, 84713, 84719, 84731, 84737, 84751, 84761, - 84787, 84793, 84809, 84811, 84827, 84857, 84859, 84869, 84871, 84913, - 84919, 84947, 84961, 84967, 84977, 84979, 84991, 85009, 85021, 85027, - 85037, 85049, 85061, 85081, 85087, 85091, 85093, 85103, 85109, 85121, - 85133, 85147, 85159, 85193, 85199, 85201, 85213, 85223, 85229, 85237, - 85243, 85247, 85259, 85297, 85303, 85313, 85331, 85333, 85361, 85363, - 85369, 85381, 85411, 85427, 85429, 85439, 85447, 85451, 85453, 85469, - 85487, 85513, 85517, 85523, 85531, 85549, 85571, 85577, 85597, 85601, - 85607, 85619, 85621, 85627, 85639, 85643, 85661, 85667, 85669, 85691, - 85703, 85711, 85717, 85733, 85751, 85781, 85793, 85817, 85819, 85829, - 85831, 85837, 85843, 85847, 85853, 85889, 85903, 85909, 85931, 85933, - 85991, 85999, 86011, 86017, 86027, 86029, 86069, 86077, 86083, 86111, - 86113, 86117, 86131, 86137, 86143, 86161, 86171, 86179, 86183, 86197, - 86201, 86209, 86239, 86243, 86249, 86257, 86263, 86269, 86287, 86291, - 86293, 86297, 86311, 86323, 86341, 86351, 86353, 86357, 86369, 86371, - 86381, 86389, 86399, 86413, 86423, 86441, 86453, 86461, 86467, 86477, - 86491, 86501, 86509, 86531, 86533, 86539, 86561, 86573, 86579, 86587, - 86599, 86627, 86629, 86677, 86689, 86693, 86711, 86719, 86729, 86743, - 86753, 86767, 86771, 86783, 86813, 86837, 86843, 86851, 86857, 86861, - 86869, 86923, 86927, 86929, 86939, 86951, 86959, 86969, 86981, 86993, - 87011, 87013, 87037, 87041, 87049, 87071, 87083, 87103, 87107, 87119, - 87121, 87133, 87149, 87151, 87179, 87181, 87187, 87211, 87221, 87223, - 87251, 87253, 87257, 87277, 87281, 87293, 87299, 87313, 87317, 87323, - 87337, 87359, 87383, 87403, 87407, 87421, 87427, 87433, 87443, 87473, - 87481, 87491, 87509, 87511, 87517, 87523, 87539, 87541, 87547, 87553, - 87557, 87559, 87583, 87587, 87589, 87613, 87623, 87629, 87631, 87641, - 87643, 87649, 87671, 87679, 87683, 87691, 87697, 87701, 87719, 87721, - 87739, 87743, 87751, 87767, 87793, 87797, 87803, 87811, 87833, 87853, - 87869, 87877, 87881, 87887, 87911, 87917, 87931, 87943, 87959, 87961, - 87973, 87977, 87991, 88001, 88003, 88007, 88019, 88037, 88069, 88079, - 88093, 88117, 88129, 88169, 88177, 88211, 88223, 88237, 88241, 88259, - 88261, 88289, 88301, 88321, 88327, 88337, 88339, 88379, 88397, 88411, - 88423, 88427, 88463, 88469, 88471, 88493, 88499, 88513, 88523, 88547, - 88589, 88591, 88607, 88609, 88643, 88651, 88657, 88661, 88663, 88667, - 88681, 88721, 88729, 88741, 88747, 88771, 88789, 88793, 88799, 88801, - 88807, 88811, 88813, 88817, 88819, 88843, 88853, 88861, 88867, 88873, - 88883, 88897, 88903, 88919, 88937, 88951, 88969, 88993, 88997, 89003, - 89009, 89017, 89021, 89041, 89051, 89057, 89069, 89071, 89083, 89087, - 89101, 89107, 89113, 89119, 89123, 89137, 89153, 89189, 89203, 89209, - 89213, 89227, 89231, 89237, 89261, 89269, 89273, 89293, 89303, 89317, - 89329, 89363, 89371, 89381, 89387, 89393, 89399, 89413, 89417, 89431, - 89443, 89449, 89459, 89477, 89491, 89501, 89513, 89519, 89521, 89527, - 89533, 89561, 89563, 89567, 89591, 89597, 89599, 89603, 89611, 89627, - 89633, 89653, 89657, 89659, 89669, 89671, 89681, 89689, 89753, 89759, - 89767, 89779, 89783, 89797, 89809, 89819, 89821, 89833, 89839, 89849, - 89867, 89891, 89897, 89899, 89909, 89917, 89923, 89939, 89959, 89963, - 89977, 89983, 89989, 90001, 90007, 90011, 90017, 90019, 90023, 90031, - 90053, 90059, 90067, 90071, 90073, 90089, 90107, 90121, 90127, 90149, - 90163, 90173, 90187, 90191, 90197, 90199, 90203, 90217, 90227, 90239, - 90247, 90263, 90271, 90281, 90289, 90313, 90353, 90359, 90371, 90373, - 90379, 90397, 90401, 90403, 90407, 90437, 90439, 90469, 90473, 90481, - 90499, 90511, 90523, 90527, 90529, 90533, 90547, 90583, 90599, 90617, - 90619, 90631, 90641, 90647, 90659, 90677, 90679, 90697, 90703, 90709, - 90731, 90749, 90787, 90793, 90803, 90821, 90823, 90833, 90841, 90847, - 90863, 90887, 90901, 90907, 90911, 90917, 90931, 90947, 90971, 90977, - 90989, 90997, 91009, 91019, 91033, 91079, 91081, 91097, 91099, 91121, - 91127, 91129, 91139, 91141, 91151, 91153, 91159, 91163, 91183, 91193, - 91199, 91229, 91237, 91243, 91249, 91253, 91283, 91291, 91297, 91303, - 91309, 91331, 91367, 91369, 91373, 91381, 91387, 91393, 91397, 91411, - 91423, 91433, 91453, 91457, 91459, 91463, 91493, 91499, 91513, 91529, - 91541, 91571, 91573, 91577, 91583, 91591, 91621, 91631, 91639, 91673, - 91691, 91703, 91711, 91733, 91753, 91757, 91771, 91781, 91801, 91807, - 91811, 91813, 91823, 91837, 91841, 91867, 91873, 91909, 91921, 91939, - 91943, 91951, 91957, 91961, 91967, 91969, 91997, 92003, 92009, 92033, - 92041, 92051, 92077, 92083, 92107, 92111, 92119, 92143, 92153, 92173, - 92177, 92179, 92189, 92203, 92219, 92221, 92227, 92233, 92237, 92243, - 92251, 92269, 92297, 92311, 92317, 92333, 92347, 92353, 92357, 92363, - 92369, 92377, 92381, 92383, 92387, 92399, 92401, 92413, 92419, 92431, - 92459, 92461, 92467, 92479, 92489, 92503, 92507, 92551, 92557, 92567, - 92569, 92581, 92593, 92623, 92627, 92639, 92641, 92647, 92657, 92669, - 92671, 92681, 92683, 92693, 92699, 92707, 92717, 92723, 92737, 92753, - 92761, 92767, 92779, 92789, 92791, 92801, 92809, 92821, 92831, 92849, - 92857, 92861, 92863, 92867, 92893, 92899, 92921, 92927, 92941, 92951, - 92957, 92959, 92987, 92993, 93001, 93047, 93053, 93059, 93077, 93083, - 93089, 93097, 93103, 93113, 93131, 93133, 93139, 93151, 93169, 93179, - 93187, 93199, 93229, 93239, 93241, 93251, 93253, 93257, 93263, 93281, - 93283, 93287, 93307, 93319, 93323, 93329, 93337, 93371, 93377, 93383, - 93407, 93419, 93427, 93463, 93479, 93481, 93487, 93491, 93493, 93497, - 93503, 93523, 93529, 93553, 93557, 93559, 93563, 93581, 93601, 93607, - 93629, 93637, 93683, 93701, 93703, 93719, 93739, 93761, 93763, 93787, - 93809, 93811, 93827, 93851, 93871, 93887, 93889, 93893, 93901, 93911, - 93913, 93923, 93937, 93941, 93949, 93967, 93971, 93979, 93983, 93997, - 94007, 94009, 94033, 94049, 94057, 94063, 94079, 94099, 94109, 94111, - 94117, 94121, 94151, 94153, 94169, 94201, 94207, 94219, 94229, 94253, - 94261, 94273, 94291, 94307, 94309, 94321, 94327, 94331, 94343, 94349, - 94351, 94379, 94397, 94399, 94421, 94427, 94433, 94439, 94441, 94447, - 94463, 94477, 94483, 94513, 94529, 94531, 94541, 94543, 94547, 94559, - 94561, 94573, 94583, 94597, 94603, 94613, 94621, 94649, 94651, 94687, - 94693, 94709, 94723, 94727, 94747, 94771, 94777, 94781, 94789, 94793, - 94811, 94819, 94823, 94837, 94841, 94847, 94849, 94873, 94889, 94903, - 94907, 94933, 94949, 94951, 94961, 94993, 94999, 95003, 95009, 95021, - 95027, 95063, 95071, 95083, 95087, 95089, 95093, 95101, 95107, 95111, - 95131, 95143, 95153, 95177, 95189, 95191, 95203, 95213, 95219, 95231, - 95233, 95239, 95257, 95261, 95267, 95273, 95279, 95287, 95311, 95317, - 95327, 95339, 95369, 95383, 95393, 95401, 95413, 95419, 95429, 95441, - 95443, 95461, 95467, 95471, 95479, 95483, 95507, 95527, 95531, 95539, - 95549, 95561, 95569, 95581, 95597, 95603, 95617, 95621, 95629, 95633, - 95651, 95701, 95707, 95713, 95717, 95723, 95731, 95737, 95747, 95773, - 95783, 95789, 95791, 95801, 95803, 95813, 95819, 95857, 95869, 95873, - 95881, 95891, 95911, 95917, 95923, 95929, 95947, 95957, 95959, 95971, - 95987, 95989, 96001, 96013, 96017, 96043, 96053, 96059, 96079, 96097, - 96137, 96149, 96157, 96167, 96179, 96181, 96199, 96211, 96221, 96223, - 96233, 96259, 96263, 96269, 96281, 96289, 96293, 96323, 96329, 96331, - 96337, 96353, 96377, 96401, 96419, 96431, 96443, 96451, 96457, 96461, - 96469, 96479, 96487, 96493, 96497, 96517, 96527, 96553, 96557, 96581, - 96587, 96589, 96601, 96643, 96661, 96667, 96671, 96697, 96703, 96731, - 96737, 96739, 96749, 96757, 96763, 96769, 96779, 96787, 96797, 96799, - 96821, 96823, 96827, 96847, 96851, 96857, 96893, 96907, 96911, 96931, - 96953, 96959, 96973, 96979, 96989, 96997, 97001, 97003, 97007, 97021, - 97039, 97073, 97081, 97103, 97117, 97127, 97151, 97157, 97159, 97169, - 97171, 97177, 97187, 97213, 97231, 97241, 97259, 97283, 97301, 97303, - 97327, 97367, 97369, 97373, 97379, 97381, 97387, 97397, 97423, 97429, - 97441, 97453, 97459, 97463, 97499, 97501, 97511, 97523, 97547, 97549, - 97553, 97561, 97571, 97577, 97579, 97583, 97607, 97609, 97613, 97649, - 97651, 97673, 97687, 97711, 97729, 97771, 97777, 97787, 97789, 97813, - 97829, 97841, 97843, 97847, 97849, 97859, 97861, 97871, 97879, 97883, - 97919, 97927, 97931, 97943, 97961, 97967, 97973, 97987, 98009, 98011, - 98017, 98041, 98047, 98057, 98081, 98101, 98123, 98129, 98143, 98179, - 98207, 98213, 98221, 98227, 98251, 98257, 98269, 98297, 98299, 98317, - 98321, 98323, 98327, 98347, 98369, 98377, 98387, 98389, 98407, 98411, - 98419, 98429, 98443, 98453, 98459, 98467, 98473, 98479, 98491, 98507, - 98519, 98533, 98543, 98561, 98563, 98573, 98597, 98621, 98627, 98639, - 98641, 98663, 98669, 98689, 98711, 98713, 98717, 98729, 98731, 98737, - 98773, 98779, 98801, 98807, 98809, 98837, 98849, 98867, 98869, 98873, - 98887, 98893, 98897, 98899, 98909, 98911, 98927, 98929, 98939, 98947, - 98953, 98963, 98981, 98993, 98999, 99013, 99017, 99023, 99041, 99053, - 99079, 99083, 99089, 99103, 99109, 99119, 99131, 99133, 99137, 99139, - 99149, 99173, 99181, 99191, 99223, 99233, 99241, 99251, 99257, 99259, - 99277, 99289, 99317, 99347, 99349, 99367, 99371, 99377, 99391, 99397, - 99401, 99409, 99431, 99439, 99469, 99487, 99497, 99523, 99527, 99529, - 99551, 99559, 99563, 99571, 99577, 99581, 99607, 99611, 99623, 99643, - 99661, 99667, 99679, 99689, 99707, 99709, 99713, 99719, 99721, 99733, - 99761, 99767, 99787, 99793, 99809, 99817, 99823, 99829, 99833, 99839, - 99859, 99871, 99877, 99881, 99901, 99907, 99923, 99929, 99961, 99971, - 99989, 99991, 100003, 100019, 100043, 100049, 100057, 100069, 100103, 100109, -100129, 100151, 100153, 100169, 100183, 100189, 100193, 100207, 100213, 100237, -100267, 100271, 100279, 100291, 100297, 100313, 100333, 100343, 100357, 100361, -100363, 100379, 100391, 100393, 100403, 100411, 100417, 100447, 100459, 100469, -100483, 100493, 100501, 100511, 100517, 100519, 100523, 100537, 100547, 100549, -100559, 100591, 100609, 100613, 100621, 100649, 100669, 100673, 100693, 100699, -100703, 100733, 100741, 100747, 100769, 100787, 100799, 100801, 100811, 100823, -100829, 100847, 100853, 100907, 100913, 100927, 100931, 100937, 100943, 100957, -100981, 100987, 100999, 101009, 101021, 101027, 101051, 101063, 101081, 101089, -101107, 101111, 101113, 101117, 101119, 101141, 101149, 101159, 101161, 101173, -101183, 101197, 101203, 101207, 101209, 101221, 101267, 101273, 101279, 101281, -101287, 101293, 101323, 101333, 101341, 101347, 101359, 101363, 101377, 101383, -101399, 101411, 101419, 101429, 101449, 101467, 101477, 101483, 101489, 101501, -101503, 101513, 101527, 101531, 101533, 101537, 101561, 101573, 101581, 101599, -101603, 101611, 101627, 101641, 101653, 101663, 101681, 101693, 101701, 101719, -101723, 101737, 101741, 101747, 101749, 101771, 101789, 101797, 101807, 101833, -101837, 101839, 101863, 101869, 101873, 101879, 101891, 101917, 101921, 101929, -101939, 101957, 101963, 101977, 101987, 101999, 102001, 102013, 102019, 102023, -102031, 102043, 102059, 102061, 102071, 102077, 102079, 102101, 102103, 102107, -102121, 102139, 102149, 102161, 102181, 102191, 102197, 102199, 102203, 102217, -102229, 102233, 102241, 102251, 102253, 102259, 102293, 102299, 102301, 102317, -102329, 102337, 102359, 102367, 102397, 102407, 102409, 102433, 102437, 102451, -102461, 102481, 102497, 102499, 102503, 102523, 102533, 102539, 102547, 102551, -102559, 102563, 102587, 102593, 102607, 102611, 102643, 102647, 102653, 102667, -102673, 102677, 102679, 102701, 102761, 102763, 102769, 102793, 102797, 102811, -102829, 102841, 102859, 102871, 102877, 102881, 102911, 102913, 102929, 102931, -102953, 102967, 102983, 103001, 103007, 103043, 103049, 103067, 103069, 103079, -103087, 103091, 103093, 103099, 103123, 103141, 103171, 103177, 103183, 103217, -103231, 103237, 103289, 103291, 103307, 103319, 103333, 103349, 103357, 103387, -103391, 103393, 103399, 103409, 103421, 103423, 103451, 103457, 103471, 103483, -103511, 103529, 103549, 103553, 103561, 103567, 103573, 103577, 103583, 103591, -103613, 103619, 103643, 103651, 103657, 103669, 103681, 103687, 103699, 103703, -103723, 103769, 103787, 103801, 103811, 103813, 103837, 103841, 103843, 103867, -103889, 103903, 103913, 103919, 103951, 103963, 103967, 103969, 103979, 103981, -103991, 103993, 103997, 104003, 104009, 104021, 104033, 104047, 104053, 104059, -104087, 104089, 104107, 104113, 104119, 104123, 104147, 104149, 104161, 104173, -104179, 104183, 104207, 104231, 104233, 104239, 104243, 104281, 104287, 104297, -104309, 104311, 104323, 104327, 104347, 104369, 104381, 104383, 104393, 104399, -104417, 104459, 104471, 104473, 104479, 104491, 104513, 104527, 104537, 104543, -104549, 104551, 104561, 104579, 104593, 104597, 104623, 104639, 104651, 104659, -104677, 104681, 104683, 104693, 104701, 104707, 104711, 104717, 104723, 104729, -) diff --git a/Crypto/Util/number.pyi b/Crypto/Util/number.pyi deleted file mode 100644 index f8680bf..0000000 --- a/Crypto/Util/number.pyi +++ /dev/null @@ -1,19 +0,0 @@ -from typing import List, Optional, Callable - - -def ceil_div(n: int, d: int) -> int: ... -def size (N: int) -> int: ... -def getRandomInteger(N: int, randfunc: Optional[Callable]=None) -> int: ... -def getRandomRange(a: int, b: int, randfunc: Optional[Callable]=None) -> int: ... -def getRandomNBitInteger(N: int, randfunc: Optional[Callable]=None) -> int: ... -def GCD(x: int,y: int) -> int: ... -def inverse(u: int, v: int) -> int: ... -def getPrime(N: int, randfunc: Optional[Callable]=None) -> int: ... -def getStrongPrime(N: int, e: Optional[int]=0, false_positive_prob: Optional[float]=1e-6, randfunc: Optional[Callable]=None) -> int: ... -def isPrime(N: int, false_positive_prob: Optional[float]=1e-6, randfunc: Optional[Callable]=None) -> bool: ... -def long_to_bytes(n: int, blocksize: Optional[int]=0) -> bytes: ... -def bytes_to_long(s: bytes) -> int: ... -def long2str(n: int, blocksize: Optional[int]=0) -> bytes: ... -def str2long(s: bytes) -> int: ... - -sieve_base: List[int] diff --git a/Crypto/Util/py3compat.py b/Crypto/Util/py3compat.py deleted file mode 100644 index cf9bb92..0000000 --- a/Crypto/Util/py3compat.py +++ /dev/null @@ -1,160 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Util/py3compat.py : Compatibility code for handling Py3k / Python 2.x -# -# Written in 2010 by Thorsten Behrens -# -# =================================================================== -# The contents of this file are dedicated to the public domain. To -# the extent that dedication to the public domain is not available, -# everyone is granted a worldwide, perpetual, royalty-free, -# non-exclusive license to exercise all rights associated with the -# contents of this file for any purpose whatsoever. -# No rights are reserved. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS -# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN -# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# =================================================================== - -"""Compatibility code for handling string/bytes changes from Python 2.x to Py3k - -In Python 2.x, strings (of type ''str'') contain binary data, including encoded -Unicode text (e.g. UTF-8). The separate type ''unicode'' holds Unicode text. -Unicode literals are specified via the u'...' prefix. Indexing or slicing -either type always produces a string of the same type as the original. -Data read from a file is always of '''str'' type. - -In Python 3.x, strings (type ''str'') may only contain Unicode text. The u'...' -prefix and the ''unicode'' type are now redundant. A new type (called -''bytes'') has to be used for binary data (including any particular -''encoding'' of a string). The b'...' prefix allows one to specify a binary -literal. Indexing or slicing a string produces another string. Slicing a byte -string produces another byte string, but the indexing operation produces an -integer. Data read from a file is of '''str'' type if the file was opened in -text mode, or of ''bytes'' type otherwise. - -Since PyCrypto aims at supporting both Python 2.x and 3.x, the following helper -functions are used to keep the rest of the library as independent as possible -from the actual Python version. - -In general, the code should always deal with binary strings, and use integers -instead of 1-byte character strings. - -b(s) - Take a text string literal (with no prefix or with u'...' prefix) and - make a byte string. -bchr(c) - Take an integer and make a 1-character byte string. -bord(c) - Take the result of indexing on a byte string and make an integer. -tobytes(s) - Take a text string, a byte string, or a sequence of character taken from - a byte string and make a byte string. -""" - -import sys -import abc - - -if sys.version_info[0] == 2: - def b(s): - return s - def bchr(s): - return chr(s) - def bstr(s): - return str(s) - def bord(s): - return ord(s) - def tobytes(s, encoding="latin-1"): - if isinstance(s, unicode): - return s.encode(encoding) - elif isinstance(s, str): - return s - elif isinstance(s, bytearray): - return bytes(s) - else: - return ''.join(s) - def tostr(bs): - return bs - def byte_string(s): - return isinstance(s, str) - - # In Pyton 2.x, StringIO is a stand-alone module - from StringIO import StringIO as BytesIO - - from sys import maxint - - iter_range = xrange - - def is_native_int(x): - return isinstance(x, (int, long)) - - def is_string(x): - return isinstance(x, basestring) - - ABC = abc.ABCMeta('ABC', (object,), {'__slots__': ()}) - - FileNotFoundError = IOError - -else: - def b(s): - return s.encode("latin-1") # utf-8 would cause some side-effects we don't want - def bchr(s): - return bytes([s]) - def bstr(s): - if isinstance(s,str): - return bytes(s,"latin-1") - else: - return bytes(s) - def bord(s): - return s - def tobytes(s, encoding="latin-1"): - if isinstance(s, bytes): - return s - elif isinstance(s, bytearray): - return bytes(s) - elif isinstance(s,str): - return s.encode(encoding) - else: - return bytes([s]) - def tostr(bs): - return bs.decode("latin-1") - def byte_string(s): - return isinstance(s, bytes) - - # In Python 3.x, StringIO is a sub-module of io - from io import BytesIO - from sys import maxsize as maxint - - iter_range = range - - def is_native_int(x): - return isinstance(x, int) - - def is_string(x): - return isinstance(x, str) - - from abc import ABC - - FileNotFoundError = FileNotFoundError - - -def _copy_bytes(start, end, seq): - """Return an immutable copy of a sequence (byte string, byte array, memoryview) - in a certain interval [start:seq]""" - - if isinstance(seq, memoryview): - return seq[start:end].tobytes() - elif isinstance(seq, bytearray): - return bytes(seq[start:end]) - else: - return seq[start:end] - -del sys -del abc diff --git a/Crypto/Util/py3compat.pyi b/Crypto/Util/py3compat.pyi deleted file mode 100644 index 52de77f..0000000 --- a/Crypto/Util/py3compat.pyi +++ /dev/null @@ -1,31 +0,0 @@ -from typing import Union, Any, Optional, IO - -Buffer = Union[bytes, bytearray, memoryview] - -import sys - -def b(s: str) -> bytes: ... -def bchr(s: int) -> bytes: ... -def bord(s: bytes) -> int: ... -def tobytes(s: Union[bytes, str]) -> bytes: ... -def tostr(b: bytes) -> str: ... -def bytestring(x: Any) -> bool: ... - -def is_native_int(s: Any) -> bool: ... -def is_string(x: Any) -> bool: ... - -def BytesIO(b: bytes) -> IO[bytes]: ... - -if sys.version_info[0] == 2: - from sys import maxint - iter_range = xrange - -else: - from sys import maxsize as maxint - iter_range = range - -class FileNotFoundError: - def __init__(self, err: int, msg: str, filename: str) -> None: - pass - -def _copy_bytes(start: Optional[int], end: Optional[int], seq: Buffer) -> bytes: ... diff --git a/Crypto/Util/strxor.py b/Crypto/Util/strxor.py deleted file mode 100644 index 2bff250..0000000 --- a/Crypto/Util/strxor.py +++ /dev/null @@ -1,137 +0,0 @@ -# =================================================================== -# -# Copyright (c) 2014, Legrandin -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# =================================================================== - -from Crypto.Util._raw_api import (load_pycryptodome_raw_lib, c_size_t, - create_string_buffer, get_raw_buffer, - c_uint8_ptr, is_writeable_buffer) - -_raw_strxor = load_pycryptodome_raw_lib("Crypto.Util._strxor", - """ - void strxor(const uint8_t *in1, - const uint8_t *in2, - uint8_t *out, size_t len); - void strxor_c(const uint8_t *in, - uint8_t c, - uint8_t *out, - size_t len); - """) - - -def strxor(term1, term2, output=None): - """XOR two byte strings. - - Args: - term1 (bytes/bytearray/memoryview): - The first term of the XOR operation. - term2 (bytes/bytearray/memoryview): - The second term of the XOR operation. - output (bytearray/memoryview): - The location where the result must be written to. - If ``None``, the result is returned. - :Return: - If ``output`` is ``None``, a new ``bytes`` string with the result. - Otherwise ``None``. - """ - - if len(term1) != len(term2): - raise ValueError("Only byte strings of equal length can be xored") - - if output is None: - result = create_string_buffer(len(term1)) - else: - # Note: output may overlap with either input - result = output - - if not is_writeable_buffer(output): - raise TypeError("output must be a bytearray or a writeable memoryview") - - if len(term1) != len(output): - raise ValueError("output must have the same length as the input" - " (%d bytes)" % len(term1)) - - _raw_strxor.strxor(c_uint8_ptr(term1), - c_uint8_ptr(term2), - c_uint8_ptr(result), - c_size_t(len(term1))) - - if output is None: - return get_raw_buffer(result) - else: - return None - - -def strxor_c(term, c, output=None): - """XOR a byte string with a repeated sequence of characters. - - Args: - term(bytes/bytearray/memoryview): - The first term of the XOR operation. - c (bytes): - The byte that makes up the second term of the XOR operation. - output (None or bytearray/memoryview): - If not ``None``, the location where the result is stored into. - - Return: - If ``output`` is ``None``, a new ``bytes`` string with the result. - Otherwise ``None``. - """ - - if not 0 <= c < 256: - raise ValueError("c must be in range(256)") - - if output is None: - result = create_string_buffer(len(term)) - else: - # Note: output may overlap with either input - result = output - - if not is_writeable_buffer(output): - raise TypeError("output must be a bytearray or a writeable memoryview") - - if len(term) != len(output): - raise ValueError("output must have the same length as the input" - " (%d bytes)" % len(term)) - - _raw_strxor.strxor_c(c_uint8_ptr(term), - c, - c_uint8_ptr(result), - c_size_t(len(term)) - ) - - if output is None: - return get_raw_buffer(result) - else: - return None - - -def _strxor_direct(term1, term2, result): - """Very fast XOR - check conditions!""" - _raw_strxor.strxor(term1, term2, result, c_size_t(len(term1))) - diff --git a/Crypto/Util/strxor.pyi b/Crypto/Util/strxor.pyi deleted file mode 100644 index ca896f3..0000000 --- a/Crypto/Util/strxor.pyi +++ /dev/null @@ -1,6 +0,0 @@ -from typing import Union, Optional - -Buffer = Union[bytes, bytearray, memoryview] - -def strxor(term1: bytes, term2: bytes, output: Optional[Buffer]=...) -> bytes: ... -def strxor_c(term: bytes, c: int, output: Optional[Buffer]=...) -> bytes: ... diff --git a/Crypto/__init__.py b/Crypto/__init__.py deleted file mode 100644 index e7713fe..0000000 --- a/Crypto/__init__.py +++ /dev/null @@ -1,6 +0,0 @@ -__all__ = ['Cipher', 'Hash', 'Protocol', 'PublicKey', 'Util', 'Signature', - 'IO', 'Math'] - -version_info = (3, 10, 1) - -__version__ = ".".join([str(x) for x in version_info]) diff --git a/Crypto/__init__.pyi b/Crypto/__init__.pyi deleted file mode 100644 index bc73446..0000000 --- a/Crypto/__init__.pyi +++ /dev/null @@ -1,4 +0,0 @@ -from typing import Tuple, Union - -version_info : Tuple[int, int, Union[int, str]] -__version__ : str diff --git a/Crypto/__pycache__/__init__.cpython-36.pyc b/Crypto/__pycache__/__init__.cpython-36.pyc deleted file mode 100644 index aa03a44798115315a80969d979412986ec19537c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 457 zcmYLEK}rKL6iqU*j<($MV&*!4gH2q=(91Qv6mCFaYN0SPc` zvaGmkOhM7XF~vvRjo*`C`reKN19{lX;~NVF;DAAZT@6%%dvMlyfDYUT|7UcCN8kly z&?nZJ40+UB_wd%th0$;N7?Q>sqIAv`x#oskG*#}Tt}Nm8TG{Zbyc_F=C_Y`AUT$x0 zT~2PuP*(-9CMN?ktDPo{$x1rLdiCt1-B;4OTuq2`x(X#T3jQy(YKl4ww5dQnLKh>g9#ZKI7qhSZ82%|3nxN>0t diff --git a/Crypto/py.typed b/Crypto/py.typed deleted file mode 100644 index e69de29..0000000

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 IvrXIlFXL}{{Qv*} diff --git a/Crypto/Hash/__pycache__/__init__.cpython-36.pyc b/Crypto/Hash/__pycache__/__init__.cpython-36.pyc deleted file mode 100644 index e00ee4c484a51a90bfee13d32400ced0d206c206..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 288 zcmYk%%}#?r5CGt%#TF_Yy?gDUZh?Xx8e;<{c%W(I#$~f%D#b1=;im@Q$XD8{Z{bCk z_TnV-&CF#o^g(3SVna!;P5GXK$F{p3_6PSVqI?UiYGZF+wjOM0L z!)W6t<0!BPRzl(?`s>T?ISMRqDbzUJSYjfz?bW5a-nlvtm)W)KMD>R)+K#i{a+dCP zu81iilrciSP_4^T&iur-~ diff --git a/Crypto/Hash/_ghash_clmul.abi3.so b/Crypto/Hash/_ghash_clmul.abi3.so deleted file mode 100644 index 7a4dd5807a3e11aeec5b201c0282fe309385aa85..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 50160 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 diff --git a/Crypto/Hash/_ghash_portable.abi3.so b/Crypto/Hash/_ghash_portable.abi3.so deleted file mode 100644 index eb65f83fbbcd1253053a2ab25305865d51fb4fb9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 17432 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 GivI%$YRu&T diff --git a/Crypto/Hash/_keccak.abi3.so b/Crypto/Hash/_keccak.abi3.so deleted file mode 100644 index b5b81aad497b955f1728431dfce8b90ce458594e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 33776 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 Oan~saB~c1dtoSd-R)6>a diff --git a/Crypto/Hash/_poly1305.abi3.so b/Crypto/Hash/_poly1305.abi3.so deleted file mode 100644 index 27c909d20c5efcd676077edcd9f59e9699efb78d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 33360 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 -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# =================================================================== - -from Crypto.Util.py3compat import bord - -from Crypto.Util._raw_api import (load_pycryptodome_raw_lib, - VoidPointer, SmartPointer, - create_string_buffer, - get_raw_buffer, c_size_t, - c_uint8_ptr) - -_raw_keccak_lib = load_pycryptodome_raw_lib("Crypto.Hash._keccak", - """ - int keccak_init(void **state, - size_t capacity_bytes, - uint8_t padding_byte); - int keccak_destroy(void *state); - int keccak_absorb(void *state, - const uint8_t *in, - size_t len); - int keccak_squeeze(const void *state, - uint8_t *out, - size_t len); - int keccak_digest(void *state, uint8_t *digest, size_t len); - """) - -class Keccak_Hash(object): - """A Keccak hash object. - Do not instantiate directly. - Use the :func:`new` function. - - :ivar digest_size: the size in bytes of the resulting hash - :vartype digest_size: integer - """ - - def __init__(self, data, digest_bytes, update_after_digest): - # The size of the resulting hash in bytes. - self.digest_size = digest_bytes - - self._update_after_digest = update_after_digest - self._digest_done = False - - state = VoidPointer() - result = _raw_keccak_lib.keccak_init(state.address_of(), - c_size_t(self.digest_size * 2), - 0x01) - if result: - raise ValueError("Error %d while instantiating keccak" % result) - self._state = SmartPointer(state.get(), - _raw_keccak_lib.keccak_destroy) - if data: - self.update(data) - - def update(self, data): - """Continue hashing of a message by consuming the next chunk of data. - - Args: - data (byte string/byte array/memoryview): The next chunk of the message being hashed. - """ - - if self._digest_done and not self._update_after_digest: - raise TypeError("You can only call 'digest' or 'hexdigest' on this object") - - result = _raw_keccak_lib.keccak_absorb(self._state.get(), - c_uint8_ptr(data), - c_size_t(len(data))) - if result: - raise ValueError("Error %d while updating keccak" % result) - return self - - def digest(self): - """Return the **binary** (non-printable) digest of the message that has been hashed so far. - - :return: The hash digest, computed over the data processed so far. - Binary form. - :rtype: byte string - """ - - self._digest_done = True - bfr = create_string_buffer(self.digest_size) - result = _raw_keccak_lib.keccak_digest(self._state.get(), - bfr, - c_size_t(self.digest_size)) - if result: - raise ValueError("Error %d while squeezing keccak" % result) - - return get_raw_buffer(bfr) - - def hexdigest(self): - """Return the **printable** digest of the message that has been hashed so far. - - :return: The hash digest, computed over the data processed so far. - Hexadecimal encoded. - :rtype: string - """ - - return "".join(["%02x" % bord(x) for x in self.digest()]) - - def new(self, **kwargs): - """Create a fresh Keccak hash object.""" - - if "digest_bytes" not in kwargs and "digest_bits" not in kwargs: - kwargs["digest_bytes"] = self.digest_size - - return new(**kwargs) - - -def new(**kwargs): - """Create a new hash object. - - Args: - data (bytes/bytearray/memoryview): - The very first chunk of the message to hash. - It is equivalent to an early call to :meth:`Keccak_Hash.update`. - digest_bytes (integer): - The size of the digest, in bytes (28, 32, 48, 64). - digest_bits (integer): - The size of the digest, in bits (224, 256, 384, 512). - update_after_digest (boolean): - Whether :meth:`Keccak.digest` can be followed by another - :meth:`Keccak.update` (default: ``False``). - - :Return: A :class:`Keccak_Hash` hash object - """ - - data = kwargs.pop("data", None) - update_after_digest = kwargs.pop("update_after_digest", False) - - digest_bytes = kwargs.pop("digest_bytes", None) - digest_bits = kwargs.pop("digest_bits", None) - if None not in (digest_bytes, digest_bits): - raise TypeError("Only one digest parameter must be provided") - if (None, None) == (digest_bytes, digest_bits): - raise TypeError("Digest size (bits, bytes) not provided") - if digest_bytes is not None: - if digest_bytes not in (28, 32, 48, 64): - raise ValueError("'digest_bytes' must be: 28, 32, 48 or 64") - else: - if digest_bits not in (224, 256, 384, 512): - raise ValueError("'digest_bytes' must be: 224, 256, 384 or 512") - digest_bytes = digest_bits // 8 - - if kwargs: - raise TypeError("Unknown parameters: " + str(kwargs)) - - return Keccak_Hash(data, digest_bytes, update_after_digest) diff --git a/Crypto/Hash/keccak.pyi b/Crypto/Hash/keccak.pyi deleted file mode 100644 index 844d256..0000000 --- a/Crypto/Hash/keccak.pyi +++ /dev/null @@ -1,23 +0,0 @@ -from typing import Union, Any - -Buffer = Union[bytes, bytearray, memoryview] - -class Keccak_Hash(object): - digest_size: int - def __init__(self, - data: Buffer, - digest_bytes: int, - update_after_digest: bool) -> None: ... - def update(self, data: Buffer) -> Keccak_Hash: ... - def digest(self) -> bytes: ... - def hexdigest(self) -> str: ... - def new(self, - data: Buffer = ..., - digest_bytes: int = ..., - digest_bits: int = ..., - update_after_digest: bool = ...) -> Keccak_Hash: ... - -def new(data: Buffer = ..., - digest_bytes: int = ..., - digest_bits: int = ..., - update_after_digest: bool = ...) -> Keccak_Hash: ... diff --git a/Crypto/IO/PEM.py b/Crypto/IO/PEM.py deleted file mode 100644 index 4c07b25..0000000 --- a/Crypto/IO/PEM.py +++ /dev/null @@ -1,189 +0,0 @@ -# -# Util/PEM.py : Privacy Enhanced Mail utilities -# -# =================================================================== -# -# Copyright (c) 2014, Legrandin -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# =================================================================== - -__all__ = ['encode', 'decode'] - -import re -from binascii import a2b_base64, b2a_base64, hexlify, unhexlify - -from Crypto.Hash import MD5 -from Crypto.Util.Padding import pad, unpad -from Crypto.Cipher import DES, DES3, AES -from Crypto.Protocol.KDF import PBKDF1 -from Crypto.Random import get_random_bytes -from Crypto.Util.py3compat import tobytes, tostr - - -def encode(data, marker, passphrase=None, randfunc=None): - """Encode a piece of binary data into PEM format. - - Args: - data (byte string): - The piece of binary data to encode. - marker (string): - The marker for the PEM block (e.g. "PUBLIC KEY"). - Note that there is no official master list for all allowed markers. - Still, you can refer to the OpenSSL_ source code. - passphrase (byte string): - If given, the PEM block will be encrypted. The key is derived from - the passphrase. - randfunc (callable): - Random number generation function; it accepts an integer N and returns - a byte string of random data, N bytes long. If not given, a new one is - instantiated. - - Returns: - The PEM block, as a string. - - .. _OpenSSL: https://github.com/openssl/openssl/blob/master/include/openssl/pem.h - """ - - if randfunc is None: - randfunc = get_random_bytes - - out = "-----BEGIN %s-----\n" % marker - if passphrase: - # We only support 3DES for encryption - salt = randfunc(8) - key = PBKDF1(passphrase, salt, 16, 1, MD5) - key += PBKDF1(key + passphrase, salt, 8, 1, MD5) - objenc = DES3.new(key, DES3.MODE_CBC, salt) - out += "Proc-Type: 4,ENCRYPTED\nDEK-Info: DES-EDE3-CBC,%s\n\n" %\ - tostr(hexlify(salt).upper()) - # Encrypt with PKCS#7 padding - data = objenc.encrypt(pad(data, objenc.block_size)) - elif passphrase is not None: - raise ValueError("Empty password") - - # Each BASE64 line can take up to 64 characters (=48 bytes of data) - # b2a_base64 adds a new line character! - chunks = [tostr(b2a_base64(data[i:i + 48])) - for i in range(0, len(data), 48)] - out += "".join(chunks) - out += "-----END %s-----" % marker - return out - - -def _EVP_BytesToKey(data, salt, key_len): - d = [ b'' ] - m = (key_len + 15 ) // 16 - for _ in range(m): - nd = MD5.new(d[-1] + data + salt).digest() - d.append(nd) - return b"".join(d)[:key_len] - - -def decode(pem_data, passphrase=None): - """Decode a PEM block into binary. - - Args: - pem_data (string): - The PEM block. - passphrase (byte string): - If given and the PEM block is encrypted, - the key will be derived from the passphrase. - - Returns: - A tuple with the binary data, the marker string, and a boolean to - indicate if decryption was performed. - - Raises: - ValueError: if decoding fails, if the PEM file is encrypted and no passphrase has - been provided or if the passphrase is incorrect. - """ - - # Verify Pre-Encapsulation Boundary - r = re.compile(r"\s*-----BEGIN (.*)-----\s+") - m = r.match(pem_data) - if not m: - raise ValueError("Not a valid PEM pre boundary") - marker = m.group(1) - - # Verify Post-Encapsulation Boundary - r = re.compile(r"-----END (.*)-----\s*$") - m = r.search(pem_data) - if not m or m.group(1) != marker: - raise ValueError("Not a valid PEM post boundary") - - # Removes spaces and slit on lines - lines = pem_data.replace(" ", '').split() - - # Decrypts, if necessary - if lines[1].startswith('Proc-Type:4,ENCRYPTED'): - if not passphrase: - raise ValueError("PEM is encrypted, but no passphrase available") - DEK = lines[2].split(':') - if len(DEK) != 2 or DEK[0] != 'DEK-Info': - raise ValueError("PEM encryption format not supported.") - algo, salt = DEK[1].split(',') - salt = unhexlify(tobytes(salt)) - - padding = True - - if algo == "DES-CBC": - key = _EVP_BytesToKey(passphrase, salt, 8) - objdec = DES.new(key, DES.MODE_CBC, salt) - elif algo == "DES-EDE3-CBC": - key = _EVP_BytesToKey(passphrase, salt, 24) - objdec = DES3.new(key, DES3.MODE_CBC, salt) - elif algo == "AES-128-CBC": - key = _EVP_BytesToKey(passphrase, salt[:8], 16) - objdec = AES.new(key, AES.MODE_CBC, salt) - elif algo == "AES-192-CBC": - key = _EVP_BytesToKey(passphrase, salt[:8], 24) - objdec = AES.new(key, AES.MODE_CBC, salt) - elif algo == "AES-256-CBC": - key = _EVP_BytesToKey(passphrase, salt[:8], 32) - objdec = AES.new(key, AES.MODE_CBC, salt) - elif algo.lower() == "id-aes256-gcm": - key = _EVP_BytesToKey(passphrase, salt[:8], 32) - objdec = AES.new(key, AES.MODE_GCM, nonce=salt) - padding = False - else: - raise ValueError("Unsupport PEM encryption algorithm (%s)." % algo) - lines = lines[2:] - else: - objdec = None - - # Decode body - data = a2b_base64(''.join(lines[1:-1])) - enc_flag = False - if objdec: - if padding: - data = unpad(objdec.decrypt(data), objdec.block_size) - else: - # There is no tag, so we don't use decrypt_and_verify - data = objdec.decrypt(data) - enc_flag = True - - return (data, marker, enc_flag) diff --git a/Crypto/IO/PEM.pyi b/Crypto/IO/PEM.pyi deleted file mode 100644 index 2e324c4..0000000 --- a/Crypto/IO/PEM.pyi +++ /dev/null @@ -1,10 +0,0 @@ -from typing import Tuple, Optional, Callable - -def encode(data: bytes, - marke: str, - passphrase: Optional[bytes] = ..., - randfunc: Optional[Callable[[int],bytes]] = ...) -> str: ... - - -def decode(pem_data: str, - passphrase: Optional[bytes] = ...) -> Tuple[bytes, str, bool]: ... diff --git a/Crypto/IO/PKCS8.py b/Crypto/IO/PKCS8.py deleted file mode 100644 index 3bda834..0000000 --- a/Crypto/IO/PKCS8.py +++ /dev/null @@ -1,231 +0,0 @@ -# -# PublicKey/PKCS8.py : PKCS#8 functions -# -# =================================================================== -# -# Copyright (c) 2014, Legrandin -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# =================================================================== - - -from Crypto.Util.py3compat import * - -from Crypto.Util.asn1 import ( - DerNull, - DerSequence, - DerObjectId, - DerOctetString, - ) - -from Crypto.IO._PBES import PBES1, PBES2, PbesError - - -__all__ = ['wrap', 'unwrap'] - - -def wrap(private_key, key_oid, passphrase=None, protection=None, - prot_params=None, key_params=None, randfunc=None): - """Wrap a private key into a PKCS#8 blob (clear or encrypted). - - Args: - - private_key (byte string): - The private key encoded in binary form. The actual encoding is - algorithm specific. In most cases, it is DER. - - key_oid (string): - The object identifier (OID) of the private key to wrap. - It is a dotted string, like ``1.2.840.113549.1.1.1`` (for RSA keys). - - passphrase (bytes string or string): - The secret passphrase from which the wrapping key is derived. - Set it only if encryption is required. - - protection (string): - The identifier of the algorithm to use for securely wrapping the key. - The default value is ``PBKDF2WithHMAC-SHA1AndDES-EDE3-CBC``. - - prot_params (dictionary): - Parameters for the protection algorithm. - - +------------------+-----------------------------------------------+ - | Key | Description | - +==================+===============================================+ - | iteration_count | The KDF algorithm is repeated several times to| - | | slow down brute force attacks on passwords | - | | (called *N* or CPU/memory cost in scrypt). | - | | The default value for PBKDF2 is 1000. | - | | The default value for scrypt is 16384. | - +------------------+-----------------------------------------------+ - | salt_size | Salt is used to thwart dictionary and rainbow | - | | attacks on passwords. The default value is 8 | - | | bytes. | - +------------------+-----------------------------------------------+ - | block_size | *(scrypt only)* Memory-cost (r). The default | - | | value is 8. | - +------------------+-----------------------------------------------+ - | parallelization | *(scrypt only)* CPU-cost (p). The default | - | | value is 1. | - +------------------+-----------------------------------------------+ - - key_params (DER object): - The algorithm parameters associated to the private key. - It is required for algorithms like DSA, but not for others like RSA. - - randfunc (callable): - Random number generation function; it should accept a single integer - N and return a string of random data, N bytes long. - If not specified, a new RNG will be instantiated - from :mod:`Crypto.Random`. - - Return: - The PKCS#8-wrapped private key (possibly encrypted), as a byte string. - """ - - if key_params is None: - key_params = DerNull() - - # - # PrivateKeyInfo ::= SEQUENCE { - # version Version, - # privateKeyAlgorithm PrivateKeyAlgorithmIdentifier, - # privateKey PrivateKey, - # attributes [0] IMPLICIT Attributes OPTIONAL - # } - # - pk_info = DerSequence([ - 0, - DerSequence([ - DerObjectId(key_oid), - key_params - ]), - DerOctetString(private_key) - ]) - pk_info_der = pk_info.encode() - - if passphrase is None: - return pk_info_der - - if not passphrase: - raise ValueError("Empty passphrase") - - # Encryption with PBES2 - passphrase = tobytes(passphrase) - if protection is None: - protection = 'PBKDF2WithHMAC-SHA1AndDES-EDE3-CBC' - return PBES2.encrypt(pk_info_der, passphrase, - protection, prot_params, randfunc) - - -def unwrap(p8_private_key, passphrase=None): - """Unwrap a private key from a PKCS#8 blob (clear or encrypted). - - Args: - p8_private_key (byte string): - The private key wrapped into a PKCS#8 blob, DER encoded. - passphrase (byte string or string): - The passphrase to use to decrypt the blob (if it is encrypted). - - Return: - A tuple containing - - #. the algorithm identifier of the wrapped key (OID, dotted string) - #. the private key (byte string, DER encoded) - #. the associated parameters (byte string, DER encoded) or ``None`` - - Raises: - ValueError : if decoding fails - """ - - if passphrase: - passphrase = tobytes(passphrase) - - found = False - try: - p8_private_key = PBES1.decrypt(p8_private_key, passphrase) - found = True - except PbesError as e: - error_str = "PBES1[%s]" % str(e) - except ValueError: - error_str = "PBES1[Invalid]" - - if not found: - try: - p8_private_key = PBES2.decrypt(p8_private_key, passphrase) - found = True - except PbesError as e: - error_str += ",PBES2[%s]" % str(e) - except ValueError: - error_str += ",PBES2[Invalid]" - - if not found: - raise ValueError("Error decoding PKCS#8 (%s)" % error_str) - - pk_info = DerSequence().decode(p8_private_key, nr_elements=(2, 3, 4)) - if len(pk_info) == 2 and not passphrase: - raise ValueError("Not a valid clear PKCS#8 structure " - "(maybe it is encrypted?)") - - # - # PrivateKeyInfo ::= SEQUENCE { - # version Version, - # privateKeyAlgorithm PrivateKeyAlgorithmIdentifier, - # privateKey PrivateKey, - # attributes [0] IMPLICIT Attributes OPTIONAL - # } - # Version ::= INTEGER - if pk_info[0] != 0: - raise ValueError("Not a valid PrivateKeyInfo SEQUENCE") - - # PrivateKeyAlgorithmIdentifier ::= AlgorithmIdentifier - # - # EncryptedPrivateKeyInfo ::= SEQUENCE { - # encryptionAlgorithm EncryptionAlgorithmIdentifier, - # encryptedData EncryptedData - # } - # EncryptionAlgorithmIdentifier ::= AlgorithmIdentifier - - # AlgorithmIdentifier ::= SEQUENCE { - # algorithm OBJECT IDENTIFIER, - # parameters ANY DEFINED BY algorithm OPTIONAL - # } - - algo = DerSequence().decode(pk_info[1], nr_elements=(1, 2)) - algo_oid = DerObjectId().decode(algo[0]).value - if len(algo) == 1: - algo_params = None - else: - try: - DerNull().decode(algo[1]) - algo_params = None - except: - algo_params = algo[1] - - # EncryptedData ::= OCTET STRING - private_key = DerOctetString().decode(pk_info[2]).payload - - return (algo_oid, private_key, algo_params) diff --git a/Crypto/IO/PKCS8.pyi b/Crypto/IO/PKCS8.pyi deleted file mode 100644 index ad233d4..0000000 --- a/Crypto/IO/PKCS8.pyi +++ /dev/null @@ -1,14 +0,0 @@ -from typing import Dict, Tuple, Optional, Union, Callable - -from Crypto.Util.asn1 import DerObject - -def wrap(private_key: bytes, - key_oid: str, - passphrase: Union[bytes, str] = ..., - protection: str = ..., - prot_params: Dict = ..., - key_params: DerObject = ..., - randfunc: Optional[Callable[[int],str]] = ...) -> bytes: ... - - -def unwrap(p8_private_key: bytes, passphrase: Optional[Union[bytes, str]] = ...) -> Tuple[str, bytes, Optional[bytes]]: ... diff --git a/Crypto/IO/_PBES.py b/Crypto/IO/_PBES.py deleted file mode 100644 index a47c775..0000000 --- a/Crypto/IO/_PBES.py +++ /dev/null @@ -1,435 +0,0 @@ -# -# PublicKey/_PBES.py : Password-Based Encryption functions -# -# =================================================================== -# -# Copyright (c) 2014, Legrandin -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# =================================================================== - -from Crypto import Random -from Crypto.Util.asn1 import ( - DerSequence, DerOctetString, - DerObjectId, DerInteger, - ) - -from Crypto.Util.Padding import pad, unpad -from Crypto.Hash import MD5, SHA1, SHA224, SHA256, SHA384, SHA512 -from Crypto.Cipher import DES, ARC2, DES3, AES -from Crypto.Protocol.KDF import PBKDF1, PBKDF2, scrypt - -_OID_PBE_WITH_MD5_AND_DES_CBC = "1.2.840.113549.1.5.3" -_OID_PBE_WITH_MD5_AND_RC2_CBC = "1.2.840.113549.1.5.6" -_OID_PBE_WITH_SHA1_AND_DES_CBC = "1.2.840.113549.1.5.10" -_OID_PBE_WITH_SHA1_AND_RC2_CBC = "1.2.840.113549.1.5.11" - -_OID_PBES2 = "1.2.840.113549.1.5.13" - -_OID_PBKDF2 = "1.2.840.113549.1.5.12" -_OID_SCRYPT = "1.3.6.1.4.1.11591.4.11" - -_OID_HMAC_SHA1 = "1.2.840.113549.2.7" -_OID_HMAC_SHA224 = "1.2.840.113549.2.8" -_OID_HMAC_SHA256 = "1.2.840.113549.2.9" -_OID_HMAC_SHA384 = "1.2.840.113549.2.10" -_OID_HMAC_SHA512 = "1.2.840.113549.2.11" - -_OID_DES_EDE3_CBC = "1.2.840.113549.3.7" -_OID_AES128_CBC = "2.16.840.1.101.3.4.1.2" -_OID_AES192_CBC = "2.16.840.1.101.3.4.1.22" -_OID_AES256_CBC = "2.16.840.1.101.3.4.1.42" - - -class PbesError(ValueError): - pass - -# These are the ASN.1 definitions used by the PBES1/2 logic: -# -# EncryptedPrivateKeyInfo ::= SEQUENCE { -# encryptionAlgorithm EncryptionAlgorithmIdentifier, -# encryptedData EncryptedData -# } -# -# EncryptionAlgorithmIdentifier ::= AlgorithmIdentifier -# -# EncryptedData ::= OCTET STRING -# -# AlgorithmIdentifier ::= SEQUENCE { -# algorithm OBJECT IDENTIFIER, -# parameters ANY DEFINED BY algorithm OPTIONAL -# } -# -# PBEParameter ::= SEQUENCE { -# salt OCTET STRING (SIZE(8)), -# iterationCount INTEGER -# } -# -# PBES2-params ::= SEQUENCE { -# keyDerivationFunc AlgorithmIdentifier {{PBES2-KDFs}}, -# encryptionScheme AlgorithmIdentifier {{PBES2-Encs}} -# } -# -# PBKDF2-params ::= SEQUENCE { -# salt CHOICE { -# specified OCTET STRING, -# otherSource AlgorithmIdentifier {{PBKDF2-SaltSources}} -# }, -# iterationCount INTEGER (1..MAX), -# keyLength INTEGER (1..MAX) OPTIONAL, -# prf AlgorithmIdentifier {{PBKDF2-PRFs}} DEFAULT algid-hmacWithSHA1 -# } -# -# scrypt-params ::= SEQUENCE { -# salt OCTET STRING, -# costParameter INTEGER (1..MAX), -# blockSize INTEGER (1..MAX), -# parallelizationParameter INTEGER (1..MAX), -# keyLength INTEGER (1..MAX) OPTIONAL -# } - -class PBES1(object): - """Deprecated encryption scheme with password-based key derivation - (originally defined in PKCS#5 v1.5, but still present in `v2.0`__). - - .. __: http://www.ietf.org/rfc/rfc2898.txt - """ - - @staticmethod - def decrypt(data, passphrase): - """Decrypt a piece of data using a passphrase and *PBES1*. - - The algorithm to use is automatically detected. - - :Parameters: - data : byte string - The piece of data to decrypt. - passphrase : byte string - The passphrase to use for decrypting the data. - :Returns: - The decrypted data, as a binary string. - """ - - enc_private_key_info = DerSequence().decode(data) - encrypted_algorithm = DerSequence().decode(enc_private_key_info[0]) - encrypted_data = DerOctetString().decode(enc_private_key_info[1]).payload - - pbe_oid = DerObjectId().decode(encrypted_algorithm[0]).value - cipher_params = {} - if pbe_oid == _OID_PBE_WITH_MD5_AND_DES_CBC: - # PBE_MD5_DES_CBC - hashmod = MD5 - ciphermod = DES - elif pbe_oid == _OID_PBE_WITH_MD5_AND_RC2_CBC: - # PBE_MD5_RC2_CBC - hashmod = MD5 - ciphermod = ARC2 - cipher_params['effective_keylen'] = 64 - elif pbe_oid == _OID_PBE_WITH_SHA1_AND_DES_CBC: - # PBE_SHA1_DES_CBC - hashmod = SHA1 - ciphermod = DES - elif pbe_oid == _OID_PBE_WITH_SHA1_AND_RC2_CBC: - # PBE_SHA1_RC2_CBC - hashmod = SHA1 - ciphermod = ARC2 - cipher_params['effective_keylen'] = 64 - else: - raise PbesError("Unknown OID for PBES1") - - pbe_params = DerSequence().decode(encrypted_algorithm[1], nr_elements=2) - salt = DerOctetString().decode(pbe_params[0]).payload - iterations = pbe_params[1] - - key_iv = PBKDF1(passphrase, salt, 16, iterations, hashmod) - key, iv = key_iv[:8], key_iv[8:] - - cipher = ciphermod.new(key, ciphermod.MODE_CBC, iv, **cipher_params) - pt = cipher.decrypt(encrypted_data) - return unpad(pt, cipher.block_size) - - -class PBES2(object): - """Encryption scheme with password-based key derivation - (defined in `PKCS#5 v2.0`__). - - .. __: http://www.ietf.org/rfc/rfc2898.txt.""" - - @staticmethod - def encrypt(data, passphrase, protection, prot_params=None, randfunc=None): - """Encrypt a piece of data using a passphrase and *PBES2*. - - :Parameters: - data : byte string - The piece of data to encrypt. - passphrase : byte string - The passphrase to use for encrypting the data. - protection : string - The identifier of the encryption algorithm to use. - The default value is '``PBKDF2WithHMAC-SHA1AndDES-EDE3-CBC``'. - prot_params : dictionary - Parameters of the protection algorithm. - - +------------------+-----------------------------------------------+ - | Key | Description | - +==================+===============================================+ - | iteration_count | The KDF algorithm is repeated several times to| - | | slow down brute force attacks on passwords | - | | (called *N* or CPU/memory cost in scrypt). | - | | | - | | The default value for PBKDF2 is 1 000. | - | | The default value for scrypt is 16 384. | - +------------------+-----------------------------------------------+ - | salt_size | Salt is used to thwart dictionary and rainbow | - | | attacks on passwords. The default value is 8 | - | | bytes. | - +------------------+-----------------------------------------------+ - | block_size | *(scrypt only)* Memory-cost (r). The default | - | | value is 8. | - +------------------+-----------------------------------------------+ - | parallelization | *(scrypt only)* CPU-cost (p). The default | - | | value is 1. | - +------------------+-----------------------------------------------+ - - - randfunc : callable - Random number generation function; it should accept - a single integer N and return a string of random data, - N bytes long. If not specified, a new RNG will be - instantiated from ``Crypto.Random``. - - :Returns: - The encrypted data, as a binary string. - """ - - if prot_params is None: - prot_params = {} - - if randfunc is None: - randfunc = Random.new().read - - if protection == 'PBKDF2WithHMAC-SHA1AndDES-EDE3-CBC': - key_size = 24 - module = DES3 - cipher_mode = DES3.MODE_CBC - enc_oid = _OID_DES_EDE3_CBC - elif protection in ('PBKDF2WithHMAC-SHA1AndAES128-CBC', - 'scryptAndAES128-CBC'): - key_size = 16 - module = AES - cipher_mode = AES.MODE_CBC - enc_oid = _OID_AES128_CBC - elif protection in ('PBKDF2WithHMAC-SHA1AndAES192-CBC', - 'scryptAndAES192-CBC'): - key_size = 24 - module = AES - cipher_mode = AES.MODE_CBC - enc_oid = _OID_AES192_CBC - elif protection in ('PBKDF2WithHMAC-SHA1AndAES256-CBC', - 'scryptAndAES256-CBC'): - key_size = 32 - module = AES - cipher_mode = AES.MODE_CBC - enc_oid = _OID_AES256_CBC - else: - raise ValueError("Unknown PBES2 mode") - - # Get random data - iv = randfunc(module.block_size) - salt = randfunc(prot_params.get("salt_size", 8)) - - # Derive key from password - if protection.startswith('PBKDF2'): - count = prot_params.get("iteration_count", 1000) - key = PBKDF2(passphrase, salt, key_size, count) - kdf_info = DerSequence([ - DerObjectId(_OID_PBKDF2), # PBKDF2 - DerSequence([ - DerOctetString(salt), - DerInteger(count) - ]) - ]) - else: - # It must be scrypt - count = prot_params.get("iteration_count", 16384) - scrypt_r = prot_params.get('block_size', 8) - scrypt_p = prot_params.get('parallelization', 1) - key = scrypt(passphrase, salt, key_size, - count, scrypt_r, scrypt_p) - kdf_info = DerSequence([ - DerObjectId(_OID_SCRYPT), # scrypt - DerSequence([ - DerOctetString(salt), - DerInteger(count), - DerInteger(scrypt_r), - DerInteger(scrypt_p) - ]) - ]) - - # Create cipher and use it - cipher = module.new(key, cipher_mode, iv) - encrypted_data = cipher.encrypt(pad(data, cipher.block_size)) - enc_info = DerSequence([ - DerObjectId(enc_oid), - DerOctetString(iv) - ]) - - # Result - enc_private_key_info = DerSequence([ - # encryptionAlgorithm - DerSequence([ - DerObjectId(_OID_PBES2), - DerSequence([ - kdf_info, - enc_info - ]), - ]), - DerOctetString(encrypted_data) - ]) - return enc_private_key_info.encode() - - @staticmethod - def decrypt(data, passphrase): - """Decrypt a piece of data using a passphrase and *PBES2*. - - The algorithm to use is automatically detected. - - :Parameters: - data : byte string - The piece of data to decrypt. - passphrase : byte string - The passphrase to use for decrypting the data. - :Returns: - The decrypted data, as a binary string. - """ - - enc_private_key_info = DerSequence().decode(data, nr_elements=2) - enc_algo = DerSequence().decode(enc_private_key_info[0]) - encrypted_data = DerOctetString().decode(enc_private_key_info[1]).payload - - pbe_oid = DerObjectId().decode(enc_algo[0]).value - if pbe_oid != _OID_PBES2: - raise PbesError("Not a PBES2 object") - - pbes2_params = DerSequence().decode(enc_algo[1], nr_elements=2) - - ### Key Derivation Function selection - kdf_info = DerSequence().decode(pbes2_params[0], nr_elements=2) - kdf_oid = DerObjectId().decode(kdf_info[0]).value - - kdf_key_length = None - - # We only support PBKDF2 or scrypt - if kdf_oid == _OID_PBKDF2: - - pbkdf2_params = DerSequence().decode(kdf_info[1], nr_elements=(2, 3, 4)) - salt = DerOctetString().decode(pbkdf2_params[0]).payload - iteration_count = pbkdf2_params[1] - - left = len(pbkdf2_params) - 2 - idx = 2 - - if left > 0: - try: - kdf_key_length = pbkdf2_params[idx] - 0 - left -= 1 - idx += 1 - except TypeError: - pass - - # Default is HMAC-SHA1 - pbkdf2_prf_oid = "1.2.840.113549.2.7" - if left > 0: - pbkdf2_prf_algo_id = DerSequence().decode(pbkdf2_params[idx]) - pbkdf2_prf_oid = DerObjectId().decode(pbkdf2_prf_algo_id[0]).value - - elif kdf_oid == _OID_SCRYPT: - - scrypt_params = DerSequence().decode(kdf_info[1], nr_elements=(4, 5)) - salt = DerOctetString().decode(scrypt_params[0]).payload - iteration_count, scrypt_r, scrypt_p = [scrypt_params[x] - for x in (1, 2, 3)] - if len(scrypt_params) > 4: - kdf_key_length = scrypt_params[4] - else: - kdf_key_length = None - else: - raise PbesError("Unsupported PBES2 KDF") - - ### Cipher selection - enc_info = DerSequence().decode(pbes2_params[1]) - enc_oid = DerObjectId().decode(enc_info[0]).value - - if enc_oid == _OID_DES_EDE3_CBC: - # DES_EDE3_CBC - ciphermod = DES3 - key_size = 24 - elif enc_oid == _OID_AES128_CBC: - # AES128_CBC - ciphermod = AES - key_size = 16 - elif enc_oid == _OID_AES192_CBC: - # AES192_CBC - ciphermod = AES - key_size = 24 - elif enc_oid == _OID_AES256_CBC: - # AES256_CBC - ciphermod = AES - key_size = 32 - else: - raise PbesError("Unsupported PBES2 cipher") - - if kdf_key_length and kdf_key_length != key_size: - raise PbesError("Mismatch between PBES2 KDF parameters" - " and selected cipher") - - IV = DerOctetString().decode(enc_info[1]).payload - - # Create cipher - if kdf_oid == _OID_PBKDF2: - if pbkdf2_prf_oid == _OID_HMAC_SHA1: - hmac_hash_module = SHA1 - elif pbkdf2_prf_oid == _OID_HMAC_SHA224: - hmac_hash_module = SHA224 - elif pbkdf2_prf_oid == _OID_HMAC_SHA256: - hmac_hash_module = SHA256 - elif pbkdf2_prf_oid == _OID_HMAC_SHA384: - hmac_hash_module = SHA384 - elif pbkdf2_prf_oid == _OID_HMAC_SHA512: - hmac_hash_module = SHA512 - else: - raise PbesError("Unsupported HMAC %s" % pbkdf2_prf_oid) - - key = PBKDF2(passphrase, salt, key_size, iteration_count, - hmac_hash_module=hmac_hash_module) - else: - key = scrypt(passphrase, salt, key_size, iteration_count, - scrypt_r, scrypt_p) - cipher = ciphermod.new(key, ciphermod.MODE_CBC, IV) - - # Decrypt data - pt = cipher.decrypt(encrypted_data) - return unpad(pt, cipher.block_size) diff --git a/Crypto/IO/_PBES.pyi b/Crypto/IO/_PBES.pyi deleted file mode 100644 index a8a34ce..0000000 --- a/Crypto/IO/_PBES.pyi +++ /dev/null @@ -1,19 +0,0 @@ -from typing import Dict, Optional, Callable - -class PbesError(ValueError): - ... - -class PBES1(object): - @staticmethod - def decrypt(data: bytes, passphrase: bytes) -> bytes: ... - -class PBES2(object): - @staticmethod - def encrypt(data: bytes, - passphrase: bytes, - protection: str, - prot_params: Optional[Dict] = ..., - randfunc: Optional[Callable[[int],bytes]] = ...) -> bytes: ... - - @staticmethod - def decrypt(data:bytes, passphrase: bytes) -> bytes: ... diff --git a/Crypto/IO/__init__.py b/Crypto/IO/__init__.py deleted file mode 100644 index 85a0d0b..0000000 --- a/Crypto/IO/__init__.py +++ /dev/null @@ -1,31 +0,0 @@ -# =================================================================== -# -# Copyright (c) 2014, Legrandin -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# =================================================================== - -__all__ = ['PEM', 'PKCS8'] diff --git a/Crypto/Math/Numbers.py b/Crypto/Math/Numbers.py deleted file mode 100644 index c2c4483..0000000 --- a/Crypto/Math/Numbers.py +++ /dev/null @@ -1,42 +0,0 @@ -# =================================================================== -# -# Copyright (c) 2014, Legrandin -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# =================================================================== - -__all__ = ["Integer"] - -try: - from Crypto.Math._IntegerGMP import IntegerGMP as Integer - from Crypto.Math._IntegerGMP import implementation as _implementation -except (ImportError, OSError, AttributeError): - try: - from Crypto.Math._IntegerCustom import IntegerCustom as Integer - from Crypto.Math._IntegerCustom import implementation as _implementation - except (ImportError, OSError): - from Crypto.Math._IntegerNative import IntegerNative as Integer - _implementation = {} diff --git a/Crypto/Math/Numbers.pyi b/Crypto/Math/Numbers.pyi deleted file mode 100644 index 126268c..0000000 --- a/Crypto/Math/Numbers.pyi +++ /dev/null @@ -1,4 +0,0 @@ -from Crypto.Math._IntegerBase import IntegerBase - -class Integer(IntegerBase): - pass diff --git a/Crypto/Math/Primality.py b/Crypto/Math/Primality.py deleted file mode 100644 index 884c418..0000000 --- a/Crypto/Math/Primality.py +++ /dev/null @@ -1,369 +0,0 @@ -# =================================================================== -# -# Copyright (c) 2014, Legrandin -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# =================================================================== - -"""Functions to create and test prime numbers. - -:undocumented: __package__ -""" - -from Crypto import Random -from Crypto.Math.Numbers import Integer - -from Crypto.Util.py3compat import iter_range - -COMPOSITE = 0 -PROBABLY_PRIME = 1 - - -def miller_rabin_test(candidate, iterations, randfunc=None): - """Perform a Miller-Rabin primality test on an integer. - - The test is specified in Section C.3.1 of `FIPS PUB 186-4`__. - - :Parameters: - candidate : integer - The number to test for primality. - iterations : integer - The maximum number of iterations to perform before - declaring a candidate a probable prime. - randfunc : callable - An RNG function where bases are taken from. - - :Returns: - ``Primality.COMPOSITE`` or ``Primality.PROBABLY_PRIME``. - - .. __: http://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.186-4.pdf - """ - - if not isinstance(candidate, Integer): - candidate = Integer(candidate) - - if candidate in (1, 2, 3, 5): - return PROBABLY_PRIME - - if candidate.is_even(): - return COMPOSITE - - one = Integer(1) - minus_one = Integer(candidate - 1) - - if randfunc is None: - randfunc = Random.new().read - - # Step 1 and 2 - m = Integer(minus_one) - a = 0 - while m.is_even(): - m >>= 1 - a += 1 - - # Skip step 3 - - # Step 4 - for i in iter_range(iterations): - - # Step 4.1-2 - base = 1 - while base in (one, minus_one): - base = Integer.random_range(min_inclusive=2, - max_inclusive=candidate - 2, - randfunc=randfunc) - assert(2 <= base <= candidate - 2) - - # Step 4.3-4.4 - z = pow(base, m, candidate) - if z in (one, minus_one): - continue - - # Step 4.5 - for j in iter_range(1, a): - z = pow(z, 2, candidate) - if z == minus_one: - break - if z == one: - return COMPOSITE - else: - return COMPOSITE - - # Step 5 - return PROBABLY_PRIME - - -def lucas_test(candidate): - """Perform a Lucas primality test on an integer. - - The test is specified in Section C.3.3 of `FIPS PUB 186-4`__. - - :Parameters: - candidate : integer - The number to test for primality. - - :Returns: - ``Primality.COMPOSITE`` or ``Primality.PROBABLY_PRIME``. - - .. __: http://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.186-4.pdf - """ - - if not isinstance(candidate, Integer): - candidate = Integer(candidate) - - # Step 1 - if candidate in (1, 2, 3, 5): - return PROBABLY_PRIME - if candidate.is_even() or candidate.is_perfect_square(): - return COMPOSITE - - # Step 2 - def alternate(): - value = 5 - while True: - yield value - if value > 0: - value += 2 - else: - value -= 2 - value = -value - - for D in alternate(): - if candidate in (D, -D): - continue - js = Integer.jacobi_symbol(D, candidate) - if js == 0: - return COMPOSITE - if js == -1: - break - # Found D. P=1 and Q=(1-D)/4 (note that Q is guaranteed to be an integer) - - # Step 3 - # This is \delta(n) = n - jacobi(D/n) - K = candidate + 1 - # Step 4 - r = K.size_in_bits() - 1 - # Step 5 - # U_1=1 and V_1=P - U_i = Integer(1) - V_i = Integer(1) - U_temp = Integer(0) - V_temp = Integer(0) - # Step 6 - for i in iter_range(r - 1, -1, -1): - # Square - # U_temp = U_i * V_i % candidate - U_temp.set(U_i) - U_temp *= V_i - U_temp %= candidate - # V_temp = (((V_i ** 2 + (U_i ** 2 * D)) * K) >> 1) % candidate - V_temp.set(U_i) - V_temp *= U_i - V_temp *= D - V_temp.multiply_accumulate(V_i, V_i) - if V_temp.is_odd(): - V_temp += candidate - V_temp >>= 1 - V_temp %= candidate - # Multiply - if K.get_bit(i): - # U_i = (((U_temp + V_temp) * K) >> 1) % candidate - U_i.set(U_temp) - U_i += V_temp - if U_i.is_odd(): - U_i += candidate - U_i >>= 1 - U_i %= candidate - # V_i = (((V_temp + U_temp * D) * K) >> 1) % candidate - V_i.set(V_temp) - V_i.multiply_accumulate(U_temp, D) - if V_i.is_odd(): - V_i += candidate - V_i >>= 1 - V_i %= candidate - else: - U_i.set(U_temp) - V_i.set(V_temp) - # Step 7 - if U_i == 0: - return PROBABLY_PRIME - return COMPOSITE - - -from Crypto.Util.number import sieve_base as _sieve_base_large -## The optimal number of small primes to use for the sieve -## is probably dependent on the platform and the candidate size -_sieve_base = set(_sieve_base_large[:100]) - - -def test_probable_prime(candidate, randfunc=None): - """Test if a number is prime. - - A number is qualified as prime if it passes a certain - number of Miller-Rabin tests (dependent on the size - of the number, but such that probability of a false - positive is less than 10^-30) and a single Lucas test. - - For instance, a 1024-bit candidate will need to pass - 4 Miller-Rabin tests. - - :Parameters: - candidate : integer - The number to test for primality. - randfunc : callable - The routine to draw random bytes from to select Miller-Rabin bases. - :Returns: - ``PROBABLE_PRIME`` if the number if prime with very high probability. - ``COMPOSITE`` if the number is a composite. - For efficiency reasons, ``COMPOSITE`` is also returned for small primes. - """ - - if randfunc is None: - randfunc = Random.new().read - - if not isinstance(candidate, Integer): - candidate = Integer(candidate) - - # First, check trial division by the smallest primes - if int(candidate) in _sieve_base: - return PROBABLY_PRIME - try: - map(candidate.fail_if_divisible_by, _sieve_base) - except ValueError: - return COMPOSITE - - # These are the number of Miller-Rabin iterations s.t. p(k, t) < 1E-30, - # with p(k, t) being the probability that a randomly chosen k-bit number - # is composite but still survives t MR iterations. - mr_ranges = ((220, 30), (280, 20), (390, 15), (512, 10), - (620, 7), (740, 6), (890, 5), (1200, 4), - (1700, 3), (3700, 2)) - - bit_size = candidate.size_in_bits() - try: - mr_iterations = list(filter(lambda x: bit_size < x[0], - mr_ranges))[0][1] - except IndexError: - mr_iterations = 1 - - if miller_rabin_test(candidate, mr_iterations, - randfunc=randfunc) == COMPOSITE: - return COMPOSITE - if lucas_test(candidate) == COMPOSITE: - return COMPOSITE - return PROBABLY_PRIME - - -def generate_probable_prime(**kwargs): - """Generate a random probable prime. - - The prime will not have any specific properties - (e.g. it will not be a *strong* prime). - - Random numbers are evaluated for primality until one - passes all tests, consisting of a certain number of - Miller-Rabin tests with random bases followed by - a single Lucas test. - - The number of Miller-Rabin iterations is chosen such that - the probability that the output number is a non-prime is - less than 1E-30 (roughly 2^{-100}). - - This approach is compliant to `FIPS PUB 186-4`__. - - :Keywords: - exact_bits : integer - The desired size in bits of the probable prime. - It must be at least 160. - randfunc : callable - An RNG function where candidate primes are taken from. - prime_filter : callable - A function that takes an Integer as parameter and returns - True if the number can be passed to further primality tests, - False if it should be immediately discarded. - - :Return: - A probable prime in the range 2^exact_bits > p > 2^(exact_bits-1). - - .. __: http://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.186-4.pdf - """ - - exact_bits = kwargs.pop("exact_bits", None) - randfunc = kwargs.pop("randfunc", None) - prime_filter = kwargs.pop("prime_filter", lambda x: True) - if kwargs: - raise ValueError("Unknown parameters: " + kwargs.keys()) - - if exact_bits is None: - raise ValueError("Missing exact_bits parameter") - if exact_bits < 160: - raise ValueError("Prime number is not big enough.") - - if randfunc is None: - randfunc = Random.new().read - - result = COMPOSITE - while result == COMPOSITE: - candidate = Integer.random(exact_bits=exact_bits, - randfunc=randfunc) | 1 - if not prime_filter(candidate): - continue - result = test_probable_prime(candidate, randfunc) - return candidate - - -def generate_probable_safe_prime(**kwargs): - """Generate a random, probable safe prime. - - Note this operation is much slower than generating a simple prime. - - :Keywords: - exact_bits : integer - The desired size in bits of the probable safe prime. - randfunc : callable - An RNG function where candidate primes are taken from. - - :Return: - A probable safe prime in the range - 2^exact_bits > p > 2^(exact_bits-1). - """ - - exact_bits = kwargs.pop("exact_bits", None) - randfunc = kwargs.pop("randfunc", None) - if kwargs: - raise ValueError("Unknown parameters: " + kwargs.keys()) - - if randfunc is None: - randfunc = Random.new().read - - result = COMPOSITE - while result == COMPOSITE: - q = generate_probable_prime(exact_bits=exact_bits - 1, randfunc=randfunc) - candidate = q * 2 + 1 - if candidate.size_in_bits() != exact_bits: - continue - result = test_probable_prime(candidate, randfunc=randfunc) - return candidate diff --git a/Crypto/Math/Primality.pyi b/Crypto/Math/Primality.pyi deleted file mode 100644 index 7813483..0000000 --- a/Crypto/Math/Primality.pyi +++ /dev/null @@ -1,18 +0,0 @@ -from typing import Callable, Optional, Union, Set - -PrimeResult = int - -COMPOSITE: PrimeResult -PROBABLY_PRIME: PrimeResult - -def miller_rabin_test(candidate: int, iterations: int, randfunc: Optional[Callable[[int],bytes]]=None) -> PrimeResult: ... -def lucas_test(candidate: int) -> PrimeResult: ... -_sieve_base: Set[int] -def test_probable_prime(candidate: int, randfunc: Optional[Callable[[int],bytes]]=None) -> PrimeResult: ... -def generate_probable_prime(*, - exact_bits: int = ..., - randfunc: Callable[[int],bytes] = ..., - prime_filter: Callable[[int],bool] = ...) -> int: ... -def generate_probable_safe_prime(*, - exact_bits: int = ..., - randfunc: Callable[[int],bytes] = ...) -> int: ... diff --git a/Crypto/Math/_IntegerBase.py b/Crypto/Math/_IntegerBase.py deleted file mode 100644 index 48e8f48..0000000 --- a/Crypto/Math/_IntegerBase.py +++ /dev/null @@ -1,392 +0,0 @@ -# =================================================================== -# -# Copyright (c) 2018, Helder Eijs -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# =================================================================== - -import abc - -from Crypto.Util.py3compat import iter_range, bord, bchr, ABC - -from Crypto import Random - - -class IntegerBase(ABC): - - # Conversions - @abc.abstractmethod - def __int__(self): - pass - - @abc.abstractmethod - def __str__(self): - pass - - @abc.abstractmethod - def __repr__(self): - pass - - @abc.abstractmethod - def to_bytes(self, block_size=0): - pass - - @staticmethod - @abc.abstractmethod - def from_bytes(byte_string): - pass - - # Relations - @abc.abstractmethod - def __eq__(self, term): - pass - - @abc.abstractmethod - def __ne__(self, term): - pass - - @abc.abstractmethod - def __lt__(self, term): - pass - - @abc.abstractmethod - def __le__(self, term): - pass - - @abc.abstractmethod - def __gt__(self, term): - pass - - @abc.abstractmethod - def __ge__(self, term): - pass - - @abc.abstractmethod - def __nonzero__(self): - pass - __bool__ = __nonzero__ - - @abc.abstractmethod - def is_negative(self): - pass - - # Arithmetic operations - @abc.abstractmethod - def __add__(self, term): - pass - - @abc.abstractmethod - def __sub__(self, term): - pass - - @abc.abstractmethod - def __mul__(self, factor): - pass - - @abc.abstractmethod - def __floordiv__(self, divisor): - pass - - @abc.abstractmethod - def __mod__(self, divisor): - pass - - @abc.abstractmethod - def inplace_pow(self, exponent, modulus=None): - pass - - @abc.abstractmethod - def __pow__(self, exponent, modulus=None): - pass - - @abc.abstractmethod - def __abs__(self): - pass - - @abc.abstractmethod - def sqrt(self, modulus=None): - pass - - @abc.abstractmethod - def __iadd__(self, term): - pass - - @abc.abstractmethod - def __isub__(self, term): - pass - - @abc.abstractmethod - def __imul__(self, term): - pass - - @abc.abstractmethod - def __imod__(self, term): - pass - - # Boolean/bit operations - @abc.abstractmethod - def __and__(self, term): - pass - - @abc.abstractmethod - def __or__(self, term): - pass - - @abc.abstractmethod - def __rshift__(self, pos): - pass - - @abc.abstractmethod - def __irshift__(self, pos): - pass - - @abc.abstractmethod - def __lshift__(self, pos): - pass - - @abc.abstractmethod - def __ilshift__(self, pos): - pass - - @abc.abstractmethod - def get_bit(self, n): - pass - - # Extra - @abc.abstractmethod - def is_odd(self): - pass - - @abc.abstractmethod - def is_even(self): - pass - - @abc.abstractmethod - def size_in_bits(self): - pass - - @abc.abstractmethod - def size_in_bytes(self): - pass - - @abc.abstractmethod - def is_perfect_square(self): - pass - - @abc.abstractmethod - def fail_if_divisible_by(self, small_prime): - pass - - @abc.abstractmethod - def multiply_accumulate(self, a, b): - pass - - @abc.abstractmethod - def set(self, source): - pass - - @abc.abstractmethod - def inplace_inverse(self, modulus): - pass - - @abc.abstractmethod - def inverse(self, modulus): - pass - - @abc.abstractmethod - def gcd(self, term): - pass - - @abc.abstractmethod - def lcm(self, term): - pass - - @staticmethod - @abc.abstractmethod - def jacobi_symbol(a, n): - pass - - @staticmethod - def _tonelli_shanks(n, p): - """Tonelli-shanks algorithm for computing the square root - of n modulo a prime p. - - n must be in the range [0..p-1]. - p must be at least even. - - The return value r is the square root of modulo p. If non-zero, - another solution will also exist (p-r). - - Note we cannot assume that p is really a prime: if it's not, - we can either raise an exception or return the correct value. - """ - - # See https://rosettacode.org/wiki/Tonelli-Shanks_algorithm - - if n in (0, 1): - return n - - if p % 4 == 3: - root = pow(n, (p + 1) // 4, p) - if pow(root, 2, p) != n: - raise ValueError("Cannot compute square root") - return root - - s = 1 - q = (p - 1) // 2 - while not (q & 1): - s += 1 - q >>= 1 - - z = n.__class__(2) - while True: - euler = pow(z, (p - 1) // 2, p) - if euler == 1: - z += 1 - continue - if euler == p - 1: - break - # Most probably p is not a prime - raise ValueError("Cannot compute square root") - - m = s - c = pow(z, q, p) - t = pow(n, q, p) - r = pow(n, (q + 1) // 2, p) - - while t != 1: - for i in iter_range(0, m): - if pow(t, 2**i, p) == 1: - break - if i == m: - raise ValueError("Cannot compute square root of %d mod %d" % (n, p)) - b = pow(c, 2**(m - i - 1), p) - m = i - c = b**2 % p - t = (t * b**2) % p - r = (r * b) % p - - if pow(r, 2, p) != n: - raise ValueError("Cannot compute square root") - - return r - - @classmethod - def random(cls, **kwargs): - """Generate a random natural integer of a certain size. - - :Keywords: - exact_bits : positive integer - The length in bits of the resulting random Integer number. - The number is guaranteed to fulfil the relation: - - 2^bits > result >= 2^(bits - 1) - - max_bits : positive integer - The maximum length in bits of the resulting random Integer number. - The number is guaranteed to fulfil the relation: - - 2^bits > result >=0 - - randfunc : callable - A function that returns a random byte string. The length of the - byte string is passed as parameter. Optional. - If not provided (or ``None``), randomness is read from the system RNG. - - :Return: a Integer object - """ - - exact_bits = kwargs.pop("exact_bits", None) - max_bits = kwargs.pop("max_bits", None) - randfunc = kwargs.pop("randfunc", None) - - if randfunc is None: - randfunc = Random.new().read - - if exact_bits is None and max_bits is None: - raise ValueError("Either 'exact_bits' or 'max_bits' must be specified") - - if exact_bits is not None and max_bits is not None: - raise ValueError("'exact_bits' and 'max_bits' are mutually exclusive") - - bits = exact_bits or max_bits - bytes_needed = ((bits - 1) // 8) + 1 - significant_bits_msb = 8 - (bytes_needed * 8 - bits) - msb = bord(randfunc(1)[0]) - if exact_bits is not None: - msb |= 1 << (significant_bits_msb - 1) - msb &= (1 << significant_bits_msb) - 1 - - return cls.from_bytes(bchr(msb) + randfunc(bytes_needed - 1)) - - @classmethod - def random_range(cls, **kwargs): - """Generate a random integer within a given internal. - - :Keywords: - min_inclusive : integer - The lower end of the interval (inclusive). - max_inclusive : integer - The higher end of the interval (inclusive). - max_exclusive : integer - The higher end of the interval (exclusive). - randfunc : callable - A function that returns a random byte string. The length of the - byte string is passed as parameter. Optional. - If not provided (or ``None``), randomness is read from the system RNG. - :Returns: - An Integer randomly taken in the given interval. - """ - - min_inclusive = kwargs.pop("min_inclusive", None) - max_inclusive = kwargs.pop("max_inclusive", None) - max_exclusive = kwargs.pop("max_exclusive", None) - randfunc = kwargs.pop("randfunc", None) - - if kwargs: - raise ValueError("Unknown keywords: " + str(kwargs.keys)) - if None not in (max_inclusive, max_exclusive): - raise ValueError("max_inclusive and max_exclusive cannot be both" - " specified") - if max_exclusive is not None: - max_inclusive = max_exclusive - 1 - if None in (min_inclusive, max_inclusive): - raise ValueError("Missing keyword to identify the interval") - - if randfunc is None: - randfunc = Random.new().read - - norm_maximum = max_inclusive - min_inclusive - bits_needed = cls(norm_maximum).size_in_bits() - - norm_candidate = -1 - while not 0 <= norm_candidate <= norm_maximum: - norm_candidate = cls.random( - max_bits=bits_needed, - randfunc=randfunc - ) - return norm_candidate + min_inclusive - diff --git a/Crypto/Math/_IntegerBase.pyi b/Crypto/Math/_IntegerBase.pyi deleted file mode 100644 index 3f534db..0000000 --- a/Crypto/Math/_IntegerBase.pyi +++ /dev/null @@ -1,61 +0,0 @@ -from typing import Optional, Union, Callable - -RandFunc = Callable[[int],int] - -class IntegerBase: - - def __int__(self) -> int: ... - def __str__(self) -> str: ... - def __repr__(self) -> str: ... - def to_bytes(self, block_size: Optional[int]=0) -> bytes: ... - @staticmethod - def from_bytes(byte_string: bytes) -> IntegerBase: ... - def __eq__(self, term: object) -> bool: ... - def __ne__(self, term: object) -> bool: ... - def __lt__(self, term: Union[IntegerBase, int]) -> bool: ... - def __le__(self, term: Union[IntegerBase, int]) -> bool: ... - def __gt__(self, term: Union[IntegerBase, int]) -> bool: ... - def __ge__(self, term: Union[IntegerBase, int]) -> bool: ... - def __nonzero__(self) -> bool: ... - def is_negative(self) -> bool: ... - def __add__(self, term: Union[IntegerBase, int]) -> IntegerBase: ... - def __sub__(self, term: Union[IntegerBase, int]) -> IntegerBase: ... - def __mul__(self, term: Union[IntegerBase, int]) -> IntegerBase: ... - def __floordiv__(self, divisor: Union[IntegerBase, int]) -> IntegerBase: ... - def __mod__(self, divisor: Union[IntegerBase, int]) -> IntegerBase: ... - def inplace_pow(self, exponent: int, modulus: Optional[Union[IntegerBase, int]]=None) -> IntegerBase: ... - def __pow__(self, exponent: int, modulus: Optional[int]) -> IntegerBase: ... - def __abs__(self) -> IntegerBase: ... - def sqrt(self, modulus: Optional[int]) -> IntegerBase: ... - def __iadd__(self, term: Union[IntegerBase, int]) -> IntegerBase: ... - def __isub__(self, term: Union[IntegerBase, int]) -> IntegerBase: ... - def __imul__(self, term: Union[IntegerBase, int]) -> IntegerBase: ... - def __imod__(self, divisor: Union[IntegerBase, int]) -> IntegerBase: ... - def __and__(self, term: Union[IntegerBase, int]) -> IntegerBase: ... - def __or__(self, term: Union[IntegerBase, int]) -> IntegerBase: ... - def __rshift__(self, pos: Union[IntegerBase, int]) -> IntegerBase: ... - def __irshift__(self, pos: Union[IntegerBase, int]) -> IntegerBase: ... - def __lshift__(self, pos: Union[IntegerBase, int]) -> IntegerBase: ... - def __ilshift__(self, pos: Union[IntegerBase, int]) -> IntegerBase: ... - def get_bit(self, n: int) -> bool: ... - def is_odd(self) -> bool: ... - def is_even(self) -> bool: ... - def size_in_bits(self) -> int: ... - def size_in_bytes(self) -> int: ... - def is_perfect_square(self) -> bool: ... - def fail_if_divisible_by(self, small_prime: Union[IntegerBase, int]) -> None: ... - def multiply_accumulate(self, a: Union[IntegerBase, int], b: Union[IntegerBase, int]) -> IntegerBase: ... - def set(self, source: Union[IntegerBase, int]) -> IntegerBase: ... - def inplace_inverse(self, modulus: Union[IntegerBase, int]) -> IntegerBase: ... - def inverse(self, modulus: Union[IntegerBase, int]) -> IntegerBase: ... - def gcd(self, term: Union[IntegerBase, int]) -> IntegerBase: ... - def lcm(self, term: Union[IntegerBase, int]) -> IntegerBase: ... - @staticmethod - def jacobi_symbol(a: Union[IntegerBase, int], n: Union[IntegerBase, int]) -> IntegerBase: ... - @staticmethod - def _tonelli_shanks(n: Union[IntegerBase, int], p: Union[IntegerBase, int]) -> IntegerBase : ... - @classmethod - def random(cls, **kwargs: Union[int,RandFunc]) -> IntegerBase : ... - @classmethod - def random_range(cls, **kwargs: Union[int,RandFunc]) -> IntegerBase : ... - diff --git a/Crypto/Math/_IntegerCustom.py b/Crypto/Math/_IntegerCustom.py deleted file mode 100644 index 3ed1dda..0000000 --- a/Crypto/Math/_IntegerCustom.py +++ /dev/null @@ -1,111 +0,0 @@ -# =================================================================== -# -# Copyright (c) 2018, Helder Eijs -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# =================================================================== - -from ._IntegerNative import IntegerNative - -from Crypto.Util.number import long_to_bytes, bytes_to_long - -from Crypto.Util._raw_api import (load_pycryptodome_raw_lib, - create_string_buffer, - get_raw_buffer, backend, - c_size_t, c_ulonglong) - - -from Crypto.Random.random import getrandbits - -c_defs = """ -int monty_pow(const uint8_t *base, - const uint8_t *exp, - const uint8_t *modulus, - uint8_t *out, - size_t len, - uint64_t seed); -""" - - -_raw_montgomery = load_pycryptodome_raw_lib("Crypto.Math._modexp", c_defs) -implementation = {"library": "custom", "api": backend} - - -class IntegerCustom(IntegerNative): - - @staticmethod - def from_bytes(byte_string): - return IntegerCustom(bytes_to_long(byte_string)) - - def inplace_pow(self, exponent, modulus=None): - exp_value = int(exponent) - if exp_value < 0: - raise ValueError("Exponent must not be negative") - - # No modular reduction - if modulus is None: - self._value = pow(self._value, exp_value) - return self - - # With modular reduction - mod_value = int(modulus) - if mod_value < 0: - raise ValueError("Modulus must be positive") - if mod_value == 0: - raise ZeroDivisionError("Modulus cannot be zero") - - # C extension only works with odd moduli - if (mod_value & 1) == 0: - self._value = pow(self._value, exp_value, mod_value) - return self - - # C extension only works with bases smaller than modulus - if self._value >= mod_value: - self._value %= mod_value - - max_len = len(long_to_bytes(max(self._value, exp_value, mod_value))) - - base_b = long_to_bytes(self._value, max_len) - exp_b = long_to_bytes(exp_value, max_len) - modulus_b = long_to_bytes(mod_value, max_len) - - out = create_string_buffer(max_len) - - error = _raw_montgomery.monty_pow( - out, - base_b, - exp_b, - modulus_b, - c_size_t(max_len), - c_ulonglong(getrandbits(64)) - ) - - if error: - raise ValueError("monty_pow failed with error: %d" % error) - - result = bytes_to_long(get_raw_buffer(out)) - self._value = result - return self diff --git a/Crypto/Math/_IntegerCustom.pyi b/Crypto/Math/_IntegerCustom.pyi deleted file mode 100644 index 2dd75c7..0000000 --- a/Crypto/Math/_IntegerCustom.pyi +++ /dev/null @@ -1,8 +0,0 @@ -from typing import Any - -from ._IntegerNative import IntegerNative - -_raw_montgomery = Any - -class IntegerCustom(IntegerNative): - pass diff --git a/Crypto/Math/_IntegerGMP.py b/Crypto/Math/_IntegerGMP.py deleted file mode 100644 index a231e9d..0000000 --- a/Crypto/Math/_IntegerGMP.py +++ /dev/null @@ -1,708 +0,0 @@ -# =================================================================== -# -# Copyright (c) 2014, Legrandin -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# =================================================================== - -import sys - -from Crypto.Util.py3compat import tobytes, is_native_int - -from Crypto.Util._raw_api import (backend, load_lib, - get_raw_buffer, get_c_string, - null_pointer, create_string_buffer, - c_ulong, c_size_t) - -from ._IntegerBase import IntegerBase - -gmp_defs = """typedef unsigned long UNIX_ULONG; - typedef struct { int a; int b; void *c; } MPZ; - typedef MPZ mpz_t[1]; - typedef UNIX_ULONG mp_bitcnt_t; - void __gmpz_init (mpz_t x); - void __gmpz_init_set (mpz_t rop, const mpz_t op); - void __gmpz_init_set_ui (mpz_t rop, UNIX_ULONG op); - int __gmp_sscanf (const char *s, const char *fmt, ...); - void __gmpz_set (mpz_t rop, const mpz_t op); - int __gmp_snprintf (uint8_t *buf, size_t size, const char *fmt, ...); - void __gmpz_add (mpz_t rop, const mpz_t op1, const mpz_t op2); - void __gmpz_add_ui (mpz_t rop, const mpz_t op1, UNIX_ULONG op2); - void __gmpz_sub_ui (mpz_t rop, const mpz_t op1, UNIX_ULONG op2); - void __gmpz_addmul (mpz_t rop, const mpz_t op1, const mpz_t op2); - void __gmpz_addmul_ui (mpz_t rop, const mpz_t op1, UNIX_ULONG op2); - void __gmpz_submul_ui (mpz_t rop, const mpz_t op1, UNIX_ULONG op2); - void __gmpz_import (mpz_t rop, size_t count, int order, size_t size, - int endian, size_t nails, const void *op); - void * __gmpz_export (void *rop, size_t *countp, int order, - size_t size, - int endian, size_t nails, const mpz_t op); - size_t __gmpz_sizeinbase (const mpz_t op, int base); - void __gmpz_sub (mpz_t rop, const mpz_t op1, const mpz_t op2); - void __gmpz_mul (mpz_t rop, const mpz_t op1, const mpz_t op2); - void __gmpz_mul_ui (mpz_t rop, const mpz_t op1, UNIX_ULONG op2); - int __gmpz_cmp (const mpz_t op1, const mpz_t op2); - void __gmpz_powm (mpz_t rop, const mpz_t base, const mpz_t exp, const - mpz_t mod); - void __gmpz_powm_ui (mpz_t rop, const mpz_t base, UNIX_ULONG exp, - const mpz_t mod); - void __gmpz_pow_ui (mpz_t rop, const mpz_t base, UNIX_ULONG exp); - void __gmpz_sqrt(mpz_t rop, const mpz_t op); - void __gmpz_mod (mpz_t r, const mpz_t n, const mpz_t d); - void __gmpz_neg (mpz_t rop, const mpz_t op); - void __gmpz_abs (mpz_t rop, const mpz_t op); - void __gmpz_and (mpz_t rop, const mpz_t op1, const mpz_t op2); - void __gmpz_ior (mpz_t rop, const mpz_t op1, const mpz_t op2); - void __gmpz_clear (mpz_t x); - void __gmpz_tdiv_q_2exp (mpz_t q, const mpz_t n, mp_bitcnt_t b); - void __gmpz_fdiv_q (mpz_t q, const mpz_t n, const mpz_t d); - void __gmpz_mul_2exp (mpz_t rop, const mpz_t op1, mp_bitcnt_t op2); - int __gmpz_tstbit (const mpz_t op, mp_bitcnt_t bit_index); - int __gmpz_perfect_square_p (const mpz_t op); - int __gmpz_jacobi (const mpz_t a, const mpz_t b); - void __gmpz_gcd (mpz_t rop, const mpz_t op1, const mpz_t op2); - UNIX_ULONG __gmpz_gcd_ui (mpz_t rop, const mpz_t op1, - UNIX_ULONG op2); - void __gmpz_lcm (mpz_t rop, const mpz_t op1, const mpz_t op2); - int __gmpz_invert (mpz_t rop, const mpz_t op1, const mpz_t op2); - int __gmpz_divisible_p (const mpz_t n, const mpz_t d); - int __gmpz_divisible_ui_p (const mpz_t n, UNIX_ULONG d); - """ - -if sys.platform == "win32": - raise ImportError("Not using GMP on Windows") - -lib = load_lib("gmp", gmp_defs) -implementation = {"library": "gmp", "api": backend} - -if hasattr(lib, "__mpir_version"): - raise ImportError("MPIR library detected") - -# In order to create a function that returns a pointer to -# a new MPZ structure, we need to break the abstraction -# and know exactly what ffi backend we have -if implementation["api"] == "ctypes": - from ctypes import Structure, c_int, c_void_p, byref - - class _MPZ(Structure): - _fields_ = [('_mp_alloc', c_int), - ('_mp_size', c_int), - ('_mp_d', c_void_p)] - - def new_mpz(): - return byref(_MPZ()) - -else: - # We are using CFFI - from Crypto.Util._raw_api import ffi - - def new_mpz(): - return ffi.new("MPZ*") - - -# Lazy creation of GMP methods -class _GMP(object): - - def __getattr__(self, name): - if name.startswith("mpz_"): - func_name = "__gmpz_" + name[4:] - elif name.startswith("gmp_"): - func_name = "__gmp_" + name[4:] - else: - raise AttributeError("Attribute %s is invalid" % name) - func = getattr(lib, func_name) - setattr(self, name, func) - return func - - -_gmp = _GMP() - - -class IntegerGMP(IntegerBase): - """A fast, arbitrary precision integer""" - - _zero_mpz_p = new_mpz() - _gmp.mpz_init_set_ui(_zero_mpz_p, c_ulong(0)) - - def __init__(self, value): - """Initialize the integer to the given value.""" - - self._mpz_p = new_mpz() - self._initialized = False - - if isinstance(value, float): - raise ValueError("A floating point type is not a natural number") - - self._initialized = True - - if is_native_int(value): - _gmp.mpz_init(self._mpz_p) - result = _gmp.gmp_sscanf(tobytes(str(value)), b"%Zd", self._mpz_p) - if result != 1: - raise ValueError("Error converting '%d'" % value) - elif isinstance(value, IntegerGMP): - _gmp.mpz_init_set(self._mpz_p, value._mpz_p) - else: - raise NotImplementedError - - # Conversions - def __int__(self): - # buf will contain the integer encoded in decimal plus the trailing - # zero, and possibly the negative sign. - # dig10(x) < log10(x) + 1 = log2(x)/log2(10) + 1 < log2(x)/3 + 1 - buf_len = _gmp.mpz_sizeinbase(self._mpz_p, 2) // 3 + 3 - buf = create_string_buffer(buf_len) - - _gmp.gmp_snprintf(buf, c_size_t(buf_len), b"%Zd", self._mpz_p) - return int(get_c_string(buf)) - - def __str__(self): - return str(int(self)) - - def __repr__(self): - return "Integer(%s)" % str(self) - - # Only Python 2.x - def __hex__(self): - return hex(int(self)) - - # Only Python 3.x - def __index__(self): - return int(self) - - def to_bytes(self, block_size=0): - """Convert the number into a byte string. - - This method encodes the number in network order and prepends - as many zero bytes as required. It only works for non-negative - values. - - :Parameters: - block_size : integer - The exact size the output byte string must have. - If zero, the string has the minimal length. - :Returns: - A byte string. - :Raise ValueError: - If the value is negative or if ``block_size`` is - provided and the length of the byte string would exceed it. - """ - - if self < 0: - raise ValueError("Conversion only valid for non-negative numbers") - - buf_len = (_gmp.mpz_sizeinbase(self._mpz_p, 2) + 7) // 8 - if buf_len > block_size > 0: - raise ValueError("Number is too big to convert to byte string" - "of prescribed length") - buf = create_string_buffer(buf_len) - - _gmp.mpz_export( - buf, - null_pointer, # Ignore countp - 1, # Big endian - c_size_t(1), # Each word is 1 byte long - 0, # Endianess within a word - not relevant - c_size_t(0), # No nails - self._mpz_p) - - return b'\x00' * max(0, block_size - buf_len) + get_raw_buffer(buf) - - @staticmethod - def from_bytes(byte_string): - """Convert a byte string into a number. - - :Parameters: - byte_string : byte string - The input number, encoded in network order. - It can only be non-negative. - :Return: - The ``Integer`` object carrying the same value as the input. - """ - result = IntegerGMP(0) - _gmp.mpz_import( - result._mpz_p, - c_size_t(len(byte_string)), # Amount of words to read - 1, # Big endian - c_size_t(1), # Each word is 1 byte long - 0, # Endianess within a word - not relevant - c_size_t(0), # No nails - byte_string) - return result - - # Relations - def _apply_and_return(self, func, term): - if not isinstance(term, IntegerGMP): - term = IntegerGMP(term) - return func(self._mpz_p, term._mpz_p) - - def __eq__(self, term): - if not (isinstance(term, IntegerGMP) or is_native_int(term)): - return False - return self._apply_and_return(_gmp.mpz_cmp, term) == 0 - - def __ne__(self, term): - if not (isinstance(term, IntegerGMP) or is_native_int(term)): - return True - return self._apply_and_return(_gmp.mpz_cmp, term) != 0 - - def __lt__(self, term): - return self._apply_and_return(_gmp.mpz_cmp, term) < 0 - - def __le__(self, term): - return self._apply_and_return(_gmp.mpz_cmp, term) <= 0 - - def __gt__(self, term): - return self._apply_and_return(_gmp.mpz_cmp, term) > 0 - - def __ge__(self, term): - return self._apply_and_return(_gmp.mpz_cmp, term) >= 0 - - def __nonzero__(self): - return _gmp.mpz_cmp(self._mpz_p, self._zero_mpz_p) != 0 - __bool__ = __nonzero__ - - def is_negative(self): - return _gmp.mpz_cmp(self._mpz_p, self._zero_mpz_p) < 0 - - # Arithmetic operations - def __add__(self, term): - result = IntegerGMP(0) - if not isinstance(term, IntegerGMP): - try: - term = IntegerGMP(term) - except NotImplementedError: - return NotImplemented - _gmp.mpz_add(result._mpz_p, - self._mpz_p, - term._mpz_p) - return result - - def __sub__(self, term): - result = IntegerGMP(0) - if not isinstance(term, IntegerGMP): - try: - term = IntegerGMP(term) - except NotImplementedError: - return NotImplemented - _gmp.mpz_sub(result._mpz_p, - self._mpz_p, - term._mpz_p) - return result - - def __mul__(self, term): - result = IntegerGMP(0) - if not isinstance(term, IntegerGMP): - try: - term = IntegerGMP(term) - except NotImplementedError: - return NotImplemented - _gmp.mpz_mul(result._mpz_p, - self._mpz_p, - term._mpz_p) - return result - - def __floordiv__(self, divisor): - if not isinstance(divisor, IntegerGMP): - divisor = IntegerGMP(divisor) - if _gmp.mpz_cmp(divisor._mpz_p, - self._zero_mpz_p) == 0: - raise ZeroDivisionError("Division by zero") - result = IntegerGMP(0) - _gmp.mpz_fdiv_q(result._mpz_p, - self._mpz_p, - divisor._mpz_p) - return result - - def __mod__(self, divisor): - if not isinstance(divisor, IntegerGMP): - divisor = IntegerGMP(divisor) - comp = _gmp.mpz_cmp(divisor._mpz_p, - self._zero_mpz_p) - if comp == 0: - raise ZeroDivisionError("Division by zero") - if comp < 0: - raise ValueError("Modulus must be positive") - result = IntegerGMP(0) - _gmp.mpz_mod(result._mpz_p, - self._mpz_p, - divisor._mpz_p) - return result - - def inplace_pow(self, exponent, modulus=None): - - if modulus is None: - if exponent < 0: - raise ValueError("Exponent must not be negative") - - # Normal exponentiation - if exponent > 256: - raise ValueError("Exponent is too big") - _gmp.mpz_pow_ui(self._mpz_p, - self._mpz_p, # Base - c_ulong(int(exponent)) - ) - else: - # Modular exponentiation - if not isinstance(modulus, IntegerGMP): - modulus = IntegerGMP(modulus) - if not modulus: - raise ZeroDivisionError("Division by zero") - if modulus.is_negative(): - raise ValueError("Modulus must be positive") - if is_native_int(exponent): - if exponent < 0: - raise ValueError("Exponent must not be negative") - if exponent < 65536: - _gmp.mpz_powm_ui(self._mpz_p, - self._mpz_p, - c_ulong(exponent), - modulus._mpz_p) - return self - exponent = IntegerGMP(exponent) - elif exponent.is_negative(): - raise ValueError("Exponent must not be negative") - _gmp.mpz_powm(self._mpz_p, - self._mpz_p, - exponent._mpz_p, - modulus._mpz_p) - return self - - def __pow__(self, exponent, modulus=None): - result = IntegerGMP(self) - return result.inplace_pow(exponent, modulus) - - def __abs__(self): - result = IntegerGMP(0) - _gmp.mpz_abs(result._mpz_p, self._mpz_p) - return result - - def sqrt(self, modulus=None): - """Return the largest Integer that does not - exceed the square root""" - - if modulus is None: - if self < 0: - raise ValueError("Square root of negative value") - result = IntegerGMP(0) - _gmp.mpz_sqrt(result._mpz_p, - self._mpz_p) - else: - if modulus <= 0: - raise ValueError("Modulus must be positive") - modulus = int(modulus) - result = IntegerGMP(self._tonelli_shanks(int(self) % modulus, modulus)) - - return result - - def __iadd__(self, term): - if is_native_int(term): - if 0 <= term < 65536: - _gmp.mpz_add_ui(self._mpz_p, - self._mpz_p, - c_ulong(term)) - return self - if -65535 < term < 0: - _gmp.mpz_sub_ui(self._mpz_p, - self._mpz_p, - c_ulong(-term)) - return self - term = IntegerGMP(term) - _gmp.mpz_add(self._mpz_p, - self._mpz_p, - term._mpz_p) - return self - - def __isub__(self, term): - if is_native_int(term): - if 0 <= term < 65536: - _gmp.mpz_sub_ui(self._mpz_p, - self._mpz_p, - c_ulong(term)) - return self - if -65535 < term < 0: - _gmp.mpz_add_ui(self._mpz_p, - self._mpz_p, - c_ulong(-term)) - return self - term = IntegerGMP(term) - _gmp.mpz_sub(self._mpz_p, - self._mpz_p, - term._mpz_p) - return self - - def __imul__(self, term): - if is_native_int(term): - if 0 <= term < 65536: - _gmp.mpz_mul_ui(self._mpz_p, - self._mpz_p, - c_ulong(term)) - return self - if -65535 < term < 0: - _gmp.mpz_mul_ui(self._mpz_p, - self._mpz_p, - c_ulong(-term)) - _gmp.mpz_neg(self._mpz_p, self._mpz_p) - return self - term = IntegerGMP(term) - _gmp.mpz_mul(self._mpz_p, - self._mpz_p, - term._mpz_p) - return self - - def __imod__(self, divisor): - if not isinstance(divisor, IntegerGMP): - divisor = IntegerGMP(divisor) - comp = _gmp.mpz_cmp(divisor._mpz_p, - divisor._zero_mpz_p) - if comp == 0: - raise ZeroDivisionError("Division by zero") - if comp < 0: - raise ValueError("Modulus must be positive") - _gmp.mpz_mod(self._mpz_p, - self._mpz_p, - divisor._mpz_p) - return self - - # Boolean/bit operations - def __and__(self, term): - result = IntegerGMP(0) - if not isinstance(term, IntegerGMP): - term = IntegerGMP(term) - _gmp.mpz_and(result._mpz_p, - self._mpz_p, - term._mpz_p) - return result - - def __or__(self, term): - result = IntegerGMP(0) - if not isinstance(term, IntegerGMP): - term = IntegerGMP(term) - _gmp.mpz_ior(result._mpz_p, - self._mpz_p, - term._mpz_p) - return result - - def __rshift__(self, pos): - result = IntegerGMP(0) - if pos < 0: - raise ValueError("negative shift count") - if pos > 65536: - if self < 0: - return -1 - else: - return 0 - _gmp.mpz_tdiv_q_2exp(result._mpz_p, - self._mpz_p, - c_ulong(int(pos))) - return result - - def __irshift__(self, pos): - if pos < 0: - raise ValueError("negative shift count") - if pos > 65536: - if self < 0: - return -1 - else: - return 0 - _gmp.mpz_tdiv_q_2exp(self._mpz_p, - self._mpz_p, - c_ulong(int(pos))) - return self - - def __lshift__(self, pos): - result = IntegerGMP(0) - if not 0 <= pos < 65536: - raise ValueError("Incorrect shift count") - _gmp.mpz_mul_2exp(result._mpz_p, - self._mpz_p, - c_ulong(int(pos))) - return result - - def __ilshift__(self, pos): - if not 0 <= pos < 65536: - raise ValueError("Incorrect shift count") - _gmp.mpz_mul_2exp(self._mpz_p, - self._mpz_p, - c_ulong(int(pos))) - return self - - def get_bit(self, n): - """Return True if the n-th bit is set to 1. - Bit 0 is the least significant.""" - - if self < 0: - raise ValueError("no bit representation for negative values") - if n < 0: - raise ValueError("negative bit count") - if n > 65536: - return 0 - return bool(_gmp.mpz_tstbit(self._mpz_p, - c_ulong(int(n)))) - - # Extra - def is_odd(self): - return _gmp.mpz_tstbit(self._mpz_p, 0) == 1 - - def is_even(self): - return _gmp.mpz_tstbit(self._mpz_p, 0) == 0 - - def size_in_bits(self): - """Return the minimum number of bits that can encode the number.""" - - if self < 0: - raise ValueError("Conversion only valid for non-negative numbers") - return _gmp.mpz_sizeinbase(self._mpz_p, 2) - - def size_in_bytes(self): - """Return the minimum number of bytes that can encode the number.""" - return (self.size_in_bits() - 1) // 8 + 1 - - def is_perfect_square(self): - return _gmp.mpz_perfect_square_p(self._mpz_p) != 0 - - def fail_if_divisible_by(self, small_prime): - """Raise an exception if the small prime is a divisor.""" - - if is_native_int(small_prime): - if 0 < small_prime < 65536: - if _gmp.mpz_divisible_ui_p(self._mpz_p, - c_ulong(small_prime)): - raise ValueError("The value is composite") - return - small_prime = IntegerGMP(small_prime) - if _gmp.mpz_divisible_p(self._mpz_p, - small_prime._mpz_p): - raise ValueError("The value is composite") - - def multiply_accumulate(self, a, b): - """Increment the number by the product of a and b.""" - - if not isinstance(a, IntegerGMP): - a = IntegerGMP(a) - if is_native_int(b): - if 0 < b < 65536: - _gmp.mpz_addmul_ui(self._mpz_p, - a._mpz_p, - c_ulong(b)) - return self - if -65535 < b < 0: - _gmp.mpz_submul_ui(self._mpz_p, - a._mpz_p, - c_ulong(-b)) - return self - b = IntegerGMP(b) - _gmp.mpz_addmul(self._mpz_p, - a._mpz_p, - b._mpz_p) - return self - - def set(self, source): - """Set the Integer to have the given value""" - - if not isinstance(source, IntegerGMP): - source = IntegerGMP(source) - _gmp.mpz_set(self._mpz_p, - source._mpz_p) - return self - - def inplace_inverse(self, modulus): - """Compute the inverse of this number in the ring of - modulo integers. - - Raise an exception if no inverse exists. - """ - - if not isinstance(modulus, IntegerGMP): - modulus = IntegerGMP(modulus) - - comp = _gmp.mpz_cmp(modulus._mpz_p, - self._zero_mpz_p) - if comp == 0: - raise ZeroDivisionError("Modulus cannot be zero") - if comp < 0: - raise ValueError("Modulus must be positive") - - result = _gmp.mpz_invert(self._mpz_p, - self._mpz_p, - modulus._mpz_p) - if not result: - raise ValueError("No inverse value can be computed") - return self - - def inverse(self, modulus): - result = IntegerGMP(self) - result.inplace_inverse(modulus) - return result - - def gcd(self, term): - """Compute the greatest common denominator between this - number and another term.""" - - result = IntegerGMP(0) - if is_native_int(term): - if 0 < term < 65535: - _gmp.mpz_gcd_ui(result._mpz_p, - self._mpz_p, - c_ulong(term)) - return result - term = IntegerGMP(term) - _gmp.mpz_gcd(result._mpz_p, self._mpz_p, term._mpz_p) - return result - - def lcm(self, term): - """Compute the least common multiplier between this - number and another term.""" - - result = IntegerGMP(0) - if not isinstance(term, IntegerGMP): - term = IntegerGMP(term) - _gmp.mpz_lcm(result._mpz_p, self._mpz_p, term._mpz_p) - return result - - @staticmethod - def jacobi_symbol(a, n): - """Compute the Jacobi symbol""" - - if not isinstance(a, IntegerGMP): - a = IntegerGMP(a) - if not isinstance(n, IntegerGMP): - n = IntegerGMP(n) - if n <= 0 or n.is_even(): - raise ValueError("n must be positive even for the Jacobi symbol") - return _gmp.mpz_jacobi(a._mpz_p, n._mpz_p) - - # Clean-up - def __del__(self): - - try: - if self._mpz_p is not None: - if self._initialized: - _gmp.mpz_clear(self._mpz_p) - - self._mpz_p = None - except AttributeError: - pass diff --git a/Crypto/Math/_IntegerGMP.pyi b/Crypto/Math/_IntegerGMP.pyi deleted file mode 100644 index 2181b47..0000000 --- a/Crypto/Math/_IntegerGMP.pyi +++ /dev/null @@ -1,3 +0,0 @@ -from ._IntegerBase import IntegerBase -class IntegerGMP(IntegerBase): - pass diff --git a/Crypto/Math/_IntegerNative.py b/Crypto/Math/_IntegerNative.py deleted file mode 100644 index 07bf1c6..0000000 --- a/Crypto/Math/_IntegerNative.py +++ /dev/null @@ -1,380 +0,0 @@ -# =================================================================== -# -# Copyright (c) 2014, Legrandin -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# =================================================================== - -from ._IntegerBase import IntegerBase - -from Crypto.Util.number import long_to_bytes, bytes_to_long - - -class IntegerNative(IntegerBase): - """A class to model a natural integer (including zero)""" - - def __init__(self, value): - if isinstance(value, float): - raise ValueError("A floating point type is not a natural number") - try: - self._value = value._value - except AttributeError: - self._value = value - - # Conversions - def __int__(self): - return self._value - - def __str__(self): - return str(int(self)) - - def __repr__(self): - return "Integer(%s)" % str(self) - - # Only Python 2.x - def __hex__(self): - return hex(self._value) - - # Only Python 3.x - def __index__(self): - return int(self._value) - - def to_bytes(self, block_size=0): - if self._value < 0: - raise ValueError("Conversion only valid for non-negative numbers") - result = long_to_bytes(self._value, block_size) - if len(result) > block_size > 0: - raise ValueError("Value too large to encode") - return result - - @classmethod - def from_bytes(cls, byte_string): - return cls(bytes_to_long(byte_string)) - - # Relations - def __eq__(self, term): - if term is None: - return False - return self._value == int(term) - - def __ne__(self, term): - return not self.__eq__(term) - - def __lt__(self, term): - return self._value < int(term) - - def __le__(self, term): - return self.__lt__(term) or self.__eq__(term) - - def __gt__(self, term): - return not self.__le__(term) - - def __ge__(self, term): - return not self.__lt__(term) - - def __nonzero__(self): - return self._value != 0 - __bool__ = __nonzero__ - - def is_negative(self): - return self._value < 0 - - # Arithmetic operations - def __add__(self, term): - try: - return self.__class__(self._value + int(term)) - except (ValueError, AttributeError, TypeError): - return NotImplemented - - def __sub__(self, term): - try: - return self.__class__(self._value - int(term)) - except (ValueError, AttributeError, TypeError): - return NotImplemented - - def __mul__(self, factor): - try: - return self.__class__(self._value * int(factor)) - except (ValueError, AttributeError, TypeError): - return NotImplemented - - def __floordiv__(self, divisor): - return self.__class__(self._value // int(divisor)) - - def __mod__(self, divisor): - divisor_value = int(divisor) - if divisor_value < 0: - raise ValueError("Modulus must be positive") - return self.__class__(self._value % divisor_value) - - def inplace_pow(self, exponent, modulus=None): - exp_value = int(exponent) - if exp_value < 0: - raise ValueError("Exponent must not be negative") - - if modulus is not None: - mod_value = int(modulus) - if mod_value < 0: - raise ValueError("Modulus must be positive") - if mod_value == 0: - raise ZeroDivisionError("Modulus cannot be zero") - else: - mod_value = None - self._value = pow(self._value, exp_value, mod_value) - return self - - def __pow__(self, exponent, modulus=None): - result = self.__class__(self) - return result.inplace_pow(exponent, modulus) - - def __abs__(self): - return abs(self._value) - - def sqrt(self, modulus=None): - - value = self._value - if modulus is None: - if value < 0: - raise ValueError("Square root of negative value") - # http://stackoverflow.com/questions/15390807/integer-square-root-in-python - - x = value - y = (x + 1) // 2 - while y < x: - x = y - y = (x + value // x) // 2 - result = x - else: - if modulus <= 0: - raise ValueError("Modulus must be positive") - result = self._tonelli_shanks(self % modulus, modulus) - - return self.__class__(result) - - def __iadd__(self, term): - self._value += int(term) - return self - - def __isub__(self, term): - self._value -= int(term) - return self - - def __imul__(self, term): - self._value *= int(term) - return self - - def __imod__(self, term): - modulus = int(term) - if modulus == 0: - raise ZeroDivisionError("Division by zero") - if modulus < 0: - raise ValueError("Modulus must be positive") - self._value %= modulus - return self - - # Boolean/bit operations - def __and__(self, term): - return self.__class__(self._value & int(term)) - - def __or__(self, term): - return self.__class__(self._value | int(term)) - - def __rshift__(self, pos): - try: - return self.__class__(self._value >> int(pos)) - except OverflowError: - if self._value >= 0: - return 0 - else: - return -1 - - def __irshift__(self, pos): - try: - self._value >>= int(pos) - except OverflowError: - if self._value >= 0: - return 0 - else: - return -1 - return self - - def __lshift__(self, pos): - try: - return self.__class__(self._value << int(pos)) - except OverflowError: - raise ValueError("Incorrect shift count") - - def __ilshift__(self, pos): - try: - self._value <<= int(pos) - except OverflowError: - raise ValueError("Incorrect shift count") - return self - - def get_bit(self, n): - if self._value < 0: - raise ValueError("no bit representation for negative values") - try: - try: - result = (self._value >> n._value) & 1 - if n._value < 0: - raise ValueError("negative bit count") - except AttributeError: - result = (self._value >> n) & 1 - if n < 0: - raise ValueError("negative bit count") - except OverflowError: - result = 0 - return result - - # Extra - def is_odd(self): - return (self._value & 1) == 1 - - def is_even(self): - return (self._value & 1) == 0 - - def size_in_bits(self): - - if self._value < 0: - raise ValueError("Conversion only valid for non-negative numbers") - - if self._value == 0: - return 1 - - bit_size = 0 - tmp = self._value - while tmp: - tmp >>= 1 - bit_size += 1 - - return bit_size - - def size_in_bytes(self): - return (self.size_in_bits() - 1) // 8 + 1 - - def is_perfect_square(self): - if self._value < 0: - return False - if self._value in (0, 1): - return True - - x = self._value // 2 - square_x = x ** 2 - - while square_x > self._value: - x = (square_x + self._value) // (2 * x) - square_x = x ** 2 - - return self._value == x ** 2 - - def fail_if_divisible_by(self, small_prime): - if (self._value % int(small_prime)) == 0: - raise ValueError("Value is composite") - - def multiply_accumulate(self, a, b): - self._value += int(a) * int(b) - return self - - def set(self, source): - self._value = int(source) - - def inplace_inverse(self, modulus): - modulus = int(modulus) - if modulus == 0: - raise ZeroDivisionError("Modulus cannot be zero") - if modulus < 0: - raise ValueError("Modulus cannot be negative") - r_p, r_n = self._value, modulus - s_p, s_n = 1, 0 - while r_n > 0: - q = r_p // r_n - r_p, r_n = r_n, r_p - q * r_n - s_p, s_n = s_n, s_p - q * s_n - if r_p != 1: - raise ValueError("No inverse value can be computed" + str(r_p)) - while s_p < 0: - s_p += modulus - self._value = s_p - return self - - def inverse(self, modulus): - result = self.__class__(self) - result.inplace_inverse(modulus) - return result - - def gcd(self, term): - r_p, r_n = abs(self._value), abs(int(term)) - while r_n > 0: - q = r_p // r_n - r_p, r_n = r_n, r_p - q * r_n - return self.__class__(r_p) - - def lcm(self, term): - term = int(term) - if self._value == 0 or term == 0: - return self.__class__(0) - return self.__class__(abs((self._value * term) // self.gcd(term)._value)) - - @staticmethod - def jacobi_symbol(a, n): - a = int(a) - n = int(n) - - if n <= 0: - raise ValueError("n must be a positive integer") - - if (n & 1) == 0: - raise ValueError("n must be even for the Jacobi symbol") - - # Step 1 - a = a % n - # Step 2 - if a == 1 or n == 1: - return 1 - # Step 3 - if a == 0: - return 0 - # Step 4 - e = 0 - a1 = a - while (a1 & 1) == 0: - a1 >>= 1 - e += 1 - # Step 5 - if (e & 1) == 0: - s = 1 - elif n % 8 in (1, 7): - s = 1 - else: - s = -1 - # Step 6 - if n % 4 == 3 and a1 % 4 == 3: - s = -s - # Step 7 - n1 = n % a1 - # Step 8 - return s * IntegerNative.jacobi_symbol(n1, a1) diff --git a/Crypto/Math/_IntegerNative.pyi b/Crypto/Math/_IntegerNative.pyi deleted file mode 100644 index 3f65a39..0000000 --- a/Crypto/Math/_IntegerNative.pyi +++ /dev/null @@ -1,3 +0,0 @@ -from ._IntegerBase import IntegerBase -class IntegerNative(IntegerBase): - pass diff --git a/Crypto/Math/__init__.py b/Crypto/Math/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/Crypto/Math/_modexp.abi3.so b/Crypto/Math/_modexp.abi3.so deleted file mode 100644 index 48715c0728579626c5560fd5470c35ef84a31fac..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 241256 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