|
# Copyright (C) 2011 Yann GUIBET <yannguibet@gmail.com> |
|
# See LICENSE for details. |
|
# |
|
# Software slightly changed by Jonathan Warren <bitmessage at-symbol jonwarren.org> |
|
# |
|
# Additional changes by Jesper Borgstrup <jesper at-symbol borgstrup.dk>: |
|
# * Added EC_GROUP_get0_generator, EC_GROUP_get_order, |
|
# EC_GROUP_new_by_curve_name and EC_POINT_add. |
|
|
|
import sys |
|
import ctypes |
|
|
|
OpenSSL = None |
|
|
|
|
|
class CipherName: |
|
def __init__(self, name, pointer, blocksize): |
|
self._name = name |
|
self._pointer = pointer |
|
self._blocksize = blocksize |
|
|
|
def __str__(self): |
|
return "Cipher : " + self._name + " | Blocksize : " + str(self._blocksize) + " | Fonction pointer : " + str(self._pointer) |
|
|
|
def get_pointer(self): |
|
return self._pointer() |
|
|
|
def get_name(self): |
|
return self._name |
|
|
|
def get_blocksize(self): |
|
return self._blocksize |
|
|
|
|
|
class _OpenSSL: |
|
""" |
|
Wrapper for OpenSSL using ctypes |
|
""" |
|
def __init__(self, library): |
|
""" |
|
Build the wrapper |
|
""" |
|
self._lib = ctypes.CDLL(library) |
|
|
|
self.pointer = ctypes.pointer |
|
self.c_int = ctypes.c_int |
|
self.byref = ctypes.byref |
|
self.create_string_buffer = ctypes.create_string_buffer |
|
|
|
self.BN_new = self._lib.BN_new |
|
self.BN_new.restype = ctypes.c_void_p |
|
self.BN_new.argtypes = [] |
|
|
|
self.BN_free = self._lib.BN_free |
|
self.BN_free.restype = None |
|
self.BN_free.argtypes = [ctypes.c_void_p] |
|
|
|
self.BN_num_bits = self._lib.BN_num_bits |
|
self.BN_num_bits.restype = ctypes.c_int |
|
self.BN_num_bits.argtypes = [ctypes.c_void_p] |
|
|
|
self.BN_bn2bin = self._lib.BN_bn2bin |
|
self.BN_bn2bin.restype = ctypes.c_int |
|
self.BN_bn2bin.argtypes = [ctypes.c_void_p, ctypes.c_void_p] |
|
|
|
self.BN_bin2bn = self._lib.BN_bin2bn |
|
self.BN_bin2bn.restype = ctypes.c_void_p |
|
self.BN_bin2bn.argtypes = [ctypes.c_void_p, ctypes.c_int, |
|
ctypes.c_void_p] |
|
|
|
self.EC_GROUP_get0_generator = self._lib.EC_GROUP_get0_generator |
|
self.EC_GROUP_get0_generator.restype = ctypes.c_int |
|
self.EC_GROUP_get0_generator.argtypes = [ctypes.c_void_p] |
|
|
|
self.EC_GROUP_get_order = self._lib.EC_GROUP_get_order |
|
self.EC_GROUP_get_order.restype = ctypes.c_int |
|
self.EC_GROUP_get_order.argtypes = [ctypes.c_void_p, ctypes.c_void_p, |
|
ctypes.c_void_p] |
|
|
|
self.EC_GROUP_new_by_curve_name = self._lib.EC_GROUP_new_by_curve_name |
|
self.EC_GROUP_new_by_curve_name.restype = ctypes.c_void_p |
|
self.EC_GROUP_new_by_curve_name.argtypes = [ctypes.c_int] |
|
|
|
self.EC_KEY_free = self._lib.EC_KEY_free |
|
self.EC_KEY_free.restype = None |
|
self.EC_KEY_free.argtypes = [ctypes.c_void_p] |
|
|
|
self.EC_KEY_new_by_curve_name = self._lib.EC_KEY_new_by_curve_name |
|
self.EC_KEY_new_by_curve_name.restype = ctypes.c_void_p |
|
self.EC_KEY_new_by_curve_name.argtypes = [ctypes.c_int] |
|
|
|
self.EC_KEY_generate_key = self._lib.EC_KEY_generate_key |
|
self.EC_KEY_generate_key.restype = ctypes.c_int |
|
self.EC_KEY_generate_key.argtypes = [ctypes.c_void_p] |
|
|
|
self.EC_KEY_check_key = self._lib.EC_KEY_check_key |
|
self.EC_KEY_check_key.restype = ctypes.c_int |
|
self.EC_KEY_check_key.argtypes = [ctypes.c_void_p] |
|
|
|
self.EC_KEY_get0_private_key = self._lib.EC_KEY_get0_private_key |
|
self.EC_KEY_get0_private_key.restype = ctypes.c_void_p |
|
self.EC_KEY_get0_private_key.argtypes = [ctypes.c_void_p] |
|
|
|
self.EC_KEY_get0_public_key = self._lib.EC_KEY_get0_public_key |
|
self.EC_KEY_get0_public_key.restype = ctypes.c_void_p |
|
self.EC_KEY_get0_public_key.argtypes = [ctypes.c_void_p] |
|
|
|
self.EC_KEY_get0_group = self._lib.EC_KEY_get0_group |
|
self.EC_KEY_get0_group.restype = ctypes.c_void_p |
|
self.EC_KEY_get0_group.argtypes = [ctypes.c_void_p] |
|
|
|
self.EC_POINT_get_affine_coordinates_GFp = self._lib.EC_POINT_get_affine_coordinates_GFp |
|
self.EC_POINT_get_affine_coordinates_GFp.restype = ctypes.c_int |
|
self.EC_POINT_get_affine_coordinates_GFp.argtypes = [ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p] |
|
|
|
self.EC_KEY_set_private_key = self._lib.EC_KEY_set_private_key |
|
self.EC_KEY_set_private_key.restype = ctypes.c_int |
|
self.EC_KEY_set_private_key.argtypes = [ctypes.c_void_p, |
|
ctypes.c_void_p] |
|
|
|
self.EC_KEY_set_public_key = self._lib.EC_KEY_set_public_key |
|
self.EC_KEY_set_public_key.restype = ctypes.c_int |
|
self.EC_KEY_set_public_key.argtypes = [ctypes.c_void_p, |
|
ctypes.c_void_p] |
|
|
|
self.EC_KEY_set_group = self._lib.EC_KEY_set_group |
|
self.EC_KEY_set_group.restype = ctypes.c_int |
|
self.EC_KEY_set_group.argtypes = [ctypes.c_void_p, ctypes.c_void_p] |
|
|
|
self.EC_POINT_set_affine_coordinates_GFp = self._lib.EC_POINT_set_affine_coordinates_GFp |
|
self.EC_POINT_set_affine_coordinates_GFp.restype = ctypes.c_int |
|
self.EC_POINT_set_affine_coordinates_GFp.argtypes = [ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p] |
|
|
|
self.EC_POINT_new = self._lib.EC_POINT_new |
|
self.EC_POINT_new.restype = ctypes.c_void_p |
|
self.EC_POINT_new.argtypes = [ctypes.c_void_p] |
|
|
|
self.EC_POINT_free = self._lib.EC_POINT_free |
|
self.EC_POINT_free.restype = None |
|
self.EC_POINT_free.argtypes = [ctypes.c_void_p] |
|
|
|
self.BN_CTX_free = self._lib.BN_CTX_free |
|
self.BN_CTX_free.restype = None |
|
self.BN_CTX_free.argtypes = [ctypes.c_void_p] |
|
|
|
self.EC_POINT_mul = self._lib.EC_POINT_mul |
|
self.EC_POINT_mul.restype = None |
|
self.EC_POINT_mul.argtypes = [ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p] |
|
|
|
self.EC_POINT_add = self._lib.EC_POINT_add |
|
self.EC_POINT_add.resType = None |
|
self.EC_POINT_add.argtypes = [ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p] |
|
|
|
self.EC_KEY_set_private_key = self._lib.EC_KEY_set_private_key |
|
self.EC_KEY_set_private_key.restype = ctypes.c_int |
|
self.EC_KEY_set_private_key.argtypes = [ctypes.c_void_p, |
|
ctypes.c_void_p] |
|
|
|
self.ECDH_OpenSSL = self._lib.ECDH_OpenSSL |
|
self._lib.ECDH_OpenSSL.restype = ctypes.c_void_p |
|
self._lib.ECDH_OpenSSL.argtypes = [] |
|
|
|
self.BN_CTX_new = self._lib.BN_CTX_new |
|
self._lib.BN_CTX_new.restype = ctypes.c_void_p |
|
self._lib.BN_CTX_new.argtypes = [] |
|
|
|
self.ECDH_set_method = self._lib.ECDH_set_method |
|
self._lib.ECDH_set_method.restype = ctypes.c_int |
|
self._lib.ECDH_set_method.argtypes = [ctypes.c_void_p, ctypes.c_void_p] |
|
|
|
self.ECDH_compute_key = self._lib.ECDH_compute_key |
|
self.ECDH_compute_key.restype = ctypes.c_int |
|
self.ECDH_compute_key.argtypes = [ctypes.c_void_p, |
|
ctypes.c_int, ctypes.c_void_p, ctypes.c_void_p] |
|
|
|
self.EVP_CipherInit_ex = self._lib.EVP_CipherInit_ex |
|
self.EVP_CipherInit_ex.restype = ctypes.c_int |
|
self.EVP_CipherInit_ex.argtypes = [ctypes.c_void_p, |
|
ctypes.c_void_p, ctypes.c_void_p] |
|
|
|
self.EVP_CIPHER_CTX_new = self._lib.EVP_CIPHER_CTX_new |
|
self.EVP_CIPHER_CTX_new.restype = ctypes.c_void_p |
|
self.EVP_CIPHER_CTX_new.argtypes = [] |
|
|
|
# Cipher |
|
self.EVP_aes_128_cfb128 = self._lib.EVP_aes_128_cfb128 |
|
self.EVP_aes_128_cfb128.restype = ctypes.c_void_p |
|
self.EVP_aes_128_cfb128.argtypes = [] |
|
|
|
self.EVP_aes_256_cfb128 = self._lib.EVP_aes_256_cfb128 |
|
self.EVP_aes_256_cfb128.restype = ctypes.c_void_p |
|
self.EVP_aes_256_cfb128.argtypes = [] |
|
|
|
self.EVP_aes_128_cbc = self._lib.EVP_aes_128_cbc |
|
self.EVP_aes_128_cbc.restype = ctypes.c_void_p |
|
self.EVP_aes_128_cbc.argtypes = [] |
|
|
|
self.EVP_aes_256_cbc = self._lib.EVP_aes_256_cbc |
|
self.EVP_aes_256_cbc.restype = ctypes.c_void_p |
|
self.EVP_aes_256_cbc.argtypes = [] |
|
|
|
#self.EVP_aes_128_ctr = self._lib.EVP_aes_128_ctr |
|
#self.EVP_aes_128_ctr.restype = ctypes.c_void_p |
|
#self.EVP_aes_128_ctr.argtypes = [] |
|
|
|
#self.EVP_aes_256_ctr = self._lib.EVP_aes_256_ctr |
|
#self.EVP_aes_256_ctr.restype = ctypes.c_void_p |
|
#self.EVP_aes_256_ctr.argtypes = [] |
|
|
|
self.EVP_aes_128_ofb = self._lib.EVP_aes_128_ofb |
|
self.EVP_aes_128_ofb.restype = ctypes.c_void_p |
|
self.EVP_aes_128_ofb.argtypes = [] |
|
|
|
self.EVP_aes_256_ofb = self._lib.EVP_aes_256_ofb |
|
self.EVP_aes_256_ofb.restype = ctypes.c_void_p |
|
self.EVP_aes_256_ofb.argtypes = [] |
|
|
|
self.EVP_bf_cbc = self._lib.EVP_bf_cbc |
|
self.EVP_bf_cbc.restype = ctypes.c_void_p |
|
self.EVP_bf_cbc.argtypes = [] |
|
|
|
self.EVP_bf_cfb64 = self._lib.EVP_bf_cfb64 |
|
self.EVP_bf_cfb64.restype = ctypes.c_void_p |
|
self.EVP_bf_cfb64.argtypes = [] |
|
|
|
self.EVP_rc4 = self._lib.EVP_rc4 |
|
self.EVP_rc4.restype = ctypes.c_void_p |
|
self.EVP_rc4.argtypes = [] |
|
|
|
self.EVP_CIPHER_CTX_cleanup = self._lib.EVP_CIPHER_CTX_cleanup |
|
self.EVP_CIPHER_CTX_cleanup.restype = ctypes.c_int |
|
self.EVP_CIPHER_CTX_cleanup.argtypes = [ctypes.c_void_p] |
|
|
|
self.EVP_CIPHER_CTX_free = self._lib.EVP_CIPHER_CTX_free |
|
self.EVP_CIPHER_CTX_free.restype = None |
|
self.EVP_CIPHER_CTX_free.argtypes = [ctypes.c_void_p] |
|
|
|
self.EVP_CipherUpdate = self._lib.EVP_CipherUpdate |
|
self.EVP_CipherUpdate.restype = ctypes.c_int |
|
self.EVP_CipherUpdate.argtypes = [ctypes.c_void_p, |
|
ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p, ctypes.c_int] |
|
|
|
self.EVP_CipherFinal_ex = self._lib.EVP_CipherFinal_ex |
|
self.EVP_CipherFinal_ex.restype = ctypes.c_int |
|
self.EVP_CipherFinal_ex.argtypes = [ctypes.c_void_p, |
|
ctypes.c_void_p, ctypes.c_void_p] |
|
|
|
self.EVP_DigestInit = self._lib.EVP_DigestInit |
|
self.EVP_DigestInit.restype = ctypes.c_int |
|
self._lib.EVP_DigestInit.argtypes = [ctypes.c_void_p, ctypes.c_void_p] |
|
|
|
self.EVP_DigestUpdate = self._lib.EVP_DigestUpdate |
|
self.EVP_DigestUpdate.restype = ctypes.c_int |
|
self.EVP_DigestUpdate.argtypes = [ctypes.c_void_p, |
|
ctypes.c_void_p, ctypes.c_int] |
|
|
|
self.EVP_DigestFinal = self._lib.EVP_DigestFinal |
|
self.EVP_DigestFinal.restype = ctypes.c_int |
|
self.EVP_DigestFinal.argtypes = [ctypes.c_void_p, |
|
ctypes.c_void_p, ctypes.c_void_p] |
|
|
|
self.EVP_ecdsa = self._lib.EVP_ecdsa |
|
self._lib.EVP_ecdsa.restype = ctypes.c_void_p |
|
self._lib.EVP_ecdsa.argtypes = [] |
|
|
|
self.ECDSA_sign = self._lib.ECDSA_sign |
|
self.ECDSA_sign.restype = ctypes.c_int |
|
self.ECDSA_sign.argtypes = [ctypes.c_int, ctypes.c_void_p, |
|
ctypes.c_int, ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p] |
|
|
|
self.ECDSA_verify = self._lib.ECDSA_verify |
|
self.ECDSA_verify.restype = ctypes.c_int |
|
self.ECDSA_verify.argtypes = [ctypes.c_int, ctypes.c_void_p, |
|
ctypes.c_int, ctypes.c_void_p, ctypes.c_int, ctypes.c_void_p] |
|
|
|
self.EVP_MD_CTX_create = self._lib.EVP_MD_CTX_create |
|
self.EVP_MD_CTX_create.restype = ctypes.c_void_p |
|
self.EVP_MD_CTX_create.argtypes = [] |
|
|
|
self.EVP_MD_CTX_init = self._lib.EVP_MD_CTX_init |
|
self.EVP_MD_CTX_init.restype = None |
|
self.EVP_MD_CTX_init.argtypes = [ctypes.c_void_p] |
|
|
|
self.EVP_MD_CTX_destroy = self._lib.EVP_MD_CTX_destroy |
|
self.EVP_MD_CTX_destroy.restype = None |
|
self.EVP_MD_CTX_destroy.argtypes = [ctypes.c_void_p] |
|
|
|
self.RAND_bytes = self._lib.RAND_bytes |
|
self.RAND_bytes.restype = ctypes.c_int |
|
self.RAND_bytes.argtypes = [ctypes.c_void_p, ctypes.c_int] |
|
|
|
|
|
self.EVP_sha256 = self._lib.EVP_sha256 |
|
self.EVP_sha256.restype = ctypes.c_void_p |
|
self.EVP_sha256.argtypes = [] |
|
|
|
self.i2o_ECPublicKey = self._lib.i2o_ECPublicKey |
|
self.i2o_ECPublicKey.restype = ctypes.c_void_p |
|
self.i2o_ECPublicKey.argtypes = [ctypes.c_void_p, ctypes.c_void_p] |
|
|
|
self.EVP_sha512 = self._lib.EVP_sha512 |
|
self.EVP_sha512.restype = ctypes.c_void_p |
|
self.EVP_sha512.argtypes = [] |
|
|
|
self.HMAC = self._lib.HMAC |
|
self.HMAC.restype = ctypes.c_void_p |
|
self.HMAC.argtypes = [ctypes.c_void_p, ctypes.c_void_p, ctypes.c_int, |
|
ctypes.c_void_p, ctypes.c_int, ctypes.c_void_p, ctypes.c_void_p] |
|
|
|
try: |
|
self.PKCS5_PBKDF2_HMAC = self._lib.PKCS5_PBKDF2_HMAC |
|
except: |
|
# The above is not compatible with all versions of OSX. |
|
self.PKCS5_PBKDF2_HMAC = self._lib.PKCS5_PBKDF2_HMAC_SHA1 |
|
|
|
self.PKCS5_PBKDF2_HMAC.restype = ctypes.c_int |
|
self.PKCS5_PBKDF2_HMAC.argtypes = [ctypes.c_void_p, ctypes.c_int, |
|
ctypes.c_void_p, ctypes.c_int, |
|
ctypes.c_int, ctypes.c_void_p, |
|
ctypes.c_int, ctypes.c_void_p] |
|
|
|
self._set_ciphers() |
|
self._set_curves() |
|
|
|
def _set_ciphers(self): |
|
self.cipher_algo = { |
|
'aes-128-cbc': CipherName('aes-128-cbc', self.EVP_aes_128_cbc, 16), |
|
'aes-256-cbc': CipherName('aes-256-cbc', self.EVP_aes_256_cbc, 16), |
|
'aes-128-cfb': CipherName('aes-128-cfb', self.EVP_aes_128_cfb128, 16), |
|
'aes-256-cfb': CipherName('aes-256-cfb', self.EVP_aes_256_cfb128, 16), |
|
'aes-128-ofb': CipherName('aes-128-ofb', self._lib.EVP_aes_128_ofb, 16), |
|
'aes-256-ofb': CipherName('aes-256-ofb', self._lib.EVP_aes_256_ofb, 16), |
|
#'aes-128-ctr': CipherName('aes-128-ctr', self._lib.EVP_aes_128_ctr, 16), |
|
#'aes-256-ctr': CipherName('aes-256-ctr', self._lib.EVP_aes_256_ctr, 16), |
|
'bf-cfb': CipherName('bf-cfb', self.EVP_bf_cfb64, 8), |
|
'bf-cbc': CipherName('bf-cbc', self.EVP_bf_cbc, 8), |
|
'rc4': CipherName('rc4', self.EVP_rc4, 128), # 128 is the initialisation size not block size |
|
} |
|
|
|
def _set_curves(self): |
|
self.curves = { |
|
'secp112r1': 704, |
|
'secp112r2': 705, |
|
'secp128r1': 706, |
|
'secp128r2': 707, |
|
'secp160k1': 708, |
|
'secp160r1': 709, |
|
'secp160r2': 710, |
|
'secp192k1': 711, |
|
'secp224k1': 712, |
|
'secp224r1': 713, |
|
'secp256k1': 714, |
|
'secp384r1': 715, |
|
'secp521r1': 716, |
|
'sect113r1': 717, |
|
'sect113r2': 718, |
|
'sect131r1': 719, |
|
'sect131r2': 720, |
|
'sect163k1': 721, |
|
'sect163r1': 722, |
|
'sect163r2': 723, |
|
'sect193r1': 724, |
|
'sect193r2': 725, |
|
'sect233k1': 726, |
|
'sect233r1': 727, |
|
'sect239k1': 728, |
|
'sect283k1': 729, |
|
'sect283r1': 730, |
|
'sect409k1': 731, |
|
'sect409r1': 732, |
|
'sect571k1': 733, |
|
'sect571r1': 734, |
|
} |
|
|
|
def BN_num_bytes(self, x): |
|
""" |
|
returns the length of a BN (OpenSSl API) |
|
""" |
|
return int((self.BN_num_bits(x) + 7) / 8) |
|
|
|
def get_cipher(self, name): |
|
""" |
|
returns the OpenSSL cipher instance |
|
""" |
|
if name not in self.cipher_algo: |
|
raise Exception("Unknown cipher") |
|
return self.cipher_algo[name] |
|
|
|
def get_curve(self, name): |
|
""" |
|
returns the id of a elliptic curve |
|
""" |
|
if name not in self.curves: |
|
raise Exception("Unknown curve") |
|
return self.curves[name] |
|
|
|
def get_curve_by_id(self, id): |
|
""" |
|
returns the name of a elliptic curve with his id |
|
""" |
|
res = None |
|
for i in self.curves: |
|
if self.curves[i] == id: |
|
res = i |
|
break |
|
if res is None: |
|
raise Exception("Unknown curve") |
|
return res |
|
|
|
def rand(self, size): |
|
""" |
|
OpenSSL random function |
|
""" |
|
buffer = self.malloc(0, size) |
|
# This pyelliptic library, by default, didn't check the return value of RAND_bytes. It is |
|
# evidently possible that it returned an error and not-actually-random data. However, in |
|
# tests on various operating systems, while generating hundreds of gigabytes of random |
|
# strings of various sizes I could not get an error to occur. Also Bitcoin doesn't check |
|
# the return value of RAND_bytes either. |
|
# Fixed in Bitmessage version 0.4.2 (in source code on 2013-10-13) |
|
while self.RAND_bytes(buffer, size) != 1: |
|
import time |
|
time.sleep(1) |
|
return buffer.raw |
|
|
|
def malloc(self, data, size): |
|
""" |
|
returns a create_string_buffer (ctypes) |
|
""" |
|
buffer = None |
|
if data != 0: |
|
if sys.version_info.major == 3 and isinstance(data, type('')): |
|
data = data.encode() |
|
buffer = self.create_string_buffer(data, size) |
|
else: |
|
buffer = self.create_string_buffer(size) |
|
return buffer |
|
|
|
try: |
|
OpenSSL = _OpenSSL('libcrypto.so') |
|
except: |
|
try: |
|
OpenSSL = _OpenSSL('libeay32.dll') |
|
except: |
|
try: |
|
OpenSSL = _OpenSSL('libcrypto.dylib') |
|
except: |
|
try: |
|
# try homebrew installation |
|
OpenSSL = _OpenSSL('/usr/local/opt/openssl/lib/libcrypto.dylib') |
|
except: |
|
try: |
|
# Load it from an Bitmessage.app on OSX |
|
OpenSSL = _OpenSSL('./../Frameworks/libcrypto.dylib') |
|
except: |
|
try: |
|
from os import path |
|
lib_path = path.join(sys._MEIPASS, "libeay32.dll") |
|
OpenSSL = _OpenSSL(lib_path) |
|
except: |
|
if 'linux' in sys.platform or 'darwin' in sys.platform or 'freebsd' in sys.platform: |
|
try: |
|
from ctypes.util import find_library |
|
OpenSSL = _OpenSSL(find_library('ssl')) |
|
except Exception, err: |
|
sys.stderr.write('(On Linux) Couldn\'t find and load the OpenSSL library. You must install it. If you believe that you already have it installed, this exception information might be of use:\n') |
|
from ctypes.util import find_library |
|
OpenSSL = _OpenSSL(find_library('ssl')) |
|
else: |
|
raise Exception("Couldn't find and load the OpenSSL library. You must install it.") |
This comment has been minimized.
This loads the standard OpenSSL which fails at line 421
Reverting back to the pre-revision code which uses the included openssl.py
all works well