C语言使用openssl库的MD5withRSA签名Demo

该代码实现了一个使用OpenSSL库进行MD5摘要,然后使用RSA私钥签名,最后将签名结果进行Base64编码的过程。在主函数中,程序接收一个参数作为私钥路径,对指定字符串进行签名并输出Base64编码后的签名结果。此外,还介绍了如何生成和使用RSA密钥,以及OpenSSL的相关命令。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.  此代码的功能:先使用MD5摘要,摘要的结果使用私钥签名,签名结果用base64编码输出

#include <stdio.h>
#include <string.h>
#include <openssl/rsa.h>
#include <openssl/pem.h>
#include <openssl/err.h>
#include <openssl/md5.h>

//将二进制流转换成base64编码  
char * base64_encode(const unsigned char * bindata, char * base64, int binlength)  
{
	const char * base64char = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";   
    int i, j;  
    unsigned char current;  
  
    for (i = 0, j = 0; i < binlength; i += 3)  
    {  
        current = (bindata[i] >> 2);  
        current &= (unsigned char)0x3F;  
        base64[j++] = base64char[(int)current];  
  
        current = ((unsigned char)(bindata[i] << 4)) & ((unsigned char)0x30);  
        if (i + 1 >= binlength)  
        {  
            base64[j++] = base64char[(int)current];  
            base64[j++] = '=';  
            base64[j++] = '=';  
            break;  
        }  
        current |= ((unsigned char)(bindata[i + 1] >> 4)) & ((unsigned char)0x0F);  
        base64[j++] = base64char[(int)current];  
  
        current = ((unsigned char)(bindata[i + 1] << 2)) & ((unsigned char)0x3C);  
        if (i + 2 >= binlength)  
        {  
            base64[j++] = base64char[(int)current];  
            base64[j++] = '=';  
            break;  
        }  
        current |= ((unsigned char)(bindata[i + 2] >> 6)) & ((unsigned char)0x03);  
        base64[j++] = base64char[(int)current];  
  
        current = ((unsigned char)bindata[i + 2]) & ((unsigned char)0x3F);  
        base64[j++] = base64char[(int)current];  
    }  
    base64[j] = '\0';  
    return base64;  
}  

int my_sign(const char *psrc, BIGNUM *signret, const char *pri_key_path, char *SignOut)
{
/*  RSA签名过程如下:
1)    对用户数据进行摘要;
2)  构造X509_SIG结构并DER编码,其中包括了摘要算法以及摘要结果。
3)  对2)的结果进行填充,填满RSA密钥长度字节数。比如1024位RSA密钥必须填满128字节。具体的填充方式由用户指定。
4)  对3)的结果用RSA私钥加密。
RSA_eay_private_encrypt函数实现了3)和4)过程。 */
        RSA  *p_rsa = NULL;
        FILE *file = NULL;
		unsigned char signstr[512+1];
		unsigned char MD5Str[128+1] = {0};  //MD5长度一般为128位
        int nid = NID_md5;
        int signlen;
        //int i = 0,bit = 1024;
        int ret = 0;
		//int pad = RSA_PKCS1_PADDING;
        //nid = NID_md5;

        file = fopen(pri_key_path, "rb");
        if(!file)
        {
                ret = -1;
                return ret;
        }
        if((p_rsa = PEM_read_RSAPrivateKey(file, NULL,NULL,NULL )) == NULL)
        {
                ret = -2;
                fclose(file);
                return ret;
        }
        fclose(file);
		
//. MD5摘要
		MD5((const unsigned char *)psrc, strlen(psrc), MD5Str);
//. 签名
		ret = RSA_sign(nid, MD5Str, strlen(MD5Str), signstr, &signlen, p_rsa);
        if(ret != 1)
        { 
                ret = -3;
				RSA_free(p_rsa);
                printf("RSA_sign err!\n");
                return ret;
        }
        RSA_free(p_rsa);
		
//签名成功,转换成base64  
        base64_encode(signstr, SignOut, signlen);  

        return 0;
}

int main(int argc, char**argv)
{
        BIGNUM *dst = BN_new();
		int ret;
        char SignOut[2048+1];       //签名后输出的内容
		char *psrc = "hello world"; //待签名的源字符串
        
        if(argc >= 2)
        {
				memset(dst, 0x00, sizeof(dst));
				ret = my_sign(psrc, dst, argv[1], SignOut);
                if(ret)
                {
                        fprintf(stderr, "Error\n");
                }
				else
				{
						printf("base64_SignOut:\n%s\n", SignOut);
				}
        }

        BN_free(dst);

        return ret;
}

2.编译(已经下载openssl源码并交叉编译过):

arm-linux-gnueabihf-gcc example.c -o example -I./include -L./lib -lssl -lcrypto

3.验证

 3.1 首先,使用在线工具生成密钥, 将私钥复制保存为文件testkey.pem

(如果项目中提供了私钥,按照的格式私钥编写pem文件)

 3.2 代码结果与在线签名结果对比(注:截图中的test.key  就是3.1中的testkey.pem。因为后来觉得用pem后缀显得规范点就改成testkey.pem,截图懒得更换了。秘钥文件与文件名无关)

4.拓展知识

4.1 PKCS#1 和 PKCS#8 格式的区分:有RSA的是PKCS#1

 

4.2 OpenSSL密钥相关命令

1. 生成密钥

openssl genrsa -out key.pem 1024
    -out 指定生成文件,此文件包含公钥和私钥两部分,所以即可以加密,也可以解密
    1024 生成密钥的长度

2. 提取PEM格式公钥

openssl rsa -in key.pem -pubout -out pubkey.pem
    -in 指定输入的密钥文件
    -out 指定提取生成公钥的文件(PEM公钥格式)

3. 提取PEM RSAPublicKey格式公钥

openssl rsa -in key.pem -RSAPublicKey_out -out pubkey.pem
    -in 指定输入的密钥文件
    -out 指定提取生成公钥的文件(PEM RSAPublicKey格式)

4. 公钥加密文件

openssl rsautl -encrypt -in input.file -inkey pubkey.pem -pubin -out output.file
    -in 指定被加密的文件
    -inkey 指定加密公钥文件
    -pubin 表面是用纯公钥文件加密
    -out 指定加密后的文件

5. 私钥解密文件

openssl rsautl -decrypt -in input.file -inkey key.pem -out output.file
    -in 指定需要解密的文件
    -inkey 指定私钥文件
    -out 指定解密后的文件
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值