最近在项目中遇到RSA的公私钥加密的事情,在选择公私钥类型时候遇到了问题,多方面查询资料和验证之后找到解决方式,再次分享一下过程。
问题背景
先说一下问题背景,对接客户项目,用到参数传输时候涉及到的公私钥加密,加密方式是RSA的加解密方式,对方项目是Java项目,Java的项目默认是使用pkcs8的公私钥类型。我本地项目是用python的,但是python的项目中RSA加解密方式都是pkcs1格式的公私钥,所以我这边生成的公私钥,给到客户那边客户用不了。而且也不确定两种格式的公私钥加密后是否有问题,就网上找了一些处理方式。
下面说一下自己的解决路线:
1.先定好加解密的方式,对方公钥加密,我这边私钥解密
2.其次是解决公私钥格式问题,网上查了一下,pkcs1和pkcs8的格式,两种格式的公私钥只是算法和填充方式不一样,那么公私钥加解密的原理应该以一样的。而且两个类型的可以互转
3.那么尝试一下,先生成一对pkcs1的公私钥,然后转成pkcs8的格式,同一对秘钥的两种格式类型
pkcs1的公私钥 -----BEGIN RSA PUBLIC KEY----- MIGJAoGBAIn9bvxsW/MhAO80QOcmF/tjhTRTTNlxCEsR7tx/g1YYJ0SlwIp7lFwL JUqAzaZjyk9HQc0tOq9dIJRKoBJeMHTeejBJyOXq8OGRq//YCJqUkf+hcRv7KMRI 3iEdnGzysG7xyhzl/+JO3SAzOSiS4YixdQ/STzCU+VfTPxVkm6MhAgMBAAE= -----END RSA PUBLIC KEY----- -----BEGIN RSA PRIVATE KEY----- MIICYAIBAAKBgQCJ/W78bFvzIQDvNEDnJhf7Y4U0U0zZcQhLEe7cf4NWGCdEpcCK e5RcCyVKgM2mY8pPR0HNLTqvXSCUSqASXjB03nowScjl6vDhkav/2AialJH/oXEb +yjESN4hHZxs8rBu8coc5f/iTt0gMzkokuGIsXUP0k8wlPlX0z8VZJujIQIDAQAB AoGAEpoy0x68iptBZ/3wXfj5tK8m7vXn30xopM4nGFysVPfum0eJHGIqjvoFrfSN RMghJuzhRwq45Zk1YihpLX1JNJpHbOsLDMClQQHIXN1WIC6xiKNFzDd0syNNhpPy Das4+p8HR7wytDE8T+WR3z0y6TCi9plATpjFDJ6Yb5+avb0CRQDTCuwMVvx8iTnb ux8Hk9Vn+meFOyyz5lGcaWssmnJmZFRQLS+awKR1xVJEJAxNDc42JH/32LvEfiez 7/UZNcszHbGw0wI9AKdioR1JBnZYpkk20kLrzFJsYUuzcKAe79qCNRHbSnIY9Yy4 GitIcW15MeeRJkIcS4Ww8YXIlBeIOC8DuwJEKbRz1zBtbtLTaze8Nwwg1Q5n3K1H 9TkjkYxHkKXoy5EyFDIJwUQme9uFmU+iWqvKv2pRG5Jp8LeZcvaNcfDueeh5T98C PQCkvzbElDOAGBDSztp0c5FPLs00rRCVCN4auz1wrd3AH0DPmARpxYuerEKqIPr+ 5sqOc3HEs37PCowB+jECRFTHpKz0nLMItN83HW+RWgqawuIs26RQh3OXhMK8Bajz XMIcd4sqUbT4T5vSW3XxM1rHcY0qo+D+LVRRFSBv8CmqFuTy -----END RSA PRIVATE KEY-----
然后转换成pkcs8格式的公私钥
PKCS8的公私钥 -----BEGIN PUBLIC KEY----- MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCJ/W78bFvzIQDvNEDnJhf7Y4U0 U0zZcQhLEe7cf4NWGCdEpcCKe5RcCyVKgM2mY8pPR0HNLTqvXSCUSqASXjB03now Scjl6vDhkav/2AialJH/oXEb+yjESN4hHZxs8rBu8coc5f/iTt0gMzkokuGIsXUP 0k8wlPlX0z8VZJujIQIDAQAB -----END PUBLIC KEY----- -----BEGIN PRIVATE KEY----- MIICegIBADANBgkqhkiG9w0BAQEFAASCAmQwggJgAgEAAoGBAIn9bvxsW/MhAO80 QOcmF/tjhTRTTNlxCEsR7tx/g1YYJ0SlwIp7lFwLJUqAzaZjyk9HQc0tOq9dIJRK oBJeMHTeejBJyOXq8OGRq//YCJqUkf+hcRv7KMRI3iEdnGzysG7xyhzl/+JO3SAz OSiS4YixdQ/STzCU+VfTPxVkm6MhAgMBAAECgYASmjLTHryKm0Fn/fBd+Pm0rybu 9effTGikzicYXKxU9+6bR4kcYiqO+gWt9I1EyCEm7OFHCrjlmTViKGktfUk0mkds 6wsMwKVBAchc3VYgLrGIo0XMN3SzI02Gk/INqzj6nwdHvDK0MTxP5ZHfPTLpMKL2 mUBOmMUMnphvn5q9vQJFANMK7AxW/HyJOdu7HweT1Wf6Z4U7LLPmUZxpayyacmZk VFAtL5rApHXFUkQkDE0NzjYkf/fYu8R+J7Pv9Rk1yzMdsbDTAj0Ap2KhHUkGdlim STbSQuvMUmxhS7NwoB7v2oI1EdtKchj1jLgaK0hxbXkx55EmQhxLhbDxhciUF4g4 LwO7AkQptHPXMG1u0tNrN7w3DCDVDmfcrUf1OSORjEeQpejLkTIUMgnBRCZ724WZ T6Jaq8q/alEbkmnwt5ly9o1x8O556HlP3wI9AKS/NsSUM4AYENLO2nRzkU8uzTSt EJUI3hq7PXCt3cAfQM+YBGnFi56sQqog+v7myo5zccSzfs8KjAH6MQJEVMekrPSc swi03zcdb5FaCprC4izbpFCHc5eEwrwFqPNcwhx3iypRtPhPm9JbdfEzWsdxjSqj 4P4tVFEVIG/wKaoW5PI= -----END PRIVATE KEY-----
准备好这些之后,就开始我的验证之路。
先用pkcs1的公钥,用python加密,生成加密字符串
1 import rsa 2 import base64 3 4 def create_keys(): # 生成公钥和私钥 5 (pubkey, privkey) = rsa.newkeys(1024) 6 #输出公钥文件 7 pub = pubkey.save_pkcs1() 8 with open('public.pem', 'wb+')as f: 9 f.write(pub) 10 # 输出私钥文件 11 pri = privkey.save_pkcs1() 12 with open('private.pem', 'wb+')as f: 13 f.write(pri) 14 15 #RSA加密,加密文本为base64的字符串 16 def encrypt(strs): 17 with open('public.pem', 'rb') as publickfile: 18 pub = publickfile.read() 19 pubkey = rsa.PublicKey.load_pkcs1(pub) 20 crypt_text = rsa.encrypt(strs.encode('utf8'), pubkey) 21 encrypt_str = str(base64.b64encode(crypt_text), encoding="utf-8") 22 return encrypt_str # 加密后的密文 23 24 #RSA解密,输入字符为base64字符 25 def decrypt(decrypt_content): 26 with open('private.pem', 'rb') as privatefile: 27 pri = privatefile.read() 28 privkey = rsa.PrivateKey.load_pkcs1(pri) 29 strs = base64.b64decode(decrypt_content) 30 decrypt_str = rsa.decrypt(strs, privkey).decode('utf-8') # 注意,这里如果结果是bytes类型,就需要进行decode()转化为str 31 return decrypt_str 32 33 34 if __name__ == '__main__': 35 #create_keys() 36 strs = 'helloello' 37 enstr = encrypt(strs) 38 #destr = decrypt(enstr) 39 print(enstr) 40 #print(destr)
然后生成加密串:
Lp8gB2t8feRuV9PLEJcWVApQqrD9TJ7j7nqVoebhCgGtOZpqD+63S1w8lcSMl1dFz+h9c6I2505v1kA8bwrEDFsoJmxaukEjbDH//u8KW+HWOzkZeNGxTpN1XBoNIG3RxHPvOINVByTnfnaFY5VB0L2hqAamr53bvrxKLeVaJ4Y=
之后用Java环境,用转换后的pkcs8格式的私钥解密
package com.credits.duiba.NBZX;
import com.credits.duiba.service.BuildTool;
import org.apache.tomcat.util.codec.binary.Base64;
import javax.crypto.Cipher;
import java.io.ByteArrayOutputStream;
import java.security.Key;
import java.security.KeyFactory;
import java.security.PublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
public class RsaEncrypt {
/**
* 加密公钥
* */
private static final String PUBLIC_KEY = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCJ/W78bFvzIQDvNEDnJhf7Y4U0U0zZcQhLEe7cf4NWGCdEpcCKe5RcCyVKgM2mY8pPR0HNLTqvXSCUSqASXjB03nowScjl6vDhkav/2AialJH/oXEb+yjESN4hHZxs8rBu8coc5f/iTt0gMzkokuGIsXUP0k8wlPlX0z8VZJujIQIDAQAB";
/**
* 解密私钥
* */
private static final String PRIVATE_KEY = "MIICegIBADANBgkqhkiG9w0BAQEFAASCAmQwggJgAgEAAoGBAIn9bvxsW/MhAO80QOcmF/tjhTRTTNlxCEsR7tx/g1YYJ0SlwIp7lFwLJUqAzaZjyk9HQc0tOq9dIJRKoBJeMHTeejBJyOXq8OGRq//YCJqUkf+hcRv7KMRI3iEdnGzysG7xyhzl/+JO3SAzOSiS4YixdQ/STzCU+VfTPxVkm6MhAgMBAAECgYASmjLTHryKm0Fn/fBd+Pm0rybu9effTGikzicYXKxU9+6bR4kcYiqO+gWt9I1EyCEm7OFHCrjlmTViKGktfUk0mkds6wsMwKVBAchc3VYgLrGIo0XMN3SzI02Gk/INqzj6nwdHvDK0MTxP5ZHfPTLpMKL2mUBOmMUMnphvn5q9vQJFANMK7AxW/HyJOdu7HweT1Wf6Z4U7LLPmUZxpayyacmZkVFAtL5rApHXFUkQkDE0NzjYkf/fYu8R+J7Pv9Rk1yzMdsbDTAj0Ap2KhHUkGdlimSTbSQuvMUmxhS7NwoB7v2oI1EdtKchj1jLgaK0hxbXkx55EmQhxLhbDxhciUF4g4LwO7AkQptHPXMG1u0tNrN7w3DCDVDmfcrUf1OSORjEeQpejLkTIUMgnBRCZ724WZT6Jaq8q/alEbkmnwt5ly9o1x8O556HlP3wI9AKS/NsSUM4AYENLO2nRzkU8uzTStEJUI3hq7PXCt3cAfQM+YBGnFi56sQqog+v7myo5zccSzfs8KjAH6MQJEVMekrPScswi03zcdb5FaCprC4izbpFCHc5eEwrwFqPNcwhx3iypRtPhPm9JbdfEzWsdxjSqj4P4tVFEVIG/wKaoW5PI=";
/**
* 加密算法RSA
*/
public static final String KEY_ALGORITHM = "RSA";
/** */
/**
* RSA最大加密明文大小
*/
private static final int MAX_ENCRYPT_BLOCK = 117;
/** */
/**
* RSA最大解密密文大小
*/
private static final int MAX_DECRYPT_BLOCK = 128;
public static void main(String[] args) throws Exception {
String ss2 = "FlR/doGGhzsry2zGDfaYWxIL5fmMiIvVIktAGSRgYSLpZ26IoXcYAm6rC1jGR3d3UJESFrsHz17lxujvZHAgKpfMziNw0ADWcney3AGVlQ0B7hW5jLSiE3q+NQ3xJokfmeT9XPHM0stHd4n+57jYKxrGFqjTsLzjNzl9+4wpxc0=";
System.out.println("解密= "+decrypt( ss2,PRIVATE_KEY ));
}
/**
* RSA公钥加密
*
* @param str 加密字符串
* @param publicKey 公钥
* @return 密文
* @throws Exception 加密过程中的异常信息
*/
public static String encrypt(String str, String publicKey) {
String result = "";
try {
// 将Base64编码后的公钥转换成PublicKey对象
byte[] buffer = Base64.decodeBase64(publicKey);
KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(buffer);
PublicKey rsaPublic = keyFactory.generatePublic(keySpec);
// 加密
Cipher cipher = Cipher.getInstance(KEY_ALGORITHM);
cipher.init(Cipher.ENCRYPT_MODE, rsaPublic);
byte[] inputArray = str.getBytes();
int inputLength = inputArray.length;
System.out.println("加密字节数:" + inputLength);
// 标识
int offSet = 0;
byte[] resultBytes = {};
byte[] cache = {};
while (inputLength - offSet > 0) {
if (inputLength - offSet > MAX_ENCRYPT_BLOCK) {
cache = cipher.doFinal(inputArray, offSet, MAX_ENCRYPT_BLOCK);
offSet += MAX_ENCRYPT_BLOCK;
} else {
cache = cipher.doFinal(inputArray, offSet, inputLength - offSet);
offSet = inputLength;
}
resultBytes = Arrays.copyOf(resultBytes, resultBytes.length + cache.length);
System.arraycopy(cache, 0, resultBytes, resultBytes.length - cache.length, cache.length);
}
result = Base64.encodeBase64String(resultBytes);
} catch (Exception e) {
System.out.println("rsaEncrypt error:" + e.getMessage());
}
return result;
}
/**
* RSA私钥解密
*
* @param str 加密字符串
* @param privateKey 私钥
* @return 铭文
* @throws Exception 解密过程中的异常信息
*/
public static String decrypt(String str, String privateKey) throws Exception {
byte[] inputByte = Base64.decodeBase64(str.getBytes("UTF-8"));
byte[] keyBytes = Base64.decodeBase64(privateKey);
PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
Key privateK = keyFactory.generatePrivate(pkcs8KeySpec);
Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
cipher.init(Cipher.DECRYPT_MODE, privateK);
int inputLen = inputByte.length;
ByteArrayOutputStream out = new ByteArrayOutputStream();
int offSet = 0;
byte[] cache;
int i = 0;
// 对数据分段解密
while (inputLen - offSet > 0) {
if (inputLen - offSet > MAX_DECRYPT_BLOCK) {
cache = cipher.doFinal(inputByte, offSet, MAX_DECRYPT_BLOCK);
} else {
cache = cipher.doFinal(inputByte, offSet, inputLen - offSet);
}
out.write(cache, 0, cache.length);
i++;
offSet = i * MAX_DECRYPT_BLOCK;
}
String result = out.toString();
out.close();
return result;
}
}
验证之后,可以正常,说明可以,不再另行测试
