我写这个代码用于计算ecdh密钥。使用OpenSSL-1_0_2o。
C代码在那里(所有include和lib只是OpenSSL)
void *KDF_MD5(const void *in, size_t inlen, void *out, size_t *outlen)
{
MD5_CTX ctx;
MD5_Init(&ctx);
MD5_Update(&ctx, in, inlen);
MD5_Final((unsigned char*)out, &ctx);
*outlen = MD5_DIGEST_LENGTH;
return out;
}
bool DoEcdh(int nid, unsigned char * szServerPubKey, int nLenServerPub, unsigned char * szLocalPriKey, int nLenLocalPri, unsigned char * szShareKey, int *pLenShareKey)
{
const unsigned char *public_material = (const unsigned char *)szServerPubKey;
const unsigned char *private_material = (const unsigned char *)szLocalPriKey;
EC_KEY *pub_ec_key = EC_KEY_new_by_curve_name(nid);
if (!pub_ec_key) return FALSE;
pub_ec_key = o2i_ECPublicKey(&pub_ec_key, &public_material, nLenServerPub);
if (!pub_ec_key) return FALSE;
EC_KEY *pri_ec_key = EC_KEY_new_by_curve_name(nid);
if (!pri_ec_key) return FALSE;
pri_ec_key = d2i_ECPrivateKey(&pri_ec_key, &private_material, nLenLocalPri);
if (!pri_ec_key) return FALSE;
if (MD5_DIGEST_LENGTH != ECDH_compute_key((void *)szShareKey, MD5_DIGEST_LENGTH, EC_KEY_get0_public_key(pub_ec_key), pri_ec_key, KDF_MD5))
{
EC_KEY_free(pub_ec_key);
EC_KEY_free(pri_ec_key);
return FALSE;
}
*pLenShareKey = MD5_DIGEST_LENGTH;
if (pub_ec_key)
{
EC_KEY_free(pub_ec_key);
pub_ec_key = NULL;
}
if (pri_ec_key)
{
EC_KEY_free(pri_ec_key);
pri_ec_key = NULL;
}
return TRUE;
}
然后,我在Python ctypes中重写,只需在Linux中使用带有libeay32.dll
的python,在Linux中使用 OR libcrypto.so
。
当我调用C函数ECDH_compute_key
引发OS错误时。
此功能: result = ECDH_compute_key(ShareKey_p, outlen, server_ECpoint, pri_ec, mykdf)
错误: # ------- OSError: exception: access violation reading 0xFFFFFFFFCDC562C0
from ecdhlib.openssl_wrapper import OpenSSL
import ctypes
from ctypes import c_int, c_char_p, pointer
from ctypes import *
from hashlib import md5
class Ecdh(object):
def __init__(self, curve='secp224r1'):
self.pubkey = None
self.prikey = None
self.shake_hands = None
self.curveID = OpenSSL.curves[curve]
def do_ECDHshare(self, server_ECDH_pub, priKey=None):
OUTLEN = 16
server_ECDH = server_ECDH_pub
# EC_KEY *EC_KEY_new_by_curve_name(int nid)
server_ec = OpenSSL.EC_KEY_new_by_curve_name(self.curveID)
if not server_ec:
return None, None
server_pubLen = len(server_ECDH_pub)
server_pub = ctypes.cast(server_ECDH_pub, ctypes.POINTER(ctypes.c_char * server_pubLen))
# EC_KEY *o2i_ECPublicKey(EC_KEY **a, const unsigned char **in, long len)
server_ec = c_void_p(server_ec)
server_ec = OpenSSL.o2i_ECPublicKey(ctypes.byref(server_ec),
ctypes.byref(server_pub), ctypes.c_long(server_pubLen))
if not server_ec:
return None, None
# const EC_POINT *EC_KEY_get0_public_key(const EC_KEY *key)
server_ec = c_void_p(server_ec)
server_ECpoint = c_void_p(OpenSSL.EC_KEY_get0_public_key(server_ec))
pri_ec = OpenSSL.EC_KEY_new_by_curve_name(self.curveID)
if not pri_ec:
return None, None
if not priKey:
priKey = self.prikey
priKey_len = len(priKey)
priKey = ctypes.cast(priKey, ctypes.POINTER(ctypes.c_char * priKey_len))
# EC_KEY *d2i_ECPrivateKey(EC_KEY **a, const unsigned char **in, long len)
pri_ec = c_void_p(pri_ec)
pri_ec = OpenSSL.d2i_ECPrivateKey(ctypes.byref(pri_ec),
ctypes.byref(priKey), ctypes.c_long(priKey_len))
if not pri_ec:
return None, None
ECDH_compute_key = OpenSSL.ECDH_compute_key
# void *(*KDF) (const void *in, size_t inlen, void *out, size_t *outlen))
KDF = CFUNCTYPE(c_void_p, # return type
c_void_p, c_size_t, c_void_p, POINTER(c_size_t))
@KDF
def mykdf(_in, _inlen, out, outlen):
nonlocal OUTLEN
data = addressof(_in)[:_inlen]
md5 = hashlib.md5()
md5.update(data)
outlen.contents = c_size_t(OUTLEN)
outlen = POINTER(c_int(len(out)))
return out
# int ECDH_compute_key(void *out, size_t outlen, const EC_POINT pub_key, EC_KEY ecdh,
# void (KDF) (const void in, size_t inlen, void out, size_t *outlen));
ECDH_compute_key.argtypes = (c_void_p, c_size_t,
c_void_p, c_void_p, KDF)
ECDH_compute_key.restype = c_int
ShareKey_buf = ctypes.create_string_buffer(b'\000', 128)
ShareKey_p = ctypes.cast(ShareKey_buf, ctypes.POINTER(ctypes.c_char * 128))
outlen = c_size_t(OUTLEN)
# int ECDH_compute_key(void *out, size_t outlen, const EC_POINT *pub_key,
# EC_KEY *eckey, void *(*KDF) )
result = ECDH_compute_key(ShareKey_p, outlen, server_ECpoint, pri_ec, mykdf)
# ------- OSError: exception: access violation reading 0x000000000FA805C0
OpenSSL.EC_KEY_free(server_ec), OpenSSL.EC_KEY_free(pri_ec)
if result == OUTLEN:
EcdhShareKey = ShareKey_buf[:OUTLEN]
else:
return None
if __name__ == '__main__':
EcdhPriKey = b'0\x82\x01D\x02\x01\x01\x04\x1c\xb9~,]@\x81\xe2\x04\x86\xdd\xc4\r\xa3\xaad\xc1\x8b\xa4\xb3\xef\x1ce\x9ck\xe6\x91\xc5\x1f\xa0\x81\xe20\x81\xdf\x02\x01\x010(\x06\x07*\x86H\xce=\x01\x01\x02\x1d\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x010S\x04\x1c\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\x04\x1c\xb4\x05\n\x85\x0c\x04\xb3\xab\xf5A2VPD\xb0\xb7\xd7\xbf\xd8\xba\'\x0b9C#U\xff\xb4\x03\x15\x00\xbdq4G\x99\xd5\xc7\xfc\xdcE\xb5\x9f\xa3\xb9\xab\x8fj\x94\x8b\xc5\x049\x04\xb7\x0e\x0c\xbdk\xb4\xbf\x7f2\x13\x90\xb9J\x03\xc1\xd3V\xc2\x11"42\x80\xd6\x11\\\x1d!\xbd7c\x88\xb5\xf7#\xfbL"\xdf\xe6\xcdCu\xa0Z\x07GdD\xd5\x81\x99\x85\x00~4\x02\x1d\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x16\xa2\xe0\xb8\xf0>\x13\xdd)E\\\\*=\x02\x01\x01\xa1<\x03:\x00\x04\xabd#\x90\xd3H3\xf5o\xe8.\t\x0f\xa0\x90\x8f\xb7-t\x85\xf83\xd8\x0b\xa7\xe5{\xf6\xdd%\xa4\xd6\xaa!\xb7\x8f\xfa\xdd\xe4]\x81q\xb6\xb4|E\xdc\xe0h\x14o\x98\xb4\xa1\xf3>'
ServerEcdhPubKey = b'\x04\xea/\xe0\xf3\xb0\xfb2]n-Y\x80\xa4\xea\xaa\xd2\xf6\x11\x95\xa7o\xf6Zj-\x8d\xdd\x1c\x84\xaa\x9a\n\xdf\xdf\x1f\x95h\xc0w<\x9du$\xe9\xfd\xf2\x0c%x\xab0\xf4@\xed\xa0g'
EcdhShareKey = b'\x7f+\xcc\x0b\x05\x0fC=?3\x90\xb3Bt\x89\xc8'
ec = Ecdh()
ec.do_ECDHshare(ServerEcdhPubKey, EcdhPriKey)
请告诉我该怎么办。 非常感谢。
pri_ec = OpenSSL.d2i_ECPrivateKey(ctypes.byref(pri_ec), ctypes.byref(priKey), ctypes.c_long(priKey_len))
我在openssl_wrapper.py中写道:
self.d2i_ECPrivateKey = self._lib.d2i_ECPrivateKey
self.d2i_ECPrivateKey.argtypes = [ctypes.c_void_p, ctypes.c_void_p, ctypes.c_long]
self.i2d_ECPrivateKey.restype = ctypes.c_void_p
所以,这个C函数返回一个void指针,然后在python中是一个int,如18446744072866849424
但是下一个函数需要一个指针,所以我使用pri_ec = c_void_p(pri_ec)
来传递它(这很脏,但我不知道怎么做)。
OSError:异常:访问冲突读取0x000000000FA805C0 ,此十六进制均值18446744072866849472
pri_ec的地址,是Python中的18446744072866849424。所以,我认为这就是那个bug。
怎么解决?非常感谢。