crypto.pyx 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173
  1. """A thin OpenSSL wrapper
  2. This could be replaced by PyCrypto or something similar when the performance
  3. of their PBKDF2 implementation is comparable to the OpenSSL version.
  4. """
  5. from libc.stdlib cimport malloc, free
  6. API_VERSION = 2
  7. cdef extern from "openssl/rand.h":
  8. int RAND_bytes(unsigned char *buf, int num)
  9. cdef extern from "openssl/evp.h":
  10. ctypedef struct EVP_MD:
  11. pass
  12. ctypedef struct EVP_CIPHER:
  13. pass
  14. ctypedef struct EVP_CIPHER_CTX:
  15. unsigned char *iv
  16. pass
  17. ctypedef struct ENGINE:
  18. pass
  19. const EVP_MD *EVP_sha256()
  20. const EVP_CIPHER *EVP_aes_256_ctr()
  21. void EVP_CIPHER_CTX_init(EVP_CIPHER_CTX *a)
  22. void EVP_CIPHER_CTX_cleanup(EVP_CIPHER_CTX *a)
  23. int EVP_EncryptInit_ex(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *cipher, ENGINE *impl,
  24. const unsigned char *key, const unsigned char *iv)
  25. int EVP_DecryptInit_ex(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *cipher, ENGINE *impl,
  26. const unsigned char *key, const unsigned char *iv)
  27. int EVP_EncryptUpdate(EVP_CIPHER_CTX *ctx, unsigned char *out, int *outl,
  28. const unsigned char *in_, int inl)
  29. int EVP_DecryptUpdate(EVP_CIPHER_CTX *ctx, unsigned char *out, int *outl,
  30. const unsigned char *in_, int inl)
  31. int EVP_EncryptFinal_ex(EVP_CIPHER_CTX *ctx, unsigned char *out, int *outl)
  32. int EVP_DecryptFinal_ex(EVP_CIPHER_CTX *ctx, unsigned char *out, int *outl)
  33. int PKCS5_PBKDF2_HMAC(const char *password, int passwordlen,
  34. const unsigned char *salt, int saltlen, int iter,
  35. const EVP_MD *digest,
  36. int keylen, unsigned char *out)
  37. import struct
  38. _int = struct.Struct('>I')
  39. _long = struct.Struct('>Q')
  40. bytes_to_int = lambda x, offset=0: _int.unpack_from(x, offset)[0]
  41. bytes_to_long = lambda x, offset=0: _long.unpack_from(x, offset)[0]
  42. long_to_bytes = lambda x: _long.pack(x)
  43. def num_aes_blocks(length):
  44. """Return the number of AES blocks required to encrypt/decrypt *length* bytes of data.
  45. Note: this is only correct for modes without padding, like AES-CTR.
  46. """
  47. return (length + 15) // 16
  48. def pbkdf2_sha256(password, salt, iterations, size):
  49. """Password based key derivation function 2 (RFC2898)
  50. """
  51. cdef unsigned char *key = <unsigned char *>malloc(size)
  52. if not key:
  53. raise MemoryError
  54. try:
  55. rv = PKCS5_PBKDF2_HMAC(password, len(password), salt, len(salt), iterations, EVP_sha256(), size, key)
  56. if not rv:
  57. raise Exception('PKCS5_PBKDF2_HMAC failed')
  58. return key[:size]
  59. finally:
  60. free(key)
  61. def get_random_bytes(n):
  62. """Return n cryptographically strong pseudo-random bytes
  63. """
  64. cdef unsigned char *buf = <unsigned char *>malloc(n)
  65. if not buf:
  66. raise MemoryError
  67. try:
  68. if RAND_bytes(buf, n) < 1:
  69. raise Exception('RAND_bytes failed')
  70. return buf[:n]
  71. finally:
  72. free(buf)
  73. cdef class AES:
  74. """A thin wrapper around the OpenSSL EVP cipher API
  75. """
  76. cdef EVP_CIPHER_CTX ctx
  77. cdef int is_encrypt
  78. def __cinit__(self, is_encrypt, key, iv=None):
  79. EVP_CIPHER_CTX_init(&self.ctx)
  80. self.is_encrypt = is_encrypt
  81. # Set cipher type and mode
  82. cipher_mode = EVP_aes_256_ctr()
  83. if self.is_encrypt:
  84. if not EVP_EncryptInit_ex(&self.ctx, cipher_mode, NULL, NULL, NULL):
  85. raise Exception('EVP_EncryptInit_ex failed')
  86. else: # decrypt
  87. if not EVP_DecryptInit_ex(&self.ctx, cipher_mode, NULL, NULL, NULL):
  88. raise Exception('EVP_DecryptInit_ex failed')
  89. self.reset(key, iv)
  90. def __dealloc__(self):
  91. EVP_CIPHER_CTX_cleanup(&self.ctx)
  92. def reset(self, key=None, iv=None):
  93. cdef const unsigned char *key2 = NULL
  94. cdef const unsigned char *iv2 = NULL
  95. if key:
  96. key2 = key
  97. if iv:
  98. iv2 = iv
  99. # Initialise key and IV
  100. if self.is_encrypt:
  101. if not EVP_EncryptInit_ex(&self.ctx, NULL, NULL, key2, iv2):
  102. raise Exception('EVP_EncryptInit_ex failed')
  103. else: # decrypt
  104. if not EVP_DecryptInit_ex(&self.ctx, NULL, NULL, key2, iv2):
  105. raise Exception('EVP_DecryptInit_ex failed')
  106. @property
  107. def iv(self):
  108. return self.ctx.iv[:16]
  109. def encrypt(self, data):
  110. cdef int inl = len(data)
  111. cdef int ctl = 0
  112. cdef int outl = 0
  113. # note: modes that use padding, need up to one extra AES block (16b)
  114. cdef unsigned char *out = <unsigned char *>malloc(inl+16)
  115. if not out:
  116. raise MemoryError
  117. try:
  118. if not EVP_EncryptUpdate(&self.ctx, out, &outl, data, inl):
  119. raise Exception('EVP_EncryptUpdate failed')
  120. ctl = outl
  121. if not EVP_EncryptFinal_ex(&self.ctx, out+ctl, &outl):
  122. raise Exception('EVP_EncryptFinal failed')
  123. ctl += outl
  124. return out[:ctl]
  125. finally:
  126. free(out)
  127. def decrypt(self, data):
  128. cdef int inl = len(data)
  129. cdef int ptl = 0
  130. cdef int outl = 0
  131. # note: modes that use padding, need up to one extra AES block (16b).
  132. # This is what the openssl docs say. I am not sure this is correct,
  133. # but OTOH it will not cause any harm if our buffer is a little bigger.
  134. cdef unsigned char *out = <unsigned char *>malloc(inl+16)
  135. if not out:
  136. raise MemoryError
  137. try:
  138. if not EVP_DecryptUpdate(&self.ctx, out, &outl, data, inl):
  139. raise Exception('EVP_DecryptUpdate failed')
  140. ptl = outl
  141. if EVP_DecryptFinal_ex(&self.ctx, out+ptl, &outl) <= 0:
  142. # this error check is very important for modes with padding or
  143. # authentication. for them, a failure here means corrupted data.
  144. # CTR mode does not use padding nor authentication.
  145. raise Exception('EVP_DecryptFinal failed')
  146. ptl += outl
  147. return out[:ptl]
  148. finally:
  149. free(out)