mirror of
https://git.tartarus.org/simon/putty.git
synced 2025-06-30 19:12:48 -05:00
Implement AES-GCM using the @openssh.com protocol IDs.
I only recently found out that OpenSSH defined their own protocol IDs for AES-GCM, defined to work the same as the standard ones except that they fixed the semantics for how you select the linked cipher+MAC pair during key exchange. (RFC 5647 defines protocol ids for AES-GCM in both the cipher and MAC namespaces, and requires that you MUST select both or neither - but this contradicts the selection policy set out in the base SSH RFCs, and there's no discussion of how you resolve a conflict between them! OpenSSH's answer is to do it the same way ChaCha20-Poly1305 works, because that will ensure the two suites don't fight.) People do occasionally ask us for this linked cipher/MAC pair, and now I know it's actually feasible, I've implemented it, including a pair of vector implementations for x86 and Arm using their respective architecture extensions for multiplying polynomials over GF(2). Unlike ChaCha20-Poly1305, I've kept the cipher and MAC implementations in separate objects, with an arm's-length link between them that the MAC uses when it needs to encrypt single cipher blocks to use as the inputs to the MAC algorithm. That enables the cipher and the MAC to be independently selected from their hardware-accelerated versions, just in case someone runs on a system that has polynomial multiplication instructions but not AES acceleration, or vice versa. There's a fourth implementation of the GCM MAC, which is a pure software implementation of the same algorithm used in the vectorised versions. It's too slow to use live, but I've kept it in the code for future testing needs, and because it's a convenient place to dump my design comments. The vectorised implementations are fairly crude as far as optimisation goes. I'm sure serious x86 _or_ Arm optimisation engineers would look at them and laugh. But GCM is a fast MAC compared to HMAC-SHA-256 (indeed compared to HMAC-anything-at-all), so it should at least be good enough to use. And we've got a working version with some tests now, so if someone else wants to improve them, they can.
This commit is contained in:
@ -145,6 +145,11 @@ def get_aes_impls():
|
||||
for impl in get_implementations("aes128_cbc")
|
||||
if impl.startswith("aes128_cbc_")]
|
||||
|
||||
def get_aesgcm_impls():
|
||||
return [impl.split("_", 1)[1]
|
||||
for impl in get_implementations("aesgcm")
|
||||
if impl.startswith("aesgcm_")]
|
||||
|
||||
class MyTestBase(unittest.TestCase):
|
||||
"Intermediate class that adds useful helper methods."
|
||||
def assertEqualBin(self, x, y):
|
||||
@ -2933,6 +2938,184 @@ Private-MAC: 5b1f6f4cc43eb0060d2c3e181bc0129343adba2b
|
||||
per_base_keytype_tests('rsa', run_ca_rsa_tests=True, ca_signflags=2)
|
||||
per_base_keytype_tests('rsa', run_ca_rsa_tests=True, ca_signflags=4)
|
||||
|
||||
def testAESGCMBlockBoundaries(self):
|
||||
# For standard AES-GCM test vectors, see the separate tests in
|
||||
# standard_test_vectors.testAESGCM. This function will test
|
||||
# the local interface, including the skip length and the
|
||||
# machinery for incremental MAC update.
|
||||
|
||||
def aesgcm(key, iv, aes_impl, gcm_impl):
|
||||
c = ssh_cipher_new('aes{:d}_gcm_{}'.format(8*len(key), aes_impl))
|
||||
m = ssh2_mac_new('aesgcm_{}'.format(gcm_impl), c)
|
||||
if m is None: return # skip test if HW GCM not available
|
||||
c.setkey(key)
|
||||
c.setiv(iv + b'\0'*4)
|
||||
m.setkey(b'')
|
||||
return c, m
|
||||
|
||||
def test_one(aes_impl, gcm_impl):
|
||||
# An actual test from a session with OpenSSH, which
|
||||
# demonstrates that the implementation in practice matches up
|
||||
# to what the test vectors say. This is its SSH2_MSG_EXT_INFO
|
||||
# packet.
|
||||
key = unhex('dbf98b2f56c83fb2f9476aa876511225')
|
||||
iv = unhex('9af15ecccf2bacaaa9625a6a')
|
||||
plain = unhex('1007000000020000000f736572766572'
|
||||
'2d7369672d616c6773000000db737368'
|
||||
'2d656432353531392c736b2d7373682d'
|
||||
'65643235353139406f70656e7373682e'
|
||||
'636f6d2c7373682d7273612c7273612d'
|
||||
'736861322d3235362c7273612d736861'
|
||||
'322d3531322c7373682d6473732c6563'
|
||||
'6473612d736861322d6e697374703235'
|
||||
'362c65636473612d736861322d6e6973'
|
||||
'74703338342c65636473612d73686132'
|
||||
'2d6e697374703532312c736b2d656364'
|
||||
'73612d736861322d6e69737470323536'
|
||||
'406f70656e7373682e636f6d2c776562'
|
||||
'617574686e2d736b2d65636473612d73'
|
||||
'6861322d6e69737470323536406f7065'
|
||||
'6e7373682e636f6d0000001f7075626c'
|
||||
'69636b65792d686f7374626f756e6440'
|
||||
'6f70656e7373682e636f6d0000000130'
|
||||
'5935130804ad4b19ed2789210290c438')
|
||||
aad = unhex('00000130')
|
||||
cipher = unhex('c4b88f35c1ef8aa6225033c3f185d648'
|
||||
'3c485d84930d5846f7851daacbff49d5'
|
||||
'8cf72169fca7ab3c170376df65dd69de'
|
||||
'c40a94c6b8e3da6d61161ab19be27466'
|
||||
'02e0dfa3330faae291ef4173a20e87a4'
|
||||
'd40728c645baa72916c1958531ef7b54'
|
||||
'27228513e53005e6d17b9bb384b8d8c1'
|
||||
'92b8a10b731459eed5a0fb120c283412'
|
||||
'e34445981df1257f1c35a06196731fed'
|
||||
'1b3115f419e754de0b634bf68768cb02'
|
||||
'29e70bb2259cedb5101ff6a4ac19aaad'
|
||||
'46f1c30697361b45d6c152c3069cee6b'
|
||||
'd46e9785d65ea6bf7fca41f0ac3c8e93'
|
||||
'ce940b0059c39d51e49c17f60d48d633'
|
||||
'5bae4402faab61d8d65221b24b400e65'
|
||||
'89f941ff48310231a42641851ea00832'
|
||||
'2c2d188f4cc6a4ec6002161c407d0a92'
|
||||
'f1697bb319fbec1ca63fa8e7ac171c85'
|
||||
'5b60142bfcf4e5b0a9ada3451799866e')
|
||||
|
||||
c, m = aesgcm(key, iv, aes_impl, gcm_impl)
|
||||
len_dec = c.decrypt_length(aad, 123)
|
||||
self.assertEqual(len_dec, aad) # length not actually encrypted
|
||||
m.start()
|
||||
# We expect 4 bytes skipped (the sequence number that
|
||||
# ChaCha20-Poly1305 wants at the start of its MAC), and 4
|
||||
# bytes AAD. These were initialised by the call to
|
||||
# encrypt_length.
|
||||
m.update(b'fake' + aad + cipher)
|
||||
self.assertEqualBin(m.genresult(),
|
||||
unhex('4a5a6d57d54888b4e58c57a96e00b73a'))
|
||||
self.assertEqualBin(c.decrypt(cipher), plain)
|
||||
|
||||
c, m = aesgcm(key, iv, aes_impl, gcm_impl)
|
||||
len_enc = c.encrypt_length(aad, 123)
|
||||
self.assertEqual(len_enc, aad) # length not actually encrypted
|
||||
self.assertEqualBin(c.encrypt(plain), cipher)
|
||||
|
||||
# Test incremental update.
|
||||
def testIncremental(skiplen, aad, plain):
|
||||
key, iv = b'SomeRandomKeyVal', b'SomeRandomIV'
|
||||
mac_input = b'x' * skiplen + aad + plain
|
||||
|
||||
c, m = aesgcm(key, iv, aes_impl, gcm_impl)
|
||||
aesgcm_set_prefix_lengths(m, skiplen, len(aad))
|
||||
|
||||
m.start()
|
||||
m.update(mac_input)
|
||||
reference_mac = m.genresult()
|
||||
|
||||
# Break the input just once, at each possible byte
|
||||
# position.
|
||||
for i in range(1, len(mac_input)):
|
||||
c.setiv(iv + b'\0'*4)
|
||||
m.setkey(b'')
|
||||
aesgcm_set_prefix_lengths(m, skiplen, len(aad))
|
||||
m.start()
|
||||
m.update(mac_input[:i])
|
||||
m.update(mac_input[i:])
|
||||
self.assertEqualBin(m.genresult(), reference_mac)
|
||||
|
||||
# Feed the entire input in a byte at a time.
|
||||
c.setiv(iv + b'\0'*4)
|
||||
m.setkey(b'')
|
||||
aesgcm_set_prefix_lengths(m, skiplen, len(aad))
|
||||
m.start()
|
||||
for i in range(len(mac_input)):
|
||||
m.update(mac_input[i:i+1])
|
||||
self.assertEqualBin(m.genresult(), reference_mac)
|
||||
|
||||
# Incremental test with more than a full block of each thing
|
||||
testIncremental(23, b'abcdefghijklmnopqrst',
|
||||
b'Lorem ipsum dolor sit amet')
|
||||
|
||||
# Incremental test with exactly a full block of each thing
|
||||
testIncremental(16, b'abcdefghijklmnop',
|
||||
b'Lorem ipsum dolo')
|
||||
|
||||
# Incremental test with less than a full block of each thing
|
||||
testIncremental(7, b'abcdefghij',
|
||||
b'Lorem ipsum')
|
||||
|
||||
for aes_impl in get_aes_impls():
|
||||
for gcm_impl in get_aesgcm_impls():
|
||||
with self.subTest(aes_impl=aes_impl, gcm_impl=gcm_impl):
|
||||
test_one(aes_impl, gcm_impl)
|
||||
|
||||
def testAESGCMIV(self):
|
||||
key = b'SomeRandomKeyVal'
|
||||
|
||||
def test(gcm, cbc, iv_fixed, iv_msg):
|
||||
gcm.setiv(ssh_uint32(iv_fixed) + ssh_uint64(iv_msg) + b'fake')
|
||||
|
||||
cbc.setiv(b'\0' * 16)
|
||||
preimage = cbc.decrypt(gcm.encrypt(b'\0' * 16))
|
||||
self.assertEqualBin(preimage, ssh_uint32(iv_fixed) +
|
||||
ssh_uint64(iv_msg) + ssh_uint32(1))
|
||||
cbc.setiv(b'\0' * 16)
|
||||
preimage = cbc.decrypt(gcm.encrypt(b'\0' * 16))
|
||||
self.assertEqualBin(preimage, ssh_uint32(iv_fixed) +
|
||||
ssh_uint64(iv_msg) + ssh_uint32(2))
|
||||
|
||||
gcm.next_message()
|
||||
iv_msg = (iv_msg + 1) & ((1<<64)-1)
|
||||
|
||||
cbc.setiv(b'\0' * 16)
|
||||
preimage = cbc.decrypt(gcm.encrypt(b'\0' * 16))
|
||||
self.assertEqualBin(preimage, ssh_uint32(iv_fixed) +
|
||||
ssh_uint64(iv_msg) + ssh_uint32(1))
|
||||
cbc.setiv(b'\0' * 16)
|
||||
preimage = cbc.decrypt(gcm.encrypt(b'\0' * 16))
|
||||
self.assertEqualBin(preimage, ssh_uint32(iv_fixed) +
|
||||
ssh_uint64(iv_msg) + ssh_uint32(2))
|
||||
|
||||
|
||||
for impl in get_aes_impls():
|
||||
with self.subTest(aes_impl=impl):
|
||||
gcm = ssh_cipher_new('aes{:d}_gcm_{}'.format(8*len(key), impl))
|
||||
gcm.setkey(key)
|
||||
|
||||
cbc = ssh_cipher_new('aes{:d}_cbc_{}'.format(8*len(key), impl))
|
||||
cbc.setkey(key)
|
||||
|
||||
# A simple test to ensure the low word gets
|
||||
# incremented and that the whole IV looks basically
|
||||
# the way we expect it to
|
||||
test(gcm, cbc, 0x27182818, 0x3141592653589793)
|
||||
|
||||
# Test that carries are propagated into the high word
|
||||
test(gcm, cbc, 0x27182818, 0x00000000FFFFFFFF)
|
||||
|
||||
# Test that carries _aren't_ propagated out of the
|
||||
# high word of the message counter into the fixed word
|
||||
# at the top
|
||||
test(gcm, cbc, 0x27182818, 0xFFFFFFFFFFFFFFFF)
|
||||
|
||||
class standard_test_vectors(MyTestBase):
|
||||
def testAES(self):
|
||||
def vector(cipher, key, plaintext, ciphertext):
|
||||
@ -3726,6 +3909,178 @@ class standard_test_vectors(MyTestBase):
|
||||
b'opaque="HRPCssKJSGjCrkzDg8OhwpzCiGPChXYjwrI2QmXDnsOS", '
|
||||
b'userhash=true')
|
||||
|
||||
def testAESGCM(self):
|
||||
def test(key, iv, plaintext, aad, ciphertext, mac):
|
||||
c = ssh_cipher_new('aes{:d}_gcm'.format(8*len(key)))
|
||||
m = ssh2_mac_new('aesgcm_{}'.format(impl), c)
|
||||
if m is None: return # skip test if HW GCM not available
|
||||
c.setkey(key)
|
||||
c.setiv(iv + b'\0'*4)
|
||||
m.setkey(b'')
|
||||
aesgcm_set_prefix_lengths(m, 0, len(aad))
|
||||
|
||||
# Some test cases have plaintext/ciphertext that is not a
|
||||
# multiple of the cipher block size. Our MAC
|
||||
# implementation supports this, but the cipher
|
||||
# implementation expects block-granular input.
|
||||
padlen = 15 & -len(plaintext)
|
||||
ciphertext_got = c.encrypt(plaintext + b'0' * padlen)[
|
||||
:len(plaintext)]
|
||||
|
||||
m.start()
|
||||
m.update(aad + ciphertext)
|
||||
mac_got = m.genresult()
|
||||
|
||||
self.assertEqualBin(ciphertext_got, ciphertext)
|
||||
self.assertEqualBin(mac_got, mac)
|
||||
|
||||
c.setiv(iv + b'\0'*4)
|
||||
|
||||
for impl in get_aesgcm_impls():
|
||||
# 'The Galois/Counter Mode of Operation', McGrew and
|
||||
# Viega, Appendix B. All the tests except the ones whose
|
||||
# IV is the wrong length, because handling that requires
|
||||
# an extra evaluation of the polynomial hash, which is
|
||||
# never used in an SSH context, so I didn't implement it
|
||||
# just for the sake of test vectors.
|
||||
|
||||
# Test Case 1
|
||||
test(unhex('00000000000000000000000000000000'),
|
||||
unhex('000000000000000000000000'),
|
||||
unhex(''), unhex(''), unhex(''),
|
||||
unhex('58e2fccefa7e3061367f1d57a4e7455a'))
|
||||
|
||||
# Test Case 2
|
||||
test(unhex('00000000000000000000000000000000'),
|
||||
unhex('000000000000000000000000'),
|
||||
unhex('00000000000000000000000000000000'),
|
||||
unhex(''),
|
||||
unhex('0388dace60b6a392f328c2b971b2fe78'),
|
||||
unhex('ab6e47d42cec13bdf53a67b21257bddf'))
|
||||
|
||||
# Test Case 3
|
||||
test(unhex('feffe9928665731c6d6a8f9467308308'),
|
||||
unhex('cafebabefacedbaddecaf888'),
|
||||
unhex('d9313225f88406e5a55909c5aff5269a'
|
||||
'86a7a9531534f7da2e4c303d8a318a72'
|
||||
'1c3c0c95956809532fcf0e2449a6b525'
|
||||
'b16aedf5aa0de657ba637b391aafd255'),
|
||||
unhex(''),
|
||||
unhex('42831ec2217774244b7221b784d0d49c'
|
||||
'e3aa212f2c02a4e035c17e2329aca12e'
|
||||
'21d514b25466931c7d8f6a5aac84aa05'
|
||||
'1ba30b396a0aac973d58e091473f5985'),
|
||||
unhex('4d5c2af327cd64a62cf35abd2ba6fab4'))
|
||||
|
||||
# Test Case 4
|
||||
test(unhex('feffe9928665731c6d6a8f9467308308'),
|
||||
unhex('cafebabefacedbaddecaf888'),
|
||||
unhex('d9313225f88406e5a55909c5aff5269a'
|
||||
'86a7a9531534f7da2e4c303d8a318a72'
|
||||
'1c3c0c95956809532fcf0e2449a6b525'
|
||||
'b16aedf5aa0de657ba637b39'),
|
||||
unhex('feedfacedeadbeeffeedfacedeadbeef'
|
||||
'abaddad2'),
|
||||
unhex('42831ec2217774244b7221b784d0d49c'
|
||||
'e3aa212f2c02a4e035c17e2329aca12e'
|
||||
'21d514b25466931c7d8f6a5aac84aa05'
|
||||
'1ba30b396a0aac973d58e091'),
|
||||
unhex('5bc94fbc3221a5db94fae95ae7121a47'))
|
||||
|
||||
# Test Case 7
|
||||
test(unhex('00000000000000000000000000000000'
|
||||
'0000000000000000'),
|
||||
unhex('000000000000000000000000'),
|
||||
unhex(''), unhex(''), unhex(''),
|
||||
unhex('cd33b28ac773f74ba00ed1f312572435'))
|
||||
|
||||
# Test Case 8
|
||||
test(unhex('00000000000000000000000000000000'
|
||||
'0000000000000000'),
|
||||
unhex('000000000000000000000000'),
|
||||
unhex('00000000000000000000000000000000'),
|
||||
unhex(''),
|
||||
unhex('98e7247c07f0fe411c267e4384b0f600'),
|
||||
unhex('2ff58d80033927ab8ef4d4587514f0fb'))
|
||||
|
||||
# Test Case 9
|
||||
test(unhex('feffe9928665731c6d6a8f9467308308'
|
||||
'feffe9928665731c'),
|
||||
unhex('cafebabefacedbaddecaf888'),
|
||||
unhex('d9313225f88406e5a55909c5aff5269a'
|
||||
'86a7a9531534f7da2e4c303d8a318a72'
|
||||
'1c3c0c95956809532fcf0e2449a6b525'
|
||||
'b16aedf5aa0de657ba637b391aafd255'),
|
||||
unhex(''),
|
||||
unhex('3980ca0b3c00e841eb06fac4872a2757'
|
||||
'859e1ceaa6efd984628593b40ca1e19c'
|
||||
'7d773d00c144c525ac619d18c84a3f47'
|
||||
'18e2448b2fe324d9ccda2710acade256'),
|
||||
unhex('9924a7c8587336bfb118024db8674a14'))
|
||||
|
||||
# Test Case 10
|
||||
test(unhex('feffe9928665731c6d6a8f9467308308'
|
||||
'feffe9928665731c'),
|
||||
unhex('cafebabefacedbaddecaf888'),
|
||||
unhex('d9313225f88406e5a55909c5aff5269a'
|
||||
'86a7a9531534f7da2e4c303d8a318a72'
|
||||
'1c3c0c95956809532fcf0e2449a6b525'
|
||||
'b16aedf5aa0de657ba637b39'),
|
||||
unhex('feedfacedeadbeeffeedfacedeadbeef'
|
||||
'abaddad2'),
|
||||
unhex('3980ca0b3c00e841eb06fac4872a2757'
|
||||
'859e1ceaa6efd984628593b40ca1e19c'
|
||||
'7d773d00c144c525ac619d18c84a3f47'
|
||||
'18e2448b2fe324d9ccda2710'),
|
||||
unhex('2519498e80f1478f37ba55bd6d27618c'))
|
||||
|
||||
# Test Case 13
|
||||
test(unhex('00000000000000000000000000000000'
|
||||
'00000000000000000000000000000000'),
|
||||
unhex('000000000000000000000000'),
|
||||
unhex(''), unhex(''), unhex(''),
|
||||
unhex('530f8afbc74536b9a963b4f1c4cb738b'))
|
||||
|
||||
# Test Case 14
|
||||
test(unhex('00000000000000000000000000000000'
|
||||
'00000000000000000000000000000000'),
|
||||
unhex('000000000000000000000000'),
|
||||
unhex('00000000000000000000000000000000'),
|
||||
unhex(''),
|
||||
unhex('cea7403d4d606b6e074ec5d3baf39d18'),
|
||||
unhex('d0d1c8a799996bf0265b98b5d48ab919'))
|
||||
|
||||
# Test Case 15
|
||||
test(unhex('feffe9928665731c6d6a8f9467308308'
|
||||
'feffe9928665731c6d6a8f9467308308'),
|
||||
unhex('cafebabefacedbaddecaf888'),
|
||||
unhex('d9313225f88406e5a55909c5aff5269a'
|
||||
'86a7a9531534f7da2e4c303d8a318a72'
|
||||
'1c3c0c95956809532fcf0e2449a6b525'
|
||||
'b16aedf5aa0de657ba637b391aafd255'),
|
||||
unhex(''),
|
||||
unhex('522dc1f099567d07f47f37a32a84427d'
|
||||
'643a8cdcbfe5c0c97598a2bd2555d1aa'
|
||||
'8cb08e48590dbb3da7b08b1056828838'
|
||||
'c5f61e6393ba7a0abcc9f662898015ad'),
|
||||
unhex('b094dac5d93471bdec1a502270e3cc6c'))
|
||||
|
||||
# Test Case 16
|
||||
test(unhex('feffe9928665731c6d6a8f9467308308'
|
||||
'feffe9928665731c6d6a8f9467308308'),
|
||||
unhex('cafebabefacedbaddecaf888'),
|
||||
unhex('d9313225f88406e5a55909c5aff5269a'
|
||||
'86a7a9531534f7da2e4c303d8a318a72'
|
||||
'1c3c0c95956809532fcf0e2449a6b525'
|
||||
'b16aedf5aa0de657ba637b39'),
|
||||
unhex('feedfacedeadbeeffeedfacedeadbeef'
|
||||
'abaddad2'),
|
||||
unhex('522dc1f099567d07f47f37a32a84427d'
|
||||
'643a8cdcbfe5c0c97598a2bd2555d1aa'
|
||||
'8cb08e48590dbb3da7b08b1056828838'
|
||||
'c5f61e6393ba7a0abcc9f662'),
|
||||
unhex('76fc6ece0f4e1768cddf8853bb2d551b'))
|
||||
|
||||
if __name__ == "__main__":
|
||||
# Run the tests, suppressing automatic sys.exit and collecting the
|
||||
# unittest.TestProgram instance returned by unittest.main instead.
|
||||
|
@ -25,10 +25,14 @@ def list_implementations(alg, checkfn):
|
||||
def list_cipher_implementations(alg):
|
||||
list_implementations(alg, lambda impl: ssh_cipher_new(impl) is not None)
|
||||
|
||||
def list_mac_implementations(alg):
|
||||
list_implementations(alg, lambda impl: ssh2_mac_new(impl, None) is not None)
|
||||
|
||||
def list_hash_implementations(alg):
|
||||
list_implementations(alg, lambda impl: ssh_hash_new(impl) is not None)
|
||||
|
||||
list_cipher_implementations("aes256_cbc")
|
||||
list_mac_implementations("aesgcm")
|
||||
list_hash_implementations("sha1")
|
||||
list_hash_implementations("sha256")
|
||||
list_hash_implementations("sha512")
|
||||
|
@ -36,6 +36,16 @@ BEGIN_ENUM_TYPE(macalg)
|
||||
ENUM_VALUE("hmac_sha1_96_buggy", &ssh_hmac_sha1_96_buggy)
|
||||
ENUM_VALUE("hmac_sha256", &ssh_hmac_sha256)
|
||||
ENUM_VALUE("poly1305", &ssh2_poly1305)
|
||||
ENUM_VALUE("aesgcm", &ssh2_aesgcm_mac)
|
||||
ENUM_VALUE("aesgcm", &ssh2_aesgcm_mac)
|
||||
ENUM_VALUE("aesgcm_sw", &ssh2_aesgcm_mac_sw)
|
||||
ENUM_VALUE("aesgcm_ref_poly", &ssh2_aesgcm_mac_ref_poly)
|
||||
#if HAVE_CLMUL
|
||||
ENUM_VALUE("aesgcm_clmul", &ssh2_aesgcm_mac_clmul)
|
||||
#endif
|
||||
#if HAVE_NEON_PMULL
|
||||
ENUM_VALUE("aesgcm_neon", &ssh2_aesgcm_mac_neon)
|
||||
#endif
|
||||
END_ENUM_TYPE(macalg)
|
||||
|
||||
BEGIN_ENUM_TYPE(keyalg)
|
||||
@ -60,31 +70,43 @@ BEGIN_ENUM_TYPE(cipheralg)
|
||||
ENUM_VALUE("3des_ssh1", &ssh_3des_ssh1)
|
||||
ENUM_VALUE("des_cbc", &ssh_des)
|
||||
ENUM_VALUE("aes256_ctr", &ssh_aes256_sdctr)
|
||||
ENUM_VALUE("aes256_gcm", &ssh_aes256_gcm)
|
||||
ENUM_VALUE("aes256_cbc", &ssh_aes256_cbc)
|
||||
ENUM_VALUE("aes192_ctr", &ssh_aes192_sdctr)
|
||||
ENUM_VALUE("aes192_gcm", &ssh_aes192_gcm)
|
||||
ENUM_VALUE("aes192_cbc", &ssh_aes192_cbc)
|
||||
ENUM_VALUE("aes128_ctr", &ssh_aes128_sdctr)
|
||||
ENUM_VALUE("aes128_gcm", &ssh_aes128_gcm)
|
||||
ENUM_VALUE("aes128_cbc", &ssh_aes128_cbc)
|
||||
ENUM_VALUE("aes256_ctr_sw", &ssh_aes256_sdctr_sw)
|
||||
ENUM_VALUE("aes256_gcm_sw", &ssh_aes256_gcm_sw)
|
||||
ENUM_VALUE("aes256_cbc_sw", &ssh_aes256_cbc_sw)
|
||||
ENUM_VALUE("aes192_ctr_sw", &ssh_aes192_sdctr_sw)
|
||||
ENUM_VALUE("aes192_gcm_sw", &ssh_aes192_gcm_sw)
|
||||
ENUM_VALUE("aes192_cbc_sw", &ssh_aes192_cbc_sw)
|
||||
ENUM_VALUE("aes128_ctr_sw", &ssh_aes128_sdctr_sw)
|
||||
ENUM_VALUE("aes128_gcm_sw", &ssh_aes128_gcm_sw)
|
||||
ENUM_VALUE("aes128_cbc_sw", &ssh_aes128_cbc_sw)
|
||||
#if HAVE_AES_NI
|
||||
ENUM_VALUE("aes256_ctr_ni", &ssh_aes256_sdctr_ni)
|
||||
ENUM_VALUE("aes256_gcm_ni", &ssh_aes256_gcm_ni)
|
||||
ENUM_VALUE("aes256_cbc_ni", &ssh_aes256_cbc_ni)
|
||||
ENUM_VALUE("aes192_ctr_ni", &ssh_aes192_sdctr_ni)
|
||||
ENUM_VALUE("aes192_gcm_ni", &ssh_aes192_gcm_ni)
|
||||
ENUM_VALUE("aes192_cbc_ni", &ssh_aes192_cbc_ni)
|
||||
ENUM_VALUE("aes128_ctr_ni", &ssh_aes128_sdctr_ni)
|
||||
ENUM_VALUE("aes128_gcm_ni", &ssh_aes128_gcm_ni)
|
||||
ENUM_VALUE("aes128_cbc_ni", &ssh_aes128_cbc_ni)
|
||||
#endif
|
||||
#if HAVE_NEON_CRYPTO
|
||||
ENUM_VALUE("aes256_ctr_neon", &ssh_aes256_sdctr_neon)
|
||||
ENUM_VALUE("aes256_gcm_neon", &ssh_aes256_gcm_neon)
|
||||
ENUM_VALUE("aes256_cbc_neon", &ssh_aes256_cbc_neon)
|
||||
ENUM_VALUE("aes192_ctr_neon", &ssh_aes192_sdctr_neon)
|
||||
ENUM_VALUE("aes192_gcm_neon", &ssh_aes192_gcm_neon)
|
||||
ENUM_VALUE("aes192_cbc_neon", &ssh_aes192_cbc_neon)
|
||||
ENUM_VALUE("aes128_ctr_neon", &ssh_aes128_sdctr_neon)
|
||||
ENUM_VALUE("aes128_gcm_neon", &ssh_aes128_gcm_neon)
|
||||
ENUM_VALUE("aes128_cbc_neon", &ssh_aes128_cbc_neon)
|
||||
#endif
|
||||
ENUM_VALUE("blowfish_ctr", &ssh_blowfish_ssh2_ctr)
|
||||
|
@ -277,6 +277,9 @@ FUNC(void, ssh2_mac_next_message, ARG(val_mac, m))
|
||||
FUNC_WRAPPED(val_string, ssh2_mac_genresult, ARG(val_mac, m))
|
||||
FUNC(val_string_asciz_const, ssh2_mac_text_name, ARG(val_mac, m))
|
||||
|
||||
FUNC(void, aesgcm_set_prefix_lengths,
|
||||
ARG(val_mac, m), ARG(uint, skip), ARG(uint, aad))
|
||||
|
||||
/*
|
||||
* The ssh_key abstraction. All the uses of BinarySink and
|
||||
* BinarySource in parameters are replaced with ordinary strings for
|
||||
|
@ -1329,7 +1329,16 @@ strbuf *get_implementations_commasep(ptrlen alg)
|
||||
strbuf *out = strbuf_new();
|
||||
put_datapl(out, alg);
|
||||
|
||||
if (ptrlen_startswith(alg, PTRLEN_LITERAL("aes"), NULL)) {
|
||||
if (ptrlen_startswith(alg, PTRLEN_LITERAL("aesgcm"), NULL)) {
|
||||
put_fmt(out, ",%.*s_sw", PTRLEN_PRINTF(alg));
|
||||
put_fmt(out, ",%.*s_ref_poly", PTRLEN_PRINTF(alg));
|
||||
#if HAVE_CLMUL
|
||||
put_fmt(out, ",%.*s_clmul", PTRLEN_PRINTF(alg));
|
||||
#endif
|
||||
#if HAVE_NEON_PMULL
|
||||
put_fmt(out, ",%.*s_neon", PTRLEN_PRINTF(alg));
|
||||
#endif
|
||||
} else if (ptrlen_startswith(alg, PTRLEN_LITERAL("aes"), NULL)) {
|
||||
put_fmt(out, ",%.*s_sw", PTRLEN_PRINTF(alg));
|
||||
#if HAVE_AES_NI
|
||||
put_fmt(out, ",%.*s_ni", PTRLEN_PRINTF(alg));
|
||||
|
@ -259,6 +259,12 @@ VOLATILE_WRAPPED_DEFN(static, size_t, looplimit, (size_t x))
|
||||
#define IF_SHA_NI(x)
|
||||
#endif
|
||||
|
||||
#if HAVE_CLMUL
|
||||
#define IF_CLMUL(x) x
|
||||
#else
|
||||
#define IF_CLMUL(x)
|
||||
#endif
|
||||
|
||||
#if HAVE_NEON_CRYPTO
|
||||
#define IF_NEON_CRYPTO(x) x
|
||||
#else
|
||||
@ -271,6 +277,12 @@ VOLATILE_WRAPPED_DEFN(static, size_t, looplimit, (size_t x))
|
||||
#define IF_NEON_SHA512(x)
|
||||
#endif
|
||||
|
||||
#if HAVE_NEON_PMULL
|
||||
#define IF_NEON_PMULL(x) x
|
||||
#else
|
||||
#define IF_NEON_PMULL(x)
|
||||
#endif
|
||||
|
||||
/* Ciphers that we expect to pass this test. Blowfish and Arcfour are
|
||||
* intentionally omitted, because we already know they don't. */
|
||||
#define CIPHERS(X, Y) \
|
||||
@ -280,28 +292,40 @@ VOLATILE_WRAPPED_DEFN(static, size_t, looplimit, (size_t x))
|
||||
X(Y, ssh_des) \
|
||||
X(Y, ssh_des_sshcom_ssh2) \
|
||||
X(Y, ssh_aes256_sdctr) \
|
||||
X(Y, ssh_aes256_gcm) \
|
||||
X(Y, ssh_aes256_cbc) \
|
||||
X(Y, ssh_aes192_sdctr) \
|
||||
X(Y, ssh_aes192_gcm) \
|
||||
X(Y, ssh_aes192_cbc) \
|
||||
X(Y, ssh_aes128_sdctr) \
|
||||
X(Y, ssh_aes128_gcm) \
|
||||
X(Y, ssh_aes128_cbc) \
|
||||
X(Y, ssh_aes256_sdctr_sw) \
|
||||
X(Y, ssh_aes256_gcm_sw) \
|
||||
X(Y, ssh_aes256_cbc_sw) \
|
||||
X(Y, ssh_aes192_sdctr_sw) \
|
||||
X(Y, ssh_aes192_gcm_sw) \
|
||||
X(Y, ssh_aes192_cbc_sw) \
|
||||
X(Y, ssh_aes128_sdctr_sw) \
|
||||
X(Y, ssh_aes128_gcm_sw) \
|
||||
X(Y, ssh_aes128_cbc_sw) \
|
||||
IF_AES_NI(X(Y, ssh_aes256_sdctr_ni)) \
|
||||
IF_AES_NI(X(Y, ssh_aes256_gcm_ni)) \
|
||||
IF_AES_NI(X(Y, ssh_aes256_cbc_ni)) \
|
||||
IF_AES_NI(X(Y, ssh_aes192_sdctr_ni)) \
|
||||
IF_AES_NI(X(Y, ssh_aes192_gcm_ni)) \
|
||||
IF_AES_NI(X(Y, ssh_aes192_cbc_ni)) \
|
||||
IF_AES_NI(X(Y, ssh_aes128_sdctr_ni)) \
|
||||
IF_AES_NI(X(Y, ssh_aes128_gcm_ni)) \
|
||||
IF_AES_NI(X(Y, ssh_aes128_cbc_ni)) \
|
||||
IF_NEON_CRYPTO(X(Y, ssh_aes256_sdctr_neon)) \
|
||||
IF_NEON_CRYPTO(X(Y, ssh_aes256_gcm_neon)) \
|
||||
IF_NEON_CRYPTO(X(Y, ssh_aes256_cbc_neon)) \
|
||||
IF_NEON_CRYPTO(X(Y, ssh_aes192_sdctr_neon)) \
|
||||
IF_NEON_CRYPTO(X(Y, ssh_aes192_gcm_neon)) \
|
||||
IF_NEON_CRYPTO(X(Y, ssh_aes192_cbc_neon)) \
|
||||
IF_NEON_CRYPTO(X(Y, ssh_aes128_sdctr_neon)) \
|
||||
IF_NEON_CRYPTO(X(Y, ssh_aes128_gcm_neon)) \
|
||||
IF_NEON_CRYPTO(X(Y, ssh_aes128_cbc_neon)) \
|
||||
X(Y, ssh2_chacha20_poly1305) \
|
||||
/* end of list */
|
||||
@ -317,9 +341,17 @@ VOLATILE_WRAPPED_DEFN(static, size_t, looplimit, (size_t x))
|
||||
X(Y, ssh_hmac_sha256) \
|
||||
/* end of list */
|
||||
|
||||
#define ALL_MACS(X, Y) \
|
||||
SIMPLE_MACS(X, Y) \
|
||||
X(Y, poly1305) \
|
||||
#define ALL_MACS(X, Y) \
|
||||
SIMPLE_MACS(X, Y) \
|
||||
X(Y, poly1305) \
|
||||
X(Y, aesgcm_sw_sw) \
|
||||
X(Y, aesgcm_sw_refpoly) \
|
||||
IF_AES_NI(X(Y, aesgcm_ni_sw)) \
|
||||
IF_NEON_CRYPTO(X(Y, aesgcm_neon_sw)) \
|
||||
IF_CLMUL(X(Y, aesgcm_sw_clmul)) \
|
||||
IF_NEON_PMULL(X(Y, aesgcm_sw_neon)) \
|
||||
IF_AES_NI(IF_CLMUL(X(Y, aesgcm_ni_clmul))) \
|
||||
IF_NEON_CRYPTO(IF_NEON_PMULL(X(Y, aesgcm_neon_neon))) \
|
||||
/* end of list */
|
||||
|
||||
#define MAC_TESTLIST(X, name) X(mac_ ## name)
|
||||
@ -1473,6 +1505,58 @@ static void test_mac_poly1305(void)
|
||||
test_mac(&ssh2_poly1305, &ssh2_chacha20_poly1305);
|
||||
}
|
||||
|
||||
static void test_mac_aesgcm_sw_sw(void)
|
||||
{
|
||||
test_mac(&ssh2_aesgcm_mac_sw, &ssh_aes128_gcm_sw);
|
||||
}
|
||||
|
||||
static void test_mac_aesgcm_sw_refpoly(void)
|
||||
{
|
||||
test_mac(&ssh2_aesgcm_mac_ref_poly, &ssh_aes128_gcm_sw);
|
||||
}
|
||||
|
||||
#if HAVE_AES_NI
|
||||
static void test_mac_aesgcm_ni_sw(void)
|
||||
{
|
||||
test_mac(&ssh2_aesgcm_mac_sw, &ssh_aes128_gcm_ni);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if HAVE_NEON_CRYPTO
|
||||
static void test_mac_aesgcm_neon_sw(void)
|
||||
{
|
||||
test_mac(&ssh2_aesgcm_mac_sw, &ssh_aes128_gcm_neon);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if HAVE_CLMUL
|
||||
static void test_mac_aesgcm_sw_clmul(void)
|
||||
{
|
||||
test_mac(&ssh2_aesgcm_mac_clmul, &ssh_aes128_gcm_sw);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if HAVE_NEON_PMULL
|
||||
static void test_mac_aesgcm_sw_neon(void)
|
||||
{
|
||||
test_mac(&ssh2_aesgcm_mac_neon, &ssh_aes128_gcm_sw);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if HAVE_AES_NI && HAVE_CLMUL
|
||||
static void test_mac_aesgcm_ni_clmul(void)
|
||||
{
|
||||
test_mac(&ssh2_aesgcm_mac_clmul, &ssh_aes128_gcm_ni);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if HAVE_NEON_CRYPTO && HAVE_NEON_PMULL
|
||||
static void test_mac_aesgcm_neon_neon(void)
|
||||
{
|
||||
test_mac(&ssh2_aesgcm_mac_neon, &ssh_aes128_gcm_neon);
|
||||
}
|
||||
#endif
|
||||
|
||||
static void test_hash(const ssh_hashalg *halg)
|
||||
{
|
||||
ssh_hash *h = ssh_hash_new(halg);
|
||||
|
Reference in New Issue
Block a user