Android--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才能解开数据内容。
RSAUtils工具类:
package com.example.xiaobai.aes; import java.security.KeyFactory; import java.security.KeyPair; import java.security.KeyPairGenerator; import java.security.NoSuchAlgorithmException; import java.security.PrivateKey; import java.security.PublicKey; import java.security.spec.PKCS8EncodedKeySpec; import java.security.spec.X509EncodedKeySpec; import java.util.ArrayList; import java.util.List; import javax.crypto.Cipher; /** * Created by xiaobai on 2017/12/7/007. */ public class RSAUtils { public static final String RSA = "RSA";// 非对称加密密钥算法 public static final String ECB_PKCS1_PADDING = "RSA/ECB/PKCS1Padding";//加密填充方式 public static final int DEFAULT_KEY_SIZE = 2048;//秘钥默认长度 public static final byte[] DEFAULT_SPLIT = "#PART#".getBytes(); // 当要加密的内容超过bufferSize,则采用partSplit进行分块加密 public static final int DEFAULT_BUFFERSIZE = (DEFAULT_KEY_SIZE / 8) - 11;// 当前秘钥支持加密的最大字节数 /** * 随机生成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; } } /** * 用公钥对字符串进行加密 * * @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 cp = Cipher.getInstance(ECB_PKCS1_PADDING); cp.init(Cipher.ENCRYPT_MODE, keyPublic); return cp.doFinal(data); } /** * 私钥加密 * * @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); } /** * 公钥解密 * * @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); } /** * 使用私钥进行解密 */ 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 cp = Cipher.getInstance(ECB_PKCS1_PADDING); cp.init(Cipher.DECRYPT_MODE, keyPrivate); byte[] arr = cp.doFinal(encrypted); return arr; } /** * 用公钥对字符串进行分段加密 * */ public static byte[] encryptByPublicKeyForSpilt(byte[] data, byte[] publicKey) throws Exception { int dataLen = data.length; if (dataLen <= DEFAULT_BUFFERSIZE) { return encryptByPublicKey(data, publicKey); } List allBytes = new ArrayList(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; } /** * 分段加密 * * @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 allBytes = new ArrayList(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; } /** * 公钥分段解密 * * @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 allBytes = new ArrayList(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; } /** * 使用私钥分段解密 * */ 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 allBytes = new ArrayList(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; } }
Base64:
package com.example.xiaobai.aes; /** * Created by xiaobai on 2017/12/7/007. */ import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.OutputStream; public class Base64 { private static final char[] legalChars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" .toCharArray(); public static String encode(byte[] data) { int start = 0; int len = data.length; StringBuffer buf = new StringBuffer(data.length * 3 / 2); int end = len - 3; int i = start; int n = 0; while (i <= end) { int d = ((((int) data[i]) & 0x0ff) << 16) | ((((int) data[i + 1]) & 0x0ff) << 8) | (((int) data[i + 2]) & 0x0ff); buf.append(legalChars[(d >> 18) & 63]); buf.append(legalChars[(d >> 12) & 63]); buf.append(legalChars[(d >> 6) & 63]); buf.append(legalChars[d & 63]); i += 3; if (n++ >= 14) { n = 0; buf.append(" "); } } if (i == start + len - 2) { int d = ((((int) data[i]) & 0x0ff) << 16) | ((((int) data[i + 1]) & 255) << 8); buf.append(legalChars[(d >> 18) & 63]); buf.append(legalChars[(d >> 12) & 63]); buf.append(legalChars[(d >> 6) & 63]); buf.append("="); } else if (i == start + len - 1) { int d = (((int) data[i]) & 0x0ff) << 16; buf.append(legalChars[(d >> 18) & 63]); buf.append(legalChars[(d >> 12) & 63]); buf.append("=="); } return buf.toString(); } private static int decode(char c) { if (c >= 'A' && c <= 'Z') return ((int) c) - 65; else if (c >= 'a' && c <= 'z') return ((int) c) - 97 + 26; else if (c >= '0' && c <= '9') return ((int) c) - 48 + 26 + 26; else switch (c) { case '+': return 62; case '/': return 63; case '=': return 0; default: throw new RuntimeException("unexpected code: " + c); } } /** * Decodes the given Base64 encoded String to a new byte array. The byte * array holding the decoded data is returned. */ public static byte[] decode(String s) { ByteArrayOutputStream bos = new ByteArrayOutputStream(); try { decode(s, bos); } catch (IOException e) { throw new RuntimeException(); } byte[] decodedBytes = bos.toByteArray(); try { bos.close(); bos = null; } catch (IOException ex) { System.err.println("Error while decoding BASE64: " + ex.toString()); } return decodedBytes; } private static void decode(String s, OutputStream os) throws IOException { int i = 0; int len = s.length(); while (true) { while (i < len && s.charAt(i) <= ' ') i++; if (i == len) break; int tri = (decode(s.charAt(i)) << 18) + (decode(s.charAt(i + 1)) << 12) + (decode(s.charAt(i + 2)) << 6) + (decode(s.charAt(i + 3))); os.write((tri >> 16) & 255); if (s.charAt(i + 2) == '=') break; os.write((tri >> 8) & 255); if (s.charAt(i + 3) == '=') break; os.write(tri & 255); i += 4; } } }主函数:
package com.example.xiaobai.aes; import android.app.Activity; import android.os.Bundle; import android.util.Log; import java.security.KeyPair; import java.security.interfaces.RSAPrivateKey; import java.security.interfaces.RSAPublicKey; public class MainActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); String text = "hello RSA!"; KeyPair keyPair= RSAUtils.generateRSAKeyPair(RSAUtils.DEFAULT_KEY_SIZE); // 公钥 RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic(); // 私钥 RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate(); //公钥加密 byte[] encryptBytes= new byte[0]; try { encryptBytes = RSAUtils.encryptByPublicKeyForSpilt(text.getBytes(),publicKey.getEncoded()); } catch (Exception e) { e.printStackTrace(); } String encryStr=Base64.encode(encryptBytes); Log.e("RSA","加密后的数据:"+encryStr); //私钥解密 byte[] decryptBytes= new byte[0]; try { decryptBytes = RSAUtils.decryptByPrivateKeyForSpilt(Base64.decode(encryStr),privateKey.getEncoded()); } catch (Exception e) { e.printStackTrace(); } String decryStr=new String(decryptBytes); Log.e("RSA","解密后的数据:"+decryStr); //私钥加密 try { encryptBytes= RSAUtils.encryptByPrivateKeyForSpilt(text.getBytes(),privateKey.getEncoded()); } catch (Exception e) { e.printStackTrace(); } encryStr=Base64.encode(encryptBytes); Log.e("RSA","加密后的数据:"+encryStr); //公钥解密 try { decryptBytes= RSAUtils.decryptByPublicKeyForSpilt(Base64.decode(encryStr),publicKey.getEncoded()); } catch (Exception e) { e.printStackTrace(); } decryStr=new String(decryptBytes); Log.e("RSA","解密后的数据:"+decryStr); } }打印结果:
12-07 18:59:55.909 7040-7040/? E/RSA: 加密后的数据:WXDat4zGP9ugHju+F5LP7av6SPxFYGfew/Y/k09HTmPOsxAMzr7lbnrWYziR 7Gno6933rmHMxkhV4KR3ykS7qW0i6tqw8GD8kirAGC04R2ndb698olJZEGKr ZNnf08u7P0P5r5wyqDjSkdcPFfwcdtSiMBnbGjP9csgsbTMctN9RA5zCdlQZ He6p9Kg7qoPb0gKJ7fMj92/qVrlD2UnYgsTRXvVoMf8JS2v8NCor4ySphEsI GVYKqNTfkQ+h79AF+QzFUxijhHB/qQ827p6H5Vy3XWKAejRPrYO/1T96yJDk ZF1OOulPt7Va8QyRqb5BfkPOb0++pCa0KHkt41BZug== 12-07 18:59:55.922 7040-7040/? E/RSA: 解密后的数据:hello RSA! 12-07 18:59:55.933 7040-7040/? E/RSA: 加密后的数据:OTGdrYaKyiSJXZ3xscyv1UKNcVU2nsAmkJaG+evdKbkDhx0o003ZwPyLdMAR j85R8aSGZIu0PHZ4uc9TsVFyYbKsBO507cG2x2IEaLvSwpgm7vZy40r6bDn2 XcGpqNZSTdBvv1NjABZ4htV7ZgAPMOPI6FkmkulDFGZ1UL2xTCQy+9yZv1kS dZr09EvwyW3G07HwibirBOfP7+mNeP7ULsiJWW0GFGaG/RxdoxEXFsmQ1aJa vlTUM4i6FEO8oWFxW1VGrjmJBRphurbqsFC7x9KgKnE1wXP4YwzBmXr4igoC /E4b/2yDDCUUd1e15KNFguO1iPPll6gRGe3R4298tw== 12-07 18:59:55.935 7040-7040/? E/RSA: 解密后的数据:hello RSA!附加:
通过OpenSSl工具生成密钥对
OpenSSl工具下载:OpenSSI下载,使用OpenSSl工具生成密钥对的过程如下:
首先双击打开bin文件夹下的openssl.exe,打开之后是一个命令行窗口:
然后通过如下命令生成私钥:
[plain]view plaincopygenrsa-outrsa_private_key.pem1024这条命令是让openssl随机生成了一份私钥,加密长度是1024位,密钥长度,范围:512~2048。执行完命令后就可在bin文件夹下看到rsa_private_key.pem文件了。[plain]view plaincopy
-----BEGINRSAPRIVATEKEY-----
MIICXQIBAAKBgQCfRTdcPIH10gT9f31rQuIInLwe7fl2dtEJ93gTmjE9c2H+kLVENWgECiJVQ5sonQNfwToMKdO0b3Olf4pgBKeLThraz/L3nYJYlbqjHC3jTjUnZc0l
uumpXGsox62+PuSGBlfb8zJO6hix4GV/vhyQVCpG9aYqgE7zyTRZYX9byQIDAQABAoGAO9+sYRtKC9xJDfcocfMxv+UT/1ic6EDgcqu6Uzwq+Jvwod9KlXqyQJqCr6T7
pjfodc3RAZOTx4gCZJverBvz053RH5GawCdocEgaqbXAAWJOhA+9IEU0NUud7ckFyDko0QXLoGP9tanrMEt5zMqt8QxDyl6Xcij3mk8rivOgBJECQQDNTO6dZX8xCozc
Ne0gzC53Gv/KQXANBBHMr7WkKUb2i5+tXkEJ5z3abx2ppEQXDr4AgJH8Gtbm6K7tEHV4ov4FAkEAxppD/iiT1/SVQq20be8CsiHpsjTPiestWQWdm1Qn/Y2nAkGkpCFp
yEdUvVDPtQhRN9EqNggNAnwg5kMvsuwN9QJAfHBhQe4/hk5Kyz+0l+irUW6AFOxNKtaIo3TtuK98X/yJsOAstAACMeCgLi9vRjqdWFiWJCVwlU38mZ0cVx8UsQJBALzt
M5Er+LiPKw5rQCD0JZRfPnkQU/3XgyQUe4Gv5PsHLcCvwXeBcafcc3hEz9JfPyPiDk2oCvg6LPHfKBkFBaECQQCODcKX6DBWiyVxmPaJOOcF63KpCYDPkjeovIUHro1x
ElR2GrQCC/9Q4C4vruOhBQ+vX8NMPnO6NBy5TLGDwMyc-----ENDRSAPRIVATEKEY-----
这里面的内容是标准的ASCII字符,中间的一大串字符就是私钥数据了。
[plain]view plaincopy
rsa-inrsa_private_key.pem-outrsa_public_key.pem-pubout[plain]view plaincopy
-----BEGINPUBLICKEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCfRTdcPIH10gT9f31rQuIInLwe7fl2dtEJ93gTmjE9c2H+kLVENWgECiJVQ5sonQNfwToMKdO0b3Olf4pgBKeLThra
z/L3nYJYlbqjHC3jTjUnZc0luumpXGsox62+PuSGBlfb8zJO6hix4GV/vhyQVCpG9aYqgE7zyTRZYX9byQIDAQAB
-----ENDPUBLICKEY-----可以看到是跟私钥的文件类似的。
这样密钥就基本生成了,不过这样密钥对的私钥是无法在代码中直接使用的,要想使用它需要借助RSAPrivateKeyStructure这个类,java是不自带的。所以为了方便使用,我们需要对私钥进行PKCS#8编码,命令如下:
[plain]view plaincopy
pkcs8-topk8-inrsa_private_key.pem-outpkcs8_rsa_private_key.pem-nocrypt[plain]view plaincopy
-----BEGINPRIVATEKEY-----
MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAJ9FN1w8gfXSBP1/fWtC4gicvB7t+XZ20Qn3eBOaMT1zYf6QtUQ1aAQKIlVDmyidA1/BOgwp07Rvc6V/
imAEp4tOGtrP8vedgliVuqMcLeNONSdlzSW66alcayjHrb4+5IYGV9vzMk7qGLHgZX++HJBUKkb1piqATvPJNFlhf1vJAgMBAAECgYA736xhG0oL3EkN9yhx8zG/5RP/
WJzoQOByq7pTPCr4m/Ch30qVerJAmoKvpPumN+h1zdEBk5PHiAJkm96sG/PTndEfkZrAJ2hwSBqptcABYk6ED70gRTQ1S53tyQXIOSjRBcugY/21qeswS3nMyq3xDEPK
XpdyKPeaTyuK86AEkQJBAM1M7p1lfzEKjNw17SDMLnca/8pBcA0EEcyvtaQpRvaLn61eQQnnPdpvHamkRBcOvgCAkfwa1uboru0QdXii/gUCQQDGmkP+KJPX9JVCrbRt
7wKyIemyNM+J6y1ZBZ2bVCf9jacCQaSkIWnIR1S9UM+1CFE30So2CA0CfCDmQy+y7A31AkB8cGFB7j+GTkrLP7SX6KtRboAU7E0q1oijdO24r3xf/Imw4Cy0AAIx4KAu
L29GOp1YWJYkJXCVTfyZnRxXHxSxAkEAvO0zkSv4uI8rDmtAIPQllF8+eRBT/deDJBR7ga/k+wctwK/Bd4Fxp9xzeETP0l8/I+IOTagK+Dos8d8oGQUFoQJBAI4Nwpfo
MFaLJXGY9ok45wXrcqkJgM+SN6i8hQeujXESVHYatAIL/1DgLi+u46EFD69fw0w+c7o0HLlMsYPAzJw=
-----ENDPRIVATEKEY-----可以看到中间的私钥内容有所变化了,这样的私钥我们在代码里就方便使用了。
以上的密钥文件使用时需要注意吧头和尾的字符串去掉,我们只取中间的内容。
上一篇: 基于PHP的校园bbs论坛系统
下一篇: spark流式读取hdfs中数据讲解