Android-RSA 分段加密解密
Android-Openssl创建RSA公钥和私钥
Android-AES加解密
Android-DH 秘钥交换1. RSA 介绍
RSA是一种非对称加密算法,所谓非对称,就是指该算法需要一对密钥,使用其中一个(公钥)加密,则需要用另一个(私钥)才能解密。该算法的理论基于一个数论事实:将两个大素数相乘得出乘积十分容易,但是要对它的乘积进行因式分解却极其困难。
因此可以将乘积公开称为公钥,公钥可以给任何人使用,乘数称为私钥,私钥保密。RSA的安全性依赖于因式分解。在RSA中可以用公钥加密私钥解密,也可以用私钥加密公钥解密。
2. 生成 RSA 公钥和私钥
2.1 使用 Openssl 生成 RSA 公钥和私钥,参考:
https://www.jianshu.com/p/44ba9c8510ad
2.2 使用Java代码生成 RSA 公钥和私钥:
import android.content.Context; import android.text.TextUtils; import android.util.Log; import java.io.BufferedReader; import java.io.ByteArrayOutputStream; import java.io.InputStream; import java.io.InputStreamReader; import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; import java.security.KeyFactory; import java.security.KeyPair; import java.security.KeyPairGenerator; import java.security.PrivateKey; import java.security.PublicKey; import java.security.spec.PKCS8EncodedKeySpec; import java.security.spec.X509EncodedKeySpec; import javax.crypto.Cipher; * RSA 非对称加密算法,加解密工具类, * 加密长度 不能超过 128 个字节。 public class RSAEncrypt { public static final String TAG = RSAEncrypt.class.getSimpleName() + " --> "; public static final Charset CHARSET_UTF8 = StandardCharsets.UTF_8; * 标准 jdk 加密填充方式,加解密算法/工作模式/填充方式 public static final String ECB_PKCS1_PADDING = "RSA/ECB/PKCS1Padding"; * 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; * 随机生成 RSA 密钥对 * @param keyLength 密钥长度,范围:512~2048,一般:1024 public static KeyPair getKeyPair(int keyLength) { try { KeyPairGenerator generator = KeyPairGenerator.getInstance(KEY_ALGORITHM); generator.initialize(keyLength); return generator.genKeyPair(); } catch (Exception e) { handleException(e); return null; * 获取公钥 Base64 编码 * @param publicKey 公钥 public static String getPublicKeyBase64(PublicKey publicKey) { return DataUtils.base64Encode(publicKey.getEncoded()); * 获取私钥 Base64 编码 * @param privateKey 公钥 public static String getPrivateKeyBase64(PrivateKey privateKey) { return DataUtils.base64Encode(privateKey.getEncoded()); * 获取 PublicKey 对象 * @param pubKey 公钥,X509 格式 public static PublicKey getPublicKey(String pubKey) { try { // 将公钥进行 Base64 解码 byte[] publicKey = DataUtils.base64Decode(pubKey); // 创建 PublicKey 对象并返回 return KeyFactory.getInstance(KEY_ALGORITHM).generatePublic( new X509EncodedKeySpec(publicKey)); } catch (Exception e) { handleException(e); return null; * 获取 PrivateKey 对象 * @param prvKey 私钥,PKCS8 格式 public static PrivateKey getPrivateKey(String prvKey) { try { // 私钥数据 byte[] privateKey = DataUtils.base64Decode(prvKey); // 创建 PrivateKey 对象并返回 return KeyFactory.getInstance(KEY_ALGORITHM) .generatePrivate(new PKCS8EncodedKeySpec(privateKey)); } catch (Exception e) { handleException(e); return null; * 处理异常 private static void handleException(Exception e) { e.printStackTrace(); Log.e(TAG, TAG + e);
2.3 数据工具类
import android.util.Base64; import java.math.BigInteger; import java.nio.ByteBuffer; import java.nio.charset.StandardCharsets; import java.security.MessageDigest; import java.util.ArrayList; * 数据工具类 public class DataUtils { * 将 Base64 字符串 解码成 字节数组 public static byte[] base64Decode(String data) { return Base64.decode(data, Base64.NO_WRAP); * 将 字节数组 转换成 Base64 编码 public static String base64Encode(byte[] data) { return Base64.encodeToString(data, Base64.NO_WRAP); * 将字节数组转换成 int 类型 public static int byte2Int(byte[] bytes) { ByteBuffer buffer = ByteBuffer.wrap(bytes); return buffer.getInt(); * 将 int 转换成 byte 数组 public static byte[] int2byte(int data) { ByteBuffer buffer = ByteBuffer.allocate(4); buffer.putInt(data); return buffer.array();
3. RSA 分段加密解密
3.1 公钥加密,私钥解密
* 使用公钥将数据进行分段加密 * @param data 要加密的数据 * @param pubKey 公钥 Base64 字符串,X509 格式 * @return 加密后的 Base64 编码数据,加密失败返回 null public static String encryptByPublicKey(String data, String pubKey) { try { byte[] bytes = data.getBytes(CHARSET_UTF8); // 创建 Cipher 对象 Cipher cipher = Cipher.getInstance(ECB_PKCS1_PADDING); // 初始化 Cipher 对象,加密模式 cipher.init(Cipher.ENCRYPT_MODE, getPublicKey(pubKey)); int inputLen = bytes.length; // 保存加密的数据 ByteArrayOutputStream out = new ByteArrayOutputStream(); int offSet = 0, i = 0; byte[] cache; // 使用 RSA 对数据分段加密 while (inputLen - offSet > 0) { if (inputLen - offSet > MAX_ENCRYPT_BLOCK) { cache = cipher.doFinal(bytes, offSet, MAX_ENCRYPT_BLOCK); } else { cache = cipher.doFinal(bytes, offSet, inputLen - offSet); // 将加密以后的数据保存到内存 out.write(cache, 0, cache.length); offSet = i * MAX_ENCRYPT_BLOCK; byte[] encryptedData = out.toByteArray(); out.close(); // 将加密后的数据转换成 Base64 字符串 return DataUtils.base64Encode(encryptedData); } catch (Exception e) { handleException(e); return null; * 使用私钥将加密后的 Base64 字符串进行分段解密 * @param encryptBase64Data 加密后的 Base64 字符串 * @param prvKey 私钥 Base64 字符串,PKCS8 格式 * @return 解密后的明文,解密失败返回 null public static String decryptByPrivateKey(String encryptBase64Data, String prvKey) { try { // 将要解密的数据,进行 Base64 解码 byte[] encryptedData = DataUtils.base64Decode(encryptBase64Data); // 创建 Cipher 对象,用来解密 Cipher cipher = Cipher.getInstance(ECB_PKCS1_PADDING); // 初始化 Cipher 对象,解密模式 cipher.init(Cipher.DECRYPT_MODE, getPrivateKey(prvKey)); int inputLen = encryptedData.length; // 保存解密的数据 ByteArrayOutputStream out = new ByteArrayOutputStream(); int offSet = 0, i = 0; byte[] cache; // 对数据分段解密 while (inputLen - offSet > 0) { if (inputLen - offSet > MAX_DECRYPT_BLOCK) { cache = cipher.doFinal(encryptedData, offSet, MAX_DECRYPT_BLOCK); } else { cache = cipher.doFinal(encryptedData, offSet, inputLen - offSet); // 将解密后的数据保存到内存 out.write(cache, 0, cache.length); offSet = i * MAX_DECRYPT_BLOCK; byte[] decryptedData = out.toByteArray(); out.close(); return new String(decryptedData, CHARSET_UTF8); } catch (Exception e) { handleException(e); return null;3.2 私钥加密,公钥解密
* 使用 私钥 将数据进行分段加密 * @param data 要加密的数据 * @param prvKey 私钥 Base64 字符串,PKCS8 格式 * @return 加密后的 Base64 编码数据,加密失败返回 null public static String encryptByPrivateKey(String data, String prvKey) { try { byte[] bytes = data.getBytes(CHARSET_UTF8); // 创建 Cipher 对象 Cipher cipher = Cipher.getInstance(ECB_PKCS1_PADDING); // 初始化 Cipher 对象,加密模式 cipher.init(Cipher.ENCRYPT_MODE, getPrivateKey(prvKey)); int inputLen = bytes.length; // 保存加密的数据 ByteArrayOutputStream out = new ByteArrayOutputStream(); int offSet = 0, i = 0; byte[] cache; // 使用 RSA 对数据分段加密 while (inputLen - offSet > 0) { if (inputLen - offSet > MAX_ENCRYPT_BLOCK) { cache = cipher.doFinal(bytes, offSet, MAX_ENCRYPT_BLOCK); } else { cache = cipher.doFinal(bytes, offSet, inputLen - offSet); // 将加密以后的数据保存到内存 out.write(cache, 0, cache.length); offSet = i * MAX_ENCRYPT_BLOCK; byte[] encryptedData = out.toByteArray(); out.close(); // 将加密后的数据转换成 Base64 字符串 return DataUtils.base64Encode(encryptedData); } catch (Exception e) { handleException(e); return null; * 使用 公钥 将加密后的 Base64 字符串进行分段解密 * @param encryptBase64Data 加密后的 Base64 字符串 * @param pubKey 公钥 Base64 字符串,X509 格式 * @return 解密后的明文,解密失败返回 null public static String decryptByPublicKey(String encryptBase64Data, String pubKey) { try { // 将要解密的数据,进行 Base64 解码 byte[] encryptedData = DataUtils.base64Decode(encryptBase64Data); // 创建 Cipher 对象,用来解密 Cipher cipher = Cipher.getInstance(ECB_PKCS1_PADDING); // 初始化 Cipher 对象,解密模式 cipher.init(Cipher.DECRYPT_MODE, getPublicKey(pubKey)); int inputLen = encryptedData.length; // 保存解密的数据 ByteArrayOutputStream out = new ByteArrayOutputStream(); int offSet = 0, i = 0; byte[] cache; // 对数据分段解密 while (inputLen - offSet > 0) { if (inputLen - offSet > MAX_DECRYPT_BLOCK) { cache = cipher.doFinal(encryptedData, offSet, MAX_DECRYPT_BLOCK); } else { cache = cipher.doFinal(encryptedData, offSet, inputLen - offSet); // 将解密后的数据保存到内存 out.write(cache, 0, cache.length); offSet = i * MAX_DECRYPT_BLOCK; byte[] decryptedData = out.toByteArray(); out.close(); return new String(decryptedData, CHARSET_UTF8); } catch (Exception e) { handleException(e); return null;3.3 读取安卓 assets 目录下的 RSA 公/私钥
* 读取安卓 assets 目录下的 RSA 公/私钥 public static String getRSAKeyFromAssets(Context context, String fileName) { try { if (TextUtils.isEmpty(fileName)) return null; // 打开 assets 目录下的文件 InputStream in = context.getAssets().open(fileName); BufferedReader reader = new BufferedReader(new InputStreamReader(in)); StringBuilder builder = new StringBuilder(); String line; // 每次读取一行 while ((line = reader.readLine()) != null) { if (line.charAt(0) != '-') { builder.append(line).append('\r'); reader.close(); in.close(); return builder.toString(); } catch (Exception e) {