IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> C语言使用openssl库的MD5withRSA签名Demo -> 正文阅读

[C++知识库]C语言使用openssl库的MD5withRSA签名Demo

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 指定解密后的文件
  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2021-08-30 11:49:20  更:2021-08-30 11:49:38 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年12日历 -2024/12/27 21:29:17-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码
数据统计