def __init__(self, name, copy_from=None): self.ctx = ffi.NULL self.name = name digest_type = self.digest_type_by_name() self.digest_size = lib.EVP_MD_size(digest_type) # Allocate a lock for each HASH object. # An optimization would be to not release the GIL on small requests, # and use a custom lock only when needed. self.lock = Lock() ctx = lib.Cryptography_EVP_MD_CTX_new() if ctx == ffi.NULL: raise MemoryError ctx = ffi.gc(ctx, lib.Cryptography_EVP_MD_CTX_free) try: if copy_from is not None: # cpython uses EVP_MD_CTX_copy(...) if not lib.EVP_MD_CTX_copy_ex(ctx, copy_from): raise ValueError else: # cpython uses EVP_DigestInit lib.EVP_DigestInit_ex(ctx, digest_type, ffi.NULL) self.ctx = ctx except: # no need to gc ctx! raise
def pbkdf2_hmac(hash_name, password, salt, iterations, dklen=None): if not isinstance(hash_name, str): raise TypeError("expected 'str' for name, but got %s" % type(hash_name)) c_name = _str_to_ffi_buffer(hash_name) digest = lib.EVP_get_digestbyname(c_name) if digest == ffi.NULL: raise ValueError("unsupported hash type") if dklen is None: dklen = lib.EVP_MD_size(digest) if dklen < 1: raise ValueError("key length must be greater than 0.") if dklen >= sys.maxsize: raise OverflowError("key length is too great.") if iterations < 1: raise ValueError("iteration value must be greater than 0.") if iterations >= sys.maxsize: raise OverflowError("iteration value is too great.") buf = ffi.new("unsigned char[]", dklen) c_password = ffi.from_buffer(bytes(password)) c_salt = ffi.from_buffer(bytes(salt)) r = lib.PKCS5_PBKDF2_HMAC(c_password, len(c_password), ffi.cast("unsigned char*",c_salt), len(c_salt), iterations, digest, dklen, buf) if r == 0: raise ValueError return _bytes_with_len(buf, dklen)