1、生成pem格式的密鑰,並寫入文件。
1)創建RSA公鑰加密的上下文,id可以指定國密、RSA、橢圓曲線等算法,e為加密對象,可以傳NULL,表示默認值
EVP_PKEY_CTX *EVP_PKEY_CTX_new_id(int id, ENGINE *e);
2)對上下文進行初始化
int EVP_PKEY_keygen_init(EVP_PKEY_CTX *ctx);
3)設置密鑰長度
int EVP_PKEY_CTX_set_rsa_keygen_bits(ctx, bits)
4)生成密鑰,密鑰放在ppkey中,這個ppkey需要手動釋放;
int EVP_PKEY_keygen(EVP_PKEY_CTX *ctx, EVP_PKEY **ppkey)
5)將公私鑰寫入文件中
//從EVP_PKEY中獲取RSA對象 struct rsa_st *EVP_PKEY_get0_RSA(EVP_PKEY *pkey); //將公鑰寫入文件 int PEM_write_RSAPublicKey(FILE*fp,const RSA*x); //將私鑰寫入文件 int PEM_write_RSAPrivateKey(FILE*fp, const RSA* x, const EVP_CIPHER*enc//加密上下文, unsigned char*kstr//密鑰, int klen//密鑰長度, pem_password_cb*cb//加密回調, void*u//回調用的參數);
生成公私鑰,並寫入文件代碼實現
EVP_PKEY*GenerKey() { //1、創建RSA公鑰加密上下文,參數1為算法類型 EVP_PKEY_CTX *ctx= EVP_PKEY_CTX_new_id(EVP_PKEY_RSA, NULL); if (!ctx) { ERR_print_errors_fp(stderr); EVP_PKEY_CTX_free(ctx); return NULL; } //2、初始化密鑰對生成上下文 int ret=EVP_PKEY_keygen_init(ctx); if (!ret) { ERR_print_errors_fp(stderr); EVP_PKEY_CTX_free(ctx); return NULL; } //設置參數,RSA的密鑰位數1024位 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; //內部有malloc申請的空間 if (EVP_PKEY_keygen(ctx, &pkey) <= 0) { ERR_print_errors_fp(stderr); EVP_PKEY_CTX_free(ctx); return NULL; } EVP_PKEY_CTX_free(ctx); FILE *fp1 = fopen("./public.pem", "w"); if(!fp1) { //出錯處理 } PEM_write_RSAPublicKey(fp1, EVP_PKEY_get0_RSA(pkey)); FILE *fp2 = fopen("./private.pem", "w"); if(!fp2) { //出錯處理 } //以明文方式存儲 PEM_write_RSAPrivateKey(fp2, EVP_PKEY_get0_RSA(pkey), NULL,//加密的上下文 NULL,//key 0,//密鑰長度 NULL,//回調 NULL //回調參數 ); fclose(fp1); fclose(fp2); return pkey; }
2、加密或者解密
1)把文件中公鑰寫入RSA對象中;
int PEM_read_RSAPublicKey(FILE*fp, RSA**r, pem_password_cb *cb, void *arg);
2)通過EVP_PKEY生成EVP_PKEY_CTX上下文
//產生EVP_PKEY對象 EVP_PKEY *EVP_PKEY_new(void); //給EVP_PKEY設置RSA密鑰 int EVP_PKEY_set1_RSA(EVP_PKEY *pkey, struct rsa_st *key); //生成EVP_PKEY上下文 EVP_PKEY_CTX *EVP_PKEY_CTX_new(EVP_PKEY *pkey, ENGINE *e);
3)加密
int EVP_PKEY_encrypt_init(EVP_PKEY_CTX *ctx);//加密初始化 int EVP_PKEY_encrypt(EVP_PKEY_CTX *ctx, unsigned char *out//輸出空間 , size_t *outlen, //傳入傳出參數,傳入預留空間大小,傳出實際大小 const unsigned char *in,//輸入數據 size_t inlen /*輸入數據大小*/);
加密代碼實現
int Encrypto(const unsigned char *in, int in_len, unsigned char *out) { //1、讀取公鑰 FILE *fp = fopen("./public.pem", "r"); RSA *r = NULL; if (NULL == fp) { fclose(fp); return -1; } //把文件中公鑰寫入到RSA結構體中 PEM_read_RSAPublicKey(fp, &r, NULL, NULL); fclose(fp); if (!r) { ERR_print_errors_fp(stderr); return -1; } //2、 //密鑰長度 int key_size = RSA_size(r); //2通過EVP_PKEY生成EVP_PKEY_CTX上下文 EVP_PKEY *pkey = EVP_PKEY_new(); //設置為RSA的密鑰 EVP_PKEY_set1_RSA(pkey, r); auto ctx = EVP_PKEY_CTX_new(pkey, NULL); //3加密初始化 EVP_PKEY_encrypt_init(ctx); //數據塊大小 int block_size = key_size - RSA_PKCS1_PADDING_SIZE; int out_size = 0; int i; //4加密,分塊加密 for (i = 0; i < in_len; i += block_size) { size_t out_len = key_size; size_t ensize = block_size; if (in_len - i < block_size) ensize = in_len - i; int ret=EVP_PKEY_encrypt(ctx, out+out_size, &out_len, in+i, ensize); if (ret <= 0) { ERR_print_errors_fp(stderr); break; } out_size += out_len; } EVP_PKEY_free(pkey); EVP_PKEY_CTX_free(ctx); RSA_free(r); return out_size; }
解密代碼實現
int Decrypto(const unsigned char *in, int in_len, unsigned char *out) { //打開pem文件獲取私鑰 FILE *fp = fopen("./private.pem", "r"); if (!fp) { fclose(fp); return -1; } RSA *r = NULL; //拿私鑰 PEM_read_RSAPrivateKey(fp, &r, NULL, NULL); if (!r) { fclose(fp); RSA_free(r); } 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); fclose(fp); //解密 int out_size = 0; EVP_PKEY_decrypt_init(ctx); int block_size = key_size; for (int i = 0; i < in_len; i += block_size) { size_t outlen = key_size;//設置輸出空間大小; if (EVP_PKEY_decrypt(ctx, out+out_size, &outlen, in + i, block_size) <= 0) { ERR_print_errors_fp(stderr); return -1; } out_size += outlen; } EVP_PKEY_CTX_free(ctx); return out_size; }
測試
int test01() unsigned char data[] = "how are you?hello world!i am fine and you"; unsigned char out[512] = { 0 }; unsigned char out2[512] = { 0 }; int data_size = sizeof(data); auto pkey = GenerKey(); EVP_PKEY_free(pkey); int outsize = Encrypto(data, data_size, out); cout << "密文長度:" << outsize << endl; cout << "密文:" << out << endl; int out2size = Decrypto(out, outsize, out2); cout << "解密后的數據:" << out2<<endl; return 0; }