1.参考资料
1.1 android的Cipher官方文档
https://developer.android.com/reference/javax/crypto/Cipher
其中 构造Cipher实例时要提供加密算法参数 transformation 它的格式有两种:
- "algorithm/mode/padding"
- "algorithm"
代码如下:
Cipher c = Cipher.getInstance("DES/CBC/PKCS5Padding");
其中关于rsa的部分:
Algorithm | Modes | Paddings | Supported API Levels |
RSA | ECB NONE |
NoPadding OAEPPadding PKCS1Padding |
1+ |
OAEPwithSHA-1andMGF1Padding OAEPwithSHA-256andMGF1Padding |
10+ | ||
OAEPwithSHA-224andMGF1Padding OAEPwithSHA-384andMGF1Padding OAEPwithSHA-512andMGF1Padding |
23+ |
1.2 关于算法、Modes、Paddings
https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html#Cipher
其中 rsa 的mode ECB的介绍如下:注意红色部分。
ECB | Electronic Codebook Mode, as defined in FIPS PUB 81 (generally this mode should not be used for multiple blocks of data). |
2.生成密钥
2.1 使用openssl
第1步:生产私钥文件,rsa_private_key.pem
openssl genrsa -out rsa_private_key.pem 2048
查看下它的内容:
其中
- -----BEGIN RSA PRIVATE KEY----- 与 -----END RSA PRIVATE KEY----- 之间就是私钥经过base64编码后的字符。
- 解码后就可以得到私钥的字节数组。
第2步:根据私钥生产公钥,rsa_public_key.pem
openssl rsa -in rsa_private_key.pem -out rsa_public_key.pem -pubout
它的内容与私钥相似。
其中
- -----BEGIN PUBLIC KEY----- 与 -----END PUBLIC KEY----- 之间就是公钥经过base64编码后的字符。
- 解码后就可以得到公钥的字节数组。
第3步:对私钥进行PKCS#8编码
openssl pkcs8 -topk8 -in rsa_private_key.pem -out rsa_pkcs8_private_key.pem -nocrypt
第4步:认证(收费)
如果担心公钥的可靠性,可去权威机构认证一下,得到数字证书。
创建证书请求文件,填写各项信息,如国家、城市、公司,邮箱、密码等等。
openssl req -new -key rsa_private_key.pem -out rsa_cert.csr
用生成的 rsa_cert.csr文件 去权威机构(CA)申请证书,CA会给你数字证书文件。
2.2 用java代码生成密钥
除了上面方法外,也可以用java代码生成公钥、私钥。
1 try { 2 KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA"); 3 kpg.initialize(2048); 4 KeyPair keyPair = kpg.genKeyPair(); 5 RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic(); 6 RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate(); 7 8 } catch (NoSuchAlgorithmException e) { 9 e.printStackTrace(); 10 }
3.示例
3.1 加密、解密(支持分段)
公钥加密--->私钥解密
1 // 公钥加密,支持分段。最大 MAX_ENCRYPT_SIZE 字节 2 public static byte[] encryptByPublicKey(@NonNull byte[] data,RSAPublicKey key) throws Exception { 3 4 // 加密数据 5 Cipher cipher = Cipher.getInstance(ANDROID_TRANSFORMATION); 6 cipher.init(Cipher.ENCRYPT_MODE, key); 7 8 int inOffset = 0,outOffset = 0; 9 10 int olen = cipher.getOutputSize(data.length); 11 byte output[] = new byte[olen]; 12 Log.e("RSAUtil", "encryptByPublicKey: data.len = " + data.length + " outLen = " + olen); 13 14 int loop = data.length / MAX_ENCRYPT_SIZE; 15 16 for (int i = 0 ; i < loop; ++i){ 17 int inLen = MAX_ENCRYPT_SIZE; 18 int outLen = cipher.update(data,inOffset,inLen,output,outOffset); 19 Log.e("RSAUtil", "encryptByPublicKey: outLen = " + outLen + " inLen = " + inLen); 20 inOffset += inLen; 21 outOffset += outLen; 22 } 23 24 if (inOffset <= data.length){ 25 cipher.update(data,inOffset,data.length - inOffset,output,outOffset); 26 } 27 return cipher.doFinal(); 28 } 29 30 31 // 私钥解密,支持分段。最大 MAX_DECRYPT_SIZE 字节 32 public static byte[] decryptByPrivateKey(@NonNull byte[] encrypted,RSAPrivateKey key) throws Exception { 33 34 // 解密数据 35 Cipher cipher = Cipher.getInstance(ANDROID_TRANSFORMATION); 36 cipher.init(Cipher.DECRYPT_MODE, key); 37 38 39 int inOffset = 0,outOffset = 0; 40 41 int olen = cipher.getOutputSize(encrypted.length); 42 byte output[] = new byte[olen]; 43 Log.e("RSAUtil", "decryptByPrivateKey: data.len = " + encrypted.length + " outLen = " + olen); 44 45 int loop = encrypted.length / MAX_DECRYPT_SIZE; 46 47 for (int i = 0 ; i < loop; ++i){ 48 int inLen = MAX_DECRYPT_SIZE; 49 int outLen = cipher.update(encrypted,inOffset,inLen,output,outOffset); 50 Log.e("RSAUtil", "decryptByPrivateKey: outLen = " + outLen + " inLen = " + inLen); 51 inOffset += inLen; 52 outOffset += outLen; 53 } 54 55 if (inOffset <= encrypted.length){ 56 cipher.update(encrypted,inOffset,encrypted.length - inOffset,output,outOffset); 57 } 58 59 return cipher.doFinal(); 60 }
私钥加密--->公钥解密
1 // 私钥加密,支持分段。最大 MAX_ENCRYPT_SIZE 字节 2 public static byte[] encryptByPrivateKey(@NonNull byte[] data,RSAPrivateKey key) throws Exception { 3 4 // 数据加密 5 Cipher cipher = Cipher.getInstance(ANDROID_TRANSFORMATION); 6 cipher.init(Cipher.ENCRYPT_MODE, key); 7 8 int inOffset = 0,outOffset = 0; 9 10 int olen = cipher.getOutputSize(data.length); 11 byte output[] = new byte[olen]; 12 Log.e("RSAUtil", "encryptByPrivateKey: data.len = " + data.length + " outLen = " + olen); 13 14 int loop = data.length / MAX_ENCRYPT_SIZE; 15 16 for (int i = 0 ; i < loop; ++i){ 17 int inLen = MAX_ENCRYPT_SIZE; 18 int outLen = cipher.update(data,inOffset,inLen,output,outOffset); 19 Log.e("RSAUtil", "encryptByPrivateKey: outLen = " + outLen + " inLen = " + inLen); 20 inOffset += inLen; 21 outOffset += outLen; 22 } 23 24 if (inOffset <= data.length){ 25 cipher.update(data,inOffset,data.length - inOffset,output,outOffset); 26 } 27 return cipher.doFinal(); 28 } 29 30 // 公钥解密,支持分段。最大 MAX_DECRYPT_SIZE 字节 31 public static byte[] decryptByPublicKey(@NonNull byte[] data,RSAPublicKey key) throws Exception { 32 33 // 数据解密 34 Cipher cipher = Cipher.getInstance(ANDROID_TRANSFORMATION); 35 cipher.init(Cipher.DECRYPT_MODE, key); 36 37 int inOffset = 0,outOffset = 0; 38 39 int olen = cipher.getOutputSize(data.length); 40 byte output[] = new byte[olen]; 41 Log.e("RSAUtil", "decryptByPublicKey: data.len = " + data.length + " outLen = " + olen); 42 43 int loop = data.length / MAX_DECRYPT_SIZE; 44 45 for (int i = 0 ; i < loop; ++i){ 46 int inLen = MAX_DECRYPT_SIZE; 47 int outLen = cipher.update(data,inOffset,inLen,output,outOffset); 48 Log.e("RSAUtil", "decryptByPublicKey: outLen = " + outLen + " inLen = " + inLen); 49 inOffset += inLen; 50 outOffset += outLen; 51 } 52 53 if (inOffset <= data.length){ 54 cipher.update(data,inOffset,data.length - inOffset,output,outOffset); 55 } 56 return cipher.doFinal(); 57 }
3.2 签名、验证
1 // 签名 2 public static byte[] sign(@NonNull byte [] data,RSAPrivateKey key) throws Exception { 3 Signature signature = Signature.getInstance("SHA256withRSA"); 4 signature.initSign(key); 5 signature.update(data); 6 return signature.sign(); 7 } 8 9 // 验签 10 public static boolean verify(byte [] data, byte [] signed,RSAPublicKey key) throws Exception { 11 Signature signature = Signature.getInstance("SHA256withRSA"); 12 signature.initVerify(key); 13 signature.update(data); 14 return signature.verify(signed); 15 }
4.注意事项
- 加密最多(秘钥长度/8-11)个字节的数据,2048为245,1024为117。
- android系统的RSA实现是"RSA/None/NoPadding",标准JDK实现是"RSA/ECB/PKCS1Padding" ,有可能在android机上加密后无法在服务器上解密。
5.代码
完整示例