From 850e83609472205d389910efb77ef715852028fb Mon Sep 17 00:00:00 2001 From: Alicja Kario Date: Mon, 2 Sep 2024 19:52:42 +0200 Subject: [PATCH 1/3] more checks for correctness of the plaintext --- unit_tests/test_tlslite_utils_rsakey.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/unit_tests/test_tlslite_utils_rsakey.py b/unit_tests/test_tlslite_utils_rsakey.py index a2ab750b..68b3c6bb 100644 --- a/unit_tests/test_tlslite_utils_rsakey.py +++ b/unit_tests/test_tlslite_utils_rsakey.py @@ -2024,6 +2024,7 @@ def test_negative_11_byte_long_wrong_version_byte(self): # sanity check that the decrypted ciphertext is invalid dec = self.priv_key._raw_private_key_op_bytes(ciphertext) self.assertEqual(dec[0:2], b'\x01\x02') + self.assertTrue(all(i != 0 for i in dec[2:-12])) self.assertEqual(dec[-12:], b'\x00lorem ipsum') plaintext = a2b_hex(remove_whitespace("a1f8c9255c35cfba403ccc")) @@ -2049,6 +2050,7 @@ def test_negative_11_byte_long_wrong_type_byte(self): # sanity check that the decrypted ciphertext is invalid dec = self.priv_key._raw_private_key_op_bytes(ciphertext) self.assertEqual(dec[0:2], b'\x00\x01') + self.assertTrue(all(i != 0 for i in dec[2:-12])) self.assertEqual(dec[-12:], b'\x00lorem ipsum') plaintext = a2b_hex(remove_whitespace("e6d700309ca0ed62452254")) @@ -2154,6 +2156,7 @@ def test_negative_11_byte_long_null_type_byte(self): # sanity check that the decrypted ciphertext is invalid dec = self.priv_key._raw_private_key_op_bytes(ciphertext) self.assertEqual(dec[0:3], b'\x00\x00\x02') + self.assertTrue(all(i != 0 for i in dec[3:-12])) self.assertEqual(dec[-12:], b'\x00lorem ipsum') plaintext = a2b_hex(remove_whitespace("3d4a054d9358209e9cbbb9")) @@ -2180,6 +2183,7 @@ def test_negative_11_byte_long_null_byte_first_byte_of_padding(self): # sanity check that the decrypted ciphertext is invalid dec = self.priv_key._raw_private_key_op_bytes(ciphertext) self.assertEqual(dec[0:3], b'\x00\x02\x00') + self.assertTrue(all(i != 0 for i in dec[3:-12])) self.assertEqual(dec[-12:], b'\x00lorem ipsum') plaintext = a2b_hex("1f037dd717b07d3e7f7359") @@ -2206,8 +2210,9 @@ def test_negative_11_byte_long_null_byte_at_eight_byte_of_padding(self): # sanity check that the decrypted ciphertext is invalid dec = self.priv_key._raw_private_key_op_bytes(ciphertext) self.assertEqual(dec[0:2], b'\x00\x02') - self.assertNotEqual(dec[2:3], b'\x00') + self.assertTrue(all(i != 0 for i in dec[2:9])) self.assertEqual(dec[9:10], b'\x00') + self.assertTrue(all(i != 0 for i in dec[10:-12])) self.assertEqual(dec[-12:], b'\x00lorem ipsum') plaintext = a2b_hex("63cb0bf65fc8255dd29e17") From 5989f83ee595f5dc6e9b36a6bfaf4f8a0ad1c66f Mon Sep 17 00:00:00 2001 From: Alicja Kario Date: Mon, 2 Sep 2024 19:52:54 +0200 Subject: [PATCH 2/3] test vectors for 4096 bit RSA --- unit_tests/test_tlslite_utils_rsakey.py | 188 ++++++++++++++++++++++++ 1 file changed, 188 insertions(+) diff --git a/unit_tests/test_tlslite_utils_rsakey.py b/unit_tests/test_tlslite_utils_rsakey.py index 68b3c6bb..44089eae 100644 --- a/unit_tests/test_tlslite_utils_rsakey.py +++ b/unit_tests/test_tlslite_utils_rsakey.py @@ -3005,3 +3005,191 @@ def test_negative_9_bytes_long_missing_null_separator(self): self.assertNotEqual(msg, b'forty two') self.assertEqual(msg, plaintext) + + +class TestRSA4096Decrypt(unittest.TestCase): + @classmethod + def setUpClass(cls): + priv_key = """ +-----BEGIN PRIVATE KEY----- +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 +q4gl5hM8H5F0iWcKq25nZYHamz7f +-----END PRIVATE KEY-----""" + cls.priv_key = parsePEMKey(priv_key, private=True) + + pub_key = """ +-----BEGIN PUBLIC KEY----- +MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAj945U+VcSE8cQkquyQPf +bznTDbFgUpaAGhgtOudGjhkns4b+edH6FhsolPhosaN18xnDBrO72l/LRaETpVcO +skcxgM/hEZ+gfCXkaIyiVeIVpqxWvBEH7iQzzOhFy29V9ruMMA6cA7NCFXOI1A+n +pF07DRBVtJo8OwpES3JxlxVBQ14/yfKVb3heXMbRWYuficHBO/TF/vExB/DgFvVt +dTvbL3Dxbsx1CNIL9QYsXGSL1btKc1XEKTXir+NWWVttDzTqcpyOyYzown+Hmxmc +dN8uIu4wNi6S85243Jok9RntWvzR0uga4gP//YAo3AL4HTv0sLO6xCSxByUNIJjA +bkrd8mkKTna3o5lzV9gr8+nsENeouIYqvAK2pnMokSFR47H0CVjHoq2F+2QrKwlU +bdFhhPTz1MaP5gyGdwqUNCEcDcQsLiTt+QKi7U1GhV4UVuZf1v4W1W2k48gJndlu +eywhYz4e0uNcxAkZes7n+5Hhm2ndPeE5JvHa/vzeO5gLT/AvkNmASBLMTqmKG1ZQ +D/0c57KuknFMimoDHSm8t/BHsMm7znDf4OHw2wbO2viXadWOHBU+7oE3rYoPshyZ +SYI20EGAPLI8AD3mUQK5pzLDgbxBvhfLSyEZk/YiBuwFfHFXUNXNMatnvmyGVepK +tabLQBHCibNsEt4a96CO3Q0CAwEAAQ== +-----END PUBLIC KEY-----""" + cls.pub_key = parsePEMKey(pub_key, public=True) + + + def test_sanity(self): + self.assertIsNotNone(self.priv_key) + self.assertIsNotNone(self.pub_key) + + msg = b"message" + self.assertEqual(msg, self.priv_key.decrypt(self.pub_key.encrypt(msg))) + + def test_normal_decrypt(self): + ciphertext = a2b_hex(remove_whitespace(""" +041f9bbe8372454ffadce0befc99ad4bd01cdbe016dffb5d0d84ee879e7ff64a25dced4d504f4 +8a14b700a34a1c148e4b4028eecc9158cf5e3469daad1dddb2157b176dcf5716627aebd6072b9 +65cfb67b42b149e88c0a8dc54703ec244637b3039b80c06d1d4968aeb838f3afcd3dc675fc907 +36cf0f0adaba182e27a19a7294cef500ed1fcca324c3ffa6ff02bd749a4a66f18da138d53ff54 +9c4e6b3fff0b9ee2029ea8293fcd72a03e1dee4445629979be7fd65e5dbe5e6e77ec2aa87879a +01c3e2502af0cc4bc04b637d17b175d92b4dcd70cfe83b6c1d4f91c61e911b81cb6d60b99146f +17937d127054521b132acb9ca95cbc6f80cd926d709bd7219d48ce7378e4416328a49be6c773d +bdeb00ce23dc91f25f4807526cf4de8dd3fbb13ae1011eefe3a2aad9982f6c9268883b4633057 +d119c97c1178aae671859af0a488ab7b841c6583572d1261137a4292ba1c1caa4baf808be4207 +5940d7e612efa56ac9a7ffff3e7dbf10b6193ea14c4841fc5c43e031a69ddbd79118ccd92b16a +6ef66c7404c001ebc6402301a90248eb6562b7a2f549f52c058109dd5f2617877719ad13e81d1 +9425a4cd5cf9e56e8538f5cb09b6f7ab646910b8c2ff6bf8cf17abdb4758bfba80df9f643950a +6d4a8f60c6872700e5919d36503486667e4328a6b74b774eb483a9922706baa7f456644781cc0 +d78add9024e28da2d5e9d81""")) + self.assertEqual(len(ciphertext), numBytes(self.pub_key.n)) + + plaintext = b'lorem ipsum' + + msg = self.priv_key.decrypt(ciphertext) + + self.assertEqual(msg, plaintext) + + def test_with_no_version_byte(self): + ciphertext = a2b_hex(remove_whitespace(""" +6b11bd1777ac4f1d8f36a3ebd01090a4c2be1e2deb928cef6427c107f8cb +1d7072c9d37d3b69de959c4d9f24ac92be7f584b0737416fcf9c58268b6e +ef5c52cfbb3cd4ce241708f71fde98f9181ad5d8db734c61fe4bf2c5d1f1 +1b08d71f84bc448404041522387a67f7a2c7c9e24340343bcbf9b4d68487 +103d925751333cff995d031492542d60e55cdab81dffc882079ed578ba35 +c33d456be27fc1f56f0e2bc68d1bc35a0ce7b8a9a770816c7448013e56a1 +a8a9861885c99cf77b4beac682aa61822ffff61697e5afa566f10565644a +cd1080bef01ef14b498b329f4e0d56f5c7c97b09398e557513c33354528e +eccdb3dc167de119b0b9299e56bcc6814cc5edbbf1b49769ec3487be04b1 +0f3efa41e1a76eb9215ded0d2832923dcbc1e6444967c6945d2c975456cc +5d495f1b02b272d11ed46ddea4fa8d264709beda36b252385ffc11679daa +3fcdfe31f2980075f281dfbcfec2442092031a89323f5d83caeacbaded97 +26de616fd9b034ac076fc4a72f0331f6b9efff91b79b440af115ea1a352e +a2a9bfb4e74c0215aff27fd51dce2ac9e90332dbcc1e3de009eee079b4e7 +0d2c0ce870aeca5c329471dc54a9e0c6c5e04275f1a8c0462971c6cda9c4 +b78ed362a8bdbb6f0de87b83cc4c1bcd813fde2741259cd1aad588d48440 +3f63eca6d991b7302be939be2cf9408c6501037eeb56da342710df4b5406 +cba9""")) + self.assertEqual(len(ciphertext), numBytes(self.pub_key.n)) + + # sanity check that the decrypted ciphertext is invalid + dec = self.priv_key._raw_private_key_op_bytes(ciphertext) + self.assertEqual(dec[0:1], b'\x02') + self.assertTrue(all(i != 0 for i in dec[1:507])) + self.assertEqual(dec[507:508], b'\x00') + + plaintext = a2b_hex(remove_whitespace(""" +dd843a3331f5ca2035ac2ae0f87e544ec369e85514e295aba369179ea312 +fa074253d3670842ce05fa5a3f55c6e0dae35e0d81075319604267f513a6 +2b44600f2afe610ffa79ada034ca28682d3a4526f67e4243ad2c6d545690 +4e2aa6401d521e43c0e3753441a9db79a23eeb981c9627d6382145b09e68 +2757213fa4f4466e985e5d4975437c1d56803bc48ee269c99cd1e72c10c7 +8fe4fc6119873d4d5ee55a159ab418ff0c87b8dfe54755cdc9e8997af9ce +ff432a0913c75a""")) + + msg = self.priv_key.decrypt(ciphertext) + + self.assertEqual(msg, plaintext) + + def test_with_wrong_version_byte(self): + ciphertext = a2b_hex(remove_whitespace(""" +36e373c18770cdbb666723a84d16af1b97669f056111890863c1fa32af22 +1e2f6ab211643dcfb00a59f5ce241eba6622badcd49ca0889295d09330f6 +619f0d258ac29e1bbe6df83f664834a7c5d5337b3a870f79d2e055fc4067 +4ec959799851d269355cb51b8b42e382d66b20ca898a91afe9944dc23359 +4dd6870ef9848958396e169790751ea5679e48fa3f64da78cb99d6d8cd0e +651e9d2bcdb6e0a60c92dbdb193cd4a1013ae4d44af6bb9002e34b240ac8 +25f26345a7f5db787e30036d836b991f95e8cb2b1ebe6a722aceeabd98c6 +ebfc4ccd0d832ba4361f381790dc84d18b78814d8174f41a42932626ea80 +73356f2edb8af0cdcb09bdb03244c405f52207791aa95e783ac5bd8d4aa7 +8de41be84be6077e3e312e1775044c57b7befd5f34370fc9238bb8a9d3b8 +e18acfc2783442f121e1f9a47f4f2f688a1aebc4237afde71e070e4097ee +05fa8bd20a80433d344a1409ad22c6109cd4799d2f3238586519efa37640 +cd615bb90ef55e29bed75f40e9315b8b80a9c9b09251c9cf206cbc8a34ed +b3be4c7a0a538f4ffa20f76def706660fdd152e89b1b22660371e2a27b0f +8d046a4f76dd355c5e250264317a5f52da6c438673158e3bc7cdf95880a7 +b93f3a1ddb1841a4b819841ecc22be19bd92acf5b63b395fce376f72fb60 +9a333486a3cc287f710370dcd57179a84d895c51ea6e1def763a0c2ff138 +ceb5""")) + self.assertEqual(len(ciphertext), numBytes(self.pub_key.n)) + + # sanity check that the decrypted ciphertext is invalid + dec = self.priv_key._raw_private_key_op_bytes(ciphertext) + self.assertNotEqual(dec[0:1], b'\x00') + self.assertEqual(dec[1:2], b'\x02') + self.assertTrue(all(i != 0 for i in dec[2:507])) + self.assertEqual(dec[507:508], b'\x00') + + plaintext = a2b_hex(remove_whitespace(""" +51aa94d54ec9a891d92eb7e69cbfe6fd05a6561ea3f9768cb5224cbb1dc +b9decc0278361147e6979bc3769b9ae741fc2928e94d7a0f8625e296f20 +39f23dde67ea90adcf1afd52424d02228189fe4c3603134ce07f72994bd +d929cc5a2a4""")) + + msg = self.priv_key.decrypt(ciphertext) + + self.assertEqual(msg, plaintext) From 6a75b9a54a46fc2832139669a985347ab1a785da Mon Sep 17 00:00:00 2001 From: Alicja Kario Date: Tue, 3 Sep 2024 19:45:07 +0200 Subject: [PATCH 3/3] more checks for the 2048 bit vectors and align with the draft-irtf-cfrg-rsa-guidance Double check that the PRF outputs also match expected values and format the ciphertexts and plaintexts so that it's easy to compare the values with the values from the RFC-to-be --- unit_tests/test_tlslite_utils_rsakey.py | 537 ++++++++++++++---------- 1 file changed, 319 insertions(+), 218 deletions(-) diff --git a/unit_tests/test_tlslite_utils_rsakey.py b/unit_tests/test_tlslite_utils_rsakey.py index 44089eae..abbd5566 100644 --- a/unit_tests/test_tlslite_utils_rsakey.py +++ b/unit_tests/test_tlslite_utils_rsakey.py @@ -22,6 +22,30 @@ import unittest.mock as mock from unittest.mock import call + +def calc_kdk(key, ciphertext): + key_hash = secureHash(numberToByteArray(key.d, numBytes(key.n)), "sha256") + + kdk = secureHMAC(key_hash, ciphertext, "sha256") + + return kdk + + +def calc_lengths(key, kdk): + lengths_bytes = key._dec_prf(kdk, b"length", 128 * 2 * 8) + + max_sep_offset = numBytes(key.n) - 10 + mask = (1 << numBits(max_sep_offset)) - 1 + + lengths_iter = iter(lengths_bytes) + + lengths = [ + ((i << 8) + j) & mask + for i, j in zip(lengths_iter, lengths_iter) + ] + return lengths + + class TestRSAPSS_components(unittest.TestCase): # component functions NOT tested from test vectors @@ -1695,33 +1719,34 @@ class TestRSADecrypt(unittest.TestCase): @classmethod def setUpClass(cls): priv_key = """ ------BEGIN RSA PRIVATE KEY----- -MIIEowIBAAKCAQEAyMyDlxQJjaVsqiNkD5PciZfBY3KWj8Gwxt9RE8HJTosh5IrS -KX5lQZARtObY9ec7G3iyV0ADIdHva2AtTsjOjRQclJBetK0wZjmkkgZTS25/JgdC -Ppff/RM8iNchOZ3vvH6WzNy9fzquH+iScSv7SSmBfVEWZkQKH6y3ogj16hZZEK3Y -o/LUlyAjYMy2MgJPDQcWnBkY8xb3lLFDrvVOyHUipMApePlomYC/+/ZJwwfoGBm/ -+IQJY41IvZS+FStZ/2SfoL1inQ/6GBPDq/S1a9PC6lRl3/oUWJKSqdiiStJr5+4F -EHQbY4LUPIPVv6QKRmE9BivkRVF9vK8MtOGnaQIDAQABAoIBABRVAQ4PLVh2Y6Zm -pv8czbvw7dgQBkbQKgI5IpCJksStOeVWWSlybvZQjDpxFY7wtv91HTnQdYC7LS8G -MhBELQYD/1DbvXs1/iybsZpHoa+FpMJJAeAsqLWLeRmyDt8yqs+/Ua20vEthubfp -aMqk1XD3DvGNgGMiiJPkfUOe/KeTJZvPLNEIo9hojN8HjnrHmZafIznSwfUiuWlo -RimpM7quwmgWJeq4T05W9ER+nYj7mhmc9xAj4OJXsURBszyE07xnyoAx0mEmGBA6 -egpAhEJi912IkM1hblH5A1SI/W4Jnej/bWWk/xGCVIB8n1jS+7qLoVHcjGi+NJyX -eiBOBMECgYEA+PWta6gokxvqRZuKP23AQdI0gkCcJXHpY/MfdIYColY3GziD7UWe -z5cFJkWe3RbgVSL1pF2UdRsuwtrycsf4gWpSwA0YCAFxY02omdeXMiL1G5N2MFSG -lqn32MJKWUl8HvzUVc+5fuhtK200lyszL9owPwSZm062tcwLsz53Yd0CgYEAznou -O0mpC5YzChLcaCvfvfuujdbcA7YUeu+9V1dD8PbaTYYjUGG3Gv2crS00Al5WrIaw -93Q+s14ay8ojeJVCRGW3Bu0iF15XGMjHC2cD6o9rUQ+UW+SOWja7PDyRcytYnfwF -1y2AkDGURSvaITSGR+xylD8RqEbmL66+jrU2sP0CgYB2/hXxiuI5zfHfa0RcpLxr -uWjXiMIZM6T13NKAAz1nEgYswIpt8gTB+9C+RjB0Q+bdSmRWN1Qp1OA4yiVvrxyb -3pHGsXt2+BmV+RxIy768e/DjSUwINZ5OjNalh9e5bWIh/X4PtcVXXwgu5XdpeYBx -sru0oyI4FRtHMUu2VHkDEQKBgQCZiEiwVUmaEAnLx9KUs2sf/fICDm5zZAU+lN4a -AA3JNAWH9+JydvaM32CNdTtjN3sDtvQITSwCfEs4lgpiM7qe2XOLdvEOp1vkVgeL -9wH2fMaz8/3BhuZDNsdrNy6AkQ7ICwrcwj0C+5rhBIaigkgHW06n5W3fzziC5FFW -FHGikQKBgGQ790ZCn32DZnoGUwITR++/wF5jUfghqd67YODszeUAWtnp7DHlWPfp -LCkyjnRWnXzvfHTKvCs1XtQBoaCRS048uwZITlgZYFEWntFMqi76bqBE4FTSYUTM -FinFUBBVigThM/RLfCRNrCW/kTxXuJDuSfVIJZzWNAT+9oWdz5da ------END RSA PRIVATE KEY----- +-----BEGIN PRIVATE KEY----- +MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDIzIOXFAmNpWyq +I2QPk9yJl8FjcpaPwbDG31ETwclOiyHkitIpfmVBkBG05tj15zsbeLJXQAMh0e9r +YC1OyM6NFByUkF60rTBmOaSSBlNLbn8mB0I+l9/9EzyI1yE5ne+8fpbM3L1/Oq4f +6JJxK/tJKYF9URZmRAofrLeiCPXqFlkQrdij8tSXICNgzLYyAk8NBxacGRjzFveU +sUOu9U7IdSKkwCl4+WiZgL/79knDB+gYGb/4hAljjUi9lL4VK1n/ZJ+gvWKdD/oY +E8Or9LVr08LqVGXf+hRYkpKp2KJK0mvn7gUQdBtjgtQ8g9W/pApGYT0GK+RFUX28 +rwy04adpAgMBAAECggEAFFUBDg8tWHZjpmam/xzNu/Dt2BAGRtAqAjkikImSxK05 +5VZZKXJu9lCMOnEVjvC2/3UdOdB1gLstLwYyEEQtBgP/UNu9ezX+LJuxmkehr4Wk +wkkB4CyotYt5GbIO3zKqz79RrbS8S2G5t+loyqTVcPcO8Y2AYyKIk+R9Q578p5Ml +m88s0Qij2GiM3weOeseZlp8jOdLB9SK5aWhGKakzuq7CaBYl6rhPTlb0RH6diPua +GZz3ECPg4lexREGzPITTvGfKgDHSYSYYEDp6CkCEQmL3XYiQzWFuUfkDVIj9bgmd +6P9tZaT/EYJUgHyfWNL7uouhUdyMaL40nJd6IE4EwQKBgQD49a1rqCiTG+pFm4o/ +bcBB0jSCQJwlcelj8x90hgKiVjcbOIPtRZ7PlwUmRZ7dFuBVIvWkXZR1Gy7C2vJy +x/iBalLADRgIAXFjTaiZ15cyIvUbk3YwVIaWqffYwkpZSXwe/NRVz7l+6G0rbTSX +KzMv2jA/BJmbTra1zAuzPndh3QKBgQDOei47SakLljMKEtxoK9+9+66N1twDthR6 +771XV0Pw9tpNhiNQYbca/ZytLTQCXlashrD3dD6zXhrLyiN4lUJEZbcG7SIXXlcY +yMcLZwPqj2tRD5Rb5I5aNrs8PJFzK1id/AXXLYCQMZRFK9ohNIZH7HKUPxGoRuYv +rr6OtTaw/QKBgHb+FfGK4jnN8d9rRFykvGu5aNeIwhkzpPXc0oADPWcSBizAim3y +BMH70L5GMHRD5t1KZFY3VCnU4DjKJW+vHJvekcaxe3b4GZX5HEjLvrx78ONJTAg1 +nk6M1qWH17ltYiH9fg+1xVdfCC7ld2l5gHGyu7SjIjgVG0cxS7ZUeQMRAoGBAJmI +SLBVSZoQCcvH0pSzax/98gIObnNkBT6U3hoADck0BYf34nJ29ozfYI11O2M3ewO2 +9AhNLAJ8SziWCmIzup7Zc4t28Q6nW+RWB4v3AfZ8xrPz/cGG5kM2x2s3LoCRDsgL +CtzCPQL7muEEhqKCSAdbTqflbd/POILkUVYUcaKRAoGAZDv3RkKffYNmegZTAhNH +77/AXmNR+CGp3rtg4OzN5QBa2ensMeVY9+ksKTKOdFadfO98dMq8KzVe1AGhoJFL +Tjy7BkhOWBlgURae0UyqLvpuoETgVNJhRMwWKcVQEFWKBOEz9Et8JE2sJb+RPFe4 +kO5J9UglnNY0BP72hZ3Pl1o= +-----END PRIVATE KEY----- """ cls.priv_key = parsePEMKey(priv_key, private=True) @@ -1765,26 +1790,81 @@ def test_simple_encypt_decrypt(self): def test_decryption(self): # a random positive test case ciphertext = a2b_hex(remove_whitespace(""" -8bfe264e85d3bdeaa6b8851b8e3b956ee3d226fd3f69063a86880173a273d9f283b2eebdd1ed -35f7e02d91c571981b6737d5320bd8396b0f3ad5b019daec1b0aab3cbbc026395f4fd14f1367 -3f2dfc81f9b660ec26ac381e6db3299b4e460b43fab9955df2b3cfaa20e900e19c856238fd37 -1899c2bf2ce8c868b76754e5db3b036533fd603746be13c10d4e3e6022ebc905d20c2a7f32b2 -15a4cd53b3f44ca1c327d2c2b651145821c08396c89071f665349c25e44d2733cd9305985cee -f6430c3cf57af5fa224089221218fa34737c79c446d28a94c41c96e4e92ac53fbcf384dea841 -9ea089f8784445a492c812eb0d409467f75afd7d4d1078886205a066""")) +8bfe264e85d3bdeaa6b8851b8e3b956ee3d226fd3f69063a86880173a273d9f2 +83b2eebdd1ed35f7e02d91c571981b6737d5320bd8396b0f3ad5b019daec1b0a +ab3cbbc026395f4fd14f13673f2dfc81f9b660ec26ac381e6db3299b4e460b43 +fab9955df2b3cfaa20e900e19c856238fd371899c2bf2ce8c868b76754e5db3b +036533fd603746be13c10d4e3e6022ebc905d20c2a7f32b215a4cd53b3f44ca1 +c327d2c2b651145821c08396c89071f665349c25e44d2733cd9305985ceef643 +0c3cf57af5fa224089221218fa34737c79c446d28a94c41c96e4e92ac53fbcf3 +84dea8419ea089f8784445a492c812eb0d409467f75afd7d4d1078886205a066 +""")) self.assertEqual(len(ciphertext), numBytes(self.pub_key.n)) msg = self.priv_key.decrypt(ciphertext) self.assertEqual(msg, b'lorem ipsum dolor sit amet') + def test_valid_to_empty(self): + ciphertext = a2b_hex(remove_whitespace(""" +443ad9c5f00a1f4e9601717d274aacc93a824cb4d99b3c6a42e2b017e52e0184 +43bd77d34a80703cd9b6acf523cd3b2cd1fea31940a68fba828836f1c3ed2fef +071e95e0922ff0f47d0e81dacc13ecdeda3db6476f41e5b3f9ccfcfdf9155800 +7b68ffbbe5e93bb088f1e4f0bb39bc7d8600b38930ecd00a341d8cc76955837e +fff0f0797c4b46fb1b375bba49bcdc877f39aaadb045c56b836072383eec6627 +ae280ad4f9a45d6e5b4cc7cf61d42b194ff0b9c9167c621e5380d8333e3b7f20 +c8d564c9ec6c2805f77c0146adea2f688a943b67ce8889f4a6353e6396d551c3 +6a6dbf19359a825d14b69ccc4fd747cf14a1ca8578d7f0a67dc14b37f5e17ca3 +""")) + self.assertEqual(len(ciphertext), numBytes(self.pub_key.n)) + + # sanity check that the decrypted ciphertext is valid + dec = self.priv_key._raw_private_key_op_bytes(ciphertext) + self.assertEqual(dec[0:2], b'\x00\x02') + self.assertTrue(i != 0 for i in dec[2:-1]) + self.assertEqual(dec[-1:], b'\x00') + + msg = self.priv_key.decrypt(ciphertext) + self.assertEqual(msg, b'') + + def test_positive_11_byte_long_with_null_padded_ciphertext(self): + # ciphertext that starts with a null byte, decrypts to real 11 byte + # long plaintext + ciphertext = a2b_hex(remove_whitespace(""" +00a2e8f114ea8d05d12dc843e3cc3b2edc8229ff2a028bda29ba9d55e3cd0291 +1902fef1f42a075bf05e8016e8567213d6f260fa49e360779dd81aeea3e04c2c +b567e0d72b98bf754014561b7511e083d20e0bfb9cd23f8a0d3c88900c49d2fc +d5843ff0765607b2026f28202a87aa94678aed22a0c20724541394cd8f44e373 +eba1d2bae98f516c1e2ba3d86852d064f856b1daf24795e767a2b90396e50743 +e3150664afab131fe40ea405dcf572dd1079af1d3f0392ccadcca0a12740dbb2 +13b925ca2a06b1bc1383e83a658c82ba2e7427342379084d5f66b544579f0766 +4cb26edd4f10fd913fdbc0de05ef887d4d1ec1ac95652397ea7fd4e4759fda8b +""")) + self.assertEqual(len(ciphertext), numBytes(self.pub_key.n)) + + plaintext = b'lorem ipsum' + + # sanity check that the decrypted ciphertext is valid + dec = self.priv_key._raw_private_key_op_bytes(ciphertext) + self.assertEqual(dec[0:2], b'\x00\x02') + self.assertTrue(i != 0 for i in dec[2:-12]) + self.assertEqual(dec[-12:], b'\x00lorem ipsum') + + self.assertEqual(len(plaintext), 11) + + msg = self.priv_key.decrypt(ciphertext) + + self.assertEqual(msg, plaintext) + def test_invalid_decrypting_to_empty(self): ciphertext = a2b_hex(remove_whitespace(""" -20aaa8adbbc593a924ba1c5c7990b5c2242ae4b99d0fe636a19a4cf754edbcee774e472fe028 -160ed42634f8864900cb514006da642cae6ae8c7d087caebcfa6dad1551301e130344989a1d4 -62d4164505f6393933450c67bc6d39d8f5160907cabc251b737925a1cf21e5c6aa5781b7769f -6a2a583d97cce008c0f8b6add5f0b2bd80bee60237aa39bb20719fe75749f4bc4e42466ef5a8 -61ae3a92395c7d858d430bfe38040f445ea93fa2958b503539800ffa5ce5f8cf51fa8171a91f -36cb4f4575e8de6b4d3f096ee140b938fd2f50ee13f0d050222e2a72b0a3069ff3a6738e82c8 -7090caa5aed4fcbe882c49646aa250b98f12f83c8d528113614a29e7""")) +20aaa8adbbc593a924ba1c5c7990b5c2242ae4b99d0fe636a19a4cf754edbcee +774e472fe028160ed42634f8864900cb514006da642cae6ae8c7d087caebcfa6 +dad1551301e130344989a1d462d4164505f6393933450c67bc6d39d8f5160907 +cabc251b737925a1cf21e5c6aa5781b7769f6a2a583d97cce008c0f8b6add5f0 +b2bd80bee60237aa39bb20719fe75749f4bc4e42466ef5a861ae3a92395c7d85 +8d430bfe38040f445ea93fa2958b503539800ffa5ce5f8cf51fa8171a91f36cb +4f4575e8de6b4d3f096ee140b938fd2f50ee13f0d050222e2a72b0a3069ff3a6 +738e82c87090caa5aed4fcbe882c49646aa250b98f12f83c8d528113614a29e7 +""")) self.assertEqual(len(ciphertext), numBytes(self.pub_key.n)) # sanity check that the decrypted ciphertext is invalid @@ -1800,13 +1880,15 @@ def test_invalid_decrypting_to_max_length(self): # the last value from PRF is 245, which is exactly the max we # can return ciphertext = a2b_hex(remove_whitespace(""" -48cceab10f39a4db32f60074feea473cbcdb7accf92e150417f76b44756b190e843e79ec12aa -85083a21f5437e7bad0a60482e601198f9d86923239c8786ee728285afd0937f7dde12717f28 -389843d7375912b07b991f4fdb0190fced8ba665314367e8c5f9d2981d0f5128feeb46cb50fc -237e64438a86df198dd0209364ae3a842d77532b66b7ef263b83b1541ed671b120dfd660462e -2107a4ee7b964e734a7bd68d90dda61770658a3c242948532da32648687e0318286473f675b4 -12d6468f013f14d760a358dfcad3cda2afeec5e268a37d250c37f722f468a70dfd92d7294c3c -1ee1e7f8843b7d16f9f37ef35748c3ae93aa155cdcdfeb4e78567303""")) +48cceab10f39a4db32f60074feea473cbcdb7accf92e150417f76b44756b190e +843e79ec12aa85083a21f5437e7bad0a60482e601198f9d86923239c8786ee72 +8285afd0937f7dde12717f28389843d7375912b07b991f4fdb0190fced8ba665 +314367e8c5f9d2981d0f5128feeb46cb50fc237e64438a86df198dd0209364ae +3a842d77532b66b7ef263b83b1541ed671b120dfd660462e2107a4ee7b964e73 +4a7bd68d90dda61770658a3c242948532da32648687e0318286473f675b412d6 +468f013f14d760a358dfcad3cda2afeec5e268a37d250c37f722f468a70dfd92 +d7294c3c1ee1e7f8843b7d16f9f37ef35748c3ae93aa155cdcdfeb4e78567303 +""")) self.assertEqual(len(ciphertext), numBytes(self.pub_key.n)) # sanity check that the decrypted ciphertext is invalid @@ -1816,14 +1898,17 @@ def test_invalid_decrypting_to_max_length(self): b'\x78\x05\x5c\xc0\xd7\x02\xfe\xd7\x6a\xbe\x53') plaintext = a2b_hex(remove_whitespace(""" -22d850137b9eebe092b24f602dc5bb7918c16bd89ddbf20467b119d205f9c2e4bd7d2592cf1e -532106e0f33557565923c73a02d4f09c0c22bea89148183e60317f7028b3aa1f261f91c97939 -3101d7e15f4067e63979b32751658ef769610fe97cf9cef3278b3117d384051c3b1d82c251c2 -305418c8f6840530e631aad63e70e20e025bcd8efb54c92ec6d3b106a2f8e64eeff7d38495b0 -fc50c97138af4b1c0a67a1c4e27b077b8439332edfa8608dfeae653cd6a628ac550395f7e743 -90e42c11682234870925eeaa1fa71b76cf1f2ee3bda69f6717033ff8b7c95c9799e7a3bea5e7 -e4a1c359772fb6b1c6e6c516661dfe30c3""")) - self.assertEqual(len(plaintext), 245) +22d850137b9eebe092b24f602dc5bb7918c16bd89ddbf20467b119d205f9c2e4 +bd7d2592cf1e532106e0f33557565923c73a02d4f09c0c22bea89148183e6031 +7f7028b3aa1f261f91c979393101d7e15f4067e63979b32751658ef769610fe9 +7cf9cef3278b3117d384051c3b1d82c251c2305418c8f6840530e631aad63e70 +e20e025bcd8efb54c92ec6d3b106a2f8e64eeff7d38495b0fc50c97138af4b1c +0a67a1c4e27b077b8439332edfa8608dfeae653cd6a628ac550395f7e74390e4 +2c11682234870925eeaa1fa71b76cf1f2ee3bda69f6717033ff8b7c95c9799e7 +a3bea5e7e4a1c359772fb6b1c6e6c516661dfe30c3 +""")) + self.assertEqual(len(plaintext), numBytes(self.pub_key.n) - 2 - 8 - 1) + self.assertEqual(len(plaintext), 2048 // 8 - 2 - 8 - 1) msg = self.priv_key.decrypt(ciphertext) @@ -1833,22 +1918,39 @@ def test_invalid_decrypting_to_length_second_to_last_from_prf(self): # the last value from the PRF is 246, which is longer than the max # allowed length: 245, so it needs to select second to last: 2 ciphertext = a2b_hex(remove_whitespace(""" -1439e08c3f84c1a7fec74ce07614b20e01f6fa4e8c2a6cffdc3520d8889e5d9a950c6425798f -85d4be38d300ea5695f13ecd4cb389d1ff5b82484b494d6280ab7fa78e645933981cb934cce8 -bfcd114cc0e6811eefa47aae20af638a1cd163d2d3366186d0a07df0c81f6c9f3171cf356147 -2e98a6006bf75ddb457bed036dcce199369de7d94ef2c68e8467ee0604eea2b3009479162a78 -91ba5c40cab17f49e1c438cb6eaea4f76ce23cce0e483ff0e96fa790ea15be67671814342d0a -23f4a20262b6182e72f3a67cd289711503c85516a9ed225422f98b116f1ab080a80abd6f0216 -df88d8cfd67c139243be8dd78502a7aaf6bc99d7da71bcdf627e7354""")) +1439e08c3f84c1a7fec74ce07614b20e01f6fa4e8c2a6cffdc3520d8889e5d9a +950c6425798f85d4be38d300ea5695f13ecd4cb389d1ff5b82484b494d6280ab +7fa78e645933981cb934cce8bfcd114cc0e6811eefa47aae20af638a1cd163d2 +d3366186d0a07df0c81f6c9f3171cf3561472e98a6006bf75ddb457bed036dcc +e199369de7d94ef2c68e8467ee0604eea2b3009479162a7891ba5c40cab17f49 +e1c438cb6eaea4f76ce23cce0e483ff0e96fa790ea15be67671814342d0a23f4 +a20262b6182e72f3a67cd289711503c85516a9ed225422f98b116f1ab080a80a +bd6f0216df88d8cfd67c139243be8dd78502a7aaf6bc99d7da71bcdf627e7354 +""")) self.assertEqual(len(ciphertext), numBytes(self.pub_key.n)) + kdk = calc_kdk(self.priv_key, ciphertext) + + lengths = calc_lengths(self.priv_key, kdk) + max_len = numBytes(self.pub_key.n) - 1 - 1 - 8 -1 + + # the last_len is too long + self.assertGreater(lengths[-1], max_len) + self.assertEqual(lengths[-1], 246) + + # while second to last is short enough + self.assertLessEqual(lengths[-2], max_len) + self.assertEqual(2, lengths[-2]) + # sanity check that the decrypted ciphertext is invalid dec = self.priv_key._raw_private_key_op_bytes(ciphertext) self.assertNotEqual(dec[0:1], b'\x00') self.assertNotEqual(dec[1:2], b'\x02') self.assertEqual(dec[-3:], b'\xd1\x90\x17') - plaintext = a2b_hex(remove_whitespace("0f9b")) + plaintext = a2b_hex(remove_whitespace(""" +0f9b +""")) self.assertEqual(len(plaintext), 2) @@ -1856,6 +1958,159 @@ def test_invalid_decrypting_to_length_second_to_last_from_prf(self): self.assertEqual(msg, plaintext) + def test_negative_11_byte_long_wrong_version_byte(self): + # an otherwise correct plaintext, but with wrong first byte + # (0x01 instead of 0x00), generates a random 11 byte long plaintext + ciphertext = a2b_hex(remove_whitespace(""" +9b2ec9c0c917c98f1ad3d0119aec6be51ae3106e9af1914d48600ab6a2c0c0c8 +ae02a2dc3039906ff3aac904af32ec798fd65f3ad1afa2e69400e7c1de81f572 +8f3b3291f38263bc7a90a0563e43ce7a0d4ee9c0d8a716621ca5d3d081188769 +ce1b131af7d35b13dea99153579c86db31fe07d5a2c14d621b77854e48a8df41 +b5798563af489a291e417b6a334c63222627376118c02c53b6e86310f728734f +fc86ef9d7c8bf56c0c841b24b82b59f51aee4526ba1c4268506d301e4ebc498c +6aebb6fd5258c876bf900bac8ca4d309dd522f6a6343599a8bc3760f422c10c7 +2d0ad527ce4af1874124ace3d99bb74db8d69d2528db22c3a37644640f95c05f +""")) + self.assertEqual(len(ciphertext), numBytes(self.pub_key.n)) + + # sanity check that the decrypted ciphertext is invalid + dec = self.priv_key._raw_private_key_op_bytes(ciphertext) + self.assertEqual(dec[0:2], b'\x01\x02') + self.assertTrue(all(i != 0 for i in dec[2:-12])) + self.assertEqual(dec[-12:], b'\x00lorem ipsum') + + plaintext = a2b_hex(remove_whitespace(""" +a1f8c9255c35cfba403ccc +""")) + + msg = self.priv_key.decrypt(ciphertext) + + self.assertNotEqual(msg, b'lorem ipsum') + self.assertEqual(msg, plaintext) + + def test_negative_11_byte_long_wrong_type_byte(self): + # an otherwise correct plaintext, but with wrong second byte + # (0x01 instead of 0x02), generates a random 11 byte long plaintext + ciphertext = a2b_hex(remove_whitespace(""" +782c2b59a21a511243820acedd567c136f6d3090c115232a82a5efb0b178285f +55b5ec2d2bac96bf00d6592ea7cdc3341610c8fb07e527e5e2d20cfaf2c7f23e +375431f45e998929a02f25fd95354c33838090bca838502259e92d86d568bc2c +db132fab2a399593ca60a015dc2bb1afcd64fef8a3834e17e5358d822980dc44 +6e845b3ab4702b1ee41fe5db716d92348d5091c15d35a110555a35deb4650a5a +1d2c98025d42d4544f8b32aa6a5e02dc02deaed9a7313b73b49b0d4772a3768b +0ea0db5846ace6569cae677bf67fb0acf3c255dc01ec8400c963b6e49b106772 +8b4e563d7e1e1515664347b92ee64db7efb5452357a02fff7fcb7437abc2e579 +""")) + self.assertEqual(len(ciphertext), numBytes(self.pub_key.n)) + + # sanity check that the decrypted ciphertext is invalid + dec = self.priv_key._raw_private_key_op_bytes(ciphertext) + self.assertEqual(dec[0:2], b'\x00\x01') + self.assertTrue(all(i != 0 for i in dec[2:-12])) + self.assertEqual(dec[-12:], b'\x00lorem ipsum') + + plaintext = a2b_hex(remove_whitespace(""" +e6d700309ca0ed62452254 +""")) + + msg = self.priv_key.decrypt(ciphertext) + + self.assertNotEqual(msg, b'lorem ipsum') + self.assertEqual(msg, plaintext) + + def test_negative_11_bytes_long_with_null_padded_ciphertext(self): + # an invalid ciphertext, with a zero byte in first byte of + # ciphertext, decrypts to a random 11 byte long synthethic + # plaintext + ciphertext = a2b_hex(remove_whitespace(""" +0096136621faf36d5290b16bd26295de27f895d1faa51c800dafce73d001d607 +96cd4e2ac3fa2162131d859cd9da5a0c8a42281d9a63e5f353971b72e36b5722 +e4ac444d77f892a5443deb3dca49fa732fe855727196e23c26eeac55eeced826 +7a209ebc0f92f4656d64a6c13f7f7ce544ebeb0f668fe3a6c0f189e4bcd5ea12 +b73cf63e0c8350ee130dd62f01e5c97a1e13f52fde96a9a1bc9936ce734fdd61 +f27b18216f1d6de87f49cf4f2ea821fb8efd1f92cdad529baf7e31aff9bff407 +4f2cad2b4243dd15a711adcf7de900851fbd6bcb53dac399d7c880531d06f25f +7002e1aaf1722765865d2c2b902c7736acd27bc6cbd3e38b560e2eecf7d4b576 +""")) + self.assertEqual(len(ciphertext), numBytes(self.pub_key.n)) + + # sanity check that the decrypted ciphertext is invalid + dec = self.priv_key._raw_private_key_op_bytes(ciphertext) + self.assertEqual(dec[0:3], b'\x00\x02\x00') + self.assertNotEqual(dec[-12:-11], b'\x00') + + plaintext = a2b_hex(remove_whitespace(""" +ba27b1842e7c21c0e7ef6a +""")) + + msg = self.priv_key.decrypt(ciphertext) + + self.assertEqual(msg, plaintext) + + def test_negative_11_byte_long_null_byte_at_eight_byte_of_padding(self): + # an otherwise correct plaintext, but with a null byte on tenth + # position (eight byte of padding), generates a random 11 byte long + # plaintext + ciphertext = a2b_hex(remove_whitespace(""" +a7a340675a82c30e22219a55bc07cdf36d47d01834c1834f917f18b517419ce9 +de2a96460e745024436470ed85e94297b283537d52189c406a3f533cb405cc6a +9dba46b482ce98b6e3dd52d8fce2237425617e38c11fbc46b61897ef200d01e4 +f25f5f6c4c5b38cd0de38ba11908b86595a8036a08a42a3d05b79600a97ac18b +a368a08d6cf6ccb624f6e8002afc75599fba4de3d4f3ba7d208391ebe8d21f82 +82b18e2c10869eb2702e68f9176b42b0ddc9d763f0c86ba0ff92c957aaeab76d +9ab8da52ea297ec11d92d770146faa1b300e0f91ef969b53e7d2907ffc984e9a +9c9d11fb7d6cba91972059b46506b035efec6575c46d7114a6b935864858445f +""")) + self.assertEqual(len(ciphertext), numBytes(self.pub_key.n)) + + # sanity check that the decrypted ciphertext is invalid + dec = self.priv_key._raw_private_key_op_bytes(ciphertext) + self.assertEqual(dec[0:2], b'\x00\x02') + self.assertTrue(all(i != 0 for i in dec[2:9])) + self.assertEqual(dec[9:10], b'\x00') + self.assertTrue(all(i != 0 for i in dec[10:-12])) + self.assertEqual(dec[-12:], b'\x00lorem ipsum') + + plaintext = a2b_hex(remove_whitespace(""" +63cb0bf65fc8255dd29e17 +""")) + + msg = self.priv_key.decrypt(ciphertext) + + self.assertNotEqual(msg, b"lorem ipsum") + self.assertEqual(msg, plaintext) + + def test_negative_11_byte_long_missing_null_separator(self): + # an otherwise correct plaintext, but with missing zero separator + # decrypts to 11 byte random synthethic plaintext + ciphertext = a2b_hex(remove_whitespace(""" +3d1b97e7aa34eaf1f4fc171ceb11dcfffd9a46a5b6961205b10b302818c1fcc9 +f4ec78bf18ea0cee7e9fa5b16fb4c611463b368b3312ac11cf9c06b7cf72b54e +284848a508d3f02328c62c2999d0fb60929f81783c7a256891bc2ff4d91df2af +96a24fc5701a1823af939ce6dbdc510608e3d41eec172ad2d51b9fc61b4217c9 +23cadcf5bac321355ef8be5e5f090cdc2bd0c697d9058247db3ad613fdce87d2 +955a6d1c948a5160f93da21f731d74137f5d1f53a1923adb513d2e6e1589d44c +c079f4c6ddd471d38ac82d20d8b1d21f8d65f3b6907086809f4123e08d86fb38 +729585de026a485d8f0e703fd4772f6668febf67df947b82195fa3867e3a3065 +""")) + self.assertEqual(len(ciphertext), numBytes(self.pub_key.n)) + + # sanity check that the decrypted ciphertext is invalid + dec = self.priv_key._raw_private_key_op_bytes(ciphertext) + self.assertEqual(dec[0:2], b'\x00\x02') + for val in dec[2:-12]: + self.assertNotEqual(val, 0) + self.assertEqual(dec[-12:], b'\x01lorem ipsum') + + plaintext = a2b_hex(remove_whitespace(""" +6f09a0b62699337c497b0b +""")) + + msg = self.priv_key.decrypt(ciphertext) + + self.assertNotEqual(msg, b'lorem ipsum') + self.assertEqual(msg, plaintext) + def test_invalid_decrypting_to_length_third_to_last_from_prf(self): # the last three numbers from prf are: 2, 247, 255, so we need to # pick 2, the third one from the end @@ -1904,27 +2159,6 @@ def test_positive_11_byte_long(self): self.assertEqual(msg, plaintext) - def test_positive_11_byte_long_with_null_padded_ciphertext(self): - # ciphertext that starts with a null byte, decrypts to real 11 byte - # long plaintext - ciphertext = a2b_hex(remove_whitespace(""" -00a2e8f114ea8d05d12dc843e3cc3b2edc8229ff2a028bda29ba9d55e3cd02911902fef1f42a -075bf05e8016e8567213d6f260fa49e360779dd81aeea3e04c2cb567e0d72b98bf754014561b -7511e083d20e0bfb9cd23f8a0d3c88900c49d2fcd5843ff0765607b2026f28202a87aa94678a -ed22a0c20724541394cd8f44e373eba1d2bae98f516c1e2ba3d86852d064f856b1daf24795e7 -67a2b90396e50743e3150664afab131fe40ea405dcf572dd1079af1d3f0392ccadcca0a12740 -dbb213b925ca2a06b1bc1383e83a658c82ba2e7427342379084d5f66b544579f07664cb26edd -4f10fd913fdbc0de05ef887d4d1ec1ac95652397ea7fd4e4759fda8b""")) - self.assertEqual(len(ciphertext), numBytes(self.pub_key.n)) - - plaintext = b'lorem ipsum' - - self.assertEqual(len(plaintext), 11) - - msg = self.priv_key.decrypt(ciphertext) - - self.assertEqual(msg, plaintext) - def test_positive_11_byte_long_with_double_null_padded_ciphertext(self): # ciphertext that starts with two null bytes, decrypts to real 11 byte # long plaintext @@ -2008,84 +2242,6 @@ def test_negative_11_byte_long(self): self.assertNotEqual(msg, b'lorem ipsum') self.assertEqual(msg, plaintext) - def test_negative_11_byte_long_wrong_version_byte(self): - # an otherwise correct plaintext, but with wrong first byte - # (0x01 instead of 0x00), generates a random 11 byte long plaintext - ciphertext = a2b_hex(remove_whitespace(""" -9b2ec9c0c917c98f1ad3d0119aec6be51ae3106e9af1914d48600ab6a2c0c0c8ae02a2dc3039 -906ff3aac904af32ec798fd65f3ad1afa2e69400e7c1de81f5728f3b3291f38263bc7a90a056 -3e43ce7a0d4ee9c0d8a716621ca5d3d081188769ce1b131af7d35b13dea99153579c86db31fe -07d5a2c14d621b77854e48a8df41b5798563af489a291e417b6a334c63222627376118c02c53 -b6e86310f728734ffc86ef9d7c8bf56c0c841b24b82b59f51aee4526ba1c4268506d301e4ebc -498c6aebb6fd5258c876bf900bac8ca4d309dd522f6a6343599a8bc3760f422c10c72d0ad527 -ce4af1874124ace3d99bb74db8d69d2528db22c3a37644640f95c05f""")) - self.assertEqual(len(ciphertext), numBytes(self.pub_key.n)) - - # sanity check that the decrypted ciphertext is invalid - dec = self.priv_key._raw_private_key_op_bytes(ciphertext) - self.assertEqual(dec[0:2], b'\x01\x02') - self.assertTrue(all(i != 0 for i in dec[2:-12])) - self.assertEqual(dec[-12:], b'\x00lorem ipsum') - - plaintext = a2b_hex(remove_whitespace("a1f8c9255c35cfba403ccc")) - - msg = self.priv_key.decrypt(ciphertext) - - self.assertNotEqual(msg, b'lorem ipsum') - self.assertEqual(msg, plaintext) - - def test_negative_11_byte_long_wrong_type_byte(self): - # an otherwise correct plaintext, but with wrong second byte - # (0x01 instead of 0x02), generates a random 11 byte long plaintext - ciphertext = a2b_hex(remove_whitespace(""" -782c2b59a21a511243820acedd567c136f6d3090c115232a82a5efb0b178285f55b5ec2d2bac -96bf00d6592ea7cdc3341610c8fb07e527e5e2d20cfaf2c7f23e375431f45e998929a02f25fd -95354c33838090bca838502259e92d86d568bc2cdb132fab2a399593ca60a015dc2bb1afcd64 -fef8a3834e17e5358d822980dc446e845b3ab4702b1ee41fe5db716d92348d5091c15d35a110 -555a35deb4650a5a1d2c98025d42d4544f8b32aa6a5e02dc02deaed9a7313b73b49b0d4772a3 -768b0ea0db5846ace6569cae677bf67fb0acf3c255dc01ec8400c963b6e49b1067728b4e563d -7e1e1515664347b92ee64db7efb5452357a02fff7fcb7437abc2e579""")) - self.assertEqual(len(ciphertext), numBytes(self.pub_key.n)) - - # sanity check that the decrypted ciphertext is invalid - dec = self.priv_key._raw_private_key_op_bytes(ciphertext) - self.assertEqual(dec[0:2], b'\x00\x01') - self.assertTrue(all(i != 0 for i in dec[2:-12])) - self.assertEqual(dec[-12:], b'\x00lorem ipsum') - - plaintext = a2b_hex(remove_whitespace("e6d700309ca0ed62452254")) - - msg = self.priv_key.decrypt(ciphertext) - - self.assertNotEqual(msg, b'lorem ipsum') - self.assertEqual(msg, plaintext) - - def test_negative_11_bytes_long_with_null_padded_ciphertext(self): - # an invalid ciphertext, with a zero byte in first byte of - # ciphertext, decrypts to a random 11 byte long synthethic - # plaintext - ciphertext = a2b_hex(remove_whitespace(""" -0096136621faf36d5290b16bd26295de27f895d1faa51c800dafce73d001d60796cd4e2ac3f -a2162131d859cd9da5a0c8a42281d9a63e5f353971b72e36b5722e4ac444d77f892a5443deb -3dca49fa732fe855727196e23c26eeac55eeced8267a209ebc0f92f4656d64a6c13f7f7ce54 -4ebeb0f668fe3a6c0f189e4bcd5ea12b73cf63e0c8350ee130dd62f01e5c97a1e13f52fde96 -a9a1bc9936ce734fdd61f27b18216f1d6de87f49cf4f2ea821fb8efd1f92cdad529baf7e31a -ff9bff4074f2cad2b4243dd15a711adcf7de900851fbd6bcb53dac399d7c880531d06f25f70 -02e1aaf1722765865d2c2b902c7736acd27bc6cbd3e38b560e2eecf7d4b576 -""")) - self.assertEqual(len(ciphertext), numBytes(self.pub_key.n)) - - # sanity check that the decrypted ciphertext is invalid - dec = self.priv_key._raw_private_key_op_bytes(ciphertext) - self.assertEqual(dec[0:3], b'\x00\x02\x00') - self.assertNotEqual(dec[-12:-11], b'\x00') - - plaintext = a2b_hex(remove_whitespace("ba27b1842e7c21c0e7ef6a")) - - msg = self.priv_key.decrypt(ciphertext) - - self.assertEqual(msg, plaintext) - def test_negative_11_bytes_long_with_null_truncated_ciphertext(self): # same as test_negative_11_bytes_long_with_null_padded_ciphertext # but with the zero bytes at the beginning removed @@ -2193,61 +2349,6 @@ def test_negative_11_byte_long_null_byte_first_byte_of_padding(self): self.assertNotEqual(msg, b"lorem ipsum") self.assertEqual(msg, plaintext) - def test_negative_11_byte_long_null_byte_at_eight_byte_of_padding(self): - # an otherwise correct plaintext, but with a null byte on tenth - # position (eight byte of padding), generates a random 11 byte long - # plaintext - ciphertext = a2b_hex(remove_whitespace(""" -a7a340675a82c30e22219a55bc07cdf36d47d01834c1834f917f18b517419ce9de2a96460e74 -5024436470ed85e94297b283537d52189c406a3f533cb405cc6a9dba46b482ce98b6e3dd52d8 -fce2237425617e38c11fbc46b61897ef200d01e4f25f5f6c4c5b38cd0de38ba11908b86595a8 -036a08a42a3d05b79600a97ac18ba368a08d6cf6ccb624f6e8002afc75599fba4de3d4f3ba7d -208391ebe8d21f8282b18e2c10869eb2702e68f9176b42b0ddc9d763f0c86ba0ff92c957aaea -b76d9ab8da52ea297ec11d92d770146faa1b300e0f91ef969b53e7d2907ffc984e9a9c9d11fb -7d6cba91972059b46506b035efec6575c46d7114a6b935864858445f""")) - self.assertEqual(len(ciphertext), numBytes(self.pub_key.n)) - - # sanity check that the decrypted ciphertext is invalid - dec = self.priv_key._raw_private_key_op_bytes(ciphertext) - self.assertEqual(dec[0:2], b'\x00\x02') - self.assertTrue(all(i != 0 for i in dec[2:9])) - self.assertEqual(dec[9:10], b'\x00') - self.assertTrue(all(i != 0 for i in dec[10:-12])) - self.assertEqual(dec[-12:], b'\x00lorem ipsum') - - plaintext = a2b_hex("63cb0bf65fc8255dd29e17") - - msg = self.priv_key.decrypt(ciphertext) - - self.assertNotEqual(msg, b"lorem ipsum") - self.assertEqual(msg, plaintext) - - def test_negative_11_byte_long_missing_null_separator(self): - # an otherwise correct plaintext, but with missing zero separator - # decrypts to 11 byte random synthethic plaintext - ciphertext = a2b_hex(remove_whitespace(""" -3d1b97e7aa34eaf1f4fc171ceb11dcfffd9a46a5b6961205b10b302818c1fcc9f4ec78bf18ea -0cee7e9fa5b16fb4c611463b368b3312ac11cf9c06b7cf72b54e284848a508d3f02328c62c29 -99d0fb60929f81783c7a256891bc2ff4d91df2af96a24fc5701a1823af939ce6dbdc510608e3 -d41eec172ad2d51b9fc61b4217c923cadcf5bac321355ef8be5e5f090cdc2bd0c697d9058247 -db3ad613fdce87d2955a6d1c948a5160f93da21f731d74137f5d1f53a1923adb513d2e6e1589 -d44cc079f4c6ddd471d38ac82d20d8b1d21f8d65f3b6907086809f4123e08d86fb38729585de -026a485d8f0e703fd4772f6668febf67df947b82195fa3867e3a3065""")) - self.assertEqual(len(ciphertext), numBytes(self.pub_key.n)) - - # sanity check that the decrypted ciphertext is invalid - dec = self.priv_key._raw_private_key_op_bytes(ciphertext) - self.assertEqual(dec[0:2], b'\x00\x02') - for val in dec[2:-12]: - self.assertNotEqual(val, 0) - self.assertEqual(dec[-12:], b'\x01lorem ipsum') - - plaintext = a2b_hex(remove_whitespace("6f09a0b62699337c497b0b")) - - msg = self.priv_key.decrypt(ciphertext) - - self.assertNotEqual(msg, b'lorem ipsum') - self.assertEqual(msg, plaintext) class TestRSA2049Decrypt(unittest.TestCase):