summaryrefslogtreecommitdiff
path: root/python
diff options
context:
space:
mode:
authorStefan Metzmacher <metze@samba.org>2020-03-20 12:47:39 +0100
committerStefan Metzmacher <metze@samba.org>2020-03-27 18:17:35 +0000
commit8bdd37997686d4ca60584bdfda78440be8432405 (patch)
treeabf145ed24d0cb77e4bb24d3dfe90e1a99a887ec /python
parent679bb52c957dafcec96ff37f87d8c3496996b909 (diff)
downloadsamba-8bdd37997686d4ca60584bdfda78440be8432405.tar.gz
python/tests/krb5: convert kcrypto.py to python3-cryptography and a few Samba helpers
Signed-off-by: Stefan Metzmacher <metze@samba.org> Reviewed-by: Isaac Boukris <iboukris@samba.org>
Diffstat (limited to 'python')
-rwxr-xr-x[-rw-r--r--]python/samba/tests/krb5/kcrypto.py460
1 files changed, 273 insertions, 187 deletions
diff --git a/python/samba/tests/krb5/kcrypto.py b/python/samba/tests/krb5/kcrypto.py
index 18c0f71c24c..0907d881b68 100644..100755
--- a/python/samba/tests/krb5/kcrypto.py
+++ b/python/samba/tests/krb5/kcrypto.py
@@ -1,3 +1,5 @@
+#!/usr/bin/env python3
+#
# Copyright (C) 2013 by the Massachusetts Institute of Technology.
# All rights reserved.
#
@@ -40,14 +42,26 @@
# - Cipher state only needed for kcmd suite
# - Nonstandard enctypes and cksumtypes like des-hmac-sha1
+import sys
+import os
+
+sys.path.insert(0, "bin/python")
+os.environ["PYTHONUNBUFFERED"] = "1"
+
from math import gcd
from functools import reduce
from struct import pack, unpack
-from Crypto.Cipher import AES, DES3, ARC4
-from Crypto.Hash import HMAC, MD4, MD5, SHA
-from Crypto.Protocol.KDF import PBKDF2
-from Crypto.Random import get_random_bytes
-
+from cryptography.hazmat.primitives import hashes
+from cryptography.hazmat.primitives import hmac
+from cryptography.hazmat.primitives.ciphers import algorithms as ciphers
+from cryptography.hazmat.primitives.ciphers import modes
+from cryptography.hazmat.primitives.ciphers.base import Cipher
+from cryptography.hazmat.backends import default_backend
+from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC
+from samba.tests import TestCase
+from samba.credentials import Credentials
+from samba import generate_random_bytes as get_random_bytes
+from samba.compat import get_string, get_bytes
class Enctype(object):
DES_CRC = 1
@@ -97,6 +111,15 @@ def _mac_equal(mac1, mac2):
res |= x ^ y
return res == 0
+def SIMPLE_HASH(string, algo_cls):
+ hash_ctx = hashes.Hash(algo_cls(), default_backend())
+ hash_ctx.update(string)
+ return hash_ctx.finalize()
+
+def HMAC_HASH(key, string, algo_cls):
+ hmac_ctx = hmac.HMAC(key, algo_cls(), default_backend())
+ hmac_ctx.update(string)
+ return hmac_ctx.finalize()
def _nfold(str, nbytes):
# Convert str to a string of length nbytes using the RFC 3961 nfold
@@ -199,7 +222,7 @@ class _SimplifiedEnctype(_EnctypeProfile):
if confounder is None:
confounder = get_random_bytes(cls.blocksize)
basic_plaintext = confounder + _zeropad(plaintext, cls.padsize)
- hmac = HMAC.new(ki.contents, basic_plaintext, cls.hashmod).digest()
+ hmac = HMAC_HASH(ki.contents, basic_plaintext, cls.hashalgo)
return cls.basic_encrypt(ke, basic_plaintext) + hmac[:cls.macsize]
@classmethod
@@ -212,7 +235,7 @@ class _SimplifiedEnctype(_EnctypeProfile):
if len(basic_ctext) % cls.padsize != 0:
raise ValueError('ciphertext does not meet padding requirement')
basic_plaintext = cls.basic_decrypt(ke, basic_ctext)
- hmac = HMAC.new(ki.contents, basic_plaintext, cls.hashmod).digest()
+ hmac = HMAC_HASH(ki.contents, basic_plaintext, cls.hashalgo)
expmac = hmac[:cls.macsize]
if not _mac_equal(mac, expmac):
raise InvalidChecksum('ciphertext integrity failure')
@@ -223,7 +246,7 @@ class _SimplifiedEnctype(_EnctypeProfile):
def prf(cls, key, string):
# Hash the input. RFC 3961 says to truncate to the padding
# size, but implementations truncate to the block size.
- hashval = cls.hashmod.new(string).digest()
+ hashval = SIMPLE_HASH(string, cls.hashalgo)
truncated = hashval[:-(len(hashval) % cls.blocksize)]
# Encrypt the hash with a derived key.
kp = cls.derive(key, b'prf')
@@ -237,7 +260,7 @@ class _DES3CBC(_SimplifiedEnctype):
blocksize = 8
padsize = 8
macsize = 20
- hashmod = SHA
+ hashalgo = hashes.SHA1
@classmethod
def random_to_key(cls, seed):
@@ -272,14 +295,20 @@ class _DES3CBC(_SimplifiedEnctype):
@classmethod
def basic_encrypt(cls, key, plaintext):
assert len(plaintext) % 8 == 0
- des3 = DES3.new(key.contents, AES.MODE_CBC, bytes(8))
- return des3.encrypt(plaintext)
+ algo = ciphers.TripleDES(key.contents)
+ cbc = modes.CBC(bytes(8))
+ encryptor = Cipher(algo, cbc, default_backend()).encryptor()
+ ciphertext = encryptor.update(plaintext)
+ return ciphertext
@classmethod
def basic_decrypt(cls, key, ciphertext):
assert len(ciphertext) % 8 == 0
- des3 = DES3.new(key.contents, AES.MODE_CBC, bytes(8))
- return des3.decrypt(ciphertext)
+ algo = ciphers.TripleDES(key.contents)
+ cbc = modes.CBC(bytes(8))
+ decryptor = Cipher(algo, cbc, default_backend()).decryptor()
+ plaintext = decryptor.update(ciphertext)
+ return plaintext
class _AESEnctype(_SimplifiedEnctype):
@@ -287,21 +316,35 @@ class _AESEnctype(_SimplifiedEnctype):
blocksize = 16
padsize = 1
macsize = 12
- hashmod = SHA
+ hashalgo = hashes.SHA1
@classmethod
def string_to_key(cls, string, salt, params):
(iterations,) = unpack('>L', params or b'\x00\x00\x10\x00')
- prf = lambda p, s: HMAC.new(p, s, SHA).digest()
- seed = PBKDF2(string, salt, cls.seedsize, iterations, prf)
+ pwbytes = get_bytes(string)
+ kdf = PBKDF2HMAC(algorithm=hashes.SHA1(),
+ length=cls.seedsize,
+ salt=salt,
+ iterations=iterations,
+ backend=default_backend())
+ seed = kdf.derive(pwbytes)
tkey = cls.random_to_key(seed)
return cls.derive(tkey, b'kerberos')
@classmethod
def basic_encrypt(cls, key, plaintext):
assert len(plaintext) >= 16
- aes = AES.new(key.contents, AES.MODE_CBC, bytes(16))
- ctext = aes.encrypt(_zeropad(plaintext, 16))
+
+ algo = ciphers.AES(key.contents)
+ cbc = modes.CBC(bytes(16))
+ aes_ctx = Cipher(algo, cbc, default_backend())
+
+ def aes_encrypt(plaintext):
+ encryptor = aes_ctx.encryptor()
+ ciphertext = encryptor.update(plaintext)
+ return ciphertext
+
+ ctext = aes_encrypt(_zeropad(plaintext, 16))
if len(plaintext) > 16:
# Swap the last two ciphertext blocks and truncate the
# final block to match the plaintext length.
@@ -312,9 +355,18 @@ class _AESEnctype(_SimplifiedEnctype):
@classmethod
def basic_decrypt(cls, key, ciphertext):
assert len(ciphertext) >= 16
- aes = AES.new(key.contents, AES.MODE_ECB)
+
+ algo = ciphers.AES(key.contents)
+ cbc = modes.CBC(bytes(16))
+ aes_ctx = Cipher(algo, cbc, default_backend())
+
+ def aes_decrypt(ciphertext):
+ decryptor = aes_ctx.decryptor()
+ plaintext = decryptor.update(ciphertext)
+ return plaintext
+
if len(ciphertext) == 16:
- return aes.decrypt(ciphertext)
+ return aes_decrypt(ciphertext)
# Split the ciphertext into blocks. The last block may be partial.
cblocks = [ciphertext[p:p+16] for p in range(0, len(ciphertext), 16)]
lastlen = len(cblocks[-1])
@@ -322,19 +374,19 @@ class _AESEnctype(_SimplifiedEnctype):
prev_cblock = bytes(16)
plaintext = b''
for b in cblocks[:-2]:
- plaintext += _xorbytes(aes.decrypt(b), prev_cblock)
+ plaintext += _xorbytes(aes_decrypt(b), prev_cblock)
prev_cblock = b
# Decrypt the second-to-last cipher block. The left side of
# the decrypted block will be the final block of plaintext
# xor'd with the final partial cipher block; the right side
# will be the omitted bytes of ciphertext from the final
# block.
- b = aes.decrypt(cblocks[-2])
+ b = aes_decrypt(cblocks[-2])
lastplaintext =_xorbytes(b[:lastlen], cblocks[-1])
omitted = b[lastlen:]
# Decrypt the final cipher block plus the omitted bytes to get
# the second-to-last plaintext block.
- plaintext += _xorbytes(aes.decrypt(cblocks[-1] + omitted), prev_cblock)
+ plaintext += _xorbytes(aes_decrypt(cblocks[-1] + omitted), prev_cblock)
return plaintext + lastplaintext
@@ -365,32 +417,43 @@ class _RC4(_EnctypeProfile):
@classmethod
def string_to_key(cls, string, salt, params):
- utf16string = string.decode('UTF-8').encode('UTF-16LE')
- return Key(cls.enctype, MD4.new(utf16string).digest())
+ utf8string = get_string(string)
+ tmp = Credentials()
+ tmp.set_anonymous()
+ tmp.set_password(utf8string)
+ nthash = tmp.get_nt_hash()
+ return Key(cls.enctype, nthash)
@classmethod
def encrypt(cls, key, keyusage, plaintext, confounder):
if confounder is None:
confounder = get_random_bytes(8)
- ki = HMAC.new(key.contents, cls.usage_str(keyusage), MD5).digest()
- cksum = HMAC.new(ki, confounder + plaintext, MD5).digest()
- ke = HMAC.new(ki, cksum, MD5).digest()
- return cksum + ARC4.new(ke).encrypt(confounder + plaintext)
+ ki = HMAC_HASH(key.contents, cls.usage_str(keyusage), hashes.MD5)
+ cksum = HMAC_HASH(ki, confounder + plaintext, hashes.MD5)
+ ke = HMAC_HASH(ki, cksum, hashes.MD5)
+
+ encryptor = Cipher(ciphers.ARC4(ke), None, default_backend()).encryptor()
+ ctext = encryptor.update(confounder + plaintext)
+
+ return cksum + ctext
@classmethod
def decrypt(cls, key, keyusage, ciphertext):
if len(ciphertext) < 24:
raise ValueError('ciphertext too short')
cksum, basic_ctext = ciphertext[:16], ciphertext[16:]
- ki = HMAC.new(key.contents, cls.usage_str(keyusage), MD5).digest()
- ke = HMAC.new(ki, cksum, MD5).digest()
- basic_plaintext = ARC4.new(ke).decrypt(basic_ctext)
- exp_cksum = HMAC.new(ki, basic_plaintext, MD5).digest()
+ ki = HMAC_HASH(key.contents, cls.usage_str(keyusage), hashes.MD5)
+ ke = HMAC_HASH(ki, cksum, hashes.MD5)
+
+ decryptor = Cipher(ciphers.ARC4(ke), None, default_backend()).decryptor()
+ basic_plaintext = decryptor.update(basic_ctext)
+
+ exp_cksum = HMAC_HASH(ki, basic_plaintext, hashes.MD5)
ok = _mac_equal(cksum, exp_cksum)
if not ok and keyusage == 9:
# Try again with usage 8, due to RFC 4757 errata.
- ki = HMAC.new(key.contents, pack('<i', 8), MD5).digest()
- exp_cksum = HMAC.new(ki, basic_plaintext, MD5).digest()
+ ki = HMAC_HASH(key.contents, pack('<i', 8), hashes.MD5)
+ exp_cksum = HMAC_HASH(ki, basic_plaintext, hashes.MD5)
ok = _mac_equal(cksum, exp_cksum)
if not ok:
raise InvalidChecksum('ciphertext integrity failure')
@@ -399,7 +462,7 @@ class _RC4(_EnctypeProfile):
@classmethod
def prf(cls, key, string):
- return HMAC.new(key.contents, string, SHA).digest()
+ return HMAC_HASH(key.contents, string, hashes.SHA1)
class _ChecksumProfile(object):
@@ -424,7 +487,7 @@ class _SimplifiedChecksum(_ChecksumProfile):
@classmethod
def checksum(cls, key, keyusage, text):
kc = cls.enc.derive(key, pack('>iB', keyusage, 0x99))
- hmac = HMAC.new(kc.contents, text, cls.enc.hashmod).digest()
+ hmac = HMAC_HASH(kc.contents, text, cls.enc.hashalgo)
return hmac[:cls.macsize]
@classmethod
@@ -452,9 +515,9 @@ class _SHA1DES3(_SimplifiedChecksum):
class _HMACMD5(_ChecksumProfile):
@classmethod
def checksum(cls, key, keyusage, text):
- ksign = HMAC.new(key.contents, b'signaturekey\0', MD5).digest()
- md5hash = MD5.new(_RC4.usage_str(keyusage) + text).digest()
- return HMAC.new(ksign, md5hash, MD5).digest()
+ ksign = HMAC_HASH(key.contents, b'signaturekey\0', hashes.MD5)
+ md5hash = SIMPLE_HASH(_RC4.usage_str(keyusage) + text, hashes.MD5)
+ return HMAC_HASH(ksign, md5hash, hashes.MD5)
@classmethod
def verify(cls, key, keyusage, text, cksum):
@@ -564,150 +627,173 @@ def cf2(enctype, key1, key2, pepper1, pepper2):
return e.random_to_key(_xorbytes(prfplus(key1, pepper1, e.seedsize),
prfplus(key2, pepper2, e.seedsize)))
-
-if __name__ == '__main__':
- def h(hexstr):
- return bytes.fromhex(hexstr)
-
- # AES128 encrypt and decrypt
- kb = h('9062430C8CDA3388922E6D6A509F5B7A')
- conf = h('94B491F481485B9A0678CD3C4EA386AD')
- keyusage = 2
- plain = b'9 bytesss'
- ctxt = h('68FB9679601F45C78857B2BF820FD6E53ECA8D42FD4B1D7024A09205ABB7CD2E'
- 'C26C355D2F')
- k = Key(Enctype.AES128, kb)
- assert(encrypt(k, keyusage, plain, conf) == ctxt)
- assert(decrypt(k, keyusage, ctxt) == plain)
-
- # AES256 encrypt and decrypt
- kb = h('F1C795E9248A09338D82C3F8D5B567040B0110736845041347235B1404231398')
- conf = h('E45CA518B42E266AD98E165E706FFB60')
- keyusage = 4
- plain = b'30 bytes bytes bytes bytes byt'
- ctxt = h('D1137A4D634CFECE924DBC3BF6790648BD5CFF7DE0E7B99460211D0DAEF3D79A'
- '295C688858F3B34B9CBD6EEBAE81DAF6B734D4D498B6714F1C1D')
- k = Key(Enctype.AES256, kb)
- assert(encrypt(k, keyusage, plain, conf) == ctxt)
- assert(decrypt(k, keyusage, ctxt) == plain)
-
- # AES128 checksum
- kb = h('9062430C8CDA3388922E6D6A509F5B7A')
- keyusage = 3
- plain = b'eight nine ten eleven twelve thirteen'
- cksum = h('01A4B088D45628F6946614E3')
- k = Key(Enctype.AES128, kb)
- verify_checksum(Cksumtype.SHA1_AES128, k, keyusage, plain, cksum)
-
- # AES256 checksum
- kb = h('B1AE4CD8462AFF1677053CC9279AAC30B796FB81CE21474DD3DDBCFEA4EC76D7')
- keyusage = 4
- plain = b'fourteen'
- cksum = h('E08739E3279E2903EC8E3836')
- k = Key(Enctype.AES256, kb)
- verify_checksum(Cksumtype.SHA1_AES256, k, keyusage, plain, cksum)
-
- # AES128 string-to-key
- string = b'password'
- salt = b'ATHENA.MIT.EDUraeburn'
- params = h('00000002')
- kb = h('C651BF29E2300AC27FA469D693BDDA13')
- k = string_to_key(Enctype.AES128, string, salt, params)
- assert(k.contents == kb)
-
- # AES256 string-to-key
- string = b'X' * 64
- salt = b'pass phrase equals block size'
- params = h('000004B0')
- kb = h('89ADEE3608DB8BC71F1BFBFE459486B05618B70CBAE22092534E56C553BA4B34')
- k = string_to_key(Enctype.AES256, string, salt, params)
- assert(k.contents == kb)
-
- # AES128 prf
- kb = h('77B39A37A868920F2A51F9DD150C5717')
- k = string_to_key(Enctype.AES128, b'key1', b'key1')
- assert(prf(k, b'\x01\x61') == kb)
-
- # AES256 prf
- kb = h('0D674DD0F9A6806525A4D92E828BD15A')
- k = string_to_key(Enctype.AES256, b'key2', b'key2')
- assert(prf(k, b'\x02\x62') == kb)
-
- # AES128 cf2
- kb = h('97DF97E4B798B29EB31ED7280287A92A')
- k1 = string_to_key(Enctype.AES128, b'key1', b'key1')
- k2 = string_to_key(Enctype.AES128, b'key2', b'key2')
- k = cf2(Enctype.AES128, k1, k2, b'a', b'b')
- assert(k.contents == kb)
-
- # AES256 cf2
- kb = h('4D6CA4E629785C1F01BAF55E2E548566B9617AE3A96868C337CB93B5E72B1C7B')
- k1 = string_to_key(Enctype.AES256, b'key1', b'key1')
- k2 = string_to_key(Enctype.AES256, b'key2', b'key2')
- k = cf2(Enctype.AES256, k1, k2, b'a', b'b')
- assert(k.contents == kb)
-
- # DES3 encrypt and decrypt
- kb = h('0DD52094E0F41CECCB5BE510A764B35176E3981332F1E598')
- conf = h('94690A17B2DA3C9B')
- keyusage = 3
- plain = b'13 bytes byte'
- ctxt = h('839A17081ECBAFBCDC91B88C6955DD3C4514023CF177B77BF0D0177A16F705E8'
- '49CB7781D76A316B193F8D30')
- k = Key(Enctype.DES3, kb)
- assert(encrypt(k, keyusage, plain, conf) == ctxt)
- assert(decrypt(k, keyusage, ctxt) == _zeropad(plain, 8))
-
- # DES3 string-to-key
- string = b'password'
- salt = b'ATHENA.MIT.EDUraeburn'
- kb = h('850BB51358548CD05E86768C313E3BFEF7511937DCF72C3E')
- k = string_to_key(Enctype.DES3, string, salt)
- assert(k.contents == kb)
-
- # DES3 checksum
- kb = h('7A25DF8992296DCEDA0E135BC4046E2375B3C14C98FBC162')
- keyusage = 2
- plain = b'six seven'
- cksum = h('0EEFC9C3E049AABC1BA5C401677D9AB699082BB4')
- k = Key(Enctype.DES3, kb)
- verify_checksum(Cksumtype.SHA1_DES3, k, keyusage, plain, cksum)
-
- # DES3 cf2
- kb = h('E58F9EB643862C13AD38E529313462A7F73E62834FE54A01')
- k1 = string_to_key(Enctype.DES3, b'key1', b'key1')
- k2 = string_to_key(Enctype.DES3, b'key2', b'key2')
- k = cf2(Enctype.DES3, k1, k2, b'a', b'b')
- assert(k.contents == kb)
-
- # RC4 encrypt and decrypt
- kb = h('68F263DB3FCE15D031C9EAB02D67107A')
- conf = h('37245E73A45FBF72')
- keyusage = 4
- plain = b'30 bytes bytes bytes bytes byt'
- ctxt = h('95F9047C3AD75891C2E9B04B16566DC8B6EB9CE4231AFB2542EF87A7B5A0F260'
- 'A99F0460508DE0CECC632D07C354124E46C5D2234EB8')
- k = Key(Enctype.RC4, kb)
- assert(encrypt(k, keyusage, plain, conf) == ctxt)
- assert(decrypt(k, keyusage, ctxt) == plain)
-
- # RC4 string-to-key
- string = b'foo'
- kb = h('AC8E657F83DF82BEEA5D43BDAF7800CC')
- k = string_to_key(Enctype.RC4, string, None)
- assert(k.contents == kb)
-
- # RC4 checksum
- kb = h('F7D3A155AF5E238A0B7A871A96BA2AB2')
- keyusage = 6
- plain = b'seventeen eighteen nineteen twenty'
- cksum = h('EB38CC97E2230F59DA4117DC5859D7EC')
- k = Key(Enctype.RC4, kb)
- verify_checksum(Cksumtype.HMAC_MD5, k, keyusage, plain, cksum)
-
- # RC4 cf2
- kb = h('24D7F6B6BAE4E5C00D2082C5EBAB3672')
- k1 = string_to_key(Enctype.RC4, b'key1', b'key1')
- k2 = string_to_key(Enctype.RC4, b'key2', b'key2')
- k = cf2(Enctype.RC4, k1, k2, b'a', b'b')
- assert(k.contents == kb)
+def h(hexstr):
+ return bytes.fromhex(hexstr)
+
+class KcrytoTest(TestCase):
+ """kcrypto Test case."""
+
+ def test_aes128_crypr(self):
+ # AES128 encrypt and decrypt
+ kb = h('9062430C8CDA3388922E6D6A509F5B7A')
+ conf = h('94B491F481485B9A0678CD3C4EA386AD')
+ keyusage = 2
+ plain = b'9 bytesss'
+ ctxt = h('68FB9679601F45C78857B2BF820FD6E53ECA8D42FD4B1D7024A09205ABB7CD2E'
+ 'C26C355D2F')
+ k = Key(Enctype.AES128, kb)
+ self.assertEqual(encrypt(k, keyusage, plain, conf), ctxt)
+ self.assertEqual(decrypt(k, keyusage, ctxt), plain)
+
+ def test_aes256_crypt(self):
+ # AES256 encrypt and decrypt
+ kb = h('F1C795E9248A09338D82C3F8D5B567040B0110736845041347235B1404231398')
+ conf = h('E45CA518B42E266AD98E165E706FFB60')
+ keyusage = 4
+ plain = b'30 bytes bytes bytes bytes byt'
+ ctxt = h('D1137A4D634CFECE924DBC3BF6790648BD5CFF7DE0E7B99460211D0DAEF3D79A'
+ '295C688858F3B34B9CBD6EEBAE81DAF6B734D4D498B6714F1C1D')
+ k = Key(Enctype.AES256, kb)
+ self.assertEqual(encrypt(k, keyusage, plain, conf), ctxt)
+ self.assertEqual(decrypt(k, keyusage, ctxt), plain)
+
+ def test_aes128_checksum(self):
+ # AES128 checksum
+ kb = h('9062430C8CDA3388922E6D6A509F5B7A')
+ keyusage = 3
+ plain = b'eight nine ten eleven twelve thirteen'
+ cksum = h('01A4B088D45628F6946614E3')
+ k = Key(Enctype.AES128, kb)
+ verify_checksum(Cksumtype.SHA1_AES128, k, keyusage, plain, cksum)
+
+ def test_aes256_checksum(self):
+ # AES256 checksum
+ kb = h('B1AE4CD8462AFF1677053CC9279AAC30B796FB81CE21474DD3DDBCFEA4EC76D7')
+ keyusage = 4
+ plain = b'fourteen'
+ cksum = h('E08739E3279E2903EC8E3836')
+ k = Key(Enctype.AES256, kb)
+ verify_checksum(Cksumtype.SHA1_AES256, k, keyusage, plain, cksum)
+
+ def test_aes128_string_to_key(self):
+ # AES128 string-to-key
+ string = b'password'
+ salt = b'ATHENA.MIT.EDUraeburn'
+ params = h('00000002')
+ kb = h('C651BF29E2300AC27FA469D693BDDA13')
+ k = string_to_key(Enctype.AES128, string, salt, params)
+ self.assertEqual(k.contents, kb)
+
+ def test_aes256_string_to_key(self):
+ # AES256 string-to-key
+ string = b'X' * 64
+ salt = b'pass phrase equals block size'
+ params = h('000004B0')
+ kb = h('89ADEE3608DB8BC71F1BFBFE459486B05618B70CBAE22092534E56C553BA4B34')
+ k = string_to_key(Enctype.AES256, string, salt, params)
+ self.assertEqual(k.contents, kb)
+
+ def test_aes128_prf(self):
+ # AES128 prf
+ kb = h('77B39A37A868920F2A51F9DD150C5717')
+ k = string_to_key(Enctype.AES128, b'key1', b'key1')
+ self.assertEqual(prf(k, b'\x01\x61'), kb)
+
+ def test_aes256_prf(self):
+ # AES256 prf
+ kb = h('0D674DD0F9A6806525A4D92E828BD15A')
+ k = string_to_key(Enctype.AES256, b'key2', b'key2')
+ self.assertEqual(prf(k, b'\x02\x62'), kb)
+
+ def test_aes128_cf2(self):
+ # AES128 cf2
+ kb = h('97DF97E4B798B29EB31ED7280287A92A')
+ k1 = string_to_key(Enctype.AES128, b'key1', b'key1')
+ k2 = string_to_key(Enctype.AES128, b'key2', b'key2')
+ k = cf2(Enctype.AES128, k1, k2, b'a', b'b')
+ self.assertEqual(k.contents, kb)
+
+ def test_aes256_cf2(self):
+ # AES256 cf2
+ kb = h('4D6CA4E629785C1F01BAF55E2E548566B9617AE3A96868C337CB93B5E72B1C7B')
+ k1 = string_to_key(Enctype.AES256, b'key1', b'key1')
+ k2 = string_to_key(Enctype.AES256, b'key2', b'key2')
+ k = cf2(Enctype.AES256, k1, k2, b'a', b'b')
+ self.assertEqual(k.contents, kb)
+
+ def test_des3_crypt(self):
+ # DES3 encrypt and decrypt
+ kb = h('0DD52094E0F41CECCB5BE510A764B35176E3981332F1E598')
+ conf = h('94690A17B2DA3C9B')
+ keyusage = 3
+ plain = b'13 bytes byte'
+ ctxt = h('839A17081ECBAFBCDC91B88C6955DD3C4514023CF177B77BF0D0177A16F705E8'
+ '49CB7781D76A316B193F8D30')
+ k = Key(Enctype.DES3, kb)
+ self.assertEqual(encrypt(k, keyusage, plain, conf), ctxt)
+ self.assertEqual(decrypt(k, keyusage, ctxt), _zeropad(plain, 8))
+
+ def test_des3_string_to_key(self):
+ # DES3 string-to-key
+ string = b'password'
+ salt = b'ATHENA.MIT.EDUraeburn'
+ kb = h('850BB51358548CD05E86768C313E3BFEF7511937DCF72C3E')
+ k = string_to_key(Enctype.DES3, string, salt)
+ self.assertEqual(k.contents, kb)
+
+ def test_des3_checksum(self):
+ # DES3 checksum
+ kb = h('7A25DF8992296DCEDA0E135BC4046E2375B3C14C98FBC162')
+ keyusage = 2
+ plain = b'six seven'
+ cksum = h('0EEFC9C3E049AABC1BA5C401677D9AB699082BB4')
+ k = Key(Enctype.DES3, kb)
+ verify_checksum(Cksumtype.SHA1_DES3, k, keyusage, plain, cksum)
+
+ def test_des3_cf2(self):
+ # DES3 cf2
+ kb = h('E58F9EB643862C13AD38E529313462A7F73E62834FE54A01')
+ k1 = string_to_key(Enctype.DES3, b'key1', b'key1')
+ k2 = string_to_key(Enctype.DES3, b'key2', b'key2')
+ k = cf2(Enctype.DES3, k1, k2, b'a', b'b')
+ self.assertEqual(k.contents, kb)
+
+ def test_rc4_crypt(self):
+ # RC4 encrypt and decrypt
+ kb = h('68F263DB3FCE15D031C9EAB02D67107A')
+ conf = h('37245E73A45FBF72')
+ keyusage = 4
+ plain = b'30 bytes bytes bytes bytes byt'
+ ctxt = h('95F9047C3AD75891C2E9B04B16566DC8B6EB9CE4231AFB2542EF87A7B5A0F260'
+ 'A99F0460508DE0CECC632D07C354124E46C5D2234EB8')
+ k = Key(Enctype.RC4, kb)
+ self.assertEqual(encrypt(k, keyusage, plain, conf), ctxt)
+ self.assertEqual(decrypt(k, keyusage, ctxt), plain)
+
+ def test_rc4_string_to_key(self):
+ # RC4 string-to-key
+ string = b'foo'
+ kb = h('AC8E657F83DF82BEEA5D43BDAF7800CC')
+ k = string_to_key(Enctype.RC4, string, None)
+ self.assertEqual(k.contents, kb)
+
+ def test_rc4_checksum(self):
+ # RC4 checksum
+ kb = h('F7D3A155AF5E238A0B7A871A96BA2AB2')
+ keyusage = 6
+ plain = b'seventeen eighteen nineteen twenty'
+ cksum = h('EB38CC97E2230F59DA4117DC5859D7EC')
+ k = Key(Enctype.RC4, kb)
+ verify_checksum(Cksumtype.HMAC_MD5, k, keyusage, plain, cksum)
+
+ def test_rc4_cf2(self):
+ # RC4 cf2
+ kb = h('24D7F6B6BAE4E5C00D2082C5EBAB3672')
+ k1 = string_to_key(Enctype.RC4, b'key1', b'key1')
+ k2 = string_to_key(Enctype.RC4, b'key2', b'key2')
+ k = cf2(Enctype.RC4, k1, k2, b'a', b'b')
+ self.assertEqual(k.contents, kb)
+
+if __name__ == "__main__":
+ import unittest
+ unittest.main()