diff --git a/setup.py b/setup.py index 7c52c2ff..2c413a6a 100644 --- a/setup.py +++ b/setup.py @@ -24,7 +24,7 @@ "wormhole-server = wormhole_server.runner:entry", ]}, install_requires=["spake2==0.3", "pynacl", "requests", "argparse", - "six", "twisted >= 16.1.0"], + "six", "twisted >= 16.1.0", "hkdf"], extras_require={"tor": ["txtorcon", "ipaddr"]}, test_suite="wormhole.test", cmdclass=commands, diff --git a/src/txwormhole/transcribe.py b/src/txwormhole/transcribe.py index 9932463c..2680081a 100644 --- a/src/txwormhole/transcribe.py +++ b/src/txwormhole/transcribe.py @@ -18,9 +18,12 @@ from wormhole import codes from wormhole.errors import ServerError, Timeout, WrongPasswordError, UsageError from wormhole.timing import DebugTiming -from wormhole.hkdf import HKDF +from hkdf import Hkdf from wormhole.channel_monitor import monitor +def HKDF(skm, outlen, salt=None, CTXinfo=b""): + return Hkdf(salt, skm).expand(CTXinfo, outlen) + CONFMSG_NONCE_LENGTH = 128//8 CONFMSG_MAC_LENGTH = 256//8 def make_confmsg(confkey, nonce): diff --git a/src/txwormhole/transit.py b/src/txwormhole/transit.py index f3145be7..70eb1082 100644 --- a/src/txwormhole/transit.py +++ b/src/txwormhole/transit.py @@ -8,11 +8,14 @@ from twisted.internet.defer import inlineCallbacks, returnValue from twisted.protocols import policies from nacl.secret import SecretBox -from wormhole.hkdf import HKDF +from hkdf import Hkdf from wormhole.errors import UsageError from wormhole.timing import DebugTiming from . import ipaddrs +def HKDF(skm, outlen, salt=None, CTXinfo=b""): + return Hkdf(salt, skm).expand(CTXinfo, outlen) + def debug(msg): if False: print(msg) diff --git a/src/wormhole/blocking/transcribe.py b/src/wormhole/blocking/transcribe.py index 38bb2cf8..d4b09356 100644 --- a/src/wormhole/blocking/transcribe.py +++ b/src/wormhole/blocking/transcribe.py @@ -11,9 +11,12 @@ from .. import codes from ..errors import ServerError, Timeout, WrongPasswordError, UsageError from ..timing import DebugTiming -from ..hkdf import HKDF +from hkdf import Hkdf from ..channel_monitor import monitor +def HKDF(skm, outlen, salt=None, CTXinfo=b""): + return Hkdf(salt, skm).expand(CTXinfo, outlen) + SECOND = 1 MINUTE = 60*SECOND diff --git a/src/wormhole/hkdf.py b/src/wormhole/hkdf.py deleted file mode 100644 index c3a477d9..00000000 --- a/src/wormhole/hkdf.py +++ /dev/null @@ -1,161 +0,0 @@ -from hashlib import sha256, sha1 -import hmac -import six - -def HKDF(SKM, dkLen, XTS=None, CTXinfo=b"", digest=sha256, - _test_expected_PRK=None): - assert isinstance(SKM, six.binary_type), type(SKM) - assert isinstance(XTS, (six.binary_type,type(None))), type(XTS) - assert isinstance(CTXinfo, six.binary_type), type(CTXinfo) - hlen = len(digest(b"").digest()) - assert dkLen <= hlen*255 - if XTS is None: - XTS = b"\x00"*hlen - # extract - PRK = hmac.new(XTS, SKM, digest).digest() - if _test_expected_PRK and _test_expected_PRK != PRK: - raise ValueError("test failed") - # expand - blocks = [] - counter = 1 - t = b"" - while hlen*len(blocks) < dkLen: - t = hmac.new(PRK, t+CTXinfo+six.int2byte(counter), digest).digest() - blocks.append(t) - counter += 1 - return b"".join(blocks)[:dkLen] - -def power_on_self_test(): - from binascii import hexlify, unhexlify - - def _test(IKM, salt, info, L, PRK, OKM, digest=sha256): - def remove_prefix(prefix, s): - assert s.startswith(prefix) - return s[len(prefix):] - ikm = unhexlify(remove_prefix("0x", IKM)) - salt = unhexlify(remove_prefix("0x", salt)) - info = unhexlify(remove_prefix("0x", info)) - prk = unhexlify(remove_prefix("0x", PRK)) - okm = unhexlify(remove_prefix("0x", OKM)) - if digest is None: - out = HKDF(ikm, L, salt, info, _test_expected_PRK=prk) - else: - out = HKDF(ikm, L, salt, info, digest=digest, - _test_expected_PRK=prk) - if okm != out: - raise ValueError("got %s, expected %s" % (hexlify(out), hexlify(okm))) - - # test vectors from RFC5869 - _test(IKM="0x0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b", - salt="0x000102030405060708090a0b0c", - info="0xf0f1f2f3f4f5f6f7f8f9", - L=42, - PRK=("0x077709362c2e32df0ddc3f0dc47bba63" - "90b6c73bb50f9c3122ec844ad7c2b3e5"), - OKM=("0x3cb25f25faacd57a90434f64d0362f2a" - "2d2d0a90cf1a5a4c5db02d56ecc4c5bf" - "34007208d5b887185865")) - - _test(IKM=("0x000102030405060708090a0b0c0d0e0f" - "101112131415161718191a1b1c1d1e1f" - "202122232425262728292a2b2c2d2e2f" - "303132333435363738393a3b3c3d3e3f" - "404142434445464748494a4b4c4d4e4f"), - salt=("0x606162636465666768696a6b6c6d6e6f" - "707172737475767778797a7b7c7d7e7f" - "808182838485868788898a8b8c8d8e8f" - "909192939495969798999a9b9c9d9e9f" - "a0a1a2a3a4a5a6a7a8a9aaabacadaeaf"), - info=("0xb0b1b2b3b4b5b6b7b8b9babbbcbdbebf" - "c0c1c2c3c4c5c6c7c8c9cacbcccdcecf" - "d0d1d2d3d4d5d6d7d8d9dadbdcdddedf" - "e0e1e2e3e4e5e6e7e8e9eaebecedeeef" - "f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff"), - L=82, - PRK=("0x06a6b88c5853361a06104c9ceb35b45c" - "ef760014904671014a193f40c15fc244"), - OKM=("0xb11e398dc80327a1c8e7f78c596a4934" - "4f012eda2d4efad8a050cc4c19afa97c" - "59045a99cac7827271cb41c65e590e09" - "da3275600c2f09b8367793a9aca3db71" - "cc30c58179ec3e87c14c01d5c1f3434f" - "1d87")) - - _test(IKM="0x0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b", - salt="0x", - info="0x", - L=42, - PRK=("0x19ef24a32c717b167f33a91d6f648bdf" - "96596776afdb6377ac434c1c293ccb04"), - OKM=("0x8da4e775a563c18f715f802a063c5a31" - "b8a11f5c5ee1879ec3454e5f3c738d2d" - "9d201395faa4b61a96c8")) - - _test(digest=sha1, - IKM="0x0b0b0b0b0b0b0b0b0b0b0b", - salt="0x000102030405060708090a0b0c", - info="0xf0f1f2f3f4f5f6f7f8f9", - L=42, - PRK="0x9b6c18c432a7bf8f0e71c8eb88f4b30baa2ba243", - OKM=("0x085a01ea1b10f36933068b56efa5ad81" - "a4f14b822f5b091568a9cdd4f155fda2" - "c22e422478d305f3f896")) - _test(digest=sha1, - IKM=("0x000102030405060708090a0b0c0d0e0f" - "101112131415161718191a1b1c1d1e1f" - "202122232425262728292a2b2c2d2e2f" - "303132333435363738393a3b3c3d3e3f" - "404142434445464748494a4b4c4d4e4f"), - salt=("0x606162636465666768696a6b6c6d6e6f" - "707172737475767778797a7b7c7d7e7f" - "808182838485868788898a8b8c8d8e8f" - "909192939495969798999a9b9c9d9e9f" - "a0a1a2a3a4a5a6a7a8a9aaabacadaeaf"), - info=("0xb0b1b2b3b4b5b6b7b8b9babbbcbdbebf" - "c0c1c2c3c4c5c6c7c8c9cacbcccdcecf" - "d0d1d2d3d4d5d6d7d8d9dadbdcdddedf" - "e0e1e2e3e4e5e6e7e8e9eaebecedeeef" - "f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff"), - L=82, - PRK="0x8adae09a2a307059478d309b26c4115a224cfaf6", - OKM=("0x0bd770a74d1160f7c9f12cd5912a06eb" - "ff6adcae899d92191fe4305673ba2ffe" - "8fa3f1a4e5ad79f3f334b3b202b2173c" - "486ea37ce3d397ed034c7f9dfeb15c5e" - "927336d0441f4c4300e2cff0d0900b52" - "d3b4")) - _test(digest=sha1, - IKM="0x0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b", - salt="0x", - info="0x", - L=42, - PRK="0xda8c8a73c7fa77288ec6f5e7c297786aa0d32d01", - OKM=("0x0ac1af7002b3d761d1e55298da9d0506" - "b9ae52057220a306e07b6b87e8df21d0" - "ea00033de03984d34918")) - - _test(digest=sha1, - IKM="0x0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c", - salt="0x", - info="0x", - L=42, - PRK="0x2adccada18779e7c2077ad2eb19d3f3e731385dd", - OKM=("0x2c91117204d745f3500d636a62f64f0a" - "b3bae548aa53d423b0d1f27ebba6f5e5" - "673a081d70cce7acfc48")) - - # finally test that HKDF() without a digest= uses SHA256 - - _test(digest=None, - IKM="0x0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b", - salt="0x", - info="0x", - L=42, - PRK=("0x19ef24a32c717b167f33a91d6f648bdf" - "96596776afdb6377ac434c1c293ccb04"), - OKM=("0x8da4e775a563c18f715f802a063c5a31" - "b8a11f5c5ee1879ec3454e5f3c738d2d" - "9d201395faa4b61a96c8")) - #print "all test passed" - -power_on_self_test() diff --git a/tests/test_hkdf.py b/tests/test_hkdf.py index 32e21f12..03d48927 100644 --- a/tests/test_hkdf.py +++ b/tests/test_hkdf.py @@ -1,27 +1,20 @@ from __future__ import print_function import unittest -from binascii import hexlify, unhexlify -from wormhole.hkdf import HKDF -#from hkdf import Hkdf +from binascii import unhexlify #, hexlify +from hkdf import Hkdf -def generate_KAT(): - print("KAT = [") - for salt in (None, b"", b"salt"): - for context in (b"", b"context"): - skm = b"secret" - out = HKDF(skm, 64, XTS=salt, CTXinfo=context) - hexout = " '%s' +\n '%s'" % (hexlify(out[:32]), - hexlify(out[32:])) - print(" (%r, %r, %r,\n%s)," % (salt, context, skm, hexout)) - print("]") +#def generate_KAT(): +# print("KAT = [") +# for salt in (b"", b"salt"): +# for context in (b"", b"context"): +# skm = b"secret" +# out = HKDF(skm, 64, XTS=salt, CTXinfo=context) +# hexout = " '%s' +\n '%s'" % (hexlify(out[:32]), +# hexlify(out[32:])) +# print(" (%r, %r, %r,\n%s)," % (salt, context, skm, hexout)) +# print("]") KAT = [ - (None, '', 'secret', - '2f34e5ff91ec85d53ca9b543683174d0cf550b60d5f52b24c97b386cfcf6cbbf' + - '9cfd42fd37e1e5a214d15f03058d7fee63dc28f564b7b9fe3da514f80daad4bf'), - (None, 'context', 'secret', - 'c24c303a1adfb4c3e2b092e6254ed481c41d8955ba8ec3f6a1473493a60c957b' + - '31b723018ca75557214d3d5c61c0c7a5315b103b21ff00cb03ebe023dc347a47'), ('', '', 'secret', '2f34e5ff91ec85d53ca9b543683174d0cf550b60d5f52b24c97b386cfcf6cbbf' + '9cfd42fd37e1e5a214d15f03058d7fee63dc28f564b7b9fe3da514f80daad4bf'), @@ -42,11 +35,11 @@ def test_kat(self): for (salt, context, skm, expected_hexout) in KAT: expected_out = unhexlify(expected_hexout) for outlen in range(0, len(expected_out)): - out = HKDF(skm, outlen, XTS=salt, CTXinfo=context) + out = Hkdf(salt.encode("ascii"), + skm.encode("ascii")).expand(context.encode("ascii"), + outlen) self.assertEqual(out, expected_out[:outlen]) - #out = Hkdf(salt, skm).expand(context, outlen) - #self.assertEqual(out, expected_out[:outlen]) -if __name__ == '__main__': - generate_KAT() +#if __name__ == '__main__': +# generate_KAT()