杭州微网站开发公司电话如何建立公司网站网页
文章目录
- 1.为什么需要非对称密钥----对称密钥配送问题
- 2.什么是公钥密码-非对称密钥
- 3.神奇的数学关系-RSA加密数学原理
- 4.RSA数学步骤
- 5.RSA使用
- 5.1 使用openssl命令实现RSA加密解密
- 5.2 使用openssl API 接口实现RSA 加密解密
- 5.3 使用mbedtls API实现RSA 加密解密
- 5.4 使用openssl API 实现RSA 加签验签
- 5.5 使用mbedtls API实现RSA 加签验签
- 5.6 RSA使用总结
1.为什么需要非对称密钥----对称密钥配送问题
对称密钥配送问题是指在使用对称密钥加密算法时,如何安全地将密钥传输给通信双方的问题。由于对称密钥需要保持机密性,因此在传输过程中可能会面临被窃听或篡改的风险。
以下是几种常见的解决对称密钥配送问题的方法:
-
预先共享密钥:通信双方事先共享一个密钥,并确保在通信之前将其保存在安全的位置。这要求双方在通信开始之前就建立了一定的信任关系,并能够安全地交换密钥。
-
密钥分发中心(Key Distribution Center,KDC):KDC作为第三方可信实体,负责生成、分发和管理对称密钥。通信双方首先与KDC进行身份认证,然后从KDC获取加密通信所需的密钥。
-
混合加密机制:使用非对称加密算法结合对称加密算法,通信双方首先使用非对称密钥加密传输对称密钥,然后再使用对称密钥进行加密通信。这样可以在保证对称密钥安全性的同时,利用非对称算法解决密钥配送问题。
-
Diffie-Hellman密钥交换协议:Diffie-Hellman密钥交换协议允许通信双方在公开渠道上协商一个共享的秘密密钥,而不需要事先共享密钥或依赖可信第三方。通过数学运算,双方可以独立计算出相同的密钥。
2.什么是公钥密码-非对称密钥
公钥密码,也称为非对称密码,是一种密码算法体系,其中使用了两个相关联但不同的密钥:公钥和私钥。这两个密钥是成对生成的,其中一个用于加密数据(公钥),另一个用于解密数据(私钥)。
公钥密码系统的工作原理如下:
-
公钥加密私钥解密:发送方使用接收方的公钥对消息进行加密,然后将密文发送给接收方。只有拥有相应私钥的接收方才能解密密文并读取原始消息。
-
私钥签名公钥验签:发送方使用自己的私钥对消息进行签名,然后将签名附加到消息中。接收方可以使用发送方的公钥验证签名的真实性和完整性,以确保消息未被篡改。
公钥密码系统具有以下特点和优势:
-
安全性:公钥密码系统基于数学难题,如大素数分解、离散对数等,这些问题在计算上很难逆转。因此,即使攻击者获得了公钥,也很难从中推导出私钥,保证了数据的机密性和安全性。
-
密钥配送问题:相对于对称加密算法,公钥密码系统解决了密钥配送问题。每个用户只需要保存自己的私钥,而公钥可以自由传播。这样,通信双方无需事先共享密钥,可以安全地进行加密通信。
-
数字签名:公钥密码系统可以用于生成和验证数字签名,确保消息的完整性、真实性和不可抵赖性。通过使用私钥对消息进行签名,发送方可以证明其身份,并且无法否认自己的行为。
常见的公钥密码算法包括RSA、椭圆曲线密码学(ECC)、Diffie-Hellman密钥交换等。这些算法在信息安全领域得到广泛应用,用于加密通信、数字签名、密钥交换等场景。公钥密码系统为安全通信提供了重要的技术基础。
3.神奇的数学关系-RSA加密数学原理
- RSA密码算法中的公钥和私钥之间存在严格而神奇的数学关系,公私钥之间是一一对应的;
详细RSA 数学原理请参考 RSA加密数学原理详解
4.RSA数学步骤
RSA(Rivest-Shamir-Adleman)是一种基于数论的公钥密码算法,其核心原理涉及到以下几个数学概念和操作:
- 选择素数:
在RSA中,首先需要选择两个大素数 p 和 q。这两个素数需要保密,并且应该足够大,以增加破解的难度, 大素数一般来自于随机数, 先
使用随机数生成器生成一个大整数, 再判断该大整数是否为素数。
p = 3,q = 11 - 计算模数:
计算模数 n = p * q。模数 n 是一个大整数,它将用于加密和解密过程中的运算。
n = p * q = 33 - 计算欧拉函数:
欧拉函数 φ(n) 是与模数 n 互质的小于 n 的正整数的个数。对于两个素数 p 和 q,欧拉函数可以表示为 φ(n) = (p-1)(q-1)。
φ(n) = (p-1)(q-1) = (3-1)(11-1) = 20* - 选择加密指数:
选择一个加密指数 e,满足 1 < e < φ(n) 且 e 与 φ(n) 互质。加密指数 e 将用于加密明文。e的常见选择有3、 17和65537, 它们都是素数并可加快模幂运
算速度。
e =3 - 计算解密指数:
计算解密指数 d,使得 (d * e) mod φ(n) = 1。解密指数 d 将用于解密密文。
3d mod 20 = 1 d = 7 - 加密:
将明文 M 转换为整数 m(0 ≤ m < n),然后计算密文 C = m^e mod n。密文 C 是加密后的整数。
c=me mod N = 53 mod 33 = 26 - 解密:
接收者使用私钥(解密指数 d 和模数 n)进行解密。计算明文 m = C^d mod n,然后将整数 m 转换回原始明文 M。
m=cd mod N = 267 mod 33 = 5
5.RSA使用
5.1 使用openssl命令实现RSA加密解密
-
在 Linux 环境下,openssl genrsa 命令用于生成 RSA 密钥对。下面是详细介绍该命令的使用方法和常见参数:
openssl genrsa [options] [-out filename] [numbits]
常见参数说明:
-
-options:可选参数,用于指定不同选项。
-
-out filename:可选参数,用于指定生成的密钥文件名,默认为标准输出。
-
numbits:可选参数,用于指定密钥长度(位数),默认为 2048 位。
常见选项:- -aes128、-aes192、-aes256:分别用于指定使用 AES-128、AES-192、AES-256 加密密钥。
- -des、-des3:分别用于指定使用 DES、Triple DES 加密密钥。
- -rand file(s):用于指定随机种子文件路径,多个文件路径可以用逗号分隔。
- -rand file:file…:用于指定多个随机种子文件。
- -f4:用于指定 RSA 公钥指数(默认为 F4,即 65537)。
- -help:显示帮助信息。
-
示例用法:
- 生成默认(2048 位)的 RSA 密钥对,并将私钥保存到文件 private.pem 中:
openssl genrsa -out private.pem
- 生成 4096 位的 RSA 密钥对,并将私钥保存到文件 private.pem 中:
openssl genrsa -out private.pem 4096
- 生成默认(2048 位)的 RSA 密钥对,并使用 AES-256 加密私钥,同时将私钥保存到文件 private.pem 中:
openssl genrsa -aes256 -out private.pem
- 生成默认(2048 位)的 RSA 密钥对,并使用指定的随机种子文件生成密钥:
openssl genrsa -rand /dev/random -out private.pem
- 在 Linux 环境下,OpenSSL 提供了 openssl rsa 命令用于操作 RSA 密钥。它可以用于生成、转换和管理 RSA 密钥,以及执行与密钥相关的其他操作。下面是 openssl rsa 命令的使用方法和常见命令控制参数的详细介绍:
openssl rsa [options] [-in filename] [-out filename]
常见命令控制参数说明:
-
options:可选参数,用于指定不同选项。
-
-in filename:可选参数,用于指定输入的密钥文件名,默认为标准输入。
-
-out filename:可选参数,用于指定输出的密钥文件名,默认为标准输出。
常见选项: -
-pubin:读取公钥文件。
-
-pubout:将密钥转换为公钥形式输出。
-
-inform PEM、-inform DER:分别用于指定输入密钥的格式为 PEM 格式或 DER 格式。
-
-outform PEM、-outform DER:分别用于指定输出密钥的格式为 PEM 格式或 DER 格式。
-
-passin arg:用于指定输入密钥文件或加密密钥口令的密码。
-
-passout arg:用于指定输出密钥文件的密码。
-
-text:以文本格式显示密钥信息。
-
-noout:不进行任何输出,仅执行操作。
示例用法:- 显示 PEM 格式私钥文件 private.pem 的信息:
openssl rsa -in private.pem -text
- 将 PEM 格式私钥文件 private.pem 转换为 DER 格式,并保存到文件 private.der:
openssl rsa -in private.pem -outform DER -out private.der
- 将 PEM 格式公钥文件 public.pem 转换为 DER 格式,并保存到文件 public.der:
openssl rsa -pubin -in public.pem -outform DER -out public.der
- 将 PEM 格式密钥文件 private.pem 的密码更改为新密码,并将结果保存到文件 new_private.pem:
openssl rsa -in private.pem -passin pass:oldpass -des3 -out new_private.pem -passout pass:newpass
-
在 Linux 环境下,OpenSSL 提供了 openssl rsautl 命令用于执行 RSA 加密、解密、签名和验证等操作。它可以使用 RSA 密钥对进行数据的加解密和签名验证。下面是 openssl rsautl 命令的使用方法和常见命令控制参数的详细介绍:
openssl rsautl [options] [-in filename] [-out filename]
常见命令控制参数说明:
- options:可选参数,用于指定不同选项。
- -in filename:可选参数,用于指定输入的文件名,默认为标准输入。
- -out filename:可选参数,用于指定输出的文件名,默认为标准输出。
常见选项:
- -encrypt:使用公钥进行加密。
- -decrypt:使用私钥进行解密。
- -sign:使用私钥进行签名。
- -verify:使用公钥进行签名验证。
- -inkey filename:用于指定包含 RSA 密钥的文件名。
- -keyform PEM、-keyform DER:分别用于指定输入密钥的格式为 PEM 格式或 DER 格式。
- -pubin:读取公钥文件。
- -passin arg:用于指定输入密钥文件或加密密钥口令的密码。
- -raw:以原始二进制格式处理输入数据。
- -hexdump:以十六进制格式显示加解密后的数据。
- -oaep:使用 OAEP(Optimal Asymmetric Encryption Padding)进行加解密操作。
- -pkcs:使用 PKCS#1 标准进行加解密操作。
示例用法:
-
使用公钥文件 public.pem 对文件 plain.txt 进行加密,并将结果保存到文件 encrypted.dat:
openssl rsautl -encrypt -inkey public.pem -pubin -in plain.txt -out encrypted.dat
-
使用私钥文件 private.pem 对文件 encrypted.dat 进行解密,并将结果保存到文件 decrypted.txt:
openssl rsautl -decrypt -inkey private.pem -in encrypted.dat -out decrypted.txt
-
使用私钥文件 private.pem 对文件 data.txt 进行签名,并将结果保存到文件 signature.bin:
openssl rsautl -sign -inkey private.pem -in data.txt -out signature.bin
-
使用公钥文件 public.pem 对文件 data.txt 的签名进行验证:
openssl rsautl -verify -inkey public.pem -pubin -in data.txt -in signature.bin
注意事项:
- 在使用 openssl rsautl 命令之前,需要确保已生成 RSA 密钥对,可以使用 openssl genrsa 命令生成。
- 公钥和私钥文件一般采用 PEM 格式或 DER 格式。
- 对于加密和解密操作,需要使用匹配的公钥和私钥。
- 对于签名和验证操作,需要使用匹配的私钥和公钥。
-
下面是使用 OpenSSL 命令生成 RSA 密钥对,并使用公钥加密、私钥解密的完整命令流:
- 生成 RSA 密钥对:
openssl genrsa -out private_key.pem 2048
上述命令将生成一个长度为 2048 位的 RSA 私钥,并保存在 private_key.pem 文件中。
-
从私钥中提取公钥:
openssl rsa -in private_key.pem -out public_key.pem -pubout
上述命令将从私钥文件 private_key.pem 中提取公钥,并保存在 public_key.pem 文件中。
-
使用公钥进行加密:
openssl rsautl -encrypt -inkey public_key.pem -pubin -in plaintext.txt -out encrypted.txt
上述命令将使用公钥文件 public_key.pem 对文件 plaintext.txt 进行加密,并将结果保存到 encrypted.txt 中。
-
使用私钥进行解密:
openssl rsautl -decrypt -inkey private_key.pem -in encrypted.txt -out decrypted.txt
上述命令将使用私钥文件 private_key.pem 对文件 encrypted.txt 进行解密,并将结果保存到 decrypted.txt 中。
5.2 使用openssl API 接口实现RSA 加密解密
- 生成RSA密钥对
// 生成公钥文件和私钥文件,私钥文件带密码
int generate_key_files(const char *pub_keyfile, const char *pri_keyfile, const unsigned char *passwd, int passwd_len)
{RSA *rsa = NULL;RAND_seed(rnd_seed, sizeof(rnd_seed));rsa = RSA_generate_key(RSA_KEY_LENGTH, RSA_F4, NULL, NULL);if(rsa == NULL){printf("RSA_generate_key error!\n");return -1;}// 开始生成公钥文件BIO *bp = BIO_new(BIO_s_file());if(NULL == bp){printf("generate_key bio file new error!\n");return -1;}if(BIO_write_filename(bp, (void *)pub_keyfile) <= 0){printf("BIO_write_filename error!\n");return -1;}if(PEM_write_bio_RSAPublicKey(bp, rsa) != 1){printf("PEM_write_bio_RSAPublicKey error!\n");return -1;}// 公钥文件生成成功,释放资源printf("Create public key ok!\n");BIO_free_all(bp);// 生成私钥文件bp = BIO_new_file(pri_keyfile, "w+");if(NULL == bp){printf("generate_key bio file new error2!\n");return -1;}if(PEM_write_bio_RSAPrivateKey(bp, rsa,EVP_des_ede3_ofb(), (unsigned char *)passwd, passwd_len, NULL, NULL) != 1){printf("PEM_write_bio_RSAPublicKey error!\n");return -1;}// 释放资源printf("Create private key ok!\n");BIO_free_all(bp);RSA_free(rsa);return 0;
}
- 读取公钥
// 打开公钥文件,返回EVP_PKEY结构的指针
EVP_PKEY* open_public_key(const char *keyfile)
{EVP_PKEY* key = NULL;RSA *rsa = NULL;OpenSSL_add_all_algorithms();BIO *bp = BIO_new(BIO_s_file());;BIO_read_filename(bp, keyfile);if(NULL == bp){printf("open_public_key bio file new error!\n");return NULL;}rsa = PEM_read_bio_RSAPublicKey(bp, NULL, NULL, NULL);if(rsa == NULL){printf("open_public_key failed to PEM_read_bio_RSAPublicKey!\n");BIO_free(bp);RSA_free(rsa);return NULL;}printf("open_public_key success to PEM_read_bio_RSAPublicKey!\n");key = EVP_PKEY_new();if(NULL == key){printf("open_public_key EVP_PKEY_new failed\n");RSA_free(rsa);return NULL;}EVP_PKEY_assign_RSA(key, rsa);return key;
}
- 读取私钥
// 打开私钥文件,返回EVP_PKEY结构的指针
EVP_PKEY* open_private_key(const char *keyfile, const unsigned char *passwd)
{EVP_PKEY* key = NULL;RSA *rsa = RSA_new();OpenSSL_add_all_algorithms();BIO *bp = NULL;bp = BIO_new_file(keyfile, "rb"); if(NULL == bp){printf("open_private_key bio file new error!\n");return NULL;}rsa = PEM_read_bio_RSAPrivateKey(bp, &rsa, NULL, (void *)passwd);if(rsa == NULL){printf("open_private_key failed to PEM_read_bio_RSAPrivateKey!\n");BIO_free(bp);RSA_free(rsa);return NULL;}printf("open_private_key success to PEM_read_bio_RSAPrivateKey!\n");key = EVP_PKEY_new();if(NULL == key){printf("open_private_key EVP_PKEY_new failed\n");RSA_free(rsa);return NULL;}EVP_PKEY_assign_RSA(key, rsa);return key;
}
- 公钥加密
// 使用密钥加密,这种封装格式只适用公钥加密,私钥解密,这里key必须是公钥
int rsa_key_encrypt(EVP_PKEY *key, const unsigned char *orig_data, size_t orig_data_len, unsigned char *enc_data, size_t &enc_data_len)
{EVP_PKEY_CTX *ctx = NULL;OpenSSL_add_all_ciphers();ctx = EVP_PKEY_CTX_new(key, NULL);if(NULL == ctx){printf("ras_pubkey_encryptfailed to open ctx.\n");EVP_PKEY_free(key);return -1;}if(EVP_PKEY_encrypt_init(ctx) <= 0){printf("ras_pubkey_encryptfailed to EVP_PKEY_encrypt_init.\n");EVP_PKEY_free(key);return -1;}if(EVP_PKEY_encrypt(ctx,enc_data,&enc_data_len,orig_data,orig_data_len) <= 0){printf("ras_pubkey_encryptfailed to EVP_PKEY_encrypt.\n");EVP_PKEY_CTX_free(ctx);EVP_PKEY_free(key);return -1;}EVP_PKEY_CTX_free(ctx);EVP_PKEY_free(key);return 0;
}
- 私钥解密
// 使用密钥解密,这种封装格式只适用公钥加密,私钥解密,这里key必须是私钥
int rsa_key_decrypt(EVP_PKEY *key, const unsigned char *enc_data, size_t enc_data_len, unsigned char *orig_data, size_t &orig_data_len, const unsigned char *passwd)
{EVP_PKEY_CTX *ctx = NULL;OpenSSL_add_all_ciphers();ctx = EVP_PKEY_CTX_new(key, NULL);if(NULL == ctx){printf("ras_prikey_decryptfailed to open ctx.\n");EVP_PKEY_free(key);return -1;}if(EVP_PKEY_decrypt_init(ctx) <= 0){printf("ras_prikey_decryptfailed to EVP_PKEY_decrypt_init.\n");EVP_PKEY_free(key);return -1;}if(EVP_PKEY_decrypt(ctx,orig_data,&orig_data_len,enc_data,enc_data_len) <= 0){printf("ras_prikey_decryptfailed to EVP_PKEY_decrypt.\n");EVP_PKEY_CTX_free(ctx);EVP_PKEY_free(key);return -1;}EVP_PKEY_CTX_free(ctx);EVP_PKEY_free(key);return 0;
}
- 测试函数
int main(int argc, char **argv)
{char origin_text[] = "hello world!";char enc_text[512] = "";char dec_text[512] = "";size_t enc_len = 512;size_t dec_len = 512;// 生成公钥和私钥文件generate_key_files(PUBLIC_KEY_FILE, PRIVATE_KEY_FILE, (const unsigned char *)RSA_PRIKEY_PSW, strlen(RSA_PRIKEY_PSW));EVP_PKEY *pub_key = open_public_key(PUBLIC_KEY_FILE);EVP_PKEY *pri_key = open_private_key(PRIVATE_KEY_FILE, (const unsigned char *)RSA_PRIKEY_PSW);rsa_key_encrypt(pub_key, (const unsigned char *)&origin_text, sizeof(origin_text), (unsigned char *)enc_text, enc_len);rsa_key_decrypt(pri_key, (const unsigned char *)enc_text, enc_len, (unsigned char *)dec_text, dec_len, (const unsigned char *)RSA_PRIKEY_PSW);return 0;
}
5.3 使用mbedtls API实现RSA 加密解密
#if defined(MBEDTLS_RSA_C)#include <stdio.h>
#include "string.h"
#include "mbedtls/entropy.h"
#include "mbedtls/ctr_drbg.h"
#include "mbedtls/rsa.h"static char buf[516];static void dump_rsa_key(mbedtls_rsa_context *ctx)
{size_t olen;printf("\n +++++++++++++++++ rsa keypair +++++++++++++++++\n\n");mbedtls_mpi_write_string(&ctx->N , 16, buf, sizeof(buf), &olen);printf("N: %s\n", buf); mbedtls_mpi_write_string(&ctx->E , 16, buf, sizeof(buf), &olen);printf("E: %s\n", buf);mbedtls_mpi_write_string(&ctx->D , 16, buf, sizeof(buf), &olen);printf("D: %s\n", buf);mbedtls_mpi_write_string(&ctx->P , 16, buf, sizeof(buf), &olen);printf("P: %s\n", buf);mbedtls_mpi_write_string(&ctx->Q , 16, buf, sizeof(buf), &olen);printf("Q: %s\n", buf);mbedtls_mpi_write_string(&ctx->DP, 16, buf, sizeof(buf), &olen);printf("DP: %s\n", buf);mbedtls_mpi_write_string(&ctx->DQ, 16, buf, sizeof(buf), &olen);printf("DQ: %s\n", buf);mbedtls_mpi_write_string(&ctx->QP, 16, buf, sizeof(buf), &olen);printf("QP: %s\n", buf);printf("\n +++++++++++++++++ rsa keypair +++++++++++++++++\n\n");
}static void dump_buf(uint8_t *buf, uint32_t len)
{int i;for (i = 0; i < len; i++) {printf("%s%02X%s", i % 16 == 0 ? "\r\n\t" : " ", buf[i], i == len - 1 ? "\r\n" : "");}
}uint8_t output_buf[2048/8];int mbedtls_rsa_test(void)
{int ret;size_t olen;const char* msg = "HelloWorld";uint8_t decrypt_buf[20];const char *pers = "rsa_test";mbedtls_entropy_context entropy;mbedtls_ctr_drbg_context ctr_drbg;mbedtls_rsa_context ctx;/* 1. init structure */mbedtls_entropy_init(&entropy);mbedtls_ctr_drbg_init(&ctr_drbg);mbedtls_rsa_init(&ctx, MBEDTLS_RSA_PKCS_V21, MBEDTLS_MD_SHA256);/* 2. update seed with we own interface ported */printf( "\n . Seeding the random number generator..." );ret = mbedtls_ctr_drbg_seed( &ctr_drbg, mbedtls_entropy_func, &entropy,(const unsigned char *) pers,strlen(pers));if(ret != 0) {printf( " failed\n ! mbedtls_ctr_drbg_seed returned %d(-0x%04x)\n", ret, -ret);goto exit;}printf( " ok\n" );/* 3. generate an RSA keypair */printf( "\n . Generate RSA keypair..." );ret = mbedtls_rsa_gen_key(&ctx, mbedtls_ctr_drbg_random, &ctr_drbg, 2048, 65537);if(ret != 0) {printf( " failed\n ! mbedtls_rsa_gen_key returned %d(-0x%04x)\n", ret, -ret);goto exit;}printf( " ok\n" );/* shwo RSA keypair */dump_rsa_key(&ctx);/* 4. encrypt */printf( "\n . RSA pkcs1 encrypt..." );ret = mbedtls_rsa_pkcs1_encrypt(&ctx, mbedtls_ctr_drbg_random, &ctr_drbg, MBEDTLS_RSA_PUBLIC, strlen(msg), (uint8_t *)msg, output_buf);if(ret != 0) {printf( " failed\n ! mbedtls_rsa_pkcs1_encrypt returned %d(-0x%04x)\n", ret, -ret);goto exit;}printf( " ok\n" );/* show encrypt result */dump_buf(output_buf, sizeof(output_buf));/* 5. decrypt */printf( "\n . RSA pkcs1 decrypt..." );ret = mbedtls_rsa_pkcs1_decrypt(&ctx, mbedtls_ctr_drbg_random, &ctr_drbg, MBEDTLS_RSA_PRIVATE, &olen, output_buf, decrypt_buf, sizeof(decrypt_buf));if(ret != 0) {printf( " failed\n ! mbedtls_rsa_pkcs1_decrypt returned %d(-0x%04x)\n", ret, -ret);goto exit;}printf( " ok\n" );/* show decrypt result */decrypt_buf[olen] = '\0';printf("decrypt result:[%s]\r\n", decrypt_buf);exit:/* 5. release structure */mbedtls_ctr_drbg_free(&ctr_drbg);mbedtls_entropy_free(&entropy);mbedtls_rsa_free(&ctx);return ret;
}#endif /* MBEDTLS_RSA_C */
5.4 使用openssl API 实现RSA 加签验签
#include <iostream>
#include <openssl/rsa.h>
#include <openssl/err.h>
#include <openssl/evp.h>
#include <openssl/pem.h>
#ifdef _WIN32
#include <openssl/applink.c>
#endif
using namespace std;
#define PUBKEY_PEM "pubkey.pem"
#define PRIKEY_PEM "prikey.pem"void PrintBn(const BIGNUM* n)
{//大数对象转为二进制unsigned char to[256] = { 0 };BN_bn2bin(n, to);int byte_size = BN_num_bytes(n);for (int i = 0; i < byte_size; i++)printf("%02x", to[i]);printf("\n");
}
//
/// 生成RSA 秘钥对
/// @return 返回的pkey由调用EVP_PKEY_free释放
EVP_PKEY* EvpRsaKey()
{//1 创建RSA公钥加密上下文auto ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_RSA, NULL);if (!ctx){ERR_print_errors_fp(stderr);return NULL;}//2 初始化密钥对生成上下文if (EVP_PKEY_keygen_init(ctx) <= 0){ERR_print_errors_fp(stderr);EVP_PKEY_CTX_free(ctx);return NULL;}//3 设置参数 RSA 秘钥位数if (EVP_PKEY_CTX_set_rsa_keygen_bits(ctx, 1024) <= 0){ERR_print_errors_fp(stderr);EVP_PKEY_CTX_free(ctx);return NULL;}//4 秘钥生成EVP_PKEY* pkey = NULL;//内部会生成EVP_PKEY 空间if (EVP_PKEY_keygen(ctx, &pkey) <= 0){ERR_print_errors_fp(stderr);EVP_PKEY_CTX_free(ctx);return NULL;}//释放上下文EVP_PKEY_CTX_free(ctx);//获取参数列表auto tp = EVP_PKEY_gettable_params(pkey);while (tp){if (!tp->key)break;cout << tp->key << endl;tp++;}//获取参数的值BIGNUM* d = 0;EVP_PKEY_get_bn_param(pkey, "d", &d);PrintBn(d);BN_free(d);//输出公钥pem文件FILE* pubf = fopen(PUBKEY_PEM, "w");PEM_write_RSAPublicKey(pubf, EVP_PKEY_get0_RSA(pkey));//输出明文私钥pem文件FILE* prif = fopen(PRIKEY_PEM, "w");PEM_write_RSAPrivateKey(prif, EVP_PKEY_get0_RSA(pkey),NULL, //加密的上下文NULL, //秘钥0, //秘钥长度NULL, //加密回调函数NULL //用户数据回调使用);fclose(pubf);fclose(prif);return pkey;
}///EVP Rsa加密
int EvpRsaEncrypt(const unsigned char *in,int in_size,unsigned char *out)
{//1 读取pem中的公钥FILE* fp = fopen(PUBKEY_PEM, "r");if (!fp)return 0;RSA* r = NULL;PEM_read_RSAPublicKey(fp,&r, NULL, NULL);fclose(fp);if (!r){ERR_print_errors_fp(stderr);return 0;}//秘钥字节长度int key_size = RSA_size(r);//2 通过EVP_PKEY 生成EVP_PKEY_CTX上下文EVP_PKEY* pkey = EVP_PKEY_new();EVP_PKEY_set1_RSA(pkey, r); //设置为rsa的秘钥auto ctx = EVP_PKEY_CTX_new(pkey, NULL);EVP_PKEY_free(pkey);RSA_free(r);//3 加密初始化EVP_PKEY_encrypt_init(ctx);// 数据块大小,考虑填充 (默认pkcs1) k-11int block_size = key_size - RSA_PKCS1_PADDING_SIZE;int out_size = 0; //输出数据大小 也用做输出空间偏移//4 加密数据块for (int i = 0; i < in_size; i += block_size){//输出大小size_t out_len = key_size;//输入大小size_t bsize = block_size; //k-11 128-11 = 117if (in_size - i < block_size) //最后一块数据bsize = in_size - i;if (EVP_PKEY_encrypt(ctx,out + out_size, //输出空间&out_len, //输出空间大小,空间预留大小(输入)和实际加密后数据大小(输出)in + i, //输入数据bsize) <= 0) //输入数据大小,块大小{ERR_print_errors_fp(stderr);break;}out_size += out_len;}EVP_PKEY_CTX_free(ctx);return out_size;
}//EVP Rsa解密
int EvpRsaDecrypt(const unsigned char* in, int in_size, unsigned char* out)
{int out_size = 0;//1 打开pEM文件获取私钥FILE* fp = fopen(PRIKEY_PEM, "r");if (!fp)return 0;RSA* r = NULL;PEM_read_RSAPrivateKey(fp, &r, NULL, NULL);if (!r){fclose(fp);return 0;}fclose(fp);//秘钥字节长度int key_size = RSA_size(r);//生成PKEY 并创建上下文EVP_PKEY* pkey = EVP_PKEY_new();EVP_PKEY_set1_RSA(pkey,r);auto ctx = EVP_PKEY_CTX_new(pkey, NULL);EVP_PKEY_free(pkey);RSA_free(r);//解密初始化EVP_PKEY_decrypt_init(ctx);//解密数据for (int i = 0; i < in_size; i += key_size){size_t out_len = key_size;//需要设置输出空间大小if (EVP_PKEY_decrypt(ctx,out + out_size,&out_len,in + i,key_size) <= 0){ERR_print_errors_fp(stderr);break;}out_size += out_len;}EVP_PKEY_CTX_free(ctx);return out_size;
}//EVP RSA 签名 hash=》私钥签名
int EvpSign(const unsigned char* in, int in_size, unsigned char* sign)
{//1 打开pEM文件获取私钥FILE* fp = fopen(PRIKEY_PEM, "r");if (!fp)return 0;RSA* r = NULL;PEM_read_RSAPrivateKey(fp, &r, NULL, NULL);if (!r){fclose(fp);return 0;}fclose(fp);//秘钥字节长度int key_size = RSA_size(r);//2 生成PKEY 并创建上下文EVP_PKEY* pkey = EVP_PKEY_new();EVP_PKEY_set1_RSA(pkey, r);RSA_free(r);auto ctx = EVP_PKEY_CTX_new(pkey, NULL);//生成hash算法上下文auto mctx = EVP_MD_CTX_new();EVP_SignInit(mctx, EVP_sha512());//消息生成hash值EVP_SignUpdate(mctx, in, in_size);unsigned int size = in_size;//取出hash值并用私钥加密EVP_SignFinal(mctx, sign, &size, pkey);EVP_MD_CTX_free(mctx);EVP_PKEY_free(pkey);return size;
}bool EvpRsaVerify(const unsigned char* in, int in_size, const unsigned char* sign,int sign_size)
{//1 读取pem中的公钥FILE* fp = fopen(PUBKEY_PEM, "r");if (!fp)return 0;RSA* r = NULL;PEM_read_RSAPublicKey(fp, &r, NULL, NULL);fclose(fp);if (!r){ERR_print_errors_fp(stderr);return 0;}//秘钥字节长度int key_size = RSA_size(r);//2 生成EVP_PKEY 生成EVP_PKEY* pkey = EVP_PKEY_new();EVP_PKEY_set1_RSA(pkey, r); //设置为rsa的秘钥RSA_free(r);//验签 hash算法auto mctx = EVP_MD_CTX_new();EVP_VerifyInit(mctx, EVP_sha512());//生成单向散列EVP_VerifyUpdate(mctx, in, in_size);//公钥解密签名 ,对比生成的单向散列int re = EVP_VerifyFinal(mctx, //上下文中存放单向散列sign, //签名sign_size, pkey); //公钥解密EVP_MD_CTX_free(mctx);EVP_PKEY_free(pkey);if (re == 1)return true;return false;
}int main(int argc, char* argv[])
{unsigned char data[1024] = { 0 };unsigned char out[2046] = { 0 };unsigned char out2[2046] = { 0 };//初始化测试数据for (int i = 0; i < sizeof(data) - 1; i++){data[i] = 'A' + i % 26;}int data_size = sizeof(data);//生成签名int sign_size = EvpSign(data, data_size, out);cout << sign_size << ":" << out << endl;//验证签名if (EvpRsaVerify(data, data_size, out, sign_size)){cout << "验签成功" << endl;}elsecout << "验签失败" << endl;//数据篡改data[0] = 'C';//out[0] = 'C';if (EvpRsaVerify(data, data_size, out, sign_size)){cout << "验签成功" << endl;}elsecout << "验签失败" << endl;//生成密钥对auto pkey = EvpRsaKey();EVP_PKEY_free(pkey);//rsa加密int len = EvpRsaEncrypt(data, data_size, out);cout<<"EvpRsaEncrypt len = "<<len<<endl;//rsa解密len = EvpRsaDecrypt(out, len, out2);cout << "EvpRsaDecrypt len = " << len << endl;cout << out2 << endl;getchar();return 0;
}
5.5 使用mbedtls API实现RSA 加签验签
#if !defined(MBEDTLS_CONFIG_FILE)
#include "mbedtls/config.h"
#else
#include MBEDTLS_CONFIG_FILE
#endif#if defined(MBEDTLS_RSA_C)#include <stdio.h>
#include "string.h"
#include "mbedtls/entropy.h"
#include "mbedtls/ctr_drbg.h"
#include "mbedtls/rsa.h"static char buf[516];static void dump_rsa_key(mbedtls_rsa_context *ctx)
{size_t olen;printf("\n +++++++++++++++++ rsa keypair +++++++++++++++++\n\n");mbedtls_mpi_write_string(&ctx->N , 16, buf, sizeof(buf), &olen);printf("N: %s\n", buf); mbedtls_mpi_write_string(&ctx->E , 16, buf, sizeof(buf), &olen);printf("E: %s\n", buf);mbedtls_mpi_write_string(&ctx->D , 16, buf, sizeof(buf), &olen);printf("D: %s\n", buf);mbedtls_mpi_write_string(&ctx->P , 16, buf, sizeof(buf), &olen);printf("P: %s\n", buf);mbedtls_mpi_write_string(&ctx->Q , 16, buf, sizeof(buf), &olen);printf("Q: %s\n", buf);mbedtls_mpi_write_string(&ctx->DP, 16, buf, sizeof(buf), &olen);printf("DP: %s\n", buf);mbedtls_mpi_write_string(&ctx->DQ, 16, buf, sizeof(buf), &olen);printf("DQ: %s\n", buf);mbedtls_mpi_write_string(&ctx->QP, 16, buf, sizeof(buf), &olen);printf("QP: %s\n", buf);printf("\n +++++++++++++++++ rsa keypair +++++++++++++++++\n\n");
}static void dump_buf(uint8_t *buf, uint32_t len)
{int i;for (i = 0; i < len; i++) {printf("%s%02X%s", i % 16 == 0 ? "\r\n\t" : " ", buf[i], i == len - 1 ? "\r\n" : "");}
}static uint8_t output_buf[2048/8];int mbedtls_rsa_sign_test(void)
{int ret;const char* msg = "HelloWorld";const char *pers = "rsa_sign_test";mbedtls_entropy_context entropy;mbedtls_ctr_drbg_context ctr_drbg;mbedtls_rsa_context ctx;/* 1. init structure */mbedtls_entropy_init(&entropy);mbedtls_ctr_drbg_init(&ctr_drbg);mbedtls_rsa_init(&ctx, MBEDTLS_RSA_PKCS_V21, MBEDTLS_MD_SHA256);/* 2. update seed with we own interface ported */printf( "\n . Seeding the random number generator..." );ret = mbedtls_ctr_drbg_seed( &ctr_drbg, mbedtls_entropy_func, &entropy,(const unsigned char *) pers,strlen(pers));if(ret != 0) {printf( " failed\n ! mbedtls_ctr_drbg_seed returned %d(-0x%04x)\n", ret, -ret);goto exit;}printf( " ok\n" );/* 3. generate an RSA keypair */printf( "\n . Generate RSA keypair..." );ret = mbedtls_rsa_gen_key(&ctx, mbedtls_ctr_drbg_random, &ctr_drbg, 2048, 65537);if(ret != 0) {printf( " failed\n ! mbedtls_rsa_gen_key returned %d(-0x%04x)\n", ret, -ret);goto exit;}printf( " ok\n" );/* shwo RSA keypair */dump_rsa_key(&ctx);/* 4. sign */printf( "\n . RSA pkcs1 sign..." );ret = mbedtls_rsa_pkcs1_sign(&ctx, mbedtls_ctr_drbg_random, &ctr_drbg, MBEDTLS_RSA_PRIVATE, MBEDTLS_MD_SHA256, strlen(msg), (uint8_t *)msg, output_buf);if(ret != 0) {printf( " failed\n ! mbedtls_rsa_pkcs1_sign returned %d(-0x%04x)\n", ret, -ret);goto exit;}printf( " ok\n" );/* show sign result */dump_buf(output_buf, sizeof(output_buf));/* 5. verify sign*/printf( "\n . RSA pkcs1 verify..." );ret = mbedtls_rsa_pkcs1_verify(&ctx, mbedtls_ctr_drbg_random, &ctr_drbg, MBEDTLS_RSA_PUBLIC, MBEDTLS_MD_SHA256, strlen(msg), (uint8_t *)msg, output_buf);if(ret != 0) {printf( " failed\n ! mbedtls_rsa_pkcs1_encrypt returned %d(-0x%04x)\n", ret, -ret);goto exit;}printf( " ok\n" );exit:/* 5. release structure */mbedtls_ctr_drbg_free(&ctr_drbg);mbedtls_entropy_free(&entropy);mbedtls_rsa_free(&ctx);return ret;
}#endif /* MBEDTLS_RSA_C */