RSA加密:
RSA的加密原理我不是很理解。
RSA需要提供一对公钥和私钥。。
发送方利用公钥对原始数据进行加密,接收方利用发送方提供的私钥对密文解密。
C++实现一个RSA加密的demo。
老大提供了一个openssl的源码给我。
让我自己先调试成功。。
初次接触RSA加密,我十分迷茫。
大半天的时间才搞定,结果运行时出现了update(******)applink的错误。查了好多资料,最后加上一个applink.c似乎搞定了,但是无法移植。一下子我陷入了僵局,似乎不知道该如何往下面走了。
现在想来,估计是我的key文件没有加载好,导致出现了update的错误。
好不容易调试成功了,
接下来又出现问题了。。
提供的公钥居然是证书文件,而我的C++demo似乎只支持key文件。。
PS:其实C++也有函数支持读取证书文件的。只是我当时时间比较紧,没有仔细去钻研了。
辛辛苦苦总算将证书转换成key文件了。
实现:
读取指定目录/etc/upps/下所有key文件,并将这些key文件加载到内存中,加密时,根据传入的key文件名称选择对应的key加密。
1、linux目录下的所有文件:
解决方式:
(1) 手动添加:
这种方式是在代码中手动列出所有的key文件,将key文件依次读入内存中。
#define NUM_KEY 2 //定义key文件数量
const char* rsa_key[NUM_KEY] =
{
"/etc/upps/privatekey.key",
"/etc/upps/mepf_privatekey.key",
// "/etc/upps/privatekey12.key"
}; for(i=0; i<NUM_KEY; i++)
{
RsaKeyFile[i].pKey = load_key(bio_err, rsa_key[i], keyform, 0, passin, 0, "Private Key"); //加载key文件
strcpy(RsaKeyFile[i].path,rsa_key[i]);
}
缺点:这种方式调用key需要手动添加key文件,每次增加一个key,需要更新rsa_key 数组和NUM_KEY数量。
(2) 自动读取目录下的所有key。
计算目录下的所有key文件数量,并将key 文件名称保存起来。
struct KeyPath //将key的文件名称和RSA指针,EVP_PKEY指针对应起来。
{
RSA* gRsaKey;
EVP_PKEY* pKey;
char path[1024];
}RsaKeyFile[500];
int keyofNum = 0; //存放key的数量
#ifndef WIN32
//获取key文件数量
int getfilecount(char *path)
{
DIR *dir;
int count = 0;
struct dirent *s_dir;
struct stat file_stat;
char currfile[1024]={0};
int len = strlen(path);
if(path[len-1] != '/')
{
path[len] = '/';
path[len+1] = 0;
}
printf("%s/n",path);
if( (dir=opendir(path)) == NULL)
{
printf("opendir(path) error./n");
return -1;
}
while((s_dir=readdir(dir))!=NULL)
{
if((strcmp(s_dir->d_name,".")==0)||(strcmp(s_dir->d_name,"..")==0))
continue;
sprintf(currfile,"%s%s",path,s_dir->d_name);
stat(currfile,&file_stat);
if(S_ISDIR(file_stat.st_mode)) ;
if(IsKeyFile(currfile))
{
printf("%s/tOK/n",currfile);
printf("数量:%d",count);
strcpy(RsaKeyFile[count].path,currfile);//保存key的文件名。
count++;
}
}
closedir(dir);
return count; //获取key的数量。
}
//判断文件后缀是否为.key
int IsKeyFile(char *filePath)
{
char *ptr = NULL;
//printf("文件路径%s,文件路径长度%d/n",filePath,strlen(filePath));
ptr = strstr (filePath,".key");
if(ptr != NULL )
return 1;
else
return 0;
}
#endif
保存key的数量,将key文件名称与RSA 和EVP_PKEY对应起来。
keyofNum = getfilecount("/etc/upps/");
for(i=0; i<count; i++)
{
RsaKeyFile[i].pKey = load_key(bio_err, RsaKeyFile[i].path, keyform, 0, passin, 0, "Private Key");
//strcpy(RsaKeyFile[i].path,rsa_key[i]);
}
for(i=0;i<count;i++)
{
RsaKeyFile[i].gRsaKey = EVP_PKEY_get1_RSA(RsaKeyFile[i].pKey);
EVP_PKEY_free(RsaKeyFile[i].pKey);
}
私钥加密,根据路径选择RSA KEY。
__DLL_EXPORT__ int tsRSAPrivateEncrypt(unsigned char *input, unsigned char *output,char* path)
{
keysize = RSA_size(RsaKeyFile[1].gRsaKey);
rsa_in = OPENSSL_malloc(keysize * 2);
rsa_out = OPENSSL_malloc(keysize);
……
for(i=0; i<keyofNum; i++)
{
if(strcmp(path,RsaKeyFile[i].path) == 0)
rsa_outlen = RSA_private_encrypt(rsa_inlen, rsa_in, rsa_out, RsaKeyFile[i].gRsaKey, RSA_PKCS1_PADDING);
}
……
}
第二种方式显然比第一种要更好,它能自动读取/etc/upps/目录下所有的文件,并实现自动加载,自动设别key的功能。
代码的问题:
tsRSAPrivateEncrypt可能会出现问题,当目录下只有一个key时,RsaKeyFile[1].gRsaKey显然超出了内存范围。
应改为:
__DLL_EXPORT__ int tsRSAPrivateEncrypt(unsigned char *input, unsigned char *output,char* path)
{
……
for(i=0; i<keyofNum; i++)
{
if(strcmp(path,RsaKeyFile[i].path) == 0)
{
keysize = RSA_size(RsaKeyFile[i].gRsaKey);
rsa_in = OPENSSL_malloc(keysize * 2);
rsa_out = OPENSSL_malloc(keysize);
rsa_outlen = RSA_private_encrypt(rsa_inlen, rsa_in, rsa_out, RsaKeyFile[i].gRsaKey, RSA_PKCS1_PADDING);
}
……
}
由于时间紧迫,暂时无暇改正了。