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));
}
}
以上代码大部分都是参考自网络,感谢网友的分享