1.安装openssl

        安装完成之后,会有个lib目录,将lib目录下的 libcrypto 拷贝到/usr/lib64目录下。

2. 生成私钥和公钥

        生成私钥:openssl genrsa -out rsa_private_key.pem 2048

        生成加密的私钥:openssl genrsa -out rsa_private_key.pem -des3 2048

        生成公钥:openssl rsa -in rsa_private_key.pem -pubout -out rsa_public_key.pem  

3.签名

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <openssl/rsa.h>
#include <openssl/pem.h>
#include <openssl/err.h>
#include <openssl/sha.h> 
#include <openssl/crypto.h> 

/*
 * 参考https://blog.csdn.net/zjf535214685/article/details/82182241
*/ 

#define SHA_WHICH        NID_sha256
#define WHICH_DIGEST_LENGTH    SHA256_DIGEST_LENGTH
char transToHex[2048];	

unsigned char BASE64_CODE[]={"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"};

void printHex(unsigned char *md, int len)
{
	memset(transToHex, 0x00, sizeof(transToHex));
    int i = 0;
    for (i = 0; i < len; i++)
    {
        printf("%02x", md[i]);
        sprintf(transToHex+i*2, "%02x", md[i]);
    }

    printf("\n");
printf("transToHex[%s]\n", transToHex);
}

/*读取私钥*/
RSA* ReadPrivateKey(char* p_KeyPath)
{   
    FILE *fp = NULL; 
    RSA  *priRsa = NULL;

    printf("PrivateKeyPath[%s] \n", p_KeyPath);

    /*  打开密钥文件 */
    if(NULL == (fp = fopen(p_KeyPath, "r")))
    {
        printf( "fopen[%s] failed \n", p_KeyPath);
        return NULL;
    }
    /*  获取私钥 */
    //priRsa = PEM_read_RSAPrivateKey(fp, NULL, NULL,NULL);		/*不加密*/
    priRsa = PEM_read_RSAPrivateKey(fp, NULL, NULL,"123456");  /*加密, 密码是123456*/
    if(NULL == priRsa)
    {
        ERR_print_errors_fp(stdout);
        printf( "PEM_read_RSAPrivateKey\n");
        fclose(fp);
        return NULL;
    }
    fclose(fp);

    return priRsa;
}

/*
 * ToBase64 (Internal used by EncodeBase64)
 * Param: unsigned char psInData[3] -- IN / Pointer to 3 or less chars of Original Data
 *        unsigned char psOutData[4] -- IN / Pointer to 4 char of Encoded Base64 Data
 *        int iLen -- IN / Length of the Original Data, should only be 1, 2, or 3
 *
 * Return: 0 -- On sucess
 *         -1 -- On any error
 */
int ToBase64(unsigned char psInData[3], unsigned char psOutData[4], int iLen)
{
	psOutData[0] = BASE64_CODE[psInData[0] >> 2];
	if (iLen == 1)
	{
		psOutData[1] = BASE64_CODE[psInData[0] << 4 & 0x30];
		psOutData[2] = '=';
		psOutData[3] = '=';
		return 0;
	}
	psOutData[1] = BASE64_CODE[psInData[0] << 4 & 0x30 | psInData[1] >> 4];
	if (iLen == 2)
	{
		psOutData[2] = BASE64_CODE[psInData[1] << 2 & 0x3C];
		psOutData[3] = '=';
		return 0;
	}
	psOutData[2] = BASE64_CODE[psInData[1] << 2 & 0x3C | psInData[2] >> 6];
	psOutData[3] = BASE64_CODE[psInData[2] & 0x3F];

	return 0;
}

/* 
 * EncodeBase64
 * Param: unsigned char* psInData -- IN / Pointer to Original Data buf
 *        long lInDataLen -- IN / Length of Original Data
 *        unsigned char* psOutData -- IN / Pointer to Output Data buf
 *        long* plOutDataLen -- IN / Length of Output Data buf 
 *                              OUT / Length of Base64 Code
 *
 * Return: 0 -- On Successful
 *         -1 -- *plOutDataLen too small
 */
int EncodeBase64(unsigned char* psInData, long lInDataLen, unsigned char* psOutData, long* plOutDataLen)
{
	int i;

	if (*plOutDataLen < lInDataLen/3*4)
	{
		/*
		printf("Base64 Encode overflow! (output buf not enough)\n\n");
		*/
		return -1;
	}
	
	for (i = 0; i < lInDataLen; i += 3)
		ToBase64(&psInData[i], &psOutData[i/3*4], lInDataLen-i-3 >= 0 ? 3 : lInDataLen%3);
	*plOutDataLen = i/3*4;
	
	return 0;
}


int test_RSA_sign(char *inData, char *outData, char *keyName)
{
	
	RSA *privKey = NULL;

	char outdatab64[2000546] = {0}; /*原报文base64加密*/ /*如果定义长度2900546, 编译会报 Segmentation fault*/
 	char signbase64[2048*8] = {0};	/*签名之后base64加密*/
 	
   	char buf[2048] = {0};		/*签名之后的数据*/
    int nOutLen = sizeof(buf);	/*签名之后的长度*/
   
    long int outdatab64_len = sizeof(outdatab64);	/*原报文base加密之后的长度*/
	long int indata_len = strlen(inData);		/*原报文的长度*/	
	long int signbase64_len = sizeof(signbase64);	/*签名之后base64加密之后的长度*/
    
    int nRet = 0;
  	
  	/*对原报文进行base64加密*/
	nRet = EncodeBase64(inData, indata_len, outdatab64, &outdatab64_len);
	if (nRet != 0)
	{
		printf("EncodeBase64() error!!!\n");
		return -1;
	}
	printf("-------------------\n");
	printf("FILE[%s]LINE[%d] outdatab64_len[%ld], outdatab64[%s]\n", __FILE__, __LINE__, outdatab64_len, outdatab64);

    //对数据进行sha256算法摘要
    unsigned char md[WHICH_DIGEST_LENGTH];

    SHA256((unsigned char *)inData, strlen(inData), md);
    printHex(md, WHICH_DIGEST_LENGTH);

	privKey = ReadPrivateKey(keyName);
    if (!privKey) 
    {  
        ERR_print_errors_fp (stderr);    
        return -1;  
    }

    /* 签名 */
   nRet = RSA_sign(SHA_WHICH, md, WHICH_DIGEST_LENGTH, buf, &nOutLen, privKey);
    if(nRet != 1)
    {
        printf("RSA_sign err !!! \n");    
        goto quit;
    }
    printf("RSA_sign len = %d:", nOutLen);
    printHex(buf, nOutLen);

	nOutLen = strlen(transToHex);
    
    /*签名之后,再进行base64加密*/
//    nRet = EncodeBase64(buf, nOutLen, signbase64, &signbase64_len);
	nRet = EncodeBase64(transToHex, nOutLen, signbase64, &signbase64_len);
	if (nRet != 0)
	{
		printf("FILE[%s]LINE[%d] EncodeBase64() error!!!\n", __FILE__, __LINE__);
		return -1;
	}
printf("signbase64_len[%d],signbase64[%s]\n", signbase64_len, signbase64);    
    sprintf(outData,"<?xml version= \"1.0\"encoding= \"gb2312\"?> <msg><sourceData>%s</sourceData><signData>%s</signData></msg>",outdatab64,signbase64);
//	sprintf(outData,"<?xml version= \"1.0\"encoding= \"gb2312\"?> <msg><sourceData>%s</sourceData><signData>",outdatab64);
//	outDataHalf_len = strlen(outData);
//	memcpy(outData+strlen(outData), buf, nOutLen);
//	memcpy(outData+outDataHalf_len+nOutLen, "</sgnData></msg>", 16);
	


quit:
    RSA_free(privKey);

    return 0;   
}


int main(int argc, char *argv[])
{
	int iRet;
//	char *idata = "china"; 
	char *idata = "<?xml version = \"1.0\" encoding = \"GB2312\"?><bocb2e version=\"100\" security=\"true\" lang=\"chs\"><head><termid>E127000000001</termid><trnid>20060704001</trnid><custid>12345678</custid><cusopr>BOC</cusopr><trncod>b2e0005</trncod><token>9TTQALYGH1</token></head><trans><trn-b2e0005-rq><b2e0005-rq><account><ibknum>40001</ibknum><actacn>800100053208091001</actacn></account></b2e0005-rq><b2e0005-rq><account><ibknum>40002</ibknum><actacn>800100053108091001</actacn></account></b2e0005-rq></trn-b2e0005-rq></trans></bocb2e>";
	char StrNewBuf[2099546*2+1] = {0};	/*报文头+原数据+签名之后 的数据*/
	char StrNewBuf_tmp[2099546+1] = {0};	/*需要加签的数据*/
	char keyName[] = "./rsa_private_key.pem";	/*key的路径*/
	
	memcpy(StrNewBuf_tmp, idata, strlen(idata));
	
	iRet = test_RSA_sign(StrNewBuf_tmp, StrNewBuf, keyName); /*替换函数SM2RawSign(StrNewBuf_tmp, StrNewBuf, keyName, passWord);*/
	if(iRet != 0)
	{
		printf("test_RSA_sign() error !!!\n");
		return -1;	
	}
	printf("---------------------------\n");
    printf("FILE[%s]LINE[%d]StrNewBuf[%s]\n\n\n", __FILE__, __LINE__, StrNewBuf);
	
    return 0;
}

运行:gcc rsa_sign.c -lcrypto ; ./a.out

红色框框里的表示十六进制打印出来的签名。

4.验签

#include <string.h>
#include <openssl/rsa.h>
#include <openssl/pem.h>
#include <openssl/err.h>
#include <openssl/sha.h> 
#include <openssl/crypto.h> 

/*
 * 参考https://blog.csdn.net/zjf535214685/article/details/82182241
 */ 

//#define PUBLIC_KEY_PATH  ("./public_key.pem")
#define PUBLIC_KEY_PATH  ("./rsa_public_key.pem")

#define SHA_WHICH        NID_sha256
#define WHICH_DIGEST_LENGTH    SHA256_DIGEST_LENGTH


void printHex(unsigned char *md, int len)
{

    int i = 0;
    for (i = 0; i < len; i++)
    {
        printf("%02x", md[i]);
    }

    printf("\n");
}

/*读取公匙*/
RSA* ReadPublicKey(char* p_KeyPath)
{   
    FILE *fp = NULL; 
    RSA *pubRsa = NULL;

    printf("PublicKeyPath[%s]\n", p_KeyPath);

    /*  打开密钥文件 */
    if(NULL == (fp = fopen(p_KeyPath, "r")))
    {
        printf( "fopen[%s] \n", p_KeyPath);
        return NULL;
    }
    /*  获取公钥 */
    if(NULL == (pubRsa = PEM_read_RSA_PUBKEY(fp, NULL, NULL,NULL)))
    {
        printf( "PEM_read_RSAPrivateKey error\n");
        fclose(fp);
        return NULL;
    }
    fclose(fp);

    return pubRsa;
}

int test_RSA_verify(void)
{
    char *data = "<?xml version = \"1.0\" encoding = \"GB2312\"?><bocb2e version=\"100\" security=\"true\" lang=\"chs\"><head><termid>E127000000001</termid><trnid>20060704001</trnid><custid>12345678</custid><cusopr>BOC</cusopr><trncod>b2e0005</trncod><token>9TTQALYGH1</token></head><trans><trn-b2e0005-rq><b2e0005-rq><account><ibknum>40001</ibknum><actacn>800100053208091001</actacn></account></b2e0005-rq><b2e0005-rq><account><ibknum>40002</ibknum><actacn>800100053108091001</actacn></account></b2e0005-rq></trn-b2e0005-rq></trans></bocb2e>";
   
char buf[256] = {
			0x5d,
			0xa7,0x17,0x2b,0xe2,0x37,0x00,0xd4,0xe7,
			0x71,0xd1,0x41,0x9a,0xe2,0x81,0x46,0x97,
			0x69,0xb4,0x39,0x4d,0x84,0x1d,0x7e,0x98,
			0x72,0xe3,0x27,0xcf,0x5e,0xaf,0x3d,0xc4,
			0x8d,0xcd,0x01,0x63,0x1b,0x71,0x48,0x06,
			0xd1,0x96,0x9c,0x23,0x58,0x59,0xfc,0x96,
			0x0a,0xd9,0x24,0x6c,0x57,0xf6,0x62,0x17,
			0xb9,0xc4,0x6d,0x80,0xa7,0x01,0x08,0x7e,
			0x3d,0x91,0x70,0x6e,0xe7,0x09,0x28,0xda,
			0xe3,0xe7,0x6d,0xba,0x47,0xa5,0xd3,0x0c,
			0x51,0xe0,0x5c,0xcc,0x74,0x65,0x13,0xed,
			0x13,0x31,0xc4,0xff,0x22,0x46,0x52,0xb4,
			0x17,0x46,0xfe,0x03,0x45,0x96,0x19,0xbc,
			0x1f,0xd7,0x93,0x65,0xc6,0x48,0xae,0x4c,
			0xd3,0xbd,0x6a,0xa0,0xfc,0xb8,0x20,0x3b,
			0xa9,0x5d,0xb5,0x07,0x20,0x3f,0x38,0xaf,
			0x95,0xff,0x12,0x45,0xde,0x40,0xc3,0x62,
			0x38,0x69,0xec,0xff,0x2b,0x44,0x39,0xca,
			0x1d,0xd4,0x3e,0xba,0x1a,0x28,0x57,0x54,
			0x09,0x8c,0x3d,0x57,0xb4,0x2f,0x33,0xd9,
			0xa4,0xd9,0x45,0x72,0xec,0xbb,0x2a,0x96,
			0x34,0x97,0xe1,0x2a,0x78,0xec,0xf2,0x2b,
			0xd3,0xcc,0xa6,0xcf,0xbc,0xdf,0xa2,0x8e,
			0xab,0x90,0x28,0x18,0x0b,0x73,0x61,0x8f,
			0xfb,0xf3,0xfe,0x33,0xc5,0xaa,0x9f,0x1e,
			0xac,0x83,0x93,0x72,0x50,0xdf,0xfa,0xb5,
			0x80,0xfa,0x17,0xd2,0xe5,0x9a,0x6e,0x7f,
			0x3b,0x78,0x60,0x9b,0xb5,0xa0,0xc7,0x47,
			0x24,0x4d,0x94,0x6e,0x40,0xcb,0x73,0x86,
			0x23,0x18,0x33,0xc9,0xff,0x93,0x21,0xce,
			0xcc,0x70,0xb0,0x9f,0x14,0xef,0x72,0x61,
			0xe7,0x28,0x85,0xeb,0x51,0x39,0x68,
    		};

    RSA *pubKey = NULL;
    int nOutLen = sizeof(buf);
    int nRet = 0;

    //对数据进行sha256算法摘要
    unsigned char md[WHICH_DIGEST_LENGTH];

    SHA256((unsigned char *)data, strlen(data), md);
    printHex(md, WHICH_DIGEST_LENGTH);


    pubKey = ReadPublicKey(PUBLIC_KEY_PATH);  
    if (!pubKey)
    {
        printf("Error: can't load public key");
        return -1;
    }

    /* 验签 */
    nRet = RSA_verify(SHA_WHICH, md, WHICH_DIGEST_LENGTH, buf, nOutLen, pubKey);
    printf("RSA_verify %s(ret=%d).\r\n", (1 == nRet) ? "Success" : "Failed", nRet);

    RSA_free(pubKey);

    return 0;
}

int main(int argc, char *argv[])
{
    test_RSA_verify();
    return 0;
}

运行:gcc rsa_verify.c -lcrypto ; ./a.out

GitHub 加速计划 / ope / openssl
20
1
下载
传输层安全性/安全套接层及其加密库
最近提交(Master分支:3 个月前 )
b049ce0e Reviewed-by: Matt Caswell <matt@openssl.org> Reviewed-by: Tim Hudson <tjh@openssl.org> (Merged from https://github.com/openssl/openssl/pull/26359) 6 天前
75416c09 Once lcov is updated to 2.2 version or later, it could be dropped. Reviewed-by: Neil Horman <nhorman@openssl.org> Reviewed-by: Tom Cosgrove <tom.cosgrove@arm.com> (Merged from https://github.com/openssl/openssl/pull/26381) 7 天前
Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐