RSA私鑰公鑰加密解密與簽名、SHA256
頭文件:HashSignature.h
#ifndef _HASH_SIGNATURE_H_
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <openssl/rsa.h>
#include <openssl/pem.h>
#include <openssl/rand.h>
#include <stddef.h>
#include <iostream>
using namespace std;
#define PUBLIC_KEY_FILE "/home/xzj/Code/C++Code/RSA/rsaPublicKey.pem"
#define PRIVATE_KEY_FILE "/home/xzj/Code/C++Code/RSA/rsaPrivateKey.pem"
#define SIGNATURE_FILE "/home/xzj/Code/C++Code/RSA/sha256.sign"
#define DATA_FILE "/home/xzj/Code/C++Code/RSA/myfile.txt"
#define RSA_KEY_LENGTH 1024 // 密鑰長度
#define RSA_PRIKEY_PSW "123"
class HashSignature {
public:
HashSignature();
virtual ~HashSignature();
bool generateRSAKey(const char* public_key_path_and_file_name,
const char* private_key_path_and_file_name,
const unsigned char* passwd, int passwd_len); // 函數方法生成密鑰對
bool generateRSAKey(const char* public_key_path_and_file_name,
const char* private_key_path_and_file_name,
std::string strKey[2]); // 生成公鑰私鑰對寫入到文件里並且返回公鑰私鑰字符串數據
bool generateRSAKey(const char* public_key_path_and_file_name,
const char* private_key_path_and_file_name); // 生成公鑰私鑰對寫入到文件里
string RSAPrivateKeyEncypt(int clearText_length, const char* clearText, const char* private_key_path_and_file_name); // 私鑰加密
string RSAPrivateKeyDecypt(int cipherText_length, const char* cipherText, const char* private_key_path_and_file_name); // 私鑰解密
string RSAPublicKeyEncypt(int clearText_length, const char* clearText, const char* public_key_path_and_file_name); // 公鑰加密
string RSAPublicKeyDecypt(int cipherText_length, const char* cipherText, const char* public_key_path_and_file_name); // 公鑰解密
string create_hash_by_SHA256(const string data); // 生成hash值
string create_signature(int hash_length, string hash, const char* private_key_path_and_file_name); // 生成簽名
string get_hash_from_signature(int signature_length, string signature, const char* public_key_path_and_file_name); // 解簽
bool writeStringData_Into_File(const char* filepath, const char *data); //寫數據到文件里
string readStringData_From_File(const char* filepath); // 從文件讀取數據
bool verify_signature(const char* dataFile ,const char* public_key_path_and_file_name, const char* signatureFile); // 簽證簽名
};
#endif // _HASH_SIGNATURE_H_
源文件:HashSignature.cpp
#ifndef _HASH_SIGNATURE_H_
# include "HashSignature.h"
#endif
HashSignature::HashSignature() {
}
HashSignature::~HashSignature() {
}
/*
*@author xzj
*@copyright
*@description 生成RSA公鑰私鑰對(帶有salt的)
*[建議新手如果參考這個的帶salt的密鑰對時一定要弄清楚:
*PEM_write_bio_RSAPrivateKey/PEM_write_bio_RSAPublicKey 在生成私鑰和公鑰帶salt時,
*在PEM_read_bio_RSAPrivateKey/PEM_read_bio_RSAPublicKey時也需要帶salt,salt是你自己定義的一個字符串]
*@param public_key_path_and_file_name : 公鑰路徑+文件名
*@param private_key_path_and_file_name : 私鑰路徑+文件名
*@param passwd : 自己定義的salt
*@param passwd_len : salt長度
*@return bool true is ok; false is error
*/
bool HashSignature::generateRSAKey(const char* public_key_path_and_file_name,
const char* private_key_path_and_file_name,
const unsigned char* passwd, int passwd_len) {
// 生成密鑰對
RSA *keypair = NULL;
// keypair = RSA_generate_key(RSA_KEY_LENGTH, RSA_F4, NULL, NULL);
keypair = RSA_generate_key(RSA_KEY_LENGTH, RSA_3, NULL, NULL);
if (NULL == keypair) {
printf("RSA_generate_key error!\n");
return false;
}
//生成公鑰文件
BIO* bio_public = NULL;
bio_public= BIO_new(BIO_s_file());
if (NULL == bio_public)
{
printf("generate_key bio file new error with bio_public!\n");
return false;
}
if (BIO_write_filename(bio_public, (void *)public_key_path_and_file_name) <= 0)
{
printf("BIO_write_filename error!\n");
return false;
}
if (PEM_write_bio_RSAPublicKey(bio_public, keypair) != 1)
{
printf("PEM_write_bio_RSAPublicKey error!\n");
return false;
}
printf("Create public key successful!\n");
BIO_free_all(bio_public); // 內存釋放
// 生成私鑰文件
BIO* bio_private = NULL;
bio_private = BIO_new_file(private_key_path_and_file_name, "w+");
if (NULL == bio_private)
{
printf("generate_key bio file new error with bio_private!\n");
return false;
}
// if (PEM_write_bio_RSAPrivateKey(bio_private, keypair, EVP_des_ede3_ofb(), (unsigned char *)passwd, passwd_len, NULL, NULL) != 1)
if (PEM_write_bio_RSAPrivateKey(bio_private, keypair, NULL, NULL, 0, NULL, NULL) != 1)
{
printf("PEM_write_bio_RSAPrivateKey error!\n");
return false;
}
printf("Create private key successful!\n");
BIO_free_all(bio_private); // 內存釋放
RSA_free(keypair); // 內存釋放
return true;
}
/*
*@author xzj
*@copyright
*@description 生成公鑰私鑰對寫入到文件里並且返回公鑰私鑰字符串數據
*@param public_key_path_and_file_name : 公鑰路徑+文件名
*@param private_key_path_and_file_name : 私鑰路徑+文件名
*@param strKey : strKey[0]公鑰字符串 strKey[0] 私鑰字符串
*@return bool true is ok; false is error
*/
bool HashSignature::generateRSAKey(const char* public_key_path_and_file_name,
const char* private_key_path_and_file_name,
std::string strKey[2]) {
// 密鑰對
size_t bio_private_length;
size_t bio_public_length;
char *private_key = NULL;
char *public_key = NULL;
// 生成密鑰對
RSA *keypair = NULL;
keypair = RSA_generate_key(RSA_KEY_LENGTH, RSA_3, NULL, NULL);
if (NULL == keypair) {
printf("RSA_generate_key error!\n");
return false;
}
BIO* bio_public = NULL;
bio_public= BIO_new(BIO_s_mem());
if (NULL == bio_public)
{
printf("BIO_new has an error with bio_public!\n");
return false;
}
BIO* bio_private = NULL;
bio_private = BIO_new(BIO_s_mem());
if (NULL == bio_private)
{
printf("BIO_new has an error with bio_private!\n");
return false;
}
if (PEM_write_bio_RSAPrivateKey(bio_private, keypair, NULL, NULL, 0, NULL, NULL) != 1)
{
printf("PEM_write_bio_RSAPublicKey error!\n");
return false;
}
if (PEM_write_bio_RSAPublicKey(bio_public, keypair) != 1)
{
printf("PEM_write_bio_RSAPublicKey error!\n");
return false;
}
// 獲取長度
bio_private_length = BIO_pending(bio_private);
bio_public_length = BIO_pending(bio_public);
// 分配長度
private_key = new char[bio_private_length + 1];
public_key = new char[bio_public_length + 1];
// 秘鑰對讀取到字符串
BIO_read(bio_private, private_key, bio_private_length);
BIO_read(bio_public, public_key, bio_public_length);
private_key[bio_private_length] = '\0';
public_key[bio_public_length] = '\0';
strKey[0] = public_key;
strKey[1] = private_key;
// 把公鑰和私鑰存儲到磁盤文件當中(這種方式存儲的是begin rsa public key/ begin rsa private key開頭的)
FILE *private_file = fopen(private_key_path_and_file_name, "w");
if (NULL == private_file) {
printf("fopen failed\n");
return false;
}
fputs(private_key, private_file);
fclose(private_file);
FILE *public_file = fopen(public_key_path_and_file_name, "w");
if (NULL == public_file) {
printf("fopen failed\n");
return false;
}
fputs(public_key, public_file); // 向指定的文件寫入一個字符串
fclose(public_file);
// 內存釋放
RSA_free(keypair);
BIO_free(bio_private);
BIO_free(bio_public);
delete []private_key;
delete []public_key;
return true;
}
/*
*@author xzj
*@copyright
*@description 生成公鑰私鑰對寫入到文件里
*@param public_key_path_and_file_name : 公鑰路徑+文件名
*@param private_key_path_and_file_name : 私鑰路徑+文件名
*@return bool true is ok; false is error
*/
bool HashSignature::generateRSAKey(const char* public_key_path_and_file_name,
const char* private_key_path_and_file_name) {
// 密鑰對
size_t bio_private_length;
size_t bio_public_length;
char *private_key = NULL;
char *public_key = NULL;
// 生成密鑰對
RSA *keypair = NULL;
keypair = RSA_generate_key(RSA_KEY_LENGTH, RSA_3, NULL, NULL);
if (NULL == keypair) {
printf("RSA_generate_key error!\n");
return false;
}
BIO* bio_public = NULL;
bio_public= BIO_new(BIO_s_mem());
if (NULL == bio_public)
{
printf("BIO_new has an error with bio_public!\n");
return false;
}
BIO* bio_private = NULL;
bio_private = BIO_new(BIO_s_mem());
if (NULL == bio_private)
{
printf("BIO_new has an error with bio_private!\n");
return false;
}
// 把私鑰從密鑰對里寫到bio_private里
if (PEM_write_bio_RSAPrivateKey(bio_private, keypair, NULL, NULL, 0, NULL, NULL) != 1)
{
printf("PEM_write_bio_RSAPublicKey error!\n");
return false;
}
// 把公鑰從密鑰對里寫到bio_public里
if (PEM_write_bio_RSAPublicKey(bio_public, keypair) != 1)
{
printf("PEM_write_bio_RSAPublicKey error!\n");
return false;
}
// 獲取長度
bio_private_length = BIO_pending(bio_private);
bio_public_length = BIO_pending(bio_public);
// 分配長度
private_key = new char[bio_private_length + 1];
public_key = new char[bio_public_length + 1];
// 秘鑰對分別讀取到字符串
BIO_read(bio_private, private_key, bio_private_length);
BIO_read(bio_public, public_key, bio_public_length);
private_key[bio_private_length] = '\0';
public_key[bio_public_length] = '\0';
// 把公鑰和私鑰存儲到磁盤文件當中(這種方式存儲的是begin rsa public key/ begin rsa private key開頭的)
FILE *private_file = fopen(private_key_path_and_file_name, "w");
if (NULL == private_file) {
printf("fopen failed\n");
return false;
}
fputs(private_key, private_file);
fclose(private_file);
FILE *public_file = fopen(public_key_path_and_file_name, "w");
if (NULL == public_file) {
printf("fopen failed\n");
return false;
}
fputs(public_key, public_file);
fclose(public_file);
// 內存釋放
RSA_free(keypair);
BIO_free(bio_private);
BIO_free(bio_public);
delete []private_key;
delete []public_key;
return true;
}
// 工具生成公鑰私鑰(openssl)
//openssl genrsa -out myprivate.pem 4096
//openssl rsa -in myprivate.pem -pubout -out mypublic.pem
/*
*@author xzj
*@copyright
*@description 把數據data生成相應的hash值
*@param data : 數據
*@return string : hash值
*/
string HashSignature::create_hash_by_SHA256(const string data) {
char buf[2];
unsigned char hash[SHA256_DIGEST_LENGTH];
SHA256_CTX sha256;
SHA256_Init(&sha256);
SHA256_Update(&sha256, data.c_str(), data.size());
SHA256_Final(hash, &sha256);
std::string NewString = "";
for (int i = 0; i < SHA256_DIGEST_LENGTH; i++) {
sprintf(buf, "%02x", hash[i]);
NewString = NewString +buf;
}
return NewString;
}
/*
*@author xzj
*@copyright
*@description 通過摘要生成簽名(私鑰加簽)
*@param hash_length : hash數據長度
*@param data : hash數據
*@param private_key_path_and_file_name : 私鑰路徑+文件名
*@return string : 簽名數據
*/
string HashSignature::create_signature(int hash_length, string hash, const char* private_key_path_and_file_name) {
// int RSA_private_encrypt(int flen, unsigned char *from,unsigned char *to, RSA *rsa,int padding);
string encryptedText = "";
RSA *rsa = NULL;
BIO* bio_private = NULL;
bio_private = BIO_new(BIO_s_file());
// bio_private = BIO_new_file(private_key_path_and_file_name, "rb");
BIO_read_filename(bio_private, private_key_path_and_file_name); // 類似與fopen()
if (NULL == bio_private) {
printf("open_private_key bio file new error!\n");
return "";
}
// 此處有三種方法
// 1, 讀取內存里生成的密鑰對,再從內存生成rsa
// 2, 讀取磁盤里生成的密鑰對文本文件,在從內存生成rsa
// 3,直接從讀取文件指針生成rsa
rsa = PEM_read_bio_RSAPrivateKey(bio_private, &rsa, NULL, NULL); // 類似read()
if (rsa == NULL) {
printf("open_private_key failed to PEM_read_bio_RSAPrivateKey!\n");
BIO_free(bio_private);
RSA_free(rsa);
return "";
}
int len = RSA_size(rsa);
printf("private key RSA is [%d]\n", len);
char *out = new char[len + 1];
memset(out, 0, len + 1);
int result = RSA_private_encrypt(hash_length, (unsigned char *)hash.c_str(), (unsigned char *)out, rsa, RSA_PKCS1_PADDING);
if (-1 == result) {
printf("RSA_private_encrypt is failed\n");
BIO_free(bio_private);
RSA_free(rsa);
delete []out;
return "";
} else {
printf("RSA_private_encrypt is successful\n");
encryptedText = string(out, result);
BIO_free(bio_private);
RSA_free(rsa);
delete []out;
return encryptedText;
}
}
/*
*@author xzj
*@copyright
*@description 公鑰解簽生成摘要
*@param hash_length : 簽名數據長度
*@param data : 簽名數據
*@param public_key_path_and_file_name : 公鑰路徑+文件名
*@return string : 摘要數據
*/
string HashSignature::get_hash_from_signature(int signature_length, string signature, const char* public_key_path_and_file_name) {
// int RSA_public_decrypt(int flen, unsigned char *from, unsigned char *to, RSA *rsa,int padding);
string clearText;
RSA *rsa = NULL;
BIO* bio_public = NULL;
bio_public = BIO_new(BIO_s_file());
BIO_read_filename(bio_public, public_key_path_and_file_name); // 類似與fopen()
if (NULL == bio_public) {
printf("open_public_key bio file new error!\n");
return "";
}
// 此處有三種方法
// 1, 讀取內存里生成的密鑰對,再從內存生成rsa
// 2, 讀取磁盤里生成的密鑰對文本文件,在從內存生成rsa
// 3,直接從讀取文件指針生成rsa
rsa = PEM_read_bio_RSAPublicKey(bio_public, &rsa, NULL, NULL); // 類似與read()
if (NULL == rsa) {
printf("open_public_key failed to PEM_read_bio_RSAPublicKey!\n");
BIO_free(bio_public);
RSA_free(rsa);
return "";
}
int len = RSA_size(rsa);
printf("public key RSA is [%d]\n", len);
char *out = new char[len + 1];
memset(out, 0, len + 1);
int result = RSA_public_decrypt(signature_length, (unsigned char *)signature.c_str(), (unsigned char *)out, rsa, RSA_PKCS1_PADDING);
if (-1 == result) {
printf("RSA_public_decrypt is failed\n");
BIO_free(bio_public);
RSA_free(rsa);
delete []out;
return "";
} else {
printf("RSA_public_decrypt is successful\n");
clearText = string(out, result);
BIO_free(bio_public);
RSA_free(rsa);
delete []out;
return clearText;
}
}
/*
*@author xzj
*@copyright
*@description 寫字符數據到文件中
*@param filepath : 文件的絕對路徑
*@param data : 數據
*@return bool true is ok;false is failed
*/
bool HashSignature::writeStringData_Into_File(const char* filepath, const char *data){
bool result = false;
FILE *file = NULL;
file = fopen(filepath, "w");
do {
if(NULL == file) {
printf("文件打開失敗\n");
break;
}
if (EOF == fwrite(data, strlen(data), 1, file)) {
printf("寫文件失敗\n");
break;
}
result = true;
} while (0);
fclose(file);
return result;
}
/*
*@author xzj
*@copyright
*@description 從文件中讀取字符數據
*@param filepath : 文件的絕對路徑
*@return string 字符串數據
*/
string HashSignature::readStringData_From_File(const char* filepath){
string data = "";
FILE *file = NULL;
file = fopen(filepath,"rb");
if(NULL == file) {
printf("文件打開失敗\n");
return "";
}
unsigned char buf = {0};
while (fread(&buf, sizeof(unsigned char), 1, file)){ // 每次讀一個字符,一直讀
data += buf;
}
fclose(file);
return data;
}
/*
*@author xzj
*@copyright
*@description 給數據驗簽
*1、dataFile--->摘要----->私鑰加密生成簽名--->寫入簽名文件里(這一步已經完成,並且密鑰對也已經生成)
*@param dataFile : 數據文件
*@param public_key_path_and_file_name : 公鑰路徑+文件名
*@param signatureFile : 簽名文件的絕對路徑
*@return bool true is ok;false is failed
*/
bool HashSignature::verify_signature(const char* dataFile ,const char* public_key_path_and_file_name, const char* signatureFile) {
bool result = false;
do {
// 從文件讀取數據
string data = readStringData_From_File(dataFile);
//生成hash值
std::string dataHash = "";
dataHash = create_hash_by_SHA256(data);
printf("數據生成的hash值為[%s]\n", dataHash.c_str());
// 從文件讀取簽名
string readSignature = readStringData_From_File(signatureFile);
//簽名公鑰解密生成摘要
string hash = get_hash_from_signature(readSignature.length(), readSignature, public_key_path_and_file_name);
printf("摘要解簽的hash值為[%s]\n", hash.c_str());
int compareResult = dataHash.compare(hash);
if (0 == compareResult) {
printf("簽名驗證成功\n");
result = true;
} else {
printf("簽名驗證失敗\n");
}
} while (0);
return result;
}
/*
*@author xzj
*@copyright
*@description 私鑰加密
*@param clearText_length : 明文數據長度
*@param clearText : 明文數據
*@param private_key_path_and_file_name : 私鑰路徑+文件名
*@return string cipherText 密文數據
*/
string HashSignature::RSAPrivateKeyEncypt(int clearText_length, const char* clearText, const char* private_key_path_and_file_name) {
// int RSA_private_encrypt(int flen, unsigned char *from,unsigned char *to, RSA *rsa,int padding);
string cipherText = "";
RSA *rsa = NULL;
BIO* bio_private = NULL;
bio_private = BIO_new(BIO_s_file());
// bio_private = BIO_new_file(private_key_path_and_file_name, "rb");
BIO_read_filename(bio_private, private_key_path_and_file_name); // 類似與fopen()
if (NULL == bio_private) {
printf("open_private_key bio file new error!\n");
return cipherText;
}
// 此處有三種方法
// 1, 讀取內存里生成的密鑰對,再從內存生成rsa
// 2, 讀取磁盤里生成的密鑰對文本文件,在從內存生成rsa
// 3,直接從讀取文件指針生成rsa
rsa = PEM_read_bio_RSAPrivateKey(bio_private, &rsa, NULL, NULL); // 類似read()
if (rsa == NULL) {
printf("open_private_key failed to PEM_read_bio_RSAPrivateKey!\n");
BIO_free(bio_private);
RSA_free(rsa);
return cipherText;
}
int len = RSA_size(rsa);
printf("private key RSA is [%d]\n", len);
char *out = new char[len + 1];
memset(out, 0, len + 1);
int result = RSA_private_encrypt(clearText_length, (unsigned char *)clearText, (unsigned char *)out, rsa, RSA_PKCS1_PADDING);
if (-1 == result) {
printf("RSA_private_encrypt is failed\n");
BIO_free(bio_private);
RSA_free(rsa);
delete []out;
return cipherText;
} else {
printf("RSA_private_encrypt is successful\n");
cipherText = string(out, result);
BIO_free(bio_private);
RSA_free(rsa);
delete []out;
return cipherText;
}
}
/*
*@author xzj
*@copyright
*@description 私鑰解密
*@param cipherText_length : 密文數據長度
*@param cipherText : 密文數據
*@param private_key_path_and_file_name : 私鑰路徑+文件名
*@return string cipherText 明文數據
*/
string HashSignature::RSAPrivateKeyDecypt(int cipherText_length, const char* cipherText, const char* private_key_path_and_file_name) {
// int RSA_private_decrypt(int flen, unsigned char *from, unsigned char *to, RSA *rsa,int padding);
string clearText = "";
RSA *rsa = NULL;
BIO* bio_private = NULL;
bio_private = BIO_new(BIO_s_file());
BIO_read_filename(bio_private, private_key_path_and_file_name); // 類似與fopen()
if (NULL == bio_private) {
printf("open_private_key bio file new error!\n");
return clearText;
}
// 此處有三種方法
// 1, 讀取內存里生成的密鑰對,再從內存生成rsa
// 2, 讀取磁盤里生成的密鑰對文本文件,在從內存生成rsa
// 3,直接從讀取文件指針生成rsa
rsa = PEM_read_bio_RSAPrivateKey(bio_private, &rsa, NULL, NULL); // 類似與read()
if (NULL == rsa) {
printf("open_private_key failed to PEM_read_bio_RSAPrivateKey!\n");
BIO_free(bio_private);
RSA_free(rsa);
return clearText;
}
int len = RSA_size(rsa);
printf("private key RSA is [%d]\n", len);
char *out = new char[len + 1];
memset(out, 0, len + 1);
int result = RSA_private_decrypt(cipherText_length, (unsigned char *)cipherText, (unsigned char *)out, rsa, RSA_PKCS1_PADDING);
if (-1 == result) {
printf("RSA_private_decrypt is failed\n");
BIO_free(bio_private);
RSA_free(rsa);
delete []out;
return clearText;
} else {
printf("RSA_private_decrypt is successful\n");
clearText = string(out, result);
BIO_free(bio_private);
RSA_free(rsa);
delete []out;
return clearText;
}
}
/*
*@author xzj
*@copyright
*@description 公鑰加密
*@param clearText_length : 明文數據長度
*@param clearText : 明文數據
*@param private_key_path_and_file_name : 公鑰路徑+文件名
*@return string cipherText 密文數據
*/
string HashSignature::RSAPublicKeyEncypt(int clearText_length, const char* clearText, const char* public_key_path_and_file_name) {
// int RSA_public_encrypt(int flen, unsigned char *from,unsigned char *to, RSA *rsa,int padding);
string cipherText = "";
RSA *rsa = NULL;
BIO* bio_public = NULL;
bio_public = BIO_new(BIO_s_file());
// bio_public = BIO_new_file(public_key_path_and_file_name, "rb");
BIO_read_filename(bio_public, public_key_path_and_file_name); // 類似與fopen()
if (NULL == bio_public) {
printf("open_public_key bio file new error!\n");
return cipherText;
}
// 此處有三種方法
// 1, 讀取內存里生成的密鑰對,再從內存生成rsa
// 2, 讀取磁盤里生成的密鑰對文本文件,在從內存生成rsa
// 3,直接從讀取文件指針生成rsa
rsa = PEM_read_bio_RSAPublicKey(bio_public, &rsa, NULL, NULL); // 類似read()
if (rsa == NULL) {
printf("open_public_key failed to PEM_read_bio_RSAPublicKey!\n");
BIO_free(bio_public);
RSA_free(rsa);
return cipherText;
}
int len = RSA_size(rsa);
printf("public key RSA is [%d]\n", len);
char *out = new char[len + 1];
memset(out, 0, len + 1);
int result = RSA_public_encrypt(clearText_length, (unsigned char *)clearText, (unsigned char *)out, rsa, RSA_PKCS1_PADDING);
if (-1 == result) {
printf("RSA_public_encrypt is failed\n");
BIO_free(bio_public);
RSA_free(rsa);
delete []out;
return cipherText;
} else {
printf("RSA_public_encrypt is successful\n");
cipherText = string(out, result);
BIO_free(bio_public);
RSA_free(rsa);
delete []out;
return cipherText;
}
}
/*
*@author xzj
*@copyright
*@description 公鑰解密
*@param cipherText_length : 密文數據長度
*@param cipherText : 密文數據
*@param public_key_path_and_file_name : 公鑰路徑+文件名
*@return string cipherText 明文數據
*/
string HashSignature::RSAPublicKeyDecypt(int cipherText_length, const char* cipherText, const char* public_key_path_and_file_name) {
// int RSA_public_decrypt(int flen, unsigned char *from, unsigned char *to, RSA *rsa,int padding);
string clearText = "";
RSA *rsa = NULL;
BIO* bio_public = NULL;
bio_public = BIO_new(BIO_s_file());
BIO_read_filename(bio_public, public_key_path_and_file_name); // 類似與fopen()
if (NULL == bio_public) {
printf("open_public_key bio file new error!\n");
return clearText;
}
// 此處有三種方法
// 1, 讀取內存里生成的密鑰對,再從內存生成rsa
// 2, 讀取磁盤里生成的密鑰對文本文件,在從內存生成rsa
// 3,直接從讀取文件指針生成rsa
rsa = PEM_read_bio_RSAPublicKey(bio_public, &rsa, NULL, NULL); // 類似與read()
if (NULL == rsa) {
printf("open_public_key failed to PEM_read_bio_RSAPublicKey!\n");
BIO_free(bio_public);
RSA_free(rsa);
return clearText;
}
int len = RSA_size(rsa);
printf("public key RSA is [%d]\n", len);
char *out = new char[len + 1];
memset(out, 0, len + 1);
int result = RSA_public_decrypt(cipherText_length, (unsigned char *)cipherText, (unsigned char *)out, rsa, RSA_PKCS1_PADDING);
if (-1 == result) {
printf("RSA_public_decrypt is failed\n");
BIO_free(bio_public);
RSA_free(rsa);
delete []out;
return clearText;
} else {
printf("RSA_public_decrypt is successful\n");
clearText = string(out, result);
BIO_free(bio_public);
RSA_free(rsa);
delete []out;
return clearText;
}
}
測試入口文件:main.cpp
#ifndef _HASH_SIGNATURE_H_
# include "HashSignature.h"
#endif
#define NAME_SIZE 34
struct persion
{
int age;
unsigned char name [NAME_SIZE];
};
int main() {
// test the function generateRSAKey
HashSignature mHashSignature;
/******************************* 測試生成公鑰私自並寫入到文件中 ********************************/
// test 1
// bool res = mHashSignature.generateRSAKey(PUBLIC_KEY_FILE, PRIVATE_KEY_FILE,
// (const unsigned char *)RSA_PRIKEY_PSW,
// strlen(RSA_PRIKEY_PSW));
// if (res == false) {
// printf("test 1 RSA create key is failed\n");
// } else {
// printf("test 1 RSA create key is successful\n");
// }
// test 2
// bool res = mHashSignature.generateRSAKey(PUBLIC_KEY_FILE, PRIVATE_KEY_FILE);
// if (res == false) {
// printf("test 2 RSA create key is failed\n");
// } else {
// printf("test 2 RSA create key is successful\n");
// }
/******************************* 測試生成公鑰私自並寫入到文件中 ********************************/
/********************************** 測試對數據進行驗簽 ***********************************/
// printf("start1........\n");
// // 生成hash值
// std::string data = "hello world xzj!!!!!";
// std::string dataHash = "";
// dataHash = mHashSignature.create_hash_by_SHA256(data);
// printf("數據生成的hash值為[%s]\n", dataHash.c_str());
// //摘要私鑰加密生成簽名
// string Signature = mHashSignature.create_signature(dataHash.length(), dataHash, PRIVATE_KEY_FILE);
// printf("摘要生成的簽名為[%s]\n", Signature.c_str());
// //簽名公鑰解密生成摘要
// string hash = mHashSignature.get_hash_from_signature(Signature.length(), Signature, PUBLIC_KEY_FILE);
// printf("摘要解簽的hash值為[%s]\n", hash.c_str());
// int compareResult = dataHash.compare(hash);
// if (0 == compareResult) {
// printf("簽名驗證成功\n");
// } else {
// printf("簽名驗證失敗\n");
// }
/********************************** 測試對數據進行驗簽 ***********************************/
/********************************** 測試對文件數據進行驗簽1 ***********************************/
// printf("start2........\n");
// // 從文件讀取數據
// string data = mHashSignature.readStringData_From_File(DATA_FILE);
// //生成hash值
// std::string dataHash = "";
// dataHash = mHashSignature.create_hash_by_SHA256(data);
// printf("數據生成的hash值為[%s]\n", dataHash.c_str());
// //摘要私鑰加密生成簽名
// string Signature = mHashSignature.create_signature(dataHash.length(), dataHash, PRIVATE_KEY_FILE);
// printf("摘要生成的簽名為[%s]\n", Signature.c_str());
// // 把簽名寫入到文件里
// if (true == mHashSignature.writeStringData_Into_File(SIGNATURE_FILE, Signature.c_str())) {
// printf("簽名寫入到文件 successful!!\n");
// }
// // 從文件讀取簽名
// string readSignature = mHashSignature.readStringData_From_File(SIGNATURE_FILE);
// //簽名公鑰解密生成摘要
// string hash = mHashSignature.get_hash_from_signature(readSignature.length(), readSignature, PUBLIC_KEY_FILE);
// printf("摘要解簽的hash值為[%s]\n", hash.c_str());
// int compareResult = dataHash.compare(hash);
// if (0 == compareResult) {
// printf("簽名驗證成功\n");
// } else {
// printf("簽名驗證失敗\n");
// }
/********************************** 測試對文件數據進行驗簽1 ***********************************/
/********************************** 測試對文件數據進行驗簽2 ***********************************/
// printf("start3........\n");
// mHashSignature.verify_signature(DATA_FILE, PUBLIC_KEY_FILE, SIGNATURE_FILE);
/********************************** 測試對文件數據進行驗簽2 ***********************************/
/********************************** 私鑰加密公鑰解密 ***********************************/
// printf("start4.1........\n");
// persion m_persion = {28,"xzj8023tp"};
// char * clearText1 = new char[sizeof(persion)];
// string cipherText = "";
// memcpy(clearText1, &m_persion, sizeof(persion));
// cipherText = mHashSignature.RSAPrivateKeyEncypt(sizeof(persion), clearText1, PRIVATE_KEY_FILE);
// string clearText2 = "";
// clearText2 = mHashSignature.RSAPublicKeyDecypt(cipherText.length(), cipherText.c_str(), PUBLIC_KEY_FILE);
// persion showData;
// memcpy(&showData, (clearText2.c_str()), sizeof(persion));
// printf("my name is [%s] and I am [%d] years old\n", showData.name, showData.age);
// printf("私鑰加密公鑰解密successful\n");
// printf("start4.2........\n");
// string clearText1 = "xzjjglajgojagojhaogjagjhajhgdahgkahgoihagoihrwqai";
// string cipherText = "";
// printf("A\n");
// cipherText = mHashSignature.RSAPrivateKeyEncypt(clearText1.length(), clearText1.c_str(), PRIVATE_KEY_FILE);
// string clearText2 = "";
// printf("B\n");
// clearText2 = mHashSignature.RSAPublicKeyDecypt(cipherText.length(), cipherText.c_str(), PUBLIC_KEY_FILE);
// printf("my name is [%s]\n", clearText2.c_str());
/********************************** 私鑰加密公鑰解密 ***********************************/
/********************************** RSA公鑰加密私鑰解密 ***********************************/
printf("start5.1........\n");
persion m_persion = {28,"xzj8023tp"};
char * clearText1 = new char[sizeof(persion)];
string cipherText = "";
memcpy(clearText1, &m_persion, sizeof(persion));
cipherText = mHashSignature.RSAPublicKeyEncypt(sizeof(persion), clearText1, PUBLIC_KEY_FILE);
string clearText2 = "";
clearText2 = mHashSignature.RSAPrivateKeyDecypt(cipherText.length(), cipherText.c_str(), PRIVATE_KEY_FILE);
persion showData;
memcpy(&showData, (clearText2.c_str()), sizeof(persion));
printf("my name is [%s] and I am [%d] years old\n", showData.name, showData.age);
printf("RSA公鑰加密私鑰解密successful\n");
/********************************** RSA公鑰加密私鑰解密 ***********************************/
return 0;
}
Linux中的編譯執行:
g++ HashSignature.cpp main.cpp -o main.run -lssl -lcrypto
運行截圖:
test 1:
xzj@xzj-virtual-machine:~/Code/C++Code/RSA$ g++ HashSignature.cpp main.cpp -o main.run -lssl -lcrypto
xzj@xzj-virtual-machine:~/Code/C++Code/RSA$ ./main.run
Create public key successful!
Create private key successful!
test 1 RSA create key is successful
test2
xzj@xzj-virtual-machine:~/Code/C++Code/RSA$ g++ HashSignature.cpp main.cpp -o main.run -lssl -lcrypto
xzj@xzj-virtual-machine:~/Code/C++Code/RSA$ ./main.run
test 2 RSA create key is successful
start1
xzj@xzj-virtual-machine:~/Code/C++Code/RSA$ g++ HashSignature.cpp main.cpp -o main.run -lssl -lcrypto
xzj@xzj-virtual-machine:~/Code/C++Code/RSA$ ./main.run
start1........
數據生成的hash值為[81bbd261553e8aa21b1e36c693bf352c9a43b9453bba5e5059cd47093681ddac]
private key RSA is [128]
RSA_private_encrypt is successful
摘要生成的簽名為[��w4��=��߈�#~��p�[m�]
public key RSA is [128]
RSA_public_decrypt is successful
摘要解簽的hash值為[81bbd261553e8aa21b1e36c693bf352c9a43b9453bba5e5059cd47093681ddac]
簽名驗證成功
start2
xzj@xzj-virtual-machine:~/Code/C++Code/RSA$ g++ HashSignature.cpp main.cpp -o main.run -lssl -lcrypto
xzj@xzj-virtual-machine:~/Code/C++Code/RSA$ ./main.run
start2........
數據生成的hash值為[c691fdbd30e610ea7559db3689f4b28554a27ba30f0ab3db1092c294e0f32e41]
private key RSA is [128]
RSA_private_encrypt is successful
摘要生成的簽名為[
3ze��:�NRЏ�Cv��}.���ot�#�m��T�9be!D��r"֠i����R��HAh�;�#�P
] ���y Ǟ��͔��t����#)W�
簽名寫入到文件 successful!!
public key RSA is [128]
RSA_public_decrypt is successful
摘要解簽的hash值為[c691fdbd30e610ea7559db3689f4b28554a27ba30f0ab3db1092c294e0f32e41]
簽名驗證成功
start3
xzj@xzj-virtual-machine:~/Code/C++Code/RSA$ g++ HashSignature.cpp main.cpp -o main.run -lssl -lcrypto
xzj@xzj-virtual-machine:~/Code/C++Code/RSA$ ./main.run
start3........
數據生成的hash值為[c691fdbd30e610ea7559db3689f4b28554a27ba30f0ab3db1092c294e0f32e41]
public key RSA is [128]
RSA_public_decrypt is successful
摘要解簽的hash值為[c691fdbd30e610ea7559db3689f4b28554a27ba30f0ab3db1092c294e0f32e41]
簽名驗證成功
start4.1
xzj@xzj-virtual-machine:~/Code/C++Code/RSA$ g++ HashSignature.cpp main.cpp -o main.run -lssl -lcrypto
xzj@xzj-virtual-machine:~/Code/C++Code/RSA$ ./main.run
start4.1........
private key RSA is [128]
RSA_private_encrypt is successful
public key RSA is [128]
RSA_public_decrypt is successful
my name is [xzj8023tp] and I am [28] years old
私鑰加密公鑰解密successful
start4.2
xzj@xzj-virtual-machine:~/Code/C++Code/RSA$ g++ HashSignature.cpp main.cpp -o main.run -lssl -lcrypto
xzj@xzj-virtual-machine:~/Code/C++Code/RSA$ ./main.run
start4.2........
A
private key RSA is [128]
RSA_private_encrypt is successful
B
public key RSA is [128]
RSA_public_decrypt is successful
my name is [xzjjglajgojagojhaogjagjhajhgdahgkahgoihagoihrwqai]
start5.1
xzj@xzj-virtual-machine:~/Code/C++Code/RSA$ g++ HashSignature.cpp main.cpp -o main.run -lssl -lcrypto
xzj@xzj-virtual-machine:~/Code/C++Code/RSA$ ./main.run
start5.1........
public key RSA is [128]
RSA_public_encrypt is successful
private key RSA is [128]
RSA_private_decrypt is successful
my name is [xzj8023tp] and I am [28] years old
RSA公鑰加密私鑰解密successful
參考代碼:https://blog.csdn.net/xunmeng2002/article/details/82385004
#include <openssl/rsa.h>
#include <string.h>
#include <openssl/pem.h>
#include <openssl/rand.h>
#include <iostream>
#define PUBLIC_KEY_FILE "rsapub.key"
#define PRIVATE_KEY_FILE "rsapriv.key"
#define RSA_KEY_LENGTH 1024
#define RSA_PRIKEY_PSW "123"
int rsa_test(const unsigned char* data, size_t& len, char* encrypt_data, size_t& encrypt_data_len, char* decrypt_data, size_t& decrypt_data_len)
{
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);
int ret = rsa_key_encrypt(pub_key, data, len, (unsigned char *)encrypt_data, encrypt_data_len);
if (ret != 0)
{
printf("rsa encrypt failed!\n");
return ret;
}
else
{
printf("rsa encrypt success!\n");
}
ret = rsa_key_decrypt(pri_key, (const unsigned char *)encrypt_data, encrypt_data_len, (unsigned char *)decrypt_data, decrypt_data_len);
if (ret != 0)
{
printf("rsa decrypt failed!\n");
}
else
{
printf("rsa decrypt success!\n");
printf("encrypt data:%s\n", encrypt_data);
printf("decrypt data:%s\n", decrypt_data);
}
return ret;
}
int generate_key_files(const char* pub_key_file, const char* priv_key_file, const unsigned char* passwd, int passwd_len)
{
RSA *rsa = NULL;
rsa = RSA_generate_key(RSA_KEY_LENGTH, RSA_F4, NULL, NULL);
if (rsa == NULL)
{
printf("RSA_generate_key error!\n");
return -1;
}
//生成公鑰文件
BIO* bio_pub = BIO_new(BIO_s_file());
if (NULL == bio_pub)
{
printf("generate_key bio file new error!\n");
return -1;
}
if (BIO_write_filename(bio_pub, (void *)pub_key_file) <= 0)
{
printf("BIO_write_filename error!\n");
return -1;
}
if (PEM_write_bio_RSAPublicKey(bio_pub, rsa) != 1)
{
printf("PEM_write_bio_RSAPublicKey error!\n");
return -1;
}
printf("Create public key ok!\n");
BIO_free_all(bio_pub);
// 生成私鑰文件
BIO* bio_priv = BIO_new_file(priv_key_file, "w+");
if (NULL == bio_priv)
{
printf("generate_key bio file new error2!\n");
return -1;
}
if (PEM_write_bio_RSAPrivateKey(bio_priv, 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(bio_priv);
RSA_free(rsa);
return 0;
}
EVP_PKEY* open_public_key(const char* pub_key_file)
{
EVP_PKEY* key = NULL;
RSA *rsa = NULL;
OpenSSL_add_all_algorithms();
BIO *bio_pub = BIO_new(BIO_s_file());
BIO_read_filename(bio_pub, pub_key_file);
if (NULL == bio_pub)
{
printf("open_public_key bio file new error!\n");
return NULL;
}
rsa = PEM_read_bio_RSAPublicKey(bio_pub, NULL, NULL, NULL);
if (rsa == NULL)
{
printf("open_public_key failed to PEM_read_bio_RSAPublicKey!\n");
BIO_free(bio_pub);
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* open_private_key(const char* priv_key_file, const unsigned char *passwd)
{
EVP_PKEY* key = NULL;
RSA *rsa = RSA_new();
OpenSSL_add_all_algorithms(); /* 載入Openssl所支持的算法 */
BIO* bio_priv = NULL;
bio_priv = BIO_new_file(priv_key_file, "rb");
if (NULL == bio_priv)
{
printf("open_private_key bio file new error!\n");
return NULL;
}
rsa = PEM_read_bio_RSAPrivateKey(bio_priv, &rsa, NULL, (void *)passwd);
if (rsa == NULL)
{
printf("open_private_key failed to PEM_read_bio_RSAPrivateKey!\n");
BIO_free(bio_priv);
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;
}
int rsa_key_encrypt(EVP_PKEY *key, const unsigned char* data, size_t len, unsigned char *encrypt_data, size_t &encrypt_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, encrypt_data, &encrypt_data_len, 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;
}
int rsa_key_decrypt(EVP_PKEY *key, const unsigned char *encrypt_data, size_t encrypt_data_len, unsigned char *decrypt_data, size_t &decrypt_data_len)
{
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, decrypt_data, &decrypt_data_len, encrypt_data, encrypt_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;
}
openssl命令版本的加簽驗簽
數據文件:myfile.txt
私鑰:myprivate.pem
公鑰:mypublic.pem
簽名文件:sha256.sign
公鑰和私鑰都可以用cat查看
以"-----BEGIN..."開頭, "-----END..."結尾,內容經過BASE64編碼
查看PEM格式證書的信息:$openssl x509 -in certificate.pem -text -noout
1、生成私鑰myprivate.pem
openssl genrsa -out myprivate.pem 4096

2、通過私鑰生成公鑰mypublic.pem
openssl rsa -in myprivate.pem -pubout -out mypublic.pem

3、生成簽名
openssl dgst -sha256 -sign myprivate.pem -out sha256.sign myfile.txt
sha256.sign 就是文件 myfile.txt 的簽名文件

4、使用公鑰來驗證簽名:
openssl dgst -sha256 -verify mypublic.pem -signature sha256.sign myfile.txt

理論上也可以用私鑰來驗證簽名,只是實際上不會使用,也許發送方可能會通過私鑰驗證來證明計算的正確:
openssl dgst -sha256 -prverify myprivate.pem -signature sha256.sign myfile.txt
