Android数据安全之RSA加密(非对称加密)
2017-05-02 23:34
543 查看
RSA算法是最流行的公钥密码算法,使用长度可以变化的密钥。RSA是第一个既能用于数据加密也能用于数字签名的算法。有两把钥匙(
特点:加密速度比慢一些,但是安全系数比较高,秘钥对的话需要程序生成.不能我们自己定义。
完整代码参考github:Android-Encrypt-master
RSA的安全性依赖于大数分解,小于1024位的N已经被证明是不安全的,而且由于RSA算法进行的都是大数计算,使得RSA最快的情况也比DES慢上倍,这是RSA最大的缺陷,因此通常只能用于加密少量数据或者加密密钥,但RSA仍然不失为一种高强度的算法。
测试结果:
对比发现:私钥的加解密都很耗时,所以可以根据不同的需求采用不能方案来进行加解密。
加密后数据大小的变化:加密后数据量差不多是加密前的1.5倍
密钥对),
公钥和
私钥,公钥的话给别人.私钥自己保存;
特点:加密速度比慢一些,但是安全系数比较高,秘钥对的话需要程序生成.不能我们自己定义。
完整代码参考github:Android-Encrypt-master
背景
1977年,三位数学家Rivest、Shamir 和 Adleman 设计了一种算法,可以实现非对称加密。这种算法用他们三个人的名字命名,叫做RSA算法。从那时直到现在,RSA算法一直是最广为使用的”非对称加密算法”。毫不夸张地说,只要有计算机网络的地方,就有RSA算法。RSA的安全性依赖于大数分解,小于1024位的N已经被证明是不安全的,而且由于RSA算法进行的都是大数计算,使得RSA最快的情况也比DES慢上倍,这是RSA最大的缺陷,因此通常只能用于加密少量数据或者加密密钥,但RSA仍然不失为一种高强度的算法。
RSA算法原理
1.随机选择两个大质数p和q,p不等于q,计算N=pq; 2.选择一个大于1小于N的自然数e,e必须与(p-1)(q-1)互素。 3.用公式计算出d:d×e = 1 (mod (p-1)(q-1)) 。 4.销毁p和q。 最终得到的N和e就是“公钥”,d就是“私钥”,发送方使用N去加密数据,接收方只有使用d才能解开数据内容。
RSA代码实现
1)常量简介
public static final String RSA = "RSA";// 非对称加密密钥算法 /** * 关于加密填充方式:出现问题, Android这边加密过的数据,服务器端解密不了的情况, * 原来android系统的RSA实现是"RSA/None/NoPadding", 而标准JDK实现是"RSA/None/PKCS1Padding" , 这造成了在android机上加密后无法在服务器上解密的原因, 所以在实现的时候这个一定要注意。 */ public static final String ECB_PKCS1_PADDING = "RSA/ECB/PKCS1Padding";//加密填充方式 public static final int DEFAULT_KEY_SIZE = 4000 2048;//秘钥默认长度 public static final byte[] DEFAULT_SPLIT = "#PART#".getBytes(); // 当要加密的内容超过bufferSize,则采用partSplit进行分块加密 /** * 实现分段加密:RSA非对称加密内容长度有限制,1024位key的最多只能加密127位数据,否则就会报错(javax.crypto.IllegalBlockSizeException: Data must not be longer than 117 bytes) */ public static final int DEFAULT_BUFFERSIZE = (DEFAULT_KEY_SIZE / 8) - 11;// 当前秘钥支持加密的最大字节数
2)随机生成RSA密钥对
/** * 随机生成RSA密钥对 * * @param keyLength 密钥长度,范围:512~2048 * 一般1024 * @return */ public static KeyPair generateRSAKeyPair(int keyLength) { try { KeyPairGenerator kpg = KeyPairGenerator.getInstance(RSA); kpg.initialize(keyLength); return kpg.genKeyPair(); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); return null; } }
3)加密实现(公钥加密)
/** * 公钥加密 * * @param data 原文 */ public static byte[] encryptByPublicKey(byte[] data, byte[] publicKey) throws Exception { // 得到公钥 X509EncodedKeySpec keySpec = new X509EncodedKeySpec(publicKey); KeyFactory kf = KeyFactory.getInstance(RSA); PublicKey keyPublic = kf.generatePublic(keySpec); // 加密数据 Cipher cipher = Cipher.getInstance(ECB_PKCS1_PADDING); cipher.init(Cipher.ENCRYPT_MODE, keyPublic); return cipher.doFinal(data); }
4)加密实现(私钥加密)
/** * 私钥加密 * * @param data 待加密数据 * @param privateKey 密钥 * @return byte[] 加密数据 */ public static byte[] encryptByPrivateKey(byte[] data, byte[] privateKey) throws Exception { // 得到私钥 PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(privateKey); KeyFactory kf = KeyFactory.getInstance(RSA); PrivateKey keyPrivate = kf.generatePrivate(keySpec); // 数据加密 Cipher cipher = Cipher.getInstance(ECB_PKCS1_PADDING); cipher.init(Cipher.ENCRYPT_MODE, keyPrivate); return cipher.doFinal(data); }
5)解密实现(公钥解密)
/** * 公钥解密 * @param data 待解密数据 * @param publicKey 密钥 * @return byte[] 解密数据 */ public static byte[] decryptByPublicKey(byte[] data, byte[] publicKey) throws Exception { // 得到公钥 X509EncodedKeySpec keySpec = new X509EncodedKeySpec(publicKey); KeyFactory kf = KeyFactory.getInstance(RSA); PublicKey keyPublic = kf.generatePublic(keySpec); // 数据解密 Cipher cipher = Cipher.getInstance(ECB_PKCS1_PADDING); cipher.init(Cipher.DECRYPT_MODE, keyPublic); return cipher.doFinal(data); }
6)解密实现(私钥解密)
/** * 私钥解密 */ public static byte[] decryptByPrivateKey(byte[] encrypted, byte[] privateKey) throws Exception { // 得到私钥 PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(privateKey); KeyFactory kf = KeyFactory.getInstance(RSA); PrivateKey keyPrivate = kf.generatePrivate(keySpec); // 解密数据 Cipher cipher = Cipher.getInstance(ECB_PKCS1_PADDING); cipher.init(Cipher.DECRYPT_MODE, keyPrivate); return cipher.doFinal(encrypted); }
7)分段加密实现(公钥加密)
/** * 公钥分段加密 * */ public static byte[] encryptByPublicKeyForSpilt(byte[] data, byte[] publicKey) throws Exception { int dataLen = data.length; if (dataLen <= DEFAULT_BUFFERSIZE) { return encryptByPublicKey(data, publicKey); } List<Byte> allBytes = new ArrayList<Byte>(2048); int bufIndex = 0; int subDataLoop = 0; byte[] buf = new byte[DEFAULT_BUFFERSIZE]; for (int i = 0; i < dataLen; i++) { buf[bufIndex] = data[i]; if (++bufIndex == DEFAULT_BUFFERSIZE || i == dataLen - 1) { subDataLoop++; if (subDataLoop != 1) { for (byte b : DEFAULT_SPLIT) { allBytes.add(b); } } byte[] encryptBytes = encryptByPublicKey(buf, publicKey); for (byte b : encryptBytes) { allBytes.add(b); } bufIndex = 0; if (i == dataLen - 1) { buf = null; } else { buf = new byte[Math.min(DEFAULT_BUFFERSIZE, dataLen - i - 1)]; } } } byte[] bytes = new byte[allBytes.size()]; { int i = 0; for (Byte b : allBytes) { bytes[i++] = b.byteValue(); } } return bytes; }
8)分段加密实现(私钥加密)
/** * 私钥分段加密 * * @param data 要加密的原始数据 * @param privateKey 秘钥 */ public static byte[] encryptByPrivateKeyForSpilt(byte[] data, byte[] privateKey) throws Exception { int dataLen = data.length; if (dataLen <= DEFAULT_BUFFERSIZE) { return encryptByPrivateKey(data, privateKey); } List<Byte> allBytes = new ArrayList<Byte>(2048); int bufIndex = 0; int subDataLoop = 0; byte[] buf = new byte[DEFAULT_BUFFERSIZE]; for (int i = 0; i < dataLen; i++) { buf[bufIndex] = data[i]; if (++bufIndex == DEFAULT_BUFFERSIZE || i == dataLen - 1) { subDataLoop++; if (subDataLoop != 1) { for (byte b : DEFAULT_SPLIT) { allBytes.add(b); } } byte[] encryptBytes = encryptByPrivateKey(buf, privateKey); for (byte b : encryptBytes) { allBytes.add(b); } bufIndex = 0; if (i == dataLen - 1) { buf = null; } else { buf = new byte[Math.min(DEFAULT_BUFFERSIZE, dataLen - i - 1)]; } } } byte[] bytes = new byte[allBytes.size()]; { int i = 0; for (Byte b : allBytes) { bytes[i++] = b.byteValue(); } } return bytes; }
9)分段解密实现(公钥解密)
/** * 公钥分段解密 * * @param encrypted 待解密数据 * @param publicKey 密钥 */ public static byte[] decryptByPublicKeyForSpilt(byte[] encrypted, byte[] publicKey) throws Exception { int splitLen = DEFAULT_SPLIT.length; if (splitLen <= 0) { return decryptByPublicKey(encrypted, publicKey); } int dataLen = encrypted.length; List<Byte> allBytes = new ArrayList<Byte>(1024); int latestStartIndex = 0; for (int i = 0; i < dataLen; i++) { byte bt = encrypted[i]; boolean isMatchSplit = false; if (i == dataLen - 1) { // 到data的最后了 byte[] part = new byte[dataLen - latestStartIndex]; System.arraycopy(encrypted, latestStartIndex, part, 0, part.length); byte[] decryptPart = decryptByPublicKey(part, publicKey); for (byte b : decryptPart) { allBytes.add(b); } latestStartIndex = i + splitLen; i = latestStartIndex - 1; } else if (bt == DEFAULT_SPLIT[0]) { // 这个是以split[0]开头 if (splitLen > 1) { if (i + splitLen < dataLen) { // 没有超出data的范围 for (int j = 1; j < splitLen; j++) { if (DEFAULT_SPLIT[j] != encrypted[i + j]) { break; } if (j == splitLen - 1) { // 验证到split的最后一位,都没有break,则表明已经确认是split段 isMatchSplit = true; } } } } else { // split只有一位,则已经匹配了 isMatchSplit = true; } } if (isMatchSplit) { byte[] part = new byte[i - latestStartIndex]; System.arraycopy(encrypted, latestStartIndex, part, 0, part.length); byte[] decryptPart = decryptByPublicKey(part, publicKey); for (byte b : decryptPart) { allBytes.add(b); } latestStartIndex = i + splitLen; i = latestStartIndex - 1; } } byte[] bytes = new byte[allBytes.size()]; { int i = 0; for (Byte b : allBytes) { bytes[i++] = b.byteValue(); } } return bytes; }
10)分段解密实现(私钥解密)
/** * 使用私钥分段解密 * */ public static byte[] decryptByPrivateKeyForSpilt(byte[] encrypted, byte[] privateKey) throws Exception { int splitLen = DEFAULT_SPLIT.length; if (splitLen <= 0) { return decryptByPrivateKey(encrypted, privateKey); } int dataLen = encrypted.length; List<Byte> allBytes = new ArrayList<Byte>(1024); int latestStartIndex = 0; for (int i = 0; i < dataLen; i++) { byte bt = encrypted[i]; boolean isMatchSplit = false; if (i == dataLen - 1) { // 到data的最后了 byte[] part = new byte[dataLen - latestStartIndex]; System.arraycopy(encrypted, latestStartIndex, part, 0, part.length); byte[] decryptPart = decryptByPrivateKey(part, privateKey); for (byte b : decryptPart) { allBytes.add(b); } latestStartIndex = i + splitLen; i = latestStartIndex - 1; } else if (bt == DEFAULT_SPLIT[0]) { // 这个是以split[0]开头 if (splitLen > 1) { if (i + splitLen < dataLen) { // 没有超出data的范围 for (int j = 1; j < splitLen; j++) { if (DEFAULT_SPLIT[j] != encrypted[i + j]) { break; } if (j == splitLen - 1) { // 验证到split的最后一位,都没有break,则表明已经确认是split段 isMatchSplit = true; } } } } else { // split只有一位,则已经匹配了 isMatchSplit = true; } } if (isMatchSplit) { byte[] part = new byte[i - latestStartIndex]; System.arraycopy(encrypted, latestStartIndex, part, 0, part.length); byte[] decryptPart = decryptByPrivateKey(part, privateKey); for (byte b : decryptPart) { allBytes.add(b); } latestStartIndex = i + splitLen; i = latestStartIndex - 1; } } byte[] bytes = new byte[allBytes.size()]; { int i = 0; for (Byte b : allBytes) { bytes[i++] = b.byteValue(); } } return bytes; }
11)数字签名(私钥签名,公钥校验 )
/** * 用私钥对信息生成数字签名 * @param data 已加密数据 * @param privateKey 私钥(BASE64编码) */ public static String sign(byte[] data, byte[] privateKey) throws Exception { PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(privateKey); KeyFactory keyFactory = KeyFactory.getInstance(RSA); PrivateKey privateK = keyFactory.generatePrivate(pkcs8KeySpec); Signature signature = Signature.getInstance("MD5withRSA"); signature.initSign(privateK); signature.update(data); return Base64.encodeToString(signature.sign(), Base64.DEFAULT); } /** * 校验数字签名 * @param data 已加密数据 * @param publicKey 公钥(BASE64编码) * @param sign 数字签名 */ public static boolean verify(byte[] data, byte[] publicKey, String sign) throws Exception { X509EncodedKeySpec keySpec = new X509EncodedKeySpec(publicKey); KeyFactory keyFactory = KeyFactory.getInstance(RSA); PublicKey publicK = keyFactory.generatePublic(keySpec); Signature signature = Signature.getInstance("MD5withRSA"); signature.initVerify(publicK); signature.update(data); return signature.verify(Base64.decode(sign,Base64.DEFAULT)); }
12)测试
private String data = "这是一个测试编码和加解密的字符串数据"; private RSAPublicKey publicKey; private RSAPrivateKey privateKey; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); //获取公钥和私钥 try { KeyPair keyPair=RSAUtils.generateRSAKeyPair(RSAUtils.DEFAULT_KEY_SIZE); // 公钥 publicKey = (RSAPublicKey) keyPair.getPublic(); // 私钥 privateKey = (RSAPrivateKey) keyPair.getPrivate(); } catch (Exception e) { e.printStackTrace(); } } private boolean isRsaSign = true; /** * RSA(非对称) 私钥生成数字签名,公钥检验 */ private void rsaSign() { if (isRsaSign) { try { sign = RSAUtils.sign(data.getBytes(), privateKey.getEncoded()); Log.d("TAG:"+TAG,"----RSA私钥生成签名: "+ sign); tvContent.setText("RSA私钥生成签名: "+ sign); } catch (Exception e) { e.printStackTrace(); } }else{ try { boolean verify = RSAUtils.verify(data.getBytes(), publicKey.getEncoded(), sign); Log.d("TAG:"+TAG,"----RSA公钥检验结果: "+ verify); tvContent.setText("RSA公钥检验结果: "+ verify); } catch (Exception e) { e.printStackTrace(); } } isRsaSign = !isRsaSign; } private boolean isRsaEncryptPri = true; /** * RSA(非对称) 私钥加密,公钥解密 */ private void rsaEncryptPrivate() { if (isRsaEncryptPri) { try { byte[] encryptByPrivateKeyBytes = RSAUtils.encryptByPrivateKey(data.getBytes(), privateKey.getEncoded()); encryptPriStr64 = Base64.encodeToString(encryptByPrivateKeyBytes,Base64.DEFAULT); Log.d("TAG:"+TAG,"----RSA私钥加密: "+encryptPriStr64); tvContent.setText("RSA私钥加密: "+encryptPriStr64); } catch (Exception e) { e.printStackTrace(); Log.d("TAG:"+TAG,"----RSA私钥加密失败"); } }else{ try { byte[] decryptByPublicKeyBytes = RSAUtils.decryptByPublicKey(Base64.decode(encryptPriStr64, Base64.DEFAULT),publicKey.getEncoded()); String decryptStr = new String(decryptByPublicKeyBytes); Log.d("TAG:"+TAG,"----RSA公钥解密: "+decryptStr); tvContent.setText("RSA公钥解密: "+decryptStr); } catch (Exception e) { e.printStackTrace(); Log.d("TAG:"+TAG,"----RSA公钥解密失败"); } } isRsaEncryptPri = !isRsaEncryptPri; } private boolean isRsaEncryptPub = true; /** * RSA(非对称) 公钥加密,私钥解密 */ private void rsaEncryptPublic() { if (isRsaEncryptPub) { try { byte[] encryptByPublicKeyBytes = RSAUtils.encryptByPublicKey(data.getBytes(), publicKey.getEncoded()); //对于加密而言,操作的都是字节数组,所以得到的字节数组不属于任何一种编码格式,所以要将其转换为String的话,可以利用Base64来实现 encryptPubStr64 = Base64.encodeToString(encryptByPublicKeyBytes,Base64.DEFAULT); Log.d("TAG:"+TAG,"----RSA公钥加密: "+ encryptPubStr64); tvContent.setText("RSA公钥加密: "+ encryptPubStr64); } catch (Exception e) { e.printStackTrace(); Log.d("TAG:"+TAG,"----RSA公钥加密失败"); } }else{ try { byte[] decryptByPrivateKeyBytes = RSAUtils.decryptByPrivateKey(Base64.decode(encryptPubStr64, Base64.DEFAULT), privateKey .getEncoded()); String decryptStr = new String(decryptByPrivateKeyBytes); Log.d("TAG:"+TAG,"----RSA私钥解密: "+decryptStr); tvContent.setText("RSA私钥解密: "+decryptStr); } catch (Exception e) { e.printStackTrace(); Log.d("TAG:"+TAG,"----RSA私钥解密失败"); } } isRsaEncryptPub = !isRsaEncryptPub; }
13)针对加解密速度进行单元测试
@Test public void rsaEncryptTest() { List<Person> personList=new ArrayList<>(); int testMaxCount=100;//测试的最大数据条数 //添加测试数据 for(int i=0;i<testMaxCount;i++){ Person person =new Person(); person.setAge(i); person.setName(String.valueOf(i)); personList.add(person); } //FastJson生成json数据 // String jsonData=JsonUtils.objectToJsonForFastJson(personList); String jsonData = JSON.toJSONString(personList); Log.e("MainActivity","加密前json数据 ---->"+jsonData); Log.e("MainActivity","加密前json数据长度 ---->"+jsonData.length()); KeyPair keyPair=RSAUtils.generateRSAKeyPair(RSAUtils.DEFAULT_KEY_SIZE); // 公钥 RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic(); // 私钥 RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate(); try { //公钥加密 long start=System.currentTimeMillis(); byte[] encryptBytes= RSAUtils.encryptByPublicKeyForSpilt(jsonData.getBytes(),publicKey.getEncoded()); long end=System.currentTimeMillis(); Log.e("MainActivity","公钥加密耗时 cost time---->"+(end-start)); String encryStr=Base64Encoder.encode(encryptBytes); Log.e("MainActivity","加密后json数据 --1-->"+encryStr); Log.e("MainActivity","加密后json数据长度 --1-->"+encryStr.length()); //私钥解密 start=System.currentTimeMillis(); byte[] decryptBytes= RSAUtils.decryptByPrivateKeyForSpilt(Base64Decoder.decodeToBytes(encryStr),privateKey.getEncoded()); String decryStr=new String(decryptBytes); end=System.currentTimeMillis(); Log.e("MainActivity","私钥解密耗时 cost time---->"+(end-start)); Log.e("MainActivity","解密后json数据 --1-->"+decryStr); //私钥加密 start=System.currentTimeMillis(); encryptBytes= RSAUtils.encryptByPrivateKeyForSpilt(jsonData.getBytes(),privateKey.getEncoded()); end=System.currentTimeMillis(); Log.e("MainActivity","私钥加密密耗时 cost time---->"+(end-start)); encryStr=Base64Encoder.encode(encryptBytes); Log.e("MainActivity","加密后json数据 --2-->"+encryStr); Log.e("MainActivity","加密后json数据长度 --2-->"+encryStr.length()); //公钥解密 start=System.currentTimeMillis(); decryptBytes= RSAUtils.decryptByPublicKeyForSpilt(Base64Decoder.decodeToBytes(encryStr),publicKey.getEncoded()); decryStr=new String(decryptBytes); end=System.currentTimeMillis(); Log.e("MainActivity","公钥解密耗时 cost time---->"+(end-start)); Log.e("MainActivity","解密后json数据 --2-->"+decryStr); } catch (Exception e) { e.printStackTrace(); } }
测试结果:
对比发现:私钥的加解密都很耗时,所以可以根据不同的需求采用不能方案来进行加解密。
05-03 00:01:58.984 25300-25333/com.example.lgc.encrypt E/MainActivity: 公钥加密耗时 cost time---->7 05-03 00:01:59.074 25300-25333/com.example.lgc.encrypt E/MainActivity: 私钥解密耗时 cost time---->94 05-03 00:01:59.164 25300-25333/com.example.lgc.encrypt E/MainActivity: 私钥加密密耗时 cost time---->92 05-03 00:01:59.174 25300-25333/com.example.lgc.encrypt E/MainActivity: 公钥解密耗时 cost time---->6
加密后数据大小的变化:加密后数据量差不多是加密前的1.5倍
05-03 00:01:55.604 25300-25333/? E/MainActivity: 加密前json数据长度 ---->2281 05-03 00:01:58.984 25300-25333/com.example.lgc.encrypt E/MainActivity: 加密后json数据长度 --1-->3533 05-03 00:01:59.164 25300-25333/com.example.lgc.encrypt E/MainActivity: 加密后json数据长度 --2-->3533
相关文章推荐
- Android安全之非对称加密RSA密钥生成、加密、解密
- 数据传输加密:非对称加密算法RSA+对称算法AES(适用于java,android和Web)
- [置顶] 数据传输加密——非对称加密算法RSA+对称算法AES(适用于java,android和Web)
- android 数据安全中常用的加密算法 3 RSA
- 网络安全——数据的加密与签名,RSA介绍
- Android 中 非对称(RSA)加密和对称(AES)加密
- Android安全加密:非对称加密
- 程序员之网络安全系列(四):数据加密之非对称秘钥
- CA加密,网络安全HTTPS SSL-RSA非对称加密的一些非常规应用
- android下RSA数据加密
- Android 中 非对称(RSA)加密和对称(AES)加密
- Android数据安全之异或加密
- Android数据加密之Rsa加密的简单实现
- 关于RSA非对称加密在Android应用中的使用
- Android接口安全 - RSA+AES混合加密方案
- Android数据加密之Rsa加密
- Android安全加密:非对称加密
- Android加密算法之非对称加密RSA