mirror of
https://git.tartarus.org/simon/putty.git
synced 2025-06-02 18:00:32 -05:00
Add tests of all the AES cipher modes.
This tests the CBC and SDCTR modes, in all key lengths, and in particular includes a set of SDCTR tests designed to test the procedure for incrementing the IV as a single 128-bit integer, by checking propagation of the carry between every pair of words.
This commit is contained in:
parent
7fd815014e
commit
48ff6f13e2
@ -5,7 +5,6 @@ import struct
|
|||||||
import itertools
|
import itertools
|
||||||
import contextlib
|
import contextlib
|
||||||
import hashlib
|
import hashlib
|
||||||
from binascii import unhexlify as unhex
|
|
||||||
try:
|
try:
|
||||||
from math import gcd
|
from math import gcd
|
||||||
except ImportError:
|
except ImportError:
|
||||||
@ -28,6 +27,9 @@ def nbits(n):
|
|||||||
toret += 1
|
toret += 1
|
||||||
return toret
|
return toret
|
||||||
|
|
||||||
|
def unhex(s):
|
||||||
|
return s.replace(" ", "").replace("\n", "").decode("hex")
|
||||||
|
|
||||||
def ssh_uint32(n):
|
def ssh_uint32(n):
|
||||||
return struct.pack(">L", n)
|
return struct.pack(">L", n)
|
||||||
def ssh_string(s):
|
def ssh_string(s):
|
||||||
@ -753,6 +755,132 @@ class crypt(unittest.TestCase):
|
|||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
fp, b"768 96:12:c8:bc:e6:03:75:86:e8:c7:b9:af:d8:0c:15:75")
|
fp, b"768 96:12:c8:bc:e6:03:75:86:e8:c7:b9:af:d8:0c:15:75")
|
||||||
|
|
||||||
|
def testAES(self):
|
||||||
|
# My own test cases, generated by a mostly independent
|
||||||
|
# reference implementation of AES in Python. ('Mostly'
|
||||||
|
# independent in that it was written by me.)
|
||||||
|
|
||||||
|
def vector(cipher, key, iv, plaintext, ciphertext):
|
||||||
|
c = ssh2_cipher_new(cipher)
|
||||||
|
ssh2_cipher_setkey(c, key)
|
||||||
|
ssh2_cipher_setiv(c, iv)
|
||||||
|
self.assertEqual(ssh2_cipher_encrypt(c, plaintext), ciphertext)
|
||||||
|
ssh2_cipher_setiv(c, iv)
|
||||||
|
self.assertEqual(ssh2_cipher_decrypt(c, ciphertext), plaintext)
|
||||||
|
|
||||||
|
# Tests of CBC mode.
|
||||||
|
|
||||||
|
key = unhex(
|
||||||
|
'98483c6eb40b6c31a448c22a66ded3b5e5e8d5119cac8327b655c8b5c4836489')
|
||||||
|
iv = unhex('38f87b0b9b736160bfc0cbd8447af6ee')
|
||||||
|
plaintext = unhex('''
|
||||||
|
ee16271827b12d828f61d56fddccc38ccaa69601da2b36d3af1a34c51947b71a
|
||||||
|
362f05e07bf5e7766c24599799b252ad2d5954353c0c6ca668c46779c2659c94
|
||||||
|
8df04e4179666e335470ff042e213c8bcff57f54842237fbf9f3c7e6111620ac
|
||||||
|
1c007180edd25f0e337c2a49d890a7173f6b52d61e3d2a21ddc8e41513a0e825
|
||||||
|
afd5932172270940b01014b5b7fb8495946151520a126518946b44ea32f9b2a9
|
||||||
|
''')
|
||||||
|
|
||||||
|
vector('aes128', key[:16], iv, plaintext, unhex('''
|
||||||
|
547ee90514cb6406d5bb00855c8092892c58299646edda0b4e7c044247795c8d
|
||||||
|
3c3eb3d91332e401215d4d528b94a691969d27b7890d1ae42fe3421b91c989d5
|
||||||
|
113fefa908921a573526259c6b4f8e4d90ea888e1d8b7747457ba3a43b5b79b9
|
||||||
|
34873ebf21102d14b51836709ee85ed590b7ca618a1e884f5c57c8ea73fe3d0d
|
||||||
|
6bf8c082dd602732bde28131159ed0b6e9cf67c353ffdd010a5a634815aaa963'''))
|
||||||
|
|
||||||
|
vector('aes192', key[:24], iv, plaintext, unhex('''
|
||||||
|
e3dee5122edd3fec5fab95e7db8c784c0cb617103e2a406fba4ae3b4508dd608
|
||||||
|
4ff5723a670316cc91ed86e413c11b35557c56a6f5a7a2c660fc6ee603d73814
|
||||||
|
73a287645be0f297cdda97aef6c51faeb2392fec9d33adb65138d60f954babd9
|
||||||
|
8ee0daab0d1decaa8d1e07007c4a3c7b726948025f9fb72dd7de41f74f2f36b4
|
||||||
|
23ac6a5b4b6b39682ec74f57d9d300e547f3c3e467b77f5e4009923b2f94c903'''))
|
||||||
|
|
||||||
|
vector('aes256', key[:32], iv, plaintext, unhex('''
|
||||||
|
088c6d4d41997bea79c408925255266f6c32c03ea465a5f607c2f076ec98e725
|
||||||
|
7e0beed79609b3577c16ebdf17d7a63f8865278e72e859e2367de81b3b1fe9ab
|
||||||
|
8f045e1d008388a3cfc4ff87daffedbb47807260489ad48566dbe73256ce9dd4
|
||||||
|
ae1689770a883b29695928f5983f33e8d7aec4668f64722e943b0b671c365709
|
||||||
|
dfa86c648d5fb00544ff11bd29121baf822d867e32da942ba3a0d26299bcee13'''))
|
||||||
|
|
||||||
|
# Tests of SDCTR mode, one with a random IV and one with an IV
|
||||||
|
# about to wrap round. More vigorous tests of IV carry and
|
||||||
|
# wraparound behaviour are in the testAESSDCTR method.
|
||||||
|
|
||||||
|
sdctrIVs = [
|
||||||
|
unhex('38f87b0b9b736160bfc0cbd8447af6ee'),
|
||||||
|
unhex('fffffffffffffffffffffffffffffffe'),
|
||||||
|
]
|
||||||
|
|
||||||
|
vector('aes128_ctr', key[:16], sdctrIVs[0], plaintext[:64], unhex('''
|
||||||
|
d0061d7b6e8c4ef4fe5614b95683383f46cdd2766e66b6fb0b0f0b3a24520b2d
|
||||||
|
15d869b06cbf685ede064bcf8fb5fb6726cfd68de7016696a126e9e84420af38'''))
|
||||||
|
vector('aes128_ctr', key[:16], sdctrIVs[1], plaintext[:64], unhex('''
|
||||||
|
49ac67164fd9ce8701caddbbc9a2b06ac6524d4aa0fdac95253971974b8f3bc2
|
||||||
|
bb8d7c970f6bcd79b25218cc95582edf7711aae2384f6cf91d8d07c9d9b370bc'''))
|
||||||
|
|
||||||
|
vector('aes192_ctr', key[:24], sdctrIVs[0], plaintext[:64], unhex('''
|
||||||
|
0baa86acbe8580845f0671b7ebad4856ca11b74e5108f515e34e54fa90f87a9a
|
||||||
|
c6eee26686253c19156f9be64957f0dbc4f8ecd7cabb1f4e0afefe33888faeec'''))
|
||||||
|
vector('aes192_ctr', key[:24], sdctrIVs[1], plaintext[:64], unhex('''
|
||||||
|
2da1791250100dc0d1461afe1bbfad8fa0320253ba5d7905d837386ba0a3a41f
|
||||||
|
01965c770fcfe01cf307b5316afb3981e0e4aa59a6e755f0a5784d9accdc52be'''))
|
||||||
|
|
||||||
|
vector('aes256_ctr', key[:32], sdctrIVs[0], plaintext[:64], unhex('''
|
||||||
|
49c7b284222d408544c770137b6ef17ef770c47e24f61fa66e7e46cae4888882
|
||||||
|
f980a0f2446956bf47d2aed55ebd2e0694bfc46527ed1fd33efe708fec2f8b1f'''))
|
||||||
|
vector('aes256_ctr', key[:32], sdctrIVs[1], plaintext[:64], unhex('''
|
||||||
|
f1d013c3913ccb4fc0091e25d165804480fb0a1d5c741bf012bba144afda6db2
|
||||||
|
c512f3942018574bd7a8fdd88285a73d25ef81e621aebffb6e9b8ecc8e2549d4'''))
|
||||||
|
|
||||||
|
def testAESSDCTR(self):
|
||||||
|
# A thorough test of the IV-incrementing component of SDCTR
|
||||||
|
# mode. We set up an AES-SDCTR cipher object with the given
|
||||||
|
# input IV; we encrypt two all-zero blocks, expecting the
|
||||||
|
# return values to be the AES-ECB encryptions of the input IV
|
||||||
|
# and the incremented version. Then we decrypt each of them by
|
||||||
|
# feeding them to an AES-CBC cipher object with its IV set to
|
||||||
|
# zero.
|
||||||
|
|
||||||
|
def increment(keylen, iv):
|
||||||
|
key = b'\xab' * (keylen//8)
|
||||||
|
sdctr = ssh2_cipher_new("aes{}_ctr".format(keylen))
|
||||||
|
ssh2_cipher_setkey(sdctr, key)
|
||||||
|
cbc = ssh2_cipher_new("aes{}".format(keylen))
|
||||||
|
ssh2_cipher_setkey(cbc, key)
|
||||||
|
|
||||||
|
ssh2_cipher_setiv(sdctr, iv)
|
||||||
|
ec0 = ssh2_cipher_encrypt(sdctr, b'\x00' * 16)
|
||||||
|
ec1 = ssh2_cipher_encrypt(sdctr, b'\x00' * 16)
|
||||||
|
ssh2_cipher_setiv(cbc, b'\x00' * 16)
|
||||||
|
dc0 = ssh2_cipher_decrypt(cbc, ec0)
|
||||||
|
ssh2_cipher_setiv(cbc, b'\x00' * 16)
|
||||||
|
dc1 = ssh2_cipher_decrypt(cbc, ec1)
|
||||||
|
self.assertEqual(iv, dc0)
|
||||||
|
return dc1
|
||||||
|
|
||||||
|
def test(keylen, ivInteger):
|
||||||
|
mask = (1 << 128) - 1
|
||||||
|
ivInteger &= mask
|
||||||
|
ivBinary = unhex("{:032x}".format(ivInteger))
|
||||||
|
ivIntegerInc = (ivInteger + 1) & mask
|
||||||
|
ivBinaryInc = unhex("{:032x}".format((ivIntegerInc)))
|
||||||
|
actualResult = increment(keylen, ivBinary)
|
||||||
|
self.assertEqual(actualResult, ivBinaryInc)
|
||||||
|
|
||||||
|
# Check every input IV you can make by gluing together 32-bit
|
||||||
|
# pieces of the form 0, 1 or -1. This should test all the
|
||||||
|
# places where carry propagation within the 128-bit integer
|
||||||
|
# can go wrong.
|
||||||
|
#
|
||||||
|
# We also test this at all three AES key lengths, in case the
|
||||||
|
# core cipher routines are written separately for each one.
|
||||||
|
|
||||||
|
for keylen in [128, 192, 256]:
|
||||||
|
hexTestValues = ["00000000", "00000001", "ffffffff"]
|
||||||
|
for ivHexBytes in itertools.product(*([hexTestValues] * 4)):
|
||||||
|
ivInteger = int("".join(ivHexBytes), 16)
|
||||||
|
test(keylen, ivInteger)
|
||||||
|
|
||||||
class standard_test_vectors(unittest.TestCase):
|
class standard_test_vectors(unittest.TestCase):
|
||||||
def testAES(self):
|
def testAES(self):
|
||||||
def vector(cipher, key, plaintext, ciphertext):
|
def vector(cipher, key, plaintext, ciphertext):
|
||||||
|
Loading…
x
Reference in New Issue
Block a user