summaryrefslogtreecommitdiff
path: root/passlib/tests/test_utils_crypto.py
diff options
context:
space:
mode:
Diffstat (limited to 'passlib/tests/test_utils_crypto.py')
-rw-r--r--passlib/tests/test_utils_crypto.py550
1 files changed, 550 insertions, 0 deletions
diff --git a/passlib/tests/test_utils_crypto.py b/passlib/tests/test_utils_crypto.py
new file mode 100644
index 0000000..94c20e8
--- /dev/null
+++ b/passlib/tests/test_utils_crypto.py
@@ -0,0 +1,550 @@
+"""tests for passlib.utils.(des|pbkdf2|md4)"""
+#=========================================================
+#imports
+#=========================================================
+from __future__ import with_statement
+#core
+from binascii import hexlify, unhexlify
+import sys
+import random
+import warnings
+#site
+#pkg
+#module
+from passlib.utils.compat import b, bytes, bascii_to_str, irange, PY2, PY3, u, \
+ unicode, join_bytes
+from passlib.tests.utils import TestCase, Params as ak, enable_option, catch_warnings
+
+#=========================================================
+# support
+#=========================================================
+def hb(source):
+ return unhexlify(b(source))
+
+#=========================================================
+#test des module
+#=========================================================
+class DesTest(TestCase):
+
+ # test vectors taken from http://www.skepticfiles.org/faq/testdes.htm
+ des_test_vectors = [
+ # key, plaintext, ciphertext
+ (0x0000000000000000, 0x0000000000000000, 0x8CA64DE9C1B123A7),
+ (0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF, 0x7359B2163E4EDC58),
+ (0x3000000000000000, 0x1000000000000001, 0x958E6E627A05557B),
+ (0x1111111111111111, 0x1111111111111111, 0xF40379AB9E0EC533),
+ (0x0123456789ABCDEF, 0x1111111111111111, 0x17668DFC7292532D),
+ (0x1111111111111111, 0x0123456789ABCDEF, 0x8A5AE1F81AB8F2DD),
+ (0x0000000000000000, 0x0000000000000000, 0x8CA64DE9C1B123A7),
+ (0xFEDCBA9876543210, 0x0123456789ABCDEF, 0xED39D950FA74BCC4),
+ (0x7CA110454A1A6E57, 0x01A1D6D039776742, 0x690F5B0D9A26939B),
+ (0x0131D9619DC1376E, 0x5CD54CA83DEF57DA, 0x7A389D10354BD271),
+ (0x07A1133E4A0B2686, 0x0248D43806F67172, 0x868EBB51CAB4599A),
+ (0x3849674C2602319E, 0x51454B582DDF440A, 0x7178876E01F19B2A),
+ (0x04B915BA43FEB5B6, 0x42FD443059577FA2, 0xAF37FB421F8C4095),
+ (0x0113B970FD34F2CE, 0x059B5E0851CF143A, 0x86A560F10EC6D85B),
+ (0x0170F175468FB5E6, 0x0756D8E0774761D2, 0x0CD3DA020021DC09),
+ (0x43297FAD38E373FE, 0x762514B829BF486A, 0xEA676B2CB7DB2B7A),
+ (0x07A7137045DA2A16, 0x3BDD119049372802, 0xDFD64A815CAF1A0F),
+ (0x04689104C2FD3B2F, 0x26955F6835AF609A, 0x5C513C9C4886C088),
+ (0x37D06BB516CB7546, 0x164D5E404F275232, 0x0A2AEEAE3FF4AB77),
+ (0x1F08260D1AC2465E, 0x6B056E18759F5CCA, 0xEF1BF03E5DFA575A),
+ (0x584023641ABA6176, 0x004BD6EF09176062, 0x88BF0DB6D70DEE56),
+ (0x025816164629B007, 0x480D39006EE762F2, 0xA1F9915541020B56),
+ (0x49793EBC79B3258F, 0x437540C8698F3CFA, 0x6FBF1CAFCFFD0556),
+ (0x4FB05E1515AB73A7, 0x072D43A077075292, 0x2F22E49BAB7CA1AC),
+ (0x49E95D6D4CA229BF, 0x02FE55778117F12A, 0x5A6B612CC26CCE4A),
+ (0x018310DC409B26D6, 0x1D9D5C5018F728C2, 0x5F4C038ED12B2E41),
+ (0x1C587F1C13924FEF, 0x305532286D6F295A, 0x63FAC0D034D9F793),
+ (0x0101010101010101, 0x0123456789ABCDEF, 0x617B3A0CE8F07100),
+ (0x1F1F1F1F0E0E0E0E, 0x0123456789ABCDEF, 0xDB958605F8C8C606),
+ (0xE0FEE0FEF1FEF1FE, 0x0123456789ABCDEF, 0xEDBFD1C66C29CCC7),
+ (0x0000000000000000, 0xFFFFFFFFFFFFFFFF, 0x355550B2150E2451),
+ (0xFFFFFFFFFFFFFFFF, 0x0000000000000000, 0xCAAAAF4DEAF1DBAE),
+ (0x0123456789ABCDEF, 0x0000000000000000, 0xD5D44FF720683D0D),
+ (0xFEDCBA9876543210, 0xFFFFFFFFFFFFFFFF, 0x2A2BB008DF97C2F2),
+ ]
+
+ def test_01_expand(self):
+ "test expand_des_key()"
+ from passlib.utils.des import expand_des_key, shrink_des_key, \
+ _KDATA_MASK, INT_56_MASK
+
+ # make sure test vectors are preserved (sans parity bits)
+ # uses ints, bytes are tested under #02
+ for key1, _, _ in self.des_test_vectors:
+ key2 = shrink_des_key(key1)
+ key3 = expand_des_key(key2)
+ # NOTE: this assumes expand_des_key() sets parity bits to 0
+ self.assertEqual(key3, key1 & _KDATA_MASK)
+
+ # type checks
+ self.assertRaises(TypeError, expand_des_key, 1.0)
+
+ # too large
+ self.assertRaises(ValueError, expand_des_key, INT_56_MASK+1)
+ self.assertRaises(ValueError, expand_des_key, b("\x00")*8)
+
+ # too small
+ self.assertRaises(ValueError, expand_des_key, -1)
+ self.assertRaises(ValueError, expand_des_key, b("\x00")*6)
+
+ def test_02_shrink(self):
+ "test shrink_des_key()"
+ from passlib.utils.des import expand_des_key, shrink_des_key, \
+ INT_64_MASK
+ from passlib.utils import random, getrandbytes
+
+ # make sure reverse works for some random keys
+ # uses bytes, ints are tested under #01
+ for i in range(20):
+ key1 = getrandbytes(random, 7)
+ key2 = expand_des_key(key1)
+ key3 = shrink_des_key(key2)
+ self.assertEqual(key3, key1)
+
+ # type checks
+ self.assertRaises(TypeError, shrink_des_key, 1.0)
+
+ # too large
+ self.assertRaises(ValueError, shrink_des_key, INT_64_MASK+1)
+ self.assertRaises(ValueError, shrink_des_key, b("\x00")*9)
+
+ # too small
+ self.assertRaises(ValueError, shrink_des_key, -1)
+ self.assertRaises(ValueError, shrink_des_key, b("\x00")*7)
+
+ def _random_parity(self, key):
+ "randomize parity bits"
+ from passlib.utils.des import _KDATA_MASK, _KPARITY_MASK, INT_64_MASK
+ from passlib.utils import rng
+ return (key & _KDATA_MASK) | (rng.randint(0,INT_64_MASK) & _KPARITY_MASK)
+
+ def test_03_encrypt_bytes(self):
+ "test des_encrypt_block()"
+ from passlib.utils.des import (des_encrypt_block, shrink_des_key,
+ _pack64, _unpack64)
+
+ # run through test vectors
+ for key, plaintext, correct in self.des_test_vectors:
+ # convert to bytes
+ key = _pack64(key)
+ plaintext = _pack64(plaintext)
+ correct = _pack64(correct)
+
+ # test 64-bit key
+ result = des_encrypt_block(key, plaintext)
+ self.assertEqual(result, correct, "key=%r plaintext=%r:" %
+ (key, plaintext))
+
+ # test 56-bit version
+ key2 = shrink_des_key(key)
+ result = des_encrypt_block(key2, plaintext)
+ self.assertEqual(result, correct, "key=%r shrink(key)=%r plaintext=%r:" %
+ (key, key2, plaintext))
+
+ # test with random parity bits
+ for _ in range(20):
+ key3 = _pack64(self._random_parity(_unpack64(key)))
+ result = des_encrypt_block(key3, plaintext)
+ self.assertEqual(result, correct, "key=%r rndparity(key)=%r plaintext=%r:" %
+ (key, key3, plaintext))
+
+ # check invalid keys
+ stub = b('\x00') * 8
+ self.assertRaises(TypeError, des_encrypt_block, 0, stub)
+ self.assertRaises(ValueError, des_encrypt_block, b('\x00')*6, stub)
+
+ # check invalid input
+ self.assertRaises(TypeError, des_encrypt_block, stub, 0)
+ self.assertRaises(ValueError, des_encrypt_block, stub, b('\x00')*7)
+
+ # check invalid salts
+ self.assertRaises(ValueError, des_encrypt_block, stub, stub, salt=-1)
+ self.assertRaises(ValueError, des_encrypt_block, stub, stub, salt=1<<24)
+
+ # check invalid rounds
+ self.assertRaises(ValueError, des_encrypt_block, stub, stub, 0, rounds=0)
+
+ def test_04_encrypt_ints(self):
+ "test des_encrypt_int_block()"
+ from passlib.utils.des import (des_encrypt_int_block, shrink_des_key)
+
+ # run through test vectors
+ for key, plaintext, correct in self.des_test_vectors:
+ # test 64-bit key
+ result = des_encrypt_int_block(key, plaintext)
+ self.assertEqual(result, correct, "key=%r plaintext=%r:" %
+ (key, plaintext))
+
+ # test with random parity bits
+ for _ in range(20):
+ key3 = self._random_parity(key)
+ result = des_encrypt_int_block(key3, plaintext)
+ self.assertEqual(result, correct, "key=%r rndparity(key)=%r plaintext=%r:" %
+ (key, key3, plaintext))
+
+ # check invalid keys
+ self.assertRaises(TypeError, des_encrypt_int_block, b('\x00'), 0)
+ self.assertRaises(ValueError, des_encrypt_int_block, -1, 0)
+
+ # check invalid input
+ self.assertRaises(TypeError, des_encrypt_int_block, 0, b('\x00'))
+ self.assertRaises(ValueError, des_encrypt_int_block, 0, -1)
+
+ # check invalid salts
+ self.assertRaises(ValueError, des_encrypt_int_block, 0, 0, salt=-1)
+ self.assertRaises(ValueError, des_encrypt_int_block, 0, 0, salt=1<<24)
+
+ # check invalid rounds
+ self.assertRaises(ValueError, des_encrypt_int_block, 0, 0, 0, rounds=0)
+
+#=========================================================
+#test md4
+#=========================================================
+class _MD4_Test(TestCase):
+ #test vectors from http://www.faqs.org/rfcs/rfc1320.html - A.5
+
+ hash = None
+
+ vectors = [
+ # input -> hex digest
+ (b(""), "31d6cfe0d16ae931b73c59d7e0c089c0"),
+ (b("a"), "bde52cb31de33e46245e05fbdbd6fb24"),
+ (b("abc"), "a448017aaf21d8525fc10ae87aa6729d"),
+ (b("message digest"), "d9130a8164549fe818874806e1c7014b"),
+ (b("abcdefghijklmnopqrstuvwxyz"), "d79e1c308aa5bbcdeea8ed63df412da9"),
+ (b("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"), "043f8582f241db351ce627e153e7f0e4"),
+ (b("12345678901234567890123456789012345678901234567890123456789012345678901234567890"), "e33b4ddc9c38f2199c3e7b164fcc0536"),
+ ]
+
+ def test_md4_update(self):
+ "test md4 update"
+ md4 = self.hash
+ h = md4(b(''))
+ self.assertEqual(h.hexdigest(), "31d6cfe0d16ae931b73c59d7e0c089c0")
+
+ #NOTE: under py2, hashlib methods try to encode to ascii,
+ # though shouldn't rely on that.
+ if PY3:
+ self.assertRaises(TypeError, h.update, u('x'))
+
+ h.update(b('a'))
+ self.assertEqual(h.hexdigest(), "bde52cb31de33e46245e05fbdbd6fb24")
+
+ h.update(b('bcdefghijklmnopqrstuvwxyz'))
+ self.assertEqual(h.hexdigest(), "d79e1c308aa5bbcdeea8ed63df412da9")
+
+ def test_md4_hexdigest(self):
+ "test md4 hexdigest()"
+ md4 = self.hash
+ for input, hex in self.vectors:
+ out = md4(input).hexdigest()
+ self.assertEqual(out, hex)
+
+ def test_md4_digest(self):
+ "test md4 digest()"
+ md4 = self.hash
+ for input, hex in self.vectors:
+ out = bascii_to_str(hexlify(md4(input).digest()))
+ self.assertEqual(out, hex)
+
+ def test_md4_copy(self):
+ "test md4 copy()"
+ md4 = self.hash
+ h = md4(b('abc'))
+
+ h2 = h.copy()
+ h2.update(b('def'))
+ self.assertEqual(h2.hexdigest(), '804e7f1c2586e50b49ac65db5b645131')
+
+ h.update(b('ghi'))
+ self.assertEqual(h.hexdigest(), 'c5225580bfe176f6deeee33dee98732c')
+
+#
+#now do a bunch of things to test multiple possible backends.
+#
+import passlib.utils.md4 as md4_mod
+
+has_ssl_md4 = (md4_mod.md4 is not md4_mod._builtin_md4)
+
+if has_ssl_md4:
+ class MD4_SSL_Test(_MD4_Test):
+ descriptionPrefix = "MD4 (SSL version)"
+ hash = staticmethod(md4_mod.md4)
+
+if not has_ssl_md4 or enable_option("cover"):
+ class MD4_Builtin_Test(_MD4_Test):
+ descriptionPrefix = "MD4 (builtin version)"
+ hash = md4_mod._builtin_md4
+
+#=========================================================
+#test passlib.utils.pbkdf2
+#=========================================================
+import hashlib
+import hmac
+from passlib.utils import pbkdf2
+
+#TODO: should we bother testing hmac_sha1() function? it's verified via sha1_crypt testing.
+class CryptoTest(TestCase):
+ "test various crypto functions"
+
+ ndn_formats = ["hashlib", "iana"]
+ ndn_values = [
+ # (iana name, hashlib name, ... other unnormalized names)
+ ("md5", "md5", "SCRAM-MD5-PLUS", "MD-5"),
+ ("sha1", "sha-1", "SCRAM-SHA-1", "SHA1"),
+ ("sha256", "sha-256", "SHA_256", "sha2-256"),
+ ("ripemd", "ripemd", "SCRAM-RIPEMD", "RIPEMD"),
+ ("ripemd160", "ripemd-160",
+ "SCRAM-RIPEMD-160", "RIPEmd160"),
+ ("test128", "test-128", "TEST128"),
+ ("test2", "test2", "TEST-2"),
+ ("test3128", "test3-128", "TEST-3-128"),
+ ]
+
+ def test_norm_hash_name(self):
+ "test norm_hash_name()"
+ from itertools import chain
+ from passlib.utils.pbkdf2 import norm_hash_name, _nhn_hash_names
+
+ # test formats
+ for format in self.ndn_formats:
+ norm_hash_name("md4", format)
+ self.assertRaises(ValueError, norm_hash_name, "md4", None)
+ self.assertRaises(ValueError, norm_hash_name, "md4", "fake")
+
+ # test types
+ self.assertEqual(norm_hash_name(u("MD4")), "md4")
+ self.assertEqual(norm_hash_name(b("MD4")), "md4")
+ self.assertRaises(TypeError, norm_hash_name, None)
+
+ # test selected results
+ with catch_warnings():
+ warnings.filterwarnings("ignore", '.*unknown hash')
+ for row in chain(_nhn_hash_names, self.ndn_values):
+ for idx, format in enumerate(self.ndn_formats):
+ correct = row[idx]
+ for value in row:
+ result = norm_hash_name(value, format)
+ self.assertEqual(result, correct,
+ "name=%r, format=%r:" % (value,
+ format))
+
+class KdfTest(TestCase):
+ "test kdf helpers"
+
+ def test_pbkdf1(self):
+ "test pbkdf1"
+ for secret, salt, rounds, klen, hash, correct in [
+ #http://www.di-mgt.com.au/cryptoKDFs.html
+ (b('password'), hb('78578E5A5D63CB06'), 1000, 16, 'sha1',
+ hb('dc19847e05c64d2faf10ebfb4a3d2a20')),
+ ]:
+ result = pbkdf2.pbkdf1(secret, salt, rounds, klen, hash)
+ self.assertEqual(result, correct)
+
+ #test rounds < 1
+ #test klen < 0
+ #test klen > block size
+ #test invalid hash
+
+#NOTE: this is not run directly, but via two subclasses (below)
+class _Pbkdf2BackendTest(TestCase):
+ "test builtin unix crypt backend"
+ enable_m2crypto = False
+
+ def setUp(self):
+ #disable m2crypto support so we'll always use software backend
+ if not self.enable_m2crypto:
+ self._orig_EVP = pbkdf2._EVP
+ pbkdf2._EVP = None
+ else:
+ #set flag so tests can check for m2crypto presence quickly
+ self.enable_m2crypto = bool(pbkdf2._EVP)
+ pbkdf2._clear_prf_cache()
+
+ def tearDown(self):
+ if not self.enable_m2crypto:
+ pbkdf2._EVP = self._orig_EVP
+ pbkdf2._clear_prf_cache()
+
+ #TODO: test get_prf() behavior in various situations - though overall behavior tested via pbkdf2
+
+ def test_rfc3962(self):
+ "rfc3962 test vectors"
+ self.assertFunctionResults(pbkdf2.pbkdf2, [
+ # result, secret, salt, rounds, keylen, digest="sha1"
+
+ #test case 1 / 128 bit
+ (
+ hb("cdedb5281bb2f801565a1122b2563515"),
+ b("password"), b("ATHENA.MIT.EDUraeburn"), 1, 16
+ ),
+
+ #test case 2 / 128 bit
+ (
+ hb("01dbee7f4a9e243e988b62c73cda935d"),
+ b("password"), b("ATHENA.MIT.EDUraeburn"), 2, 16
+ ),
+
+ #test case 2 / 256 bit
+ (
+ hb("01dbee7f4a9e243e988b62c73cda935da05378b93244ec8f48a99e61ad799d86"),
+ b("password"), b("ATHENA.MIT.EDUraeburn"), 2, 32
+ ),
+
+ #test case 3 / 256 bit
+ (
+ hb("5c08eb61fdf71e4e4ec3cf6ba1f5512ba7e52ddbc5e5142f708a31e2e62b1e13"),
+ b("password"), b("ATHENA.MIT.EDUraeburn"), 1200, 32
+ ),
+
+ #test case 4 / 256 bit
+ (
+ hb("d1daa78615f287e6a1c8b120d7062a493f98d203e6be49a6adf4fa574b6e64ee"),
+ b("password"), b('\x12\x34\x56\x78\x78\x56\x34\x12'), 5, 32
+ ),
+
+ #test case 5 / 256 bit
+ (
+ hb("139c30c0966bc32ba55fdbf212530ac9c5ec59f1a452f5cc9ad940fea0598ed1"),
+ b("X"*64), b("pass phrase equals block size"), 1200, 32
+ ),
+
+ #test case 6 / 256 bit
+ (
+ hb("9ccad6d468770cd51b10e6a68721be611a8b4d282601db3b36be9246915ec82a"),
+ b("X"*65), b("pass phrase exceeds block size"), 1200, 32
+ ),
+ ])
+
+ def test_rfc6070(self):
+ "rfc6070 test vectors"
+ self.assertFunctionResults(pbkdf2.pbkdf2, [
+
+ (
+ hb("0c60c80f961f0e71f3a9b524af6012062fe037a6"),
+ b("password"), b("salt"), 1, 20,
+ ),
+
+ (
+ hb("ea6c014dc72d6f8ccd1ed92ace1d41f0d8de8957"),
+ b("password"), b("salt"), 2, 20,
+ ),
+
+ (
+ hb("4b007901b765489abead49d926f721d065a429c1"),
+ b("password"), b("salt"), 4096, 20,
+ ),
+
+ #just runs too long - could enable if ALL option is set
+ ##(
+ ##
+ ## unhexlify("eefe3d61cd4da4e4e9945b3d6ba2158c2634e984"),
+ ## "password", "salt", 16777216, 20,
+ ##),
+
+ (
+ hb("3d2eec4fe41c849b80c8d83662c0e44a8b291a964cf2f07038"),
+ b("passwordPASSWORDpassword"),
+ b("saltSALTsaltSALTsaltSALTsaltSALTsalt"),
+ 4096, 25,
+ ),
+
+ (
+ hb("56fa6aa75548099dcc37d7f03425e0c3"),
+ b("pass\00word"), b("sa\00lt"), 4096, 16,
+ ),
+ ])
+
+ def test_invalid_values(self):
+
+ #invalid rounds
+ self.assertRaises(ValueError, pbkdf2.pbkdf2, b('password'), b('salt'), -1, 16)
+ self.assertRaises(ValueError, pbkdf2.pbkdf2, b('password'), b('salt'), 0, 16)
+ self.assertRaises(TypeError, pbkdf2.pbkdf2, b('password'), b('salt'), 'x', 16)
+
+ #invalid keylen
+ self.assertRaises(ValueError, pbkdf2.pbkdf2, b('password'), b('salt'),
+ 1, 20*(2**32-1)+1)
+
+ #invalid salt type
+ self.assertRaises(TypeError, pbkdf2.pbkdf2, b('password'), 5, 1, 10)
+
+ #invalid secret type
+ self.assertRaises(TypeError, pbkdf2.pbkdf2, 5, b('salt'), 1, 10)
+
+ #invalid hash
+ self.assertRaises(ValueError, pbkdf2.pbkdf2, b('password'), b('salt'), 1, 16, 'hmac-foo')
+ self.assertRaises(ValueError, pbkdf2.pbkdf2, b('password'), b('salt'), 1, 16, 'foo')
+ self.assertRaises(TypeError, pbkdf2.pbkdf2, b('password'), b('salt'), 1, 16, 5)
+
+ def test_default_keylen(self):
+ "test keylen==-1"
+ self.assertEqual(len(pbkdf2.pbkdf2(b('password'), b('salt'), 1, -1,
+ prf='hmac-sha1')), 20)
+
+ self.assertEqual(len(pbkdf2.pbkdf2(b('password'), b('salt'), 1, -1,
+ prf='hmac-sha256')), 32)
+
+ def test_hmac_sha1(self):
+ "test independant hmac_sha1() method"
+ self.assertEqual(
+ pbkdf2.hmac_sha1(b("secret"), b("salt")),
+ b('\xfc\xd4\x0c;]\r\x97\xc6\xf1S\x8d\x93\xb9\xeb\xc6\x00\x04.\x8b\xfe')
+ )
+
+ def test_sha1_string(self):
+ "test various prf values"
+ self.assertEqual(
+ pbkdf2.pbkdf2(b("secret"), b("salt"), 10, 16, "hmac-sha1"),
+ b('\xe2H\xfbk\x136QF\xf8\xacc\x07\xcc"(\x12')
+ )
+
+ def test_sha512_string(self):
+ "test alternate digest string (sha512)"
+ self.assertFunctionResults(pbkdf2.pbkdf2, [
+ # result, secret, salt, rounds, keylen, digest="sha1"
+
+ #case taken from example in http://grub.enbug.org/Authentication
+ (
+ hb("887CFF169EA8335235D8004242AA7D6187A41E3187DF0CE14E256D85ED97A97357AAA8FF0A3871AB9EEFF458392F462F495487387F685B7472FC6C29E293F0A0"),
+ b("hello"),
+ hb("9290F727ED06C38BA4549EF7DE25CF5642659211B7FC076F2D28FEFD71784BB8D8F6FB244A8CC5C06240631B97008565A120764C0EE9C2CB0073994D79080136"),
+ 10000, 64, "hmac-sha512"
+ ),
+ ])
+
+ def test_sha512_function(self):
+ "test custom digest function"
+ def prf(key, msg):
+ return hmac.new(key, msg, hashlib.sha512).digest()
+
+ self.assertFunctionResults(pbkdf2.pbkdf2, [
+ # result, secret, salt, rounds, keylen, digest="sha1"
+
+ #case taken from example in http://grub.enbug.org/Authentication
+ (
+ hb("887CFF169EA8335235D8004242AA7D6187A41E3187DF0CE14E256D85ED97A97357AAA8FF0A3871AB9EEFF458392F462F495487387F685B7472FC6C29E293F0A0"),
+ b("hello"),
+ hb("9290F727ED06C38BA4549EF7DE25CF5642659211B7FC076F2D28FEFD71784BB8D8F6FB244A8CC5C06240631B97008565A120764C0EE9C2CB0073994D79080136"),
+ 10000, 64, prf,
+ ),
+ ])
+
+has_m2crypto = (pbkdf2._EVP is not None)
+
+if has_m2crypto:
+ class Pbkdf2_M2Crypto_Test(_Pbkdf2BackendTest):
+ descriptionPrefix = "pbkdf2 (m2crypto backend)"
+ enable_m2crypto = True
+
+if not has_m2crypto or enable_option("cover"):
+ class Pbkdf2_Builtin_Test(_Pbkdf2BackendTest):
+ descriptionPrefix = "pbkdf2 (builtin backend)"
+ enable_m2crypto = False
+
+#=========================================================
+#EOF
+#=========================================================