def test_filter_write(self): self.set_cipher(enc=True) plaintext = api.new('unsigned char[]', self.hexstr_to_numbers(self.plaintext)) ciphertext = api.new('unsigned char[]', self.hexstr_to_numbers(self.ciphertext)) output = api.new('unsigned char[]', len(ciphertext)) api.BIO_write(self.bio, plaintext, len(plaintext)) api.BIO_flush(self.bio) api.BIO_read(self.sink, output, len(output)) self.assertEqual(api.buffer(ciphertext)[:], api.buffer(output)[:])
def test_filter_read(self): self.set_cipher(enc=False) plaintext = api.new('unsigned char[]', self.hexstr_to_numbers(self.plaintext)) ciphertext = api.new('unsigned char[]', self.hexstr_to_numbers(self.ciphertext)) output = api.new('unsigned char[]', len(plaintext)) api.BIO_write(self.bio, ciphertext, len(ciphertext)) api.BIO_write(self.bio, api.new('unsigned char[]', [0] * 1), 1) api.BIO_flush(self.bio) api.BIO_read(self.sink, output, len(output)) self.assertEqual(bytes(api.buffer(plaintext)), bytes(api.buffer(output)))
def test_single_decrypt(self): self.set_mode(enc=False) plaintext = api.new('unsigned char[]', self.hexstr_to_numbers(self.plaintext)) ciphertext = api.new('unsigned char[]', self.hexstr_to_numbers(self.ciphertext)) output = api.new('unsigned char[]', len(ciphertext) + api.EVP_CIPHER_CTX_block_size(self.ctx) - 1) outlen = api.new('int*') api.EVP_CipherUpdate(self.ctx, output, outlen, ciphertext, len(ciphertext)) self.assertEqual(api.buffer(plaintext), api.buffer(output, outlen[0])) rval = api.EVP_CipherFinal_ex(self.ctx, output, outlen) self.assertEqual(rval, 1)
def test_multiple_encrypt(self): self.set_mode(enc=True) numbers = self.hexstr_to_numbers(self.plaintext) ciphertext = api.new('unsigned char[]', self.hexstr_to_numbers(self.ciphertext)) outbuf = api.new('unsigned char[]', api.EVP_CIPHER_CTX_block_size(self.ctx)) outlen = api.new('int*') output = b'' for num in numbers: plaintext = api.new('unsigned char[]', [num]) api.EVP_CipherUpdate(self.ctx, outbuf, outlen, plaintext, len(plaintext)) if outlen[0] > 0: output += bytes(api.buffer(outbuf, outlen[0])) self.assertEqual(bytes(api.buffer(ciphertext)), output) rval = api.EVP_CipherFinal_ex(self.ctx, outbuf, outlen) self.assertEqual(rval, 1)
def test_quick(self): buff = api.new('unsigned char[]', api.EVP_MAX_MD_SIZE) key = api.new('char[]', self.key) data = api.new('char[]', self.data) size = api.new('unsigned int*') api.HMAC(self.md, api.cast('void*', key), len(self.key), api.cast('void*', data), len(self.data), api.cast('void*', buff), size) self.assertEqual(self.digest, api.buffer(buff, size[0])[:])
def test_4096_iteration(self): key = b'\x4b\x00\x79\x01\xb7\x65\x48\x9a\xbe\xad\x49\xd9\x26\xf7\x21\xd0\x65\xa4\x29\xc1' password = api.new('char[]', b'password') passlen = 8 salt = api.new('char[]', b'salt') saltlen = 4 iterations = 4096 keylen = 20 out = api.new('unsigned char[]', keylen) api.PKCS5_PBKDF2_HMAC_SHA1(password, passlen, salt, saltlen, iterations, keylen, out) self.assertEqual(key, api.buffer(out)[:])
def test_4096_3_iteration(self): key = b"\x56\xfa\x6a\xa7\x55\x48\x09\x9d\xcc\x37\xd7\xf0\x34\x25\xe0\xc3" password = api.new("char[]", b"pass\0word") passlen = 9 salt = api.new("char[]", b"sa\0lt") saltlen = 5 iterations = 4096 keylen = 16 out = api.new("unsigned char[]", keylen) api.PKCS5_PBKDF2_HMAC_SHA1(password, passlen, salt, saltlen, iterations, keylen, out) self.assertEqual(key, bytes(api.buffer(out)))
def test_4096_3_iteration(self): key = b'\x56\xfa\x6a\xa7\x55\x48\x09\x9d\xcc\x37\xd7\xf0\x34\x25\xe0\xc3' password = api.new('char[]', b'pass\0word') passlen = 9 salt = api.new('char[]', b'sa\0lt') saltlen = 5 iterations = 4096 keylen = 16 out = api.new('unsigned char[]', keylen) api.PKCS5_PBKDF2_HMAC_SHA1(password, passlen, salt, saltlen, iterations, keylen, out) self.assertEqual(key, api.buffer(out)[:])
def pbkdf2(password, length, salt=None, iterations=1000): "Derive a shared secret including encryption key from password" if salt is None: salt = random.getrandbytes(8) c_password = api.new('char[]', password) c_salt = api.new('char[]', salt) c_key = api.new('unsigned char[]', length) api.PKCS5_PBKDF2_HMAC_SHA1(c_password, len(password), c_salt, len(salt), iterations, length, c_key) secret = Secret(api.buffer(c_key)[:], salt, iterations) return secret
def test_4096_2_iteration(self): key = b'\x3d\x2e\xec\x4f\xe4\x1c\x84\x9b\x80\xc8\xd8\x36\x62\xc0\xe4\x4a\x8b\x29\x1a\x96\x4c\xf2\xf0\x70\x38' password = api.new('char[]', b'passwordPASSWORDpassword') passlen = 24 salt = api.new('char[]', b'saltSALTsaltSALTsaltSALTsaltSALTsalt') saltlen = 36 iterations = 4096 keylen = 25 out = api.new('unsigned char[]', keylen) api.PKCS5_PBKDF2_HMAC_SHA1(password, passlen, salt, saltlen, iterations, keylen, out) self.assertEqual(key, api.buffer(out)[:])
def test_0001_iteration(self): key = b'\x0c\x60\xc8\x0f\x96\x1f\x0e\x71\xf3\xa9\xb5\x24\xaf\x60\x12\x06\x2f\xe0\x37\xa6' password = api.new('char[]', b'password') passlen = 8 salt = api.new('char[]', b'salt') saltlen = 4 iterations = 1 keylen = 20 out = api.new('unsigned char[]', keylen) api.PKCS5_PBKDF2_HMAC_SHA1(password, passlen, salt, saltlen, iterations, keylen, out) self.assertEqual(key, api.buffer(out)[:])
def test_0002_iteration(self): key = b'\xea\x6c\x01\x4d\xc7\x2d\x6f\x8c\xcd\x1e\xd9\x2a\xce\x1d\x41\xf0\xd8\xde\x89\x57' password = api.new('char[]', b'password') passlen = 8 salt = api.new('char[]', b'salt') saltlen = 4 iterations = 2 keylen = 20 out = api.new('unsigned char[]', keylen) api.PKCS5_PBKDF2_HMAC_SHA1(password, passlen, salt, saltlen, iterations, keylen, out) self.assertEqual(key, api.buffer(out)[:])
def test_0002_iteration(self): key = b"\xea\x6c\x01\x4d\xc7\x2d\x6f\x8c\xcd\x1e\xd9\x2a\xce\x1d\x41\xf0\xd8\xde\x89\x57" password = api.new("char[]", b"password") passlen = 8 salt = api.new("char[]", b"salt") saltlen = 4 iterations = 2 keylen = 20 out = api.new("unsigned char[]", keylen) api.PKCS5_PBKDF2_HMAC_SHA1(password, passlen, salt, saltlen, iterations, keylen, out) self.assertEqual(key, bytes(api.buffer(out)))
def pbkdf2(password, length, salt=None, iterations=1000): "Derive a shared secret including encryption key from password" if salt is None: salt = random.getrandbytes(8) c_password = api.new('char[]', password) c_salt = api.new('char[]', salt) c_key = api.new('unsigned char[]', length) api.PKCS5_PBKDF2_HMAC_SHA1(c_password, len(password), c_salt, len(salt), iterations, length, c_key) secret = Secret(bytes(api.buffer(c_key)), salt, iterations) return secret
def test_4096_iteration(self): key = b"\x4b\x00\x79\x01\xb7\x65\x48\x9a\xbe\xad\x49\xd9\x26\xf7\x21\xd0\x65\xa4\x29\xc1" password = api.new("char[]", b"password") passlen = 8 salt = api.new("char[]", b"salt") saltlen = 4 iterations = 4096 keylen = 20 out = api.new("unsigned char[]", keylen) api.PKCS5_PBKDF2_HMAC_SHA1(password, passlen, salt, saltlen, iterations, keylen, out) self.assertEqual(key, bytes(api.buffer(out)))
def test_4096_2_iteration(self): key = b"\x3d\x2e\xec\x4f\xe4\x1c\x84\x9b\x80\xc8\xd8\x36\x62\xc0\xe4\x4a\x8b\x29\x1a\x96\x4c\xf2\xf0\x70\x38" password = api.new("char[]", b"passwordPASSWORDpassword") passlen = 24 salt = api.new("char[]", b"saltSALTsaltSALTsaltSALTsaltSALTsalt") saltlen = 36 iterations = 4096 keylen = 25 out = api.new("unsigned char[]", keylen) api.PKCS5_PBKDF2_HMAC_SHA1(password, passlen, salt, saltlen, iterations, keylen, out) self.assertEqual(key, bytes(api.buffer(out)))
def test_0001_iteration(self): key = b"\x0c\x60\xc8\x0f\x96\x1f\x0e\x71\xf3\xa9\xb5\x24\xaf\x60\x12\x06\x2f\xe0\x37\xa6" password = api.new("char[]", b"password") passlen = 8 salt = api.new("char[]", b"salt") saltlen = 4 iterations = 1 keylen = 20 out = api.new("unsigned char[]", keylen) api.PKCS5_PBKDF2_HMAC_SHA1(password, passlen, salt, saltlen, iterations, keylen, out) self.assertEqual(key, bytes(api.buffer(out)))
def readall(self): segments = [] while True: size = api.BIO_pending(self._bio) data = api.new('char[]', size if size > 1 else self._bufsize) read = api.BIO_read(self._bio, data, len(data)) if read < 0: raise IOError('unsupported operation') if read == 0: break segments.append(api.buffer(data, read)[:]) return b"".join(segments)
def test_long(self): buff = api.new('unsigned char[]', api.EVP_MAX_MD_SIZE) key = api.new('char[]', self.key) data = api.new('char[]', self.data) size = api.new('unsigned int*') ctx = api.new('HMAC_CTX*') api.HMAC_CTX_init(ctx) api.HMAC_Init_ex(ctx, api.cast('void*', key), len(self.key), self.md, api.NULL) api.HMAC_Update(ctx, api.cast('void*', data), len(self.data)) api.HMAC_Final(ctx, buff, size) api.HMAC_CTX_cleanup(ctx) self.assertEqual(self.digest, api.buffer(buff, size[0])[:])
def read(self, bio, data, length): try: buff = api.buffer(data, length) if hasattr(self.fileobj, 'readinto'): count = self.fileobj.readinto(buff) count = count if count is not None else 0 else: tmp = self.fileobj.read(length) count = len(tmp) buff[:count] = tmp return count except: return self.BIO_ERROR
def test_multiple_updates(self): buff = api.new('unsigned char[]', api.EVP_MAX_MD_SIZE) key = api.new('char[]', self.key) data = api.new('char[]', self.data) size = api.new('unsigned int*') ctx = api.new('HMAC_CTX*') api.HMAC_CTX_init(ctx) api.HMAC_Init_ex(ctx, api.cast('void*', key), len(self.key), self.md, api.NULL) for pos in range(len(self.data)): api.HMAC_Update(ctx, api.cast('void*', data+pos), 1) api.HMAC_Final(ctx, buff, size) api.HMAC_CTX_cleanup(ctx) self.assertEqual(self.digest, bytes(api.buffer(buff, size[0])))
def readline(self, limit=-1): limit = sys.maxsize if limit < 0 else limit segments = [] while limit > 0: size = api.BIO_pending(self._bio) buf = api.new('char[]', min(limit, size if size > 1 else self._bufsize)) read = api.BIO_gets(self._bio, buf, len(buf)) if read <= 0 and not api.BIO_should_retry(self._bio): raise IOError('unsupported operation') segments.append(api.buffer(buf, read)[:]) limit -= read if segments[-1][-1:] == b'\n': break return b''.join(segments)
def plaintext(self): """Retrieve the available decrypted plaintext. Plain text may not be available until a complete block of data has been decrypted or finish() has been called. If finish() has been called the HMAC will be verified (if required) when plaintext() is called. """ if self._bio == api.NULL: raise ValueError("Cipher object failed to be initialised") if not self.decrypting: raise ValueError("Cipher does not decrypt") size = api.BIO_pending(self._sink) c_data = api.new('unsigned char[]', size) if size > 0: read = api.BIO_read(self._sink, c_data, size) assert size == read, "Expected to read {0}, got {1}".format(size, read) if self.encrypting or self._hmac is None: self._hmac = None return api.buffer(c_data, read)[:] else: hmac_len = self.digest_size data_len = max(0, size - hmac_len) data = api.buffer(c_data, data_len)[:] digest = api.buffer(c_data + data_len, hmac_len) self._hmac.update(data) auth = self._hmac.digest()[:] valid = 0 if api.BIO_get_cipher_status(self._bio) else 1 for x, y in zip(auth, digest): if not isinstance(x, numbers.Integral): x = ord(x) if not isinstance(y, numbers.Integral): y = ord(y) valid |= x ^ y if valid != 0: raise ValueError("Invalid decrypt") self._hmac = None return data
def ciphertext(self): """Retrieve the available encrypted ciphertext. Cipher text may not be available until a complete block of data has been encrypted or finish() has been called. """ if self._bio == api.NULL: raise ValueError("Cipher object failed to be initialised") if not self.encrypting: raise ValueError("Cipher does not encyrpt") size = api.BIO_pending(self._sink) c_data = api.new('unsigned char[]', size) read = api.BIO_read(self._sink, c_data, size) assert size == read return api.buffer(c_data, read)[:]
def digest(self): """Return the hash value of this hashing object. This returns a string containing 8-bit data. After calling digest() it's no longer possible to call update(). The digest value can continue to be retrieved. """ if hasattr(self, '_digest'): return self._digest if self._ctx is None: raise ValueError('HMAC already closed') buff = api.new('unsigned char[]', api.EVP_MAX_MD_SIZE) size = api.new('unsigned int*') api.HMAC_Final(self._ctx, buff, size) self._digest = bytes(api.buffer(buff, size[0])) self._ctx = None return self._digest
def getrandbytes(self, length): "getrandbytes(k) -> 's'. Generate a byte string with k random bytes." buff = api.new('unsigned char[]', length) self._rand_bytes(buff, length) return api.buffer(buff)[:]
def digest(self): "Return the digest value as a string of binary data." buff, size = self._digest() return api.buffer(buff, size)[:]
def write(self, bio, data, length): try: self.fileobj.write(api.buffer(data, length)) return length except: return self.BIO_ERROR