众所周知,知名项目 OpenSSL
是教科书式的屎山,代码耦合程度高达 99%,项目结构和文档都混乱不堪,自从接口封装成 EVP
之后就彻底放弃治疗了,只有命令行还算好用一点。
当然其实也有更好的选择,比如简单强大的 mbedTLS(PolarSSL)
就深得我心,可惜学校课程要求使用 OpenSSL
完成作业,笔者也就只能硬糊了。
下面是基于 OpenSSL
的 RSA
消息加密及签名实现代码:
-
load_RSA_keys
用于加载PEM
公钥及私钥 -
RSA_Encryption
用于RSA
消息加密 -
RSA_Decryption
用于RSA
消息解密 -
RSA_signature_signing
用于产生RSA
消息签名 -
RSA_signature_verify
用于验证RSA
消息签名
#include <bits/stdc++.h>
#include <openssl/bn.h>
#include <openssl/pem.h>
#include <openssl/rsa.h>
#include <openssl/evp.h>
#define PUBLICKEY "../keys/public.pem"
#define PRIVATEKEY "../keys/private.pem"
using namespace std;
RSA* rsa_private_key = NULL;
RSA* rsa_public_key = NULL;
bool load_RSA_keys() {
FILE *fp = NULL;
if ((fp = fopen(PUBLICKEY,"r"))==NULL){
printf("ERROR
");
return 0;
}
PEM_read_RSA_PUBKEY(fp,&rsa_public_key,nullptr,nullptr);
fclose(fp);
if ((fp = fopen(PRIVATEKEY,"r"))==NULL){
printf("ERROR
");
return 0;
}
PEM_read_RSAPrivateKey(fp,&rsa_private_key,nullptr,nullptr);
fclose(fp);
return 1;
}
string RSA_Encryption(string plaintext)
{
load_RSA_keys();
EVP_PKEY_CTX *ctx;
unsigned char out[256];
RSA_public_encrypt(plaintext.length(),(const unsigned char *)plaintext.c_str(),out,rsa_public_key,RSA_PKCS1_PADDING);
unsigned char output[512];
memset(output,0,sizeof(output));
EVP_EncodeBlock((unsigned char *)output, (const unsigned char *)out, 256);
return string((char *)output);
}
string RSA_Decryption(string ciphertext)
{
load_RSA_keys();
unsigned char out[256];
EVP_DecodeBlock(out, (const unsigned char *)ciphertext.c_str(), ciphertext.length());
unsigned char output[256];
memset(output,0,sizeof(output));
RSA_private_decrypt(256,out,output,rsa_private_key,RSA_PKCS1_PADDING);
return string((char *)output);
}
string RSA_signature_signing(string input)
{
load_RSA_keys();
EVP_PKEY* priKey = EVP_PKEY_new();
EVP_PKEY_assign_RSA(priKey, rsa_private_key);
EVP_MD_CTX *mdctx = NULL;
size_t slen = 0;
size_t blen = 0;
unsigned char sig[256];
mdctx = EVP_MD_CTX_create();
EVP_DigestSignInit(mdctx, NULL, EVP_sha1(), NULL, priKey);
EVP_DigestSignUpdate(mdctx, input.c_str(), input.length());
EVP_DigestSignFinal(mdctx, NULL, &slen);
OPENSSL_malloc(sizeof(unsigned char) * (slen));
EVP_DigestSignFinal(mdctx, sig, &slen);
EVP_MD_CTX_destroy(mdctx);
unsigned char output[512];
memset(output,0,sizeof(output));
EVP_EncodeBlock((unsigned char *)output, (const unsigned char *)sig, 256);
return string((char *)output);
}
bool RSA_signature_verify(string message, string signature)
{
load_RSA_keys();
unsigned char out[256];
EVP_DecodeBlock(out, (const unsigned char *)signature.c_str(), signature.length());
EVP_PKEY* pubKey = EVP_PKEY_new();
EVP_PKEY_assign_RSA(pubKey, rsa_public_key);
EVP_MD_CTX *mdctx = NULL;
mdctx = EVP_MD_CTX_create();
EVP_DigestVerifyInit(mdctx, NULL, EVP_sha1(), NULL, pubKey);
EVP_DigestVerifyUpdate(mdctx, message.c_str(), message.length());
bool ret = 0;
if(1 == EVP_DigestVerifyFinal(mdctx, out, 256))
ret = 1;
EVP_MD_CTX_destroy(mdctx);
return ret;
}
int main(){
string c = RSA_Encryption(string("1234567890"));
printf("c:%s
",c.c_str());
string m = RSA_Decryption(c);
printf("m:%s
",m.c_str());
string s = RSA_signature_signing(string("1234567890"));
printf("s:%s
",s.c_str());
printf("v:%d
",RSA_signature_verify(string("1234567890"),s));
printf("v:%d
",RSA_signature_verify(string("1234567899"),s));
}
`