1.关于RSA算法的原理解析参考:http://www.ruanyifeng.com/blog/2013/06/rsa_algorithm_part_one.html
2.RSA密钥长度、明文长度和密文长度参考:https://blog.csdn.net/liuhuabai100/article/details/7585879
3.以下示例代码可以将密钥Base64转码之后保存到文本文件内,也可以从文本文件中读取密钥。
public class RSAGenerator { /** * 算法 */ private String ALGORITHM_RSA = "RSA"; private String DEFAULT_ENCODING = "UTF-8"; public static final String KEY_TYPE_PUBLIC = "PUBLIC"; public static final String KEY_TYPE_PRIVATE = "PRIVATE"; /** * 公钥 */ private RSAPublicKey publicKey; private String publicKeyStr; /** * 私钥 */ private RSAPrivateKey privateKey; private String privateKeyStr; /** * 用于加解密 */ private Cipher cipher; /** * 明文块的长度 它必须小于密文块的长度 - 11 */ private int originLength = 128; /** * 密文块的长度 */ private int encrytLength = 256; /** * 生成密钥对 * @return */ public RSAGenerator generateKeyPair() { try { // RSA加密算法 KeyPairGenerator keyPairGenerator = KeyPairGenerator .getInstance(ALGORITHM_RSA); // 创建密钥对,长度采用2048 keyPairGenerator.initialize(2048); KeyPair keyPair = keyPairGenerator.generateKeyPair(); // 分别得到公钥和私钥 publicKey = (RSAPublicKey) keyPair.getPublic(); privateKey = (RSAPrivateKey) keyPair.getPrivate(); // 使用 Base64编码 publicKeyStr = Base64Util.encode(publicKey.getEncoded()); privateKeyStr = Base64Util.encode(privateKey.getEncoded()); //将BASE64编码的结果保存到文件内 String classPath = this.getClass().getClassLoader().getResource("").toString(); String prefix = classPath.substring(classPath.indexOf(":") + 1); String publicFilePath = prefix+"public.txt"; File publicFile= new File(publicFilePath); saveBase64KeyToFile(publicFile, publicKeyStr); String privateFilePath = prefix+"private.txt"; File privateFile= new File(privateFilePath); saveBase64KeyToFile(privateFile, privateKeyStr); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } return this; } /** * 用公钥加密 * @param content * @return 加密后的16进制字符串 */ public String encryptByPublic(String content) { String encode = ""; try { cipher = Cipher.getInstance(ALGORITHM_RSA); cipher.init(Cipher.ENCRYPT_MODE, publicKey); // 该密钥能够加密的最大字节长度 int splitLength = publicKey.getModulus().bitLength() / 8 - 11; byte[][] arrays = splitBytes(content.getBytes(), splitLength); // 加密 StringBuffer buffer = new StringBuffer(); for (byte[] array : arrays) { buffer.append(bytesToHexString(cipher.doFinal(array))); } encode = buffer.toString(); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } catch (NoSuchPaddingException e) { e.printStackTrace(); } catch (InvalidKeyException e) { e.printStackTrace(); } catch (IllegalBlockSizeException e) { e.printStackTrace(); } catch (BadPaddingException e) { e.printStackTrace(); } return encode; } /** * 用私钥加密 * * @param content * @return 加密后的16进制字符串 */ public String encryptByPrivate(String content) { try { Cipher cipher = Cipher.getInstance(ALGORITHM_RSA); cipher.init(Cipher.ENCRYPT_MODE, privateKey); // 该密钥能够加密的最大字节长度 int splitLength = ((RSAPrivateKey) privateKey).getModulus() .bitLength() / 8 - 11; byte[][] arrays = splitBytes(content.getBytes(), splitLength); StringBuffer stringBuffer = new StringBuffer(); for (byte[] array : arrays) { stringBuffer.append(bytesToHexString(cipher.doFinal(array))); } return stringBuffer.toString(); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } catch (NoSuchPaddingException e) { e.printStackTrace(); } catch (InvalidKeyException e) { e.printStackTrace(); } catch (BadPaddingException e) { e.printStackTrace(); } catch (IllegalBlockSizeException e) { e.printStackTrace(); } return null; } /** * 用私钥解密 * @param content * @return 解密后的原文 */ public String decryptByPrivate(String content) { String decode = ""; try { cipher = Cipher.getInstance(ALGORITHM_RSA); cipher.init(Cipher.DECRYPT_MODE, privateKey); // 该密钥能够加密的最大字节长度 int splitLength = privateKey.getModulus().bitLength() / 8; byte[] contentBytes = hexStringToBytes(content); byte[][] arrays = splitBytes(contentBytes, splitLength); StringBuffer stringBuffer = new StringBuffer(); for (byte[] array : arrays) { stringBuffer.append(new String(cipher.doFinal(array))); } decode = stringBuffer.toString(); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } catch (NoSuchPaddingException e) { e.printStackTrace(); } catch (InvalidKeyException e) { e.printStackTrace(); } catch (IllegalBlockSizeException e) { e.printStackTrace(); } catch (BadPaddingException e) { e.printStackTrace(); } return decode; } /** * 用私钥解密 * * @param content * @return 解密后的原文 */ public String decryptByPublic(String content) { String decode = ""; try { cipher = Cipher.getInstance(ALGORITHM_RSA); cipher.init(Cipher.DECRYPT_MODE, publicKey); // 该密钥能够加密的最大字节长度 int splitLength = publicKey.getModulus().bitLength() / 8; byte[] contentBytes = hexStringToBytes(content); byte[][] arrays = splitBytes(contentBytes, splitLength); StringBuffer stringBuffer = new StringBuffer(); for (byte[] array : arrays) { stringBuffer.append(new String(cipher.doFinal(array))); } decode = stringBuffer.toString(); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } catch (NoSuchPaddingException e) { e.printStackTrace(); } catch (InvalidKeyException e) { e.printStackTrace(); } catch (IllegalBlockSizeException e) { e.printStackTrace(); } catch (BadPaddingException e) { e.printStackTrace(); } return decode; } /** * 根据限定的每组字节长度,将字节数组分组 * @param bytes 等待分组的字节组 * @param splitLength 每组长度 * @return 分组后的字节组 */ public static byte[][] splitBytes(byte[] bytes, int splitLength) { // bytes与splitLength的余数 int remainder = bytes.length % splitLength; // 数据拆分后的组数,余数不为0时加1 int quotient = remainder > 0 ? bytes.length / splitLength + 1 : bytes.length / splitLength; byte[][] arrays = new byte[quotient][]; byte[] array = null; for (int i = 0; i < quotient; i++) { // 如果是最后一组(quotient-1),同时余数不等于0,就将最后一组设置为remainder的长度 if (i == quotient - 1 && remainder != 0) { array = new byte[remainder]; System.arraycopy(bytes, i * splitLength, array, 0, remainder); } else { array = new byte[splitLength]; System.arraycopy(bytes, i * splitLength, array, 0, splitLength); } arrays[i] = array; } return arrays; } /** * 将字节数组转换成16进制字符串 * @param bytes 即将转换的数据 * @return 16进制字符串 */ public static String bytesToHexString(byte[] bytes) { StringBuffer sb = new StringBuffer(bytes.length); String temp = null; for (int i = 0; i < bytes.length; i++) { temp = Integer.toHexString(0xFF & bytes[i]); if (temp.length() < 2) { sb.append(0); } sb.append(temp); } return sb.toString(); } /** * 将16进制字符串转换成字节数组 * * @param hex * 16进制字符串 * @return byte[] */ public static byte[] hexStringToBytes(String hex) { int len = (hex.length() / 2); hex = hex.toUpperCase(); byte[] result = new byte[len]; char[] chars = hex.toCharArray(); for (int i = 0; i < len; i++) { int pos = i * 2; result[i] = (byte) (toByte(chars[pos]) << 4 | toByte(chars[pos + 1])); } return result; } /** * 将char转换为byte * * @param c * char * @return byte */ private static byte toByte(char c) { return (byte) "0123456789ABCDEF".indexOf(c); } /** * 保存公钥到文件 * * @param file * @return */ public boolean savePublicKey(File file) { return saveKeyToFile(publicKey, file); } /** * 保存私钥到文件 * * @param file * @return */ public boolean savePrivateKey(File file) { return saveKeyToFile(privateKey, file); } /** * 保存密钥到文件 * @param key 密钥 * @param file 文件 * @return */ private boolean saveKeyToFile(Key key, File file) { boolean result = false; FileOutputStream fos = null; try { fos = new FileOutputStream(file); ObjectOutputStream oos = new ObjectOutputStream(fos); // 公钥默认使用的是X.509编码,私钥默认采用的是PKCS #8编码 byte[] encode = key.getEncoded(); // 注意,此处采用writeObject方法,读取时也要采用readObject方法 oos.writeObject(encode); oos.close(); result = true; } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } finally { try { fos.close(); } catch (IOException e) { e.printStackTrace(); } } return result; } private boolean saveBase64KeyToFile(File file, String key) { boolean result = false; FileOutputStream fos = null; try { fos = new FileOutputStream(file); fos.write(key.getBytes()); fos.close(); result = true; } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } finally { try { fos.close(); } catch (IOException e) { e.printStackTrace(); } } return result; } /** * 从BASE64文件中读取KEY值 * @param fileName * @param keyType */ public void getKeyFromBase64File(String fileName,String keyType) { try { InputStream inputStream = this.getClass().getClassLoader().getResource(fileName).openStream(); ByteArrayOutputStream outStream = new ByteArrayOutputStream(); byte[] subByte = new byte[1024]; int len = 0; while((len=inputStream.read(subByte))>0) { outStream.write(subByte,0,len); } inputStream.close(); outStream.close(); String base64Key = new String(outStream.toByteArray(), DEFAULT_ENCODING); byte[] keybyte = Base64Util.decode(base64Key); // 默认编码 KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM_RSA); if (KEY_TYPE_PUBLIC.equals(keyType)) { X509EncodedKeySpec x509eks = new X509EncodedKeySpec(keybyte); publicKey = (RSAPublicKey) keyFactory.generatePublic(x509eks); System.out.println(publicKey.getAlgorithm()); } else { PKCS8EncodedKeySpec pkcs8eks = new PKCS8EncodedKeySpec(keybyte); privateKey = (RSAPrivateKey) keyFactory .generatePrivate(pkcs8eks); } } catch (IOException e) { e.printStackTrace(); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } catch (InvalidKeySpecException e) { e.printStackTrace(); } } /** * 从文件中得到公钥 * * @param file */ public void getPublicKey(File file) { getKey(file, KEY_TYPE_PUBLIC); } /** * 从文件中得到私钥 * * @param file */ public void getPrivateKey(File file) { getKey(file, KEY_TYPE_PRIVATE); } /** * 从文件中得到密钥 * * @param file * @param keyType */ private void getKey(File file, String keyType) { FileInputStream fis = null; try { fis = new FileInputStream(file); ObjectInputStream ois = new ObjectInputStream(fis); byte[] keybyte = (byte[]) ois.readObject(); // 关闭资源 ois.close(); // 默认编码 KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM_RSA); if (KEY_TYPE_PUBLIC.equals(keyType)) { X509EncodedKeySpec x509eks = new X509EncodedKeySpec(keybyte); publicKey = (RSAPublicKey) keyFactory.generatePublic(x509eks); System.out.println(publicKey.getAlgorithm()); } else { PKCS8EncodedKeySpec pkcs8eks = new PKCS8EncodedKeySpec(keybyte); privateKey = (RSAPrivateKey) keyFactory .generatePrivate(pkcs8eks); } } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } catch (InvalidKeySpecException e) { e.printStackTrace(); } finally { try { fis.close(); } catch (IOException e) { e.printStackTrace(); } } } }
代码中涉及到的Base64Util如下:
public class Base64Util { private static final char S_BASE64CHAR[] = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/' }; private static final byte S_DECODETABLE[]; static { S_DECODETABLE = new byte[128]; for (int i = 0; i < S_DECODETABLE.length; i++) S_DECODETABLE[i] = 127; for (int i = 0; i < S_BASE64CHAR.length; i++) S_DECODETABLE[S_BASE64CHAR[i]] = (byte) i; } /** * * @param ibuf * @param obuf * @param wp * @return */ private static int decode0(char ibuf[], byte obuf[], int wp) { int outlen = 3; if (ibuf[3] == '=') outlen = 2; if (ibuf[2] == '=') outlen = 1; int b0 = S_DECODETABLE[ibuf[0]]; int b1 = S_DECODETABLE[ibuf[1]]; int b2 = S_DECODETABLE[ibuf[2]]; int b3 = S_DECODETABLE[ibuf[3]]; switch (outlen) { case 1: // '\001' obuf[wp] = (byte) (b0 << 2 & 252 | b1 >> 4 & 3); return 1; case 2: // '\002' obuf[wp++] = (byte) (b0 << 2 & 252 | b1 >> 4 & 3); obuf[wp] = (byte) (b1 << 4 & 240 | b2 >> 2 & 15); return 2; case 3: // '\003' obuf[wp++] = (byte) (b0 << 2 & 252 | b1 >> 4 & 3); obuf[wp++] = (byte) (b1 << 4 & 240 | b2 >> 2 & 15); obuf[wp] = (byte) (b2 << 6 & 192 | b3 & 63); return 3; } throw new RuntimeException("Internal error"); } /** * * @param data * @param off * @param len * @return */ public static byte[] decode(char data[], int off, int len) { char ibuf[] = new char[4]; int ibufcount = 0; byte obuf[] = new byte[(len / 4) * 3 + 3]; int obufcount = 0; for (int i = off; i < off + len; i++) { char ch = data[i]; if (ch != '=' && (ch >= S_DECODETABLE.length || S_DECODETABLE[ch] == 127)) continue; ibuf[ibufcount++] = ch; if (ibufcount == ibuf.length) { ibufcount = 0; obufcount += decode0(ibuf, obuf, obufcount); } } if (obufcount == obuf.length) { return obuf; } else { byte ret[] = new byte[obufcount]; System.arraycopy(obuf, 0, ret, 0, obufcount); return ret; } } /** * * @param data * @return */ public static byte[] decode(String data) { char ibuf[] = new char[4]; int ibufcount = 0; byte obuf[] = new byte[(data.length() / 4) * 3 + 3]; int obufcount = 0; for (int i = 0; i < data.length(); i++) { char ch = data.charAt(i); if (ch != '=' && (ch >= S_DECODETABLE.length || S_DECODETABLE[ch] == 127)) continue; ibuf[ibufcount++] = ch; if (ibufcount == ibuf.length) { ibufcount = 0; obufcount += decode0(ibuf, obuf, obufcount); } } if (obufcount == obuf.length) { return obuf; } else { byte ret[] = new byte[obufcount]; System.arraycopy(obuf, 0, ret, 0, obufcount); return ret; } } /** * * @param data * @param off * @param len * @param ostream * @throws IOException */ public static void decode(char data[], int off, int len, OutputStream ostream) throws IOException { char ibuf[] = new char[4]; int ibufcount = 0; byte obuf[] = new byte[3]; for (int i = off; i < off + len; i++) { char ch = data[i]; if (ch != '=' && (ch >= S_DECODETABLE.length || S_DECODETABLE[ch] == 127)) continue; ibuf[ibufcount++] = ch; if (ibufcount == ibuf.length) { ibufcount = 0; int obufcount = decode0(ibuf, obuf, 0); ostream.write(obuf, 0, obufcount); } } } /** * * @param data * @param ostream * @throws IOException */ public static void decode(String data, OutputStream ostream) throws IOException { char ibuf[] = new char[4]; int ibufcount = 0; byte obuf[] = new byte[3]; for (int i = 0; i < data.length(); i++) { char ch = data.charAt(i); if (ch != '=' && (ch >= S_DECODETABLE.length || S_DECODETABLE[ch] == 127)) continue; ibuf[ibufcount++] = ch; if (ibufcount == ibuf.length) { ibufcount = 0; int obufcount = decode0(ibuf, obuf, 0); ostream.write(obuf, 0, obufcount); } } } /** * * @param data * @return */ public static String encode(byte data[]) { return encode(data, 0, data.length); } /** * * @param data * @param off * @param len * @return */ public static String encode(byte data[], int off, int len) { if (len <= 0) return ""; char out[] = new char[(len / 3) * 4 + 4]; int rindex = off; int windex = 0; int rest; for (rest = len - off; rest >= 3; rest -= 3) { int i = ((data[rindex] & 255) << 16) + ((data[rindex + 1] & 255) << 8) + (data[rindex + 2] & 255); out[windex++] = S_BASE64CHAR[i >> 18]; out[windex++] = S_BASE64CHAR[i >> 12 & 63]; out[windex++] = S_BASE64CHAR[i >> 6 & 63]; out[windex++] = S_BASE64CHAR[i & 63]; rindex += 3; } if (rest == 1) { int i = data[rindex] & 255; out[windex++] = S_BASE64CHAR[i >> 2]; out[windex++] = S_BASE64CHAR[i << 4 & 63]; out[windex++] = '='; out[windex++] = '='; } else if (rest == 2) { int i = ((data[rindex] & 255) << 8) + (data[rindex + 1] & 255); out[windex++] = S_BASE64CHAR[i >> 10]; out[windex++] = S_BASE64CHAR[i >> 4 & 63]; out[windex++] = S_BASE64CHAR[i << 2 & 63]; out[windex++] = '='; } return new String(out, 0, windex); } /** * * @param data * @param off * @param len * @param ostream * @throws IOException */ public static void encode(byte data[], int off, int len, OutputStream ostream) throws IOException { if (len <= 0) return; byte out[] = new byte[4]; int rindex = off; int rest; for (rest = len - off; rest >= 3; rest -= 3) { int i = ((data[rindex] & 255) << 16) + ((data[rindex + 1] & 255) << 8) + (data[rindex + 2] & 255); out[0] = (byte) S_BASE64CHAR[i >> 18]; out[1] = (byte) S_BASE64CHAR[i >> 12 & 63]; out[2] = (byte) S_BASE64CHAR[i >> 6 & 63]; out[3] = (byte) S_BASE64CHAR[i & 63]; ostream.write(out, 0, 4); rindex += 3; } if (rest == 1) { int i = data[rindex] & 255; out[0] = (byte) S_BASE64CHAR[i >> 2]; out[1] = (byte) S_BASE64CHAR[i << 4 & 63]; out[2] = 61; out[3] = 61; ostream.write(out, 0, 4); } else if (rest == 2) { int i = ((data[rindex] & 255) << 8) + (data[rindex + 1] & 255); out[0] = (byte) S_BASE64CHAR[i >> 10]; out[1] = (byte) S_BASE64CHAR[i >> 4 & 63]; out[2] = (byte) S_BASE64CHAR[i << 2 & 63]; out[3] = 61; ostream.write(out, 0, 4); } } /** * * @param data * @param off * @param len * @param writer * @throws IOException */ public static void encode(byte data[], int off, int len, Writer writer) throws IOException { if (len <= 0) return; char out[] = new char[4]; int rindex = off; int rest = len - off; int output = 0; do { if (rest < 3) break; int i = ((data[rindex] & 255) << 16) + ((data[rindex + 1] & 255) << 8) + (data[rindex + 2] & 255); out[0] = S_BASE64CHAR[i >> 18]; out[1] = S_BASE64CHAR[i >> 12 & 63]; out[2] = S_BASE64CHAR[i >> 6 & 63]; out[3] = S_BASE64CHAR[i & 63]; writer.write(out, 0, 4); rindex += 3; rest -= 3; if ((output += 4) % 76 == 0) writer.write("\n"); } while (true); if (rest == 1) { int i = data[rindex] & 255; out[0] = S_BASE64CHAR[i >> 2]; out[1] = S_BASE64CHAR[i << 4 & 63]; out[2] = '='; out[3] = '='; writer.write(out, 0, 4); } else if (rest == 2) { int i = ((data[rindex] & 255) << 8) + (data[rindex + 1] & 255); out[0] = S_BASE64CHAR[i >> 10]; out[1] = S_BASE64CHAR[i >> 4 & 63]; out[2] = S_BASE64CHAR[i << 2 & 63]; out[3] = '='; writer.write(out, 0, 4); } } }
测试类:
public class RSATest { @Test public void test() { RSAGenerator rsaGenerator = new RSAGenerator().generateKeyPair(); String str="数表的质数又称素数。指整数在一个大于1的自然数中,除了1和此整数自身外,没法被其他自然数整除的数"; String encode = rsaGenerator.encryptByPublic(str); System.out.println(encode); System.out.println(rsaGenerator.decryptByPrivate(encode)); System.out.println("用私钥加密公钥解密"); String encrypt = rsaGenerator.encryptByPrivate(str); System.out.println(encrypt); System.out.println(rsaGenerator.decryptByPublic(encrypt)); } @Test public void readKeyFromBase64File(){ //从BASE64文件中读取KEY值 RSAGenerator rsaGenerator = new RSAGenerator(); rsaGenerator.getKeyFromBase64File("private.txt", RSAGenerator.KEY_TYPE_PRIVATE); rsaGenerator.getKeyFromBase64File("public.txt", RSAGenerator.KEY_TYPE_PUBLIC); String str="数表的质数又称素数。指整数在一个大于1的自然数中,除了1和此整数自身外,没法被其他自然数整除的数"; String encode = rsaGenerator.encryptByPublic(str); System.out.println(encode); System.out.println(rsaGenerator.decryptByPrivate(encode)); } }
以上代码大部分都是参考自网络,感谢网友的分享