crypto.py 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101
  1. from binascii import hexlify
  2. from ctypes import cdll, c_char_p, c_int, c_uint, c_void_p, byref, POINTER, create_string_buffer
  3. from ctypes.util import find_library
  4. import struct
  5. import unittest
  6. libcrypto = cdll.LoadLibrary(find_library('crypto'))
  7. libcrypto.PKCS5_PBKDF2_HMAC.argtypes = (c_char_p, c_int, c_char_p, c_int, c_int, c_void_p, c_int, c_char_p)
  8. libcrypto.EVP_sha256.restype = c_void_p
  9. libcrypto.AES_set_encrypt_key.argtypes = (c_char_p, c_int, c_char_p)
  10. libcrypto.AES_ctr128_encrypt.argtypes = (c_char_p, c_char_p, c_int, c_char_p, c_char_p, c_char_p, POINTER(c_uint))
  11. _int = struct.Struct('>I')
  12. _long = struct.Struct('>Q')
  13. bytes_to_int = lambda x, offset=0: _int.unpack_from(x, offset)[0]
  14. bytes_to_long = lambda x, offset=0: _long.unpack_from(x, offset)[0]
  15. long_to_bytes = lambda x: _long.pack(x)
  16. def pbkdf2_sha256(password, salt, iterations, size):
  17. key = create_string_buffer(size)
  18. rv = libcrypto.PKCS5_PBKDF2_HMAC(password, len(password), salt, len(salt), iterations, libcrypto.EVP_sha256(), size, key)
  19. if not rv:
  20. raise Exception('PKCS5_PBKDF2_HMAC failed')
  21. return key.raw
  22. def get_random_bytes(n):
  23. """Return n cryptographically strong pseudo-random bytes
  24. """
  25. buf = create_string_buffer(n)
  26. if not libcrypto.RAND_bytes(buf, n):
  27. raise Exception('RAND_bytes failed')
  28. return buf.raw
  29. class AES:
  30. def __init__(self, key, iv=None):
  31. self.key = create_string_buffer(2000)
  32. self.iv = create_string_buffer(16)
  33. self.buf = create_string_buffer(16)
  34. self.num = c_uint()
  35. self.reset(key, iv)
  36. def reset(self, key=None, iv=None):
  37. if key:
  38. libcrypto.AES_set_encrypt_key(key, len(key) * 8, self.key)
  39. if iv:
  40. self.iv.raw = iv
  41. self.num.value = 0
  42. def encrypt(self, data):
  43. out = create_string_buffer(len(data))
  44. libcrypto.AES_ctr128_encrypt(data, out, len(data), self.key, self.iv, self.buf, self.num)
  45. return out.raw
  46. decrypt = encrypt
  47. class CryptoTestCase(unittest.TestCase):
  48. def test_bytes_to_int(self):
  49. self.assertEqual(bytes_to_int(b'\0\0\0\1'), 1)
  50. def test_bytes_to_long(self):
  51. self.assertEqual(bytes_to_long(b'\0\0\0\0\0\0\0\1'), 1)
  52. self.assertEqual(long_to_bytes(1), b'\0\0\0\0\0\0\0\1')
  53. def test_pbkdf2_sha256(self):
  54. self.assertEqual(hexlify(pbkdf2_sha256(b'password', b'salt', 1, 32)),
  55. b'120fb6cffcf8b32c43e7225256c4f837a86548c92ccc35480805987cb70be17b')
  56. self.assertEqual(hexlify(pbkdf2_sha256(b'password', b'salt', 2, 32)),
  57. b'ae4d0c95af6b46d32d0adff928f06dd02a303f8ef3c251dfd6e2d85a95474c43')
  58. self.assertEqual(hexlify(pbkdf2_sha256(b'password', b'salt', 4096, 32)),
  59. b'c5e478d59288c841aa530db6845c4c8d962893a001ce4e11a4963873aa98134a')
  60. def test_get_random_bytes(self):
  61. bytes = get_random_bytes(10)
  62. bytes2 = get_random_bytes(10)
  63. self.assertEqual(len(bytes), 10)
  64. self.assertEqual(len(bytes2), 10)
  65. self.assertNotEqual(bytes, bytes2)
  66. def test_aes(self):
  67. key = b'X' * 32
  68. data = b'foo' * 10
  69. aes = AES(key)
  70. self.assertEqual(bytes_to_long(aes.iv.raw, 8), 0)
  71. cdata = aes.encrypt(data)
  72. self.assertEqual(hexlify(cdata), b'c6efb702de12498f34a2c2bbc8149e759996d08bf6dc5c610aefc0c3a466')
  73. self.assertEqual(bytes_to_long(aes.iv.raw, 8), 2)
  74. self.assertNotEqual(data, aes.decrypt(cdata))
  75. aes.reset(iv=b'\0' * 16)
  76. self.assertEqual(data, aes.decrypt(cdata))
  77. def suite():
  78. return unittest.TestLoader().loadTestsFromTestCase(CryptoTestCase)
  79. if __name__ == '__main__':
  80. unittest.main()