RSA加解密,密钥对生成,加密与签名
密钥格式常用的有PKCS1和PKCS8
C++使用openssl库这两种密钥格式都可以生成,生成密钥代码如下,使用不同的密钥格式生成不同的密钥:
static bool generate_key(std::string & publicKey, std::string & privateKey) { BUF_MEM *bptr = NULL; RSA *rsa = RSA_generate_key(1024, 65537, NULL, NULL); RSA *pubrsa = RSA_new(); BIO *bmemPri = BIO_new(BIO_s_mem()); BIO *bmemPub = BIO_new(BIO_s_mem()); EVP_PKEY *evpKey = EVP_PKEY_new(); if(!rsa || !pubrsa || !bmemPri || !bmemPub || !evpKey) { LLOGE("err happens\n"); if(rsa)RSA_free(rsa); if(pubrsa)RSA_free(pubrsa); if(bmemPri)BIO_free(bmemPri); if(bmemPub)BIO_free(bmemPub); if(evpKey)EVP_PKEY_free(evpKey); return false; } EVP_PKEY_set1_RSA(evpKey, rsa); if(!PEM_write_bio_PKCS8PrivateKey(bmemPri, evpKey, NULL, NULL, 0, NULL, NULL))//pkcs8 //if(!PEM_write_bio_RSAPrivateKey(bmemPri, rsa, NULL, NULL, 0, NULL, NULL))//pkcs1 { LLOGE("PEM_write_bio_RSAPrivateKey error\n"); RSA_free(rsa); RSA_free(pubrsa); BIO_free(bmemPri); BIO_free(bmemPub); EVP_PKEY_free(evpKey); return false; } BIO_get_mem_ptr(bmemPri,&bptr); if(!bptr) { LLOGE("BIO_get_mem_ptr error\n"); RSA_free(rsa); RSA_free(pubrsa); BIO_free(bmemPri); BIO_free(bmemPub); EVP_PKEY_free(evpKey); return false; } privateKey.assign(bptr->data, bptr->length); unsigned char *n_b = (unsigned char *)calloc(RSA_size(rsa), sizeof(unsigned char)); unsigned char *e_b = (unsigned char *)calloc(RSA_size(rsa), sizeof(unsigned char)); int n_size = BN_bn2bin(rsa->n, n_b); int b_size = BN_bn2bin(rsa->e, e_b); pubrsa->n = BN_bin2bn(n_b, n_size, NULL); pubrsa->e = BN_bin2bn(e_b, b_size, NULL); if(!PEM_write_bio_PUBKEY(bmemPub, evpKey))//pkcs8 //if(!PEM_write_bio_RSAPublicKey(bmemPub, pubrsa))//pkcs1 { LLOGE("PEM_write_bio_RSAPublicKey error\n"); RSA_free(rsa); RSA_free(pubrsa); BIO_free(bmemPri); BIO_free(bmemPub); EVP_PKEY_free(evpKey); return false; } BIO_get_mem_ptr(bmemPub,&bptr); if(!bptr) { LLOGE("BIO_get_mem_ptr error\n"); RSA_free(rsa); RSA_free(pubrsa); BIO_free(bmemPri); BIO_free(bmemPub); EVP_PKEY_free(evpKey); return false; } std::string puKey(bptr->data, bptr->length); z_pubKeyModify(puKey, publicKey); RSA_free(rsa); RSA_free(pubrsa); BIO_free(bmemPri); BIO_free(bmemPub); EVP_PKEY_free(evpKey); return true; }
公钥加解密代码,使用不同的公钥格式要使用不同的函数读取
static bool public_encrypt(const std::string & pubKey, const std::string & in, std::string & out) { std::string publicKey; z_pubKeyTrans(pubKey, publicKey); BIO *bkey = BIO_new_mem_buf((void*)publicKey.c_str(), publicKey.length()); if(!bkey) { LLOGE("BIO_new_mem_buf error\n"); return false; } EVP_PKEY *evpKey = PEM_read_bio_PUBKEY(bkey, NULL,NULL,NULL);//pkcs8 if(!evpKey) { printf("PEM_read_bio_PUBKEY error\n"); BIO_free(bkey); return false; } RSA *rsa = EVP_PKEY_get1_RSA(evpKey); //RSA *rsa = PEM_read_bio_RSAPublicKey(bkey,NULL,NULL,NULL);//pkcs1 if(!rsa) { LLOGE("PEM_read_bio_RSAPublicKey error\n"); BIO_free(bkey); EVP_PKEY_free(evpKey); return false; } if((int)in.length() > RSA_size(rsa) - 11) // RSA_PKCS1_PADDING RSA_size(rsa) - 11 { LLOGE("public_encrypt, in string to long, max encrypt text len[%d]\n", RSA_size(rsa) - 11); BIO_free(bkey); RSA_free(rsa); EVP_PKEY_free(evpKey); return false; } char *encryptBuf = (char *)malloc(RSA_size(rsa) + 1); if(!encryptBuf) { LLOGE("malloc error\n"); BIO_free(bkey); RSA_free(rsa); EVP_PKEY_free(evpKey); return false; } memset(encryptBuf, 0, RSA_size(rsa) + 1); int encryptLen = RSA_public_encrypt(in.length(), (unsigned char *)in.c_str(), (unsigned char*)encryptBuf, rsa, RSA_PKCS1_PADDING); if (encryptLen < 0) { LLOGE("RSA_public_encrypt error\n"); BIO_free(bkey); RSA_free(rsa); EVP_PKEY_free(evpKey); free(encryptBuf); return false; } BIO_free(bkey); RSA_free(rsa); EVP_PKEY_free(evpKey); //base64 encode BIO *b64 = BIO_new(BIO_f_base64()); BIO *bmem = BIO_new(BIO_s_mem()); b64 = BIO_push(b64, bmem); if(BIO_write(b64, encryptBuf, encryptLen) < 0) { LLOGE("BIO_write error\n"); BIO_free_all(b64); free(encryptBuf); return false; } BIO_flush(b64); BUF_MEM *bptr = NULL; BIO_get_mem_ptr(b64,&bptr); if(!bptr) { LLOGE("BIO_get_mem_ptr error\n"); BIO_free_all(b64); free(encryptBuf); return false; } out.assign(bptr->data, bptr->length); BIO_free_all(b64); free(encryptBuf); return true; } static bool public_decrypt(const std::string & pubKey, const std::string & in, std::string & out) { std::string publicKey; z_pubKeyTrans(pubKey, publicKey); BIO *b64 = BIO_new(BIO_f_base64()); BIO *bkey = BIO_new_mem_buf((void*)publicKey.c_str(), publicKey.length()); BIO *bmem = BIO_new_mem_buf((void*)in.c_str(), in.length()); if(!bkey || !b64 || !bmem) { LLOGE("error\n"); if(bkey)BIO_free(bkey); if(b64)BIO_free(b64); if(bmem)BIO_free(bmem); return false; } EVP_PKEY *evpKey = PEM_read_bio_PUBKEY(bkey, NULL,NULL,NULL);//pkcs8 if(!evpKey) { printf("PEM_read_bio_PUBKEY error\n"); if(bkey)BIO_free(bkey); if(b64)BIO_free(b64); if(bmem)BIO_free(bmem); return false; } //RSA *rsa = PEM_read_bio_RSAPublicKey(bkey,NULL,NULL,NULL); //pkcs1 RSA *rsa = EVP_PKEY_get1_RSA(evpKey); if(!rsa){ LLOGE("error2\n"); if(bkey)BIO_free(bkey); if(b64)BIO_free(b64); if(bmem)BIO_free(bmem); EVP_PKEY_free(evpKey); return false; } b64 = BIO_push(b64,bmem); std::string encryptStr; char decode[256] = {0}; int ret = BIO_read(b64,decode,sizeof(decode)); while(ret > 0) { encryptStr.append(decode, ret); memset(decode, 0, sizeof(decode)); ret = BIO_read(b64,decode,sizeof(decode)); } //LLOGE("encrypt len[%d]\n", encryptStr.length()); int rsa_len = RSA_size(rsa); char *decryptBuf = (char *)malloc(rsa_len + 1); if(!decryptBuf) { if(bkey)BIO_free(bkey); if(b64)BIO_free(b64); if(bmem)BIO_free(bmem); if(rsa)RSA_free(rsa); EVP_PKEY_free(evpKey); return false; } memset(decryptBuf, 0, rsa_len + 1); int decryptLen = RSA_public_decrypt(rsa_len, (unsigned char *)encryptStr.data(), (unsigned char*)decryptBuf, rsa, RSA_PKCS1_PADDING); if (decryptLen < 0) { LLOGE("RSA_public_decrypt error\n"); if(bkey)BIO_free(bkey); if(b64)BIO_free(b64); if(bmem)BIO_free(bmem); if(rsa)RSA_free(rsa); EVP_PKEY_free(evpKey); if(decryptBuf)free(decryptBuf); return false; } out.assign(decryptBuf, decryptLen); if(bkey)BIO_free(bkey); if(b64)BIO_free(b64); if(bmem)BIO_free(bmem); if(rsa)RSA_free(rsa); EVP_PKEY_free(evpKey); if(decryptBuf)free(decryptBuf); return true; }
私钥加解密代码,使用不同的公钥格式要使用不同的函数读取
static bool private_encrypt(const std::string & privateKey, const std::string & in, std::string & out) { BIO *bkey = BIO_new_mem_buf((void*)privateKey.c_str(), privateKey.length()); if(!bkey) { LLOGE("BIO_new_mem_buf error\n"); return false; } EVP_PKEY *evpKey = PEM_read_bio_PrivateKey(bkey,NULL,NULL,NULL); if(!evpKey) { LLOGE("PEM_read_bio_PrivateKey error\n"); BIO_free(bkey); return false; } RSA *rsa = EVP_PKEY_get1_RSA(evpKey); //RSA *rsa = PEM_read_bio_RSAPrivateKey(bkey,NULL,NULL,NULL); if(!rsa) { LLOGE("PEM_read_bio_RSAPrivateKey error\n"); BIO_free(bkey); EVP_PKEY_free(evpKey); return false; } if((int)in.length() > RSA_size(rsa) - 11) // RSA_PKCS1_PADDING RSA_size(rsa) - 11 { LLOGE("public_decrypt, in string to long, max encrypt text len[%d]\n", RSA_size(rsa) - 11); BIO_free(bkey); RSA_free(rsa); EVP_PKEY_free(evpKey); return false; } char *encryptBuf = (char *)malloc(RSA_size(rsa) + 1); if(!encryptBuf) { LLOGE("malloc error\n"); BIO_free(bkey); RSA_free(rsa); EVP_PKEY_free(evpKey); return false; } memset(encryptBuf, 0, RSA_size(rsa) + 1); int encryptLen = RSA_private_encrypt(in.length(), (unsigned char *)in.c_str(), (unsigned char*)encryptBuf, rsa, RSA_PKCS1_PADDING); if (encryptLen < 0) { LLOGE("RSA_private_encrypt error\n"); BIO_free(bkey); RSA_free(rsa); EVP_PKEY_free(evpKey); free(encryptBuf); return false; } BIO_free(bkey); RSA_free(rsa); EVP_PKEY_free(evpKey); //base64 encode BIO *b64 = BIO_new(BIO_f_base64()); BIO *bmem = BIO_new(BIO_s_mem()); b64 = BIO_push(b64, bmem); if(BIO_write(b64, encryptBuf, encryptLen) < 0) { LLOGE("BIO_write error\n"); BIO_free_all(b64); free(encryptBuf); return false; } BIO_flush(b64); BUF_MEM *bptr = NULL; BIO_get_mem_ptr(b64,&bptr); if(!bptr) { LLOGE("BIO_get_mem_ptr error\n"); BIO_free_all(b64); free(encryptBuf); return false; } out.assign(bptr->data, bptr->length); BIO_free_all(b64); free(encryptBuf); return true; } static bool private_decrypt(const std::string & privateKey, const std::string & in, std::string & out) { BIO *b64 = BIO_new(BIO_f_base64()); BIO *bkey = BIO_new_mem_buf((void*)privateKey.c_str(), privateKey.length()); BIO *bmem = BIO_new_mem_buf((void*)in.c_str(), in.length()); if(!bkey || !b64 || !bmem) { LLOGE("error\n"); if(bkey)BIO_free(bkey); if(b64)BIO_free(b64); if(bmem)BIO_free(bmem); return false; } EVP_PKEY *evpKey = PEM_read_bio_PrivateKey(bkey,NULL,NULL,NULL);//pkcs8 if(!evpKey) { LLOGE("PEM_read_bio_PrivateKey error\n"); if(bkey)BIO_free(bkey); if(b64)BIO_free(b64); if(bmem)BIO_free(bmem); return false; } RSA *rsa = EVP_PKEY_get1_RSA(evpKey); //RSA *rsa = PEM_read_bio_RSAPrivateKey(bkey,NULL,NULL,NULL); //pkcs1 if(!rsa){ LLOGE("error2\n"); if(bkey)BIO_free(bkey); if(b64)BIO_free(b64); if(bmem)BIO_free(bmem); EVP_PKEY_free(evpKey); return false; } b64 = BIO_push(b64,bmem); std::string encryptStr; char decode[256] = {0}; int ret = BIO_read(b64,decode,sizeof(decode)); while(ret > 0) { encryptStr.append(decode, ret); memset(decode, 0, sizeof(decode)); ret = BIO_read(b64,decode,sizeof(decode)); } //LLOGE("encrypt len[%d]\n", encryptStr.length()); int rsa_len = RSA_size(rsa); char *decryptBuf = (char *)malloc(rsa_len + 1); if(!decryptBuf) { if(bkey)BIO_free(bkey); if(b64)BIO_free(b64); if(bmem)BIO_free(bmem); if(rsa)RSA_free(rsa); EVP_PKEY_free(evpKey); return false; } memset(decryptBuf, 0, rsa_len + 1); int decryptLen = RSA_private_decrypt(rsa_len, (unsigned char *)encryptStr.data(), (unsigned char*)decryptBuf, rsa, RSA_PKCS1_PADDING); if (decryptLen < 0) { LLOGE("RSA_private_decrypt error\n"); if(bkey)BIO_free(bkey); if(b64)BIO_free(b64); if(bmem)BIO_free(bmem); if(rsa)RSA_free(rsa); EVP_PKEY_free(evpKey); if(decryptBuf)free(decryptBuf); return false; } out.assign(decryptBuf, decryptLen); if(bkey)BIO_free(bkey); if(b64)BIO_free(b64); if(bmem)BIO_free(bmem); if(rsa)RSA_free(rsa); EVP_PKEY_free(evpKey); if(decryptBuf)free(decryptBuf); return true; }
RSA结构与EVP_PKEY结构转换
RSA *rsa = EVP_PKEY_get1_RSA(evpKey);
有一系列这样的函数,带1的是要分别释放内存的。
JAVA语言生成RSA密钥对默认编码后是PKCS8格式的
import java.util.Base64; import java.util.HashMap; import java.util.Map; import java.security.KeyFactory; import java.security.PrivateKey; import java.security.PublicKey; import java.security.KeyPairGenerator; import java.security.KeyPair; import java.security.interfaces.RSAPrivateKey; import java.security.interfaces.RSAPublicKey; import java.security.spec.X509EncodedKeySpec; import java.security.spec.PKCS8EncodedKeySpec; import javax.crypto.Cipher; public class TRsaOperation { public static Map<String, String> generate_key() throws Exception { KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA"); keyPairGenerator.initialize(1024); KeyPair keyPair = keyPairGenerator.generateKeyPair(); RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic(); RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate(); Map<String, String> keyMap = new HashMap<String, String>(); keyMap.put("public", yaoBase64.getEncoder().encodeToString(publicKey.getEncoded())); keyMap.put("private", Base64.getEncoder().encodeToString(privateKey.getEncoded())); return keyMap; } public static String public_encrypt(String pubKey, String in) throws Exception { PublicKey publicKey = KeyFactory.getInstance("RSA").generatePublic(new X509EncodedKeySpec(Base64.getDecoder().decode(pubKey.getBytes()))); Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding"); cipher.init(Cipher.ENCRYPT_MODE, publicKey); byte[] result = cipher.doFinal(in.getBytes()); return Base64.getEncoder().encodeToString(result); } public static String public_decrypt(String pubKey, String in) throws Exception { PublicKey publicKey = KeyFactory.getInstance("RSA").generatePublic(new X509EncodedKeySpec(Base64.getDecoder().decode(pubKey.getBytes()))); Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding"); cipher.init(Cipher.DECRYPT_MODE, publicKey); byte[] result = cipher.doFinal(Base64.getDecoder().decode(in.getBytes())); return new String(result); } public static String private_encrypt(String priKey, String in) throws Exception { PrivateKey privateKey = KeyFactory.getInstance("RSA").generatePrivate(new PKCS8EncodedKeySpec(Base64.getDecoder().decode(priKey.getBytes()))); Cipher cipher2 = Cipher.getInstance("RSA/ECB/PKCS1Padding"); cipher2.init(Cipher.ENCRYPT_MODE, privateKey); byte[] result = cipher2.doFinal(in.getBytes()); return Base64.getEncoder().encodeToString(result); } public static String private_decrypt(String priKey, String in) throws Exception { PrivateKey privateKey = KeyFactory.getInstance("RSA").generatePrivate(new PKCS8EncodedKeySpec(Base64.getDecoder().decode(priKey.getBytes()))); Cipher cipher2 = Cipher.getInstance("RSA/ECB/PKCS1Padding"); cipher2.init(Cipher.DECRYPT_MODE, privateKey); byte[] result = cipher2.doFinal(Base64.getDecoder().decode(in.getBytes())); return new String(result); } }
JAVA生成的密钥与opensll生成的密钥差异
1 直接使用Base64.getEncoder().encodeToString(publicKey.getEncoded())获取到的公钥没有开始与结束标志,没有按照64字节分行,要在openssl中使用要添加开始与结束标志,按照64字节分行(添加每64字节添加‘\n’)。
2 openssl生成的公钥在java中使用做相反的操作。