test_crypto_des.py 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194
  1. """passlib.tests -- unittests for passlib.crypto.des"""
  2. #=============================================================================
  3. # imports
  4. #=============================================================================
  5. from __future__ import with_statement, division
  6. # core
  7. from functools import partial
  8. # site
  9. # pkg
  10. # module
  11. from passlib.utils import getrandbytes
  12. from passlib.tests.utils import TestCase
  13. #=============================================================================
  14. # test DES routines
  15. #=============================================================================
  16. class DesTest(TestCase):
  17. descriptionPrefix = "passlib.crypto.des"
  18. # test vectors taken from http://www.skepticfiles.org/faq/testdes.htm
  19. des_test_vectors = [
  20. # key, plaintext, ciphertext
  21. (0x0000000000000000, 0x0000000000000000, 0x8CA64DE9C1B123A7),
  22. (0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF, 0x7359B2163E4EDC58),
  23. (0x3000000000000000, 0x1000000000000001, 0x958E6E627A05557B),
  24. (0x1111111111111111, 0x1111111111111111, 0xF40379AB9E0EC533),
  25. (0x0123456789ABCDEF, 0x1111111111111111, 0x17668DFC7292532D),
  26. (0x1111111111111111, 0x0123456789ABCDEF, 0x8A5AE1F81AB8F2DD),
  27. (0x0000000000000000, 0x0000000000000000, 0x8CA64DE9C1B123A7),
  28. (0xFEDCBA9876543210, 0x0123456789ABCDEF, 0xED39D950FA74BCC4),
  29. (0x7CA110454A1A6E57, 0x01A1D6D039776742, 0x690F5B0D9A26939B),
  30. (0x0131D9619DC1376E, 0x5CD54CA83DEF57DA, 0x7A389D10354BD271),
  31. (0x07A1133E4A0B2686, 0x0248D43806F67172, 0x868EBB51CAB4599A),
  32. (0x3849674C2602319E, 0x51454B582DDF440A, 0x7178876E01F19B2A),
  33. (0x04B915BA43FEB5B6, 0x42FD443059577FA2, 0xAF37FB421F8C4095),
  34. (0x0113B970FD34F2CE, 0x059B5E0851CF143A, 0x86A560F10EC6D85B),
  35. (0x0170F175468FB5E6, 0x0756D8E0774761D2, 0x0CD3DA020021DC09),
  36. (0x43297FAD38E373FE, 0x762514B829BF486A, 0xEA676B2CB7DB2B7A),
  37. (0x07A7137045DA2A16, 0x3BDD119049372802, 0xDFD64A815CAF1A0F),
  38. (0x04689104C2FD3B2F, 0x26955F6835AF609A, 0x5C513C9C4886C088),
  39. (0x37D06BB516CB7546, 0x164D5E404F275232, 0x0A2AEEAE3FF4AB77),
  40. (0x1F08260D1AC2465E, 0x6B056E18759F5CCA, 0xEF1BF03E5DFA575A),
  41. (0x584023641ABA6176, 0x004BD6EF09176062, 0x88BF0DB6D70DEE56),
  42. (0x025816164629B007, 0x480D39006EE762F2, 0xA1F9915541020B56),
  43. (0x49793EBC79B3258F, 0x437540C8698F3CFA, 0x6FBF1CAFCFFD0556),
  44. (0x4FB05E1515AB73A7, 0x072D43A077075292, 0x2F22E49BAB7CA1AC),
  45. (0x49E95D6D4CA229BF, 0x02FE55778117F12A, 0x5A6B612CC26CCE4A),
  46. (0x018310DC409B26D6, 0x1D9D5C5018F728C2, 0x5F4C038ED12B2E41),
  47. (0x1C587F1C13924FEF, 0x305532286D6F295A, 0x63FAC0D034D9F793),
  48. (0x0101010101010101, 0x0123456789ABCDEF, 0x617B3A0CE8F07100),
  49. (0x1F1F1F1F0E0E0E0E, 0x0123456789ABCDEF, 0xDB958605F8C8C606),
  50. (0xE0FEE0FEF1FEF1FE, 0x0123456789ABCDEF, 0xEDBFD1C66C29CCC7),
  51. (0x0000000000000000, 0xFFFFFFFFFFFFFFFF, 0x355550B2150E2451),
  52. (0xFFFFFFFFFFFFFFFF, 0x0000000000000000, 0xCAAAAF4DEAF1DBAE),
  53. (0x0123456789ABCDEF, 0x0000000000000000, 0xD5D44FF720683D0D),
  54. (0xFEDCBA9876543210, 0xFFFFFFFFFFFFFFFF, 0x2A2BB008DF97C2F2),
  55. ]
  56. def test_01_expand(self):
  57. """expand_des_key()"""
  58. from passlib.crypto.des import expand_des_key, shrink_des_key, \
  59. _KDATA_MASK, INT_56_MASK
  60. # make sure test vectors are preserved (sans parity bits)
  61. # uses ints, bytes are tested under # 02
  62. for key1, _, _ in self.des_test_vectors:
  63. key2 = shrink_des_key(key1)
  64. key3 = expand_des_key(key2)
  65. # NOTE: this assumes expand_des_key() sets parity bits to 0
  66. self.assertEqual(key3, key1 & _KDATA_MASK)
  67. # type checks
  68. self.assertRaises(TypeError, expand_des_key, 1.0)
  69. # too large
  70. self.assertRaises(ValueError, expand_des_key, INT_56_MASK+1)
  71. self.assertRaises(ValueError, expand_des_key, b"\x00"*8)
  72. # too small
  73. self.assertRaises(ValueError, expand_des_key, -1)
  74. self.assertRaises(ValueError, expand_des_key, b"\x00"*6)
  75. def test_02_shrink(self):
  76. """shrink_des_key()"""
  77. from passlib.crypto.des import expand_des_key, shrink_des_key, INT_64_MASK
  78. rng = self.getRandom()
  79. # make sure reverse works for some random keys
  80. # uses bytes, ints are tested under # 01
  81. for i in range(20):
  82. key1 = getrandbytes(rng, 7)
  83. key2 = expand_des_key(key1)
  84. key3 = shrink_des_key(key2)
  85. self.assertEqual(key3, key1)
  86. # type checks
  87. self.assertRaises(TypeError, shrink_des_key, 1.0)
  88. # too large
  89. self.assertRaises(ValueError, shrink_des_key, INT_64_MASK+1)
  90. self.assertRaises(ValueError, shrink_des_key, b"\x00"*9)
  91. # too small
  92. self.assertRaises(ValueError, shrink_des_key, -1)
  93. self.assertRaises(ValueError, shrink_des_key, b"\x00"*7)
  94. def _random_parity(self, key):
  95. """randomize parity bits"""
  96. from passlib.crypto.des import _KDATA_MASK, _KPARITY_MASK, INT_64_MASK
  97. rng = self.getRandom()
  98. return (key & _KDATA_MASK) | (rng.randint(0,INT_64_MASK) & _KPARITY_MASK)
  99. def test_03_encrypt_bytes(self):
  100. """des_encrypt_block()"""
  101. from passlib.crypto.des import (des_encrypt_block, shrink_des_key,
  102. _pack64, _unpack64)
  103. # run through test vectors
  104. for key, plaintext, correct in self.des_test_vectors:
  105. # convert to bytes
  106. key = _pack64(key)
  107. plaintext = _pack64(plaintext)
  108. correct = _pack64(correct)
  109. # test 64-bit key
  110. result = des_encrypt_block(key, plaintext)
  111. self.assertEqual(result, correct, "key=%r plaintext=%r:" %
  112. (key, plaintext))
  113. # test 56-bit version
  114. key2 = shrink_des_key(key)
  115. result = des_encrypt_block(key2, plaintext)
  116. self.assertEqual(result, correct, "key=%r shrink(key)=%r plaintext=%r:" %
  117. (key, key2, plaintext))
  118. # test with random parity bits
  119. for _ in range(20):
  120. key3 = _pack64(self._random_parity(_unpack64(key)))
  121. result = des_encrypt_block(key3, plaintext)
  122. self.assertEqual(result, correct, "key=%r rndparity(key)=%r plaintext=%r:" %
  123. (key, key3, plaintext))
  124. # check invalid keys
  125. stub = b'\x00' * 8
  126. self.assertRaises(TypeError, des_encrypt_block, 0, stub)
  127. self.assertRaises(ValueError, des_encrypt_block, b'\x00'*6, stub)
  128. # check invalid input
  129. self.assertRaises(TypeError, des_encrypt_block, stub, 0)
  130. self.assertRaises(ValueError, des_encrypt_block, stub, b'\x00'*7)
  131. # check invalid salts
  132. self.assertRaises(ValueError, des_encrypt_block, stub, stub, salt=-1)
  133. self.assertRaises(ValueError, des_encrypt_block, stub, stub, salt=1<<24)
  134. # check invalid rounds
  135. self.assertRaises(ValueError, des_encrypt_block, stub, stub, 0, rounds=0)
  136. def test_04_encrypt_ints(self):
  137. """des_encrypt_int_block()"""
  138. from passlib.crypto.des import des_encrypt_int_block
  139. # run through test vectors
  140. for key, plaintext, correct in self.des_test_vectors:
  141. # test 64-bit key
  142. result = des_encrypt_int_block(key, plaintext)
  143. self.assertEqual(result, correct, "key=%r plaintext=%r:" %
  144. (key, plaintext))
  145. # test with random parity bits
  146. for _ in range(20):
  147. key3 = self._random_parity(key)
  148. result = des_encrypt_int_block(key3, plaintext)
  149. self.assertEqual(result, correct, "key=%r rndparity(key)=%r plaintext=%r:" %
  150. (key, key3, plaintext))
  151. # check invalid keys
  152. self.assertRaises(TypeError, des_encrypt_int_block, b'\x00', 0)
  153. self.assertRaises(ValueError, des_encrypt_int_block, -1, 0)
  154. # check invalid input
  155. self.assertRaises(TypeError, des_encrypt_int_block, 0, b'\x00')
  156. self.assertRaises(ValueError, des_encrypt_int_block, 0, -1)
  157. # check invalid salts
  158. self.assertRaises(ValueError, des_encrypt_int_block, 0, 0, salt=-1)
  159. self.assertRaises(ValueError, des_encrypt_int_block, 0, 0, salt=1<<24)
  160. # check invalid rounds
  161. self.assertRaises(ValueError, des_encrypt_int_block, 0, 0, 0, rounds=0)
  162. #=============================================================================
  163. # eof
  164. #=============================================================================