ECDH密钥交换的C程序

由于项目需要,使用openssl编写一段ECDH代码实现网络两端实体的密钥交换。

虽然对openssl不熟悉,但也开始做。


最先参照的是openssl官方wiki上的Elliptic Curve Diffie Hellman:http://wiki.openssl.org/index.php/Elliptic_Curve_Diffie_Hellman

直接使用文中的代码。不过其中有段代码需要替换:

/* Get the peer's public key, and provide the peer with our public key -
 * how this is done will be specific to your circumstances */
 peerkey = get_peerkey(pkey);

我以为只要将这pkey和peerkey指向的密钥块通过网络交换一下就行了。

先不经过网络交换这两个密钥数据,在本地测试,完全通过。但是,一涉及网络交换,程序就崩溃,并爆出内存错误。

总以为是外围程序的问题,调试了好久好久……

直到后来,最后打印出pkey和peerkey指向的类型为EVP_PKEY的数据来看,才发现EVP_PKEY占存储量很小(32字节),这才发现奇怪。因为密钥块一般挺大的。

在openssl库安装路径include目录中找到evp.h,打开查看,发现:

struct evp_pkey_st
	{
	int type;
	int save_type;
	int references;
	const EVP_PKEY_ASN1_METHOD *ameth;
	ENGINE *engine;
	union	{
		char *ptr;
#ifndef OPENSSL_NO_RSA
		struct rsa_st *rsa;	/* RSA */
#endif
#ifndef OPENSSL_NO_DSA
		struct dsa_st *dsa;	/* DSA */
#endif
#ifndef OPENSSL_NO_DH
		struct dh_st *dh;	/* DH */
#endif
#ifndef OPENSSL_NO_EC
		struct ec_key_st *ec;	/* ECC */
#endif
		} pkey;
	int save_parameters;
	STACK_OF(X509_ATTRIBUTE) *attributes; /* [ 0 ] */
	} /* EVP_PKEY */;

这下明白了,原来在网络上传输的我以为的“密钥块”原来是一堆指针!(而且是公私密钥对的指针。。。。)

于是得想办法解决。找到这个帖子:

How does one access the raw ECDH public key, private key and params inside OpenSSL's EVP_PKEY structure?

http://stackoverflow.com/questions/18155559/how-does-one-access-the-raw-ecdh-public-key-private-key-and-params-inside-opens

文中指出要进行公钥的序列化。

然后挨个搜索API的说明,花了不少时间。又是一阵子调试……

最后还是卡在反序列化过程中EC_KEY_set_public_key() to get an EC_KEY和EC_KEY to EVP_PKEY_set1_EC_KEY上了。


心想只好换一种方法了。调试途中在google搜索EC_POINT_point2oct关键字时发现了一个页面:

OpenSSL - User - ECDH http://openssl.6102.n7.nabble.com/ECDH-td22150.html

3楼Rick的回复给的代码比较好。采用并改进,调试之。


最终得到完整的ECDH代码:

#include 
#define ECDH_SIZE 33

void handleErrors()
{
	printf("Error occurred.\n");
}
static void disp(const char *str, const void *pbuf, const int size)
{
	int i=0;
	if(str != NULL){
		printf("%s:\n", str);
	}
	if(pbuf != NULL && size > 0){
		for(i=0;i

之后抽象、整理封装后的ECDH代码:

#include 
#define ECDH_SIZE 33

void handleErrors()
{
	printf("Error occurred.\n");
}
static void disp(const char *str, const void *pbuf, const int size)
{
	int i=0;
	if(str != NULL){
		printf("%s:\n", str);
	}
	if(pbuf != NULL && size > 0){
		for(i=0;i

调试时在“ECDH_SIZE-1”的问题上纠结了好一阵子,不小心把EC_POINT_oct2point中参数ECDH_SIZE换成值为ECDH_SIZE-1的secret_len了;导致ECDH_compute_key一直返回-1,怎么搜索都得不到解决。

最后还是耐心的一步步调试、对比前面参考的源码、调整变量数值,终于解决。编译通过,执行的非常好。

耐心真的是非常重要,失之毫厘差之千里。


参考资料:

ECC加密算法原理入门介绍

http://blog.csdn.net/sahusoft/article/details/6868016

你可能感兴趣的:(程序设计语言与编程,密码学和网络安全)