md5
md5是一种散列算法,不可逆,是一种消息摘要算法,生成的字节数组的长度是128位
,也就是等于16个字节,那么有的字节转化为字符之后,这些字符不一定是存在于ascii码之中,通常为了便于输出,我们会将每个字节转变为16进制字符串,每个16进制都是2个字符,所以md5转化之后的字符是32个字符。
这里有个技术点需要注意的是,在对每个字节进行转化为16进制的字符串的 时候,0-15这几个值的字节,转化为的字符串的长度都是1,所以需要在前面补0
jdk原生md5
/**
* jdk原生md5
*/
public static void md5() throws Exception {
String str = "hello聚合";
String algorithm = "MD5";
MessageDigest instance = MessageDigest.getInstance(algorithm);
byte[] digest = instance.digest(str.getBytes(StandardCharsets.UTF_8));
System.out.println(new String(digest));
//如果直接输出的话,是乱码�G�s�.u�Iz�۲�
//这是因为md5生成的消息摘要是128位,也就是等于16个字节,那么有的字节转化为字符之后,这些字符不一定是存在于ascii码之中的
//通常为了便于输出,我们会将每个字节转变为16进制字符串,每个16进制都是2个字符,所以md5转化之后的字符是32个字符
StringBuilder stringBuilder = new StringBuilder();
for (byte b : digest) {
//每个字节转与0xff(1111 1111)按位与,得到这个字节的补码
String hex = Integer.toHexString(b & 0xff);
//如果生成的16进制的字符的长度是1,那么需要在前面补0,比如
//0,5,10,13,15的16进制分别是是0,5,a,d,f,长度只有1,所以需要前面补0
if (hex.length() == 1) {
hex = "0" + hex;
}
stringBuilder.append(hex);
}
System.out.println(stringBuilder);
}
}
使用commons-codec
需要引入jar包
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>1.15</version>
</dependency>
/**
* 使用commons-codec
*/
public static void md5codec() {
String str = "hello聚合";
String encode = DigestUtils.md5Hex(str.getBytes(StandardCharsets.UTF_8));
System.out.println(encode);
}
全部代码
package codec.md5;
import org.apache.commons.codec.digest.DigestUtils;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
/**
* @author micro.cloud.fly
* @date 2021/8/30 11:28 上午
* @desc md5消息摘要算法学习笔记
*/
public class Demo1 {
public static void main(String[] args) throws Exception {
md5();
System.out.println();
md5codec();
}
/**
* jdk原生md5
*/
public static void md5() throws Exception {
String str = "hello聚合";
String algorithm = "MD5";
MessageDigest instance = MessageDigest.getInstance(algorithm);
byte[] digest = instance.digest(str.getBytes(StandardCharsets.UTF_8));
System.out.println(new String(digest));
//如果直接输出的话,是乱码�G�s�.u�Iz�۲�
//这是因为md5生成的消息摘要是128位,也就是等于16个字节,那么有的字节转化为字符之后,这些字符不一定是存在于ascii码之中的
//通常为了便于输出,我们会将每个字节转变为16进制字符串,每个16进制都是2个字符,所以md5转化之后的字符是32个字符
StringBuilder stringBuilder = new StringBuilder();
for (byte b : digest) {
//每个字节转与0xff(1111 1111)按位与,得到这个字节的补码
String hex = Integer.toHexString(b & 0xff);
//如果生成的16进制的字符的长度是1,那么需要在前面补0,比如
//0,5,10,13,15的16进制分别是是0,5,a,d,f,长度只有1,所以需要前面补0
if (hex.length() == 1) {
hex = "0" + hex;
}
stringBuilder.append(hex);
}
System.out.println(stringBuilder);
}
/**
* 使用commons-codec
*/
public static void md5codec() {
String str = "hello聚合";
String encode = DigestUtils.md5Hex(str.getBytes(StandardCharsets.UTF_8));
System.out.println(encode);
}
}
SHA-256
sha-256和md5一样,都是消息摘要算法,只不过是摘要后的长度是256位,也就是32个字节,同理,在转化为16进制的字符串之后,是64个字节,实现了md5之后,只要把算法algorithm改为SHA-256即可,以下是全部的代码
全部代码
package codec.sha256;
import org.apache.commons.codec.digest.DigestUtils;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
/**
* @author micro.cloud.fly
* @date 2021/8/30 11:28 上午
* @desc sha256消息摘要算法学习笔记
*/
public class Demo {
public static void main(String[] args) throws Exception {
md5();
System.out.println();
md5codec();
}
/**
* jdk原生md5
*/
public static void md5() throws Exception {
String str = "hello聚合";
String algorithm = "SHA-256";
MessageDigest instance = MessageDigest.getInstance(algorithm);
byte[] digest = instance.digest(str.getBytes(StandardCharsets.UTF_8));
System.out.println(new String(digest));
//如果直接输出的话,是乱码�G�s�.u�Iz�۲�
//这是因为md5生成的消息摘要是128位,也就是等于16个字节,那么有的字节转化为字符之后,这些字符不一定是存在于ascii码之中的
//通常为了便于输出,我们会将每个字节转变为16进制字符串,每个16进制都是2个字符,所以md5转化之后的字符是32个字符
StringBuilder stringBuilder = new StringBuilder();
for (byte b : digest) {
//每个字节转与0xff(1111 1111)按位与,得到这个字节的补码
String hex = Integer.toHexString(b & 0xff);
//如果生成的16进制的字符的长度是1,那么需要在前面补0,比如
//0,5,10,13,15的16进制分别是是0,5,a,d,f,长度只有1,所以需要前面补0
if (hex.length() == 1) {
hex = "0" + hex;
}
stringBuilder.append(hex);
}
System.out.println(stringBuilder);
}
/**
* 使用commons-codec
*/
public static void md5codec() {
String str = "hello聚合";
String encode = DigestUtils.sha256Hex(str.getBytes(StandardCharsets.UTF_8));
System.out.println(encode);
}
}
SHA-512
同sha-256原理一样,只要把algorithm算法名改为sha-512即可,以下是全部代码
package codec.sha512;
import org.apache.commons.codec.digest.DigestUtils;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
/**
* @author micro.cloud.fly
* @date 2021/8/30 11:28 上午
* @desc sha512消息摘要算法学习笔记
*/
public class Demo {
public static void main(String[] args) throws Exception {
md5();
System.out.println();
md5codec();
}
/**
* jdk原生
*/
public static void md5() throws Exception {
String str = "hello聚合";
String algorithm = "SHA-512";
MessageDigest instance = MessageDigest.getInstance(algorithm);
byte[] digest = instance.digest(str.getBytes(StandardCharsets.UTF_8));
System.out.println(new String(digest));
//如果直接输出的话,是乱码�G�s�.u�Iz�۲�
//这是因为md5生成的消息摘要是128位,也就是等于16个字节,那么有的字节转化为字符之后,这些字符不一定是存在于ascii码之中的
//通常为了便于输出,我们会将每个字节转变为16进制字符串,每个16进制都是2个字符,所以md5转化之后的字符是32个字符
StringBuilder stringBuilder = new StringBuilder();
for (byte b : digest) {
//每个字节转与0xff(1111 1111)按位与,得到这个字节的补码
String hex = Integer.toHexString(b & 0xff);
//如果生成的16进制的字符的长度是1,那么需要在前面补0,比如
//0,5,10,13,15的16进制分别是是0,5,a,d,f,长度只有1,所以需要前面补0
if (hex.length() == 1) {
hex = "0" + hex;
}
stringBuilder.append(hex);
}
System.out.println(stringBuilder);
}
/**
* 使用commons-codec
*/
public static void md5codec() {
String str = "hello聚合";
String encode = DigestUtils.sha512Hex(str.getBytes(StandardCharsets.UTF_8));
System.out.println(encode);
}
}
MAC
mac也是一种消息摘要,同md5、SHA256算法不同的是,它在进行消息摘要的时候,需要一个key,相同于密钥,mac算法有macMD5、macSHA256、macSHA512等多种,在实现的时候,也是只需要改一个算法名称即可,以下是实现的全部代码
package codec.lesson05_mac;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.codec.digest.HmacAlgorithms;
import org.apache.commons.codec.digest.HmacUtils;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
/**
* @author micro.cloud.fly
* @date 2021/8/30 11:28 上午
* @desc mac消息摘要算法学习笔记
*/
public class Demo1 {
public static void main(String[] args) throws Exception {
mac();
System.out.println();
maccodec();
}
/**
* jdk原生md5
*/
public static void mac() throws Exception {
String str = "hello聚合";
String key = "123";
String algorithm = "HmacMD5";
//使用其他算法,只需要改一下名字即可
algorithm = "HmacSHA256";
algorithm = "HmacSHA512";
//实例化mac对象
Mac mac = Mac.getInstance(algorithm);
//实例化key对象
SecretKeySpec secretKeySpec = new SecretKeySpec(key.getBytes(StandardCharsets.UTF_8), algorithm);
//mac对象初始化
mac.init(secretKeySpec);
byte[] bytes = mac.doFinal(str.getBytes(StandardCharsets.UTF_8));
StringBuilder stringBuilder = new StringBuilder();
for (byte b : bytes) {
//每个字节转与0xff(1111 1111)按位与,得到这个字节的补码
String hex = Integer.toHexString(b & 0xff);
//如果生成的16进制的字符的长度是1,那么需要在前面补0,比如
//0,5,10,13,15的16进制分别是是0,5,a,d,f,长度只有1,所以需要前面补0
if (hex.length() == 1) {
hex = "0" + hex;
}
stringBuilder.append(hex);
}
System.out.println(stringBuilder);
}
/**
* 使用commons-codec
*/
public static void maccodec() {
String str = "hello聚合";
String key = "123";
System.out.println("hmacMD5:"+new HmacUtils(HmacAlgorithms.HMAC_MD5, key.getBytes(StandardCharsets.UTF_8)).hmacHex(str.getBytes(StandardCharsets.UTF_8)));
System.out.println("hmacSHA256:"+new HmacUtils(HmacAlgorithms.HMAC_SHA_256, key.getBytes(StandardCharsets.UTF_8)).hmacHex(str.getBytes(StandardCharsets.UTF_8)));
System.out.println("hmacSHA512:"+new HmacUtils(HmacAlgorithms.HMAC_SHA_512, key.getBytes(StandardCharsets.UTF_8)).hmacHex(str.getBytes(StandardCharsets.UTF_8)));
}
}
DES
des是一种对称加密算法,相对于非对称加密算法来说,更快,现在des已经过时,被AES给取代了,需要注意的是,des算法的时候,key必须是8个字节,不然会报错。以下是使用des加密解密的全部代码。
package codec;
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
/**
* @author micro.cloud.fly
* @date 2021/8/30 2:04 下午
* @desc 学习des算法,des是对称加密,比起非对称加密,有点是更快,因为只使用一个key
*/
public class lesson06_DES {
public static void main(String[] args) throws Exception {
String encryptedString = encrypt();
String decryptedString = decrypt(encryptedString);
System.out.println(decryptedString);
}
private static String decrypt(String encryptedString) throws Exception {
String algorithm = "DES";
Cipher cipher = Cipher.getInstance(algorithm);
String key = "12345678";//这里必须是8个字节
SecretKeySpec secretKeySpec = new SecretKeySpec(key.getBytes(StandardCharsets.UTF_8), algorithm);
cipher.init(Cipher.DECRYPT_MODE, secretKeySpec);
//传参过来的明文,是base64编码后的内容,所以,需要先进行base64解码
byte[] bytes = cipher.doFinal(Base64.getDecoder().decode(encryptedString.getBytes(StandardCharsets.UTF_8)));
return new String(bytes, StandardCharsets.UTF_8);
}
/**
* 使用DES加密
*
* @return 加密后的内容
*/
public static String encrypt() throws Exception {
String algorithm = "DES";
String str = "hello聚合";
//cipher是密码的意思,这里是实例化一个cipher对象,
//这里ECB是指加密的模式,是java的默认加密模式,PKCS7Padding是指填充模式,加密模式和填充模式也可以不进行指定
Cipher cipher = Cipher.getInstance("DES/ECB/PKCS5Padding");
String key = "12345678";//这里必须是8个字节
//实例化一个密钥,第一个参数是密钥,第二个参数是算法
SecretKeySpec secretKeySpec = new SecretKeySpec(key.getBytes(StandardCharsets.UTF_8), algorithm);
//cipher初始化,第一个参数是加解密模式,即,cipher是为了加密,还是用来解密,第二个参数是密钥对象
cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec);
byte[] bytes = cipher.doFinal(str.getBytes(StandardCharsets.UTF_8));
//得到的是字节数组,通常的做法是把此处的字节数组转为base64进行展示
byte[] encode = Base64.getEncoder().encode(bytes);
System.out.println(new String(encode, StandardCharsets.UTF_8));
return new String(encode);
}
}
AES
aes和des差不多,只需要改algorithm的名字即可,不同点是,aes的key的长度必须是16、24、32个字节,不过可以通过key generator进行优化,优化后可以使用任意的长度的key,当使用填充模式为NoPadding的方式时,des的key必须为8个字节,aes的key必须是16,24,32个字节。
ECB:java默认的 加密模式,是指把明文分组之后,每个组进行并行加密,然后拼接,所以效率会比较高
CBC:采用的是将明文进行分组,后面分组的内容加密时,依赖前一个分组加密后的密文,也就是每次加密后的密文,后面的组进行加密的时候,都根据这个密文与后面的组的明文进行一起加密,这种模式下,需要一个initialization vector,简称IV,即初始化向量,这个初始化向量默认必须是16个字节。
以下是完整的代码展示
package codec.lesson07_AES;
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.SecureRandom;
import java.util.Base64;
/**
* @author micro.cloud.fly
* @date 2021/8/30 2:04 下午
* @desc 学习aes算法,aes是对称加密,比起非对称加密,有点是更快,因为只使用一个key
*/
public class Demo02 {
public static void main(String[] args) throws Exception {
//常规加密
String encryptedString = encrypt();
//常规解密
String decryptedString = decrypt(encryptedString);
System.out.println(decryptedString);
System.out.println();
//优化后的加密
String s = encryptOptimise();
//优化后的解密
String s1 = decryptOptimise(s);
System.out.println(s1);
}
/**
* 使用AES加密
*
* @return 加密后的内容
*/
public static String encrypt() throws Exception {
String algorithm = "AES";
String str = "hello聚合";
//cipher是密码的意思,这里是实例化一个cipher对象,
//这里ECB是指加密的模式,是java的默认加密模式,
// PKCS5Padding是指填充模式,也是java默认的填充方式,
Cipher cipher = Cipher.getInstance(algorithm);
//这里与des区别的地方是,des必须是8个字节,而aes必须是16,24,32个字节
/*在接口AESConstants中明确规定了长度
interface AESConstants {
int AES_BLOCK_SIZE = 16;
int[] AES_KEYSIZES = new int[]{16, 24, 32};
}*/
String key = "1234567812345678";
//实例化一个密钥,第一个参数是密钥,第二个参数是算法
SecretKeySpec secretKeySpec = new SecretKeySpec(key.getBytes(StandardCharsets.UTF_8), algorithm);
//cipher初始化,第一个参数是加解密模式,即,cipher是为了加密,还是用来解密,第二个参数是密钥对象
//默认的是ECB加密模式,如果使用的CBC模式的话,需要多传一个IV向量,即initialization vector
String iv = "12345678abcdabcd";
IvParameterSpec ivParameterSpec = new IvParameterSpec(iv.getBytes(StandardCharsets.UTF_8));
cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec);
//CBC模式下,必须有第三个参数IV
//cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec,ivParameterSpec);
byte[] bytes = cipher.doFinal(str.getBytes(StandardCharsets.UTF_8));
//得到的是字节数组,通常的做法是把此处的字节数组转为base64进行展示
byte[] encode = Base64.getEncoder().encode(bytes);
System.out.println(new String(encode, StandardCharsets.UTF_8));
return new String(encode);
}
private static String decrypt(String encryptedString) throws Exception {
String algorithm = "AES";
Cipher cipher = Cipher.getInstance(algorithm);
String key = "1234567812345678";//这里必须是8个字节
SecretKeySpec secretKeySpec = new SecretKeySpec(key.getBytes(StandardCharsets.UTF_8), algorithm);
cipher.init(Cipher.DECRYPT_MODE, secretKeySpec);
//传参过来的明文,是base64编码后的内容,所以,需要先进行base64解码
byte[] bytes = cipher.doFinal(Base64.getDecoder().decode(encryptedString.getBytes(StandardCharsets.UTF_8)));
return new String(bytes, StandardCharsets.UTF_8);
}
/**
* 优化后的aes加密算法,这是因为默认key的长度只能是16, 24, 32个字节,此处使用key工厂,可以传递任意字节的密钥
*
* @return 加密后的内容
*/
public static String encryptOptimise() throws Exception {
String algorithm = "AES";
String str = "hello聚合";
//cipher是密码的意思,这里是实例化一个cipher对象,
Cipher cipher = Cipher.getInstance(algorithm);
//实例化key工厂
KeyGenerator keyGenerator = KeyGenerator.getInstance(algorithm);
//初始化secureRandom,并指定生成key的算法
SecureRandom secureRandom = SecureRandom.getInstance("SHA1PRNG");
String key = "1234567812345";
//设置key工厂的种子
secureRandom.setSeed(key.getBytes(StandardCharsets.UTF_8));
//第一个参数是生成原始key的长度,第二个参数是SecureRandom对象
keyGenerator.init(128, secureRandom);
SecretKey secretKey = keyGenerator.generateKey();
//获取到新的密钥的字节数组
byte[] encodedKey = secretKey.getEncoded();
//实例化一个密钥,第一个参数是密钥,第二个参数是算法
SecretKeySpec secretKeySpec = new SecretKeySpec(encodedKey, algorithm);
//cipher初始化,第一个参数是加解密模式,即,cipher是为了加密,还是用来解密,第二个参数是密钥对象
cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec);
byte[] bytes = cipher.doFinal(str.getBytes(StandardCharsets.UTF_8));
//得到的是字节数组,通常的做法是把此处的字节数组转为base64进行展示
byte[] encode = Base64.getEncoder().encode(bytes);
System.out.println(new String(encode, StandardCharsets.UTF_8));
return new String(encode);
}
/**
* 优化后的aes解密算法,这是因为默认key的长度只能是16, 24, 32个字节,此处使用key工厂,可以传递任意字节的密钥
*
* @return 加密后的内容
*/
public static String decryptOptimise(String encryptStr) throws Exception {
String algorithm = "AES";
//cipher是密码的意思,这里是实例化一个cipher对象,
Cipher cipher = Cipher.getInstance(algorithm);
//实例化key工厂
KeyGenerator keyGenerator = KeyGenerator.getInstance(algorithm);
//初始化secureRandom,并指定生成key的算法
SecureRandom secureRandom = SecureRandom.getInstance("SHA1PRNG");
String key = "1234567812345";
//设置key工厂的种子
secureRandom.setSeed(key.getBytes(StandardCharsets.UTF_8));
//第一个参数是生成原始key的长度,第二个参数是SecureRandom对象
keyGenerator.init(128, secureRandom);
SecretKey secretKey = keyGenerator.generateKey();
//获取到新的密钥的字节数组
byte[] encodedKey = secretKey.getEncoded();
//实例化一个密钥,第一个参数是密钥,第二个参数是算法
SecretKeySpec secretKeySpec = new SecretKeySpec(encodedKey, algorithm);
//cipher初始化,第一个参数是加解密模式,即,cipher是为了加密,还是用来解密,第二个参数是密钥对象
cipher.init(Cipher.DECRYPT_MODE, secretKeySpec);
byte[] bytes = cipher.doFinal(Base64.getDecoder().decode(encryptStr.getBytes(StandardCharsets.UTF_8)));
return new String(bytes);
}
}
RSA 非对称加密算法
简介:
① 非对称加密算法又称现代加密算法。
② 非对称加密是计算机通信安全的基石,保证了加密数据不会被破解。
③ 与对称加密算法不同,非对称加密算法需要两个密钥:公开密钥(publickey) 和私有密(privatekey)
④ 公开密钥和私有密钥是一对
⑤ 如果用公开密钥对数据进行加密,只有用对应的私有密钥才能解密。
⑥ 如果用私有密钥对数据进行加密,只有用对应的公开密钥才能解密。
⑦ 因为加密和解密使用的是两个不同的密钥,所以这种算法叫作非对称加密算法。
原理示例
首先生成密钥对, 公钥为(5,14), 私钥为(11,14)
现在A希望将原文2发送给B
A使用公钥加密数据. 2的5次方mod 14 = 4 , 将密文4发送给B
B使用私钥解密数据. 4的11次方mod14 = 2, 得到原文2
特点
加密和解密使用不同的密钥
如果使用私钥加密, 只能使用公钥解密
如果使用公钥加密, 只能使用私钥解密
处理数据的速度较慢, 因为安全级别高
常见算法
- RSA
- ECC
数字签名
带数字签名的非对称加密算法
package codec.lesson08_RSA;
import org.apache.commons.io.FileUtils;
import javax.crypto.Cipher;
import java.io.File;
import java.nio.charset.StandardCharsets;
import java.security.*;
import java.security.spec.KeySpec;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Arrays;
import java.util.Base64;
/**
* @author micro.cloud.fly
* @date 2021/8/31 11:33 上午
* @desc RSA 加密的测试用例
*/
public class RSACodeCUtil {
public static String PUB_PATH;
public static String PRI_PATH;
public static void main(String[] args) throws Exception {
// writeKeyPair2LocalFile();
//这里需要格外注意的是,加密的数据长度不能超过117个字节,解密的数据的长度不能超过128个字节,如果超过了,需要分段进行处理
String str = "你好聚合数据你好聚合数据你好聚合jjjjj数据你好聚合数据你好聚合数据你好聚合数据你好聚合数据你好聚合数据你好聚合数据你好聚合数据";
// str = "anhui";
String encryptStr = encrypt(str);
// String encryptStr = encrypt("安徽");
System.out.println("加密后的数据是:" + encryptStr);
String decrypt = decrypt(encryptStr);
System.out.println("解密后的数据为:" + decrypt);
String sign = sign(str);
System.out.println("得到的签名数据是:" + sign);
boolean verify = verify(str, sign);
System.out.println("签名的验证结果是:" + verify);
}
/**
* 消息签名
*
* @param data 原始消息内容
* @return 消息签名
*/
public static String sign(String data) throws Exception {
Signature signature = Signature.getInstance("sha256withrsa");
signature.initSign(getPrivateKey());
signature.update(data.getBytes(StandardCharsets.UTF_8));
return Base64.getEncoder().encodeToString(signature.sign());
}
/**
* 验证签名
* @param data 原始数据
* @param sign 签名内容
* @return 签名是否验证成功
*/
public static boolean verify(String data, String sign) throws Exception {
//给过来的签名是base64编码过的,所以此处需要base64进行解码
byte[] bytes = Base64.getDecoder().decode(sign.getBytes(StandardCharsets.UTF_8));
Signature signature = Signature.getInstance("sha256withrsa");
signature.initVerify(getPublicKey());
signature.update(data.getBytes(StandardCharsets.UTF_8));
return signature.verify(bytes);
}
/**
* 加密
*
* @param input 待加密的字符串
* @return 加密内容
*/
public static String encrypt(String input) throws Exception {
Cipher cipher = Cipher.getInstance("RSA");
//第一个参数:加密模式
//第二个参数:使用公钥加密还是私钥加密,此处使用的是公钥
cipher.init(Cipher.ENCRYPT_MODE, getPublicKey());
byte[] inputArray = input.getBytes();
int inputLength = inputArray.length;
System.out.println("加密字节数:" + inputLength);
// 最大加密字节数,超出最大字节数需要分组加密
int MAX_ENCRYPT_BLOCK = 117;
// 标识
int offSet = 0;
byte[] resultBytes = {};
byte[] cache;
while (inputLength - offSet > 0) {
if (inputLength - offSet > MAX_ENCRYPT_BLOCK) {
cache = cipher.doFinal(inputArray, offSet, MAX_ENCRYPT_BLOCK);
offSet += MAX_ENCRYPT_BLOCK;
} else {
cache = cipher.doFinal(inputArray, offSet, inputLength - offSet);
offSet = inputLength;
}
resultBytes = Arrays.copyOf(resultBytes, resultBytes.length + cache.length);
System.arraycopy(cache, 0, resultBytes, resultBytes.length - cache.length, cache.length);
}
return Base64.getEncoder().encodeToString(resultBytes);
}
/**
* 解密
* @param encryptStr 被加密过的base64编码过的密文
* @return 原始内容
*/
public static String decrypt(String encryptStr) throws Exception {
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.DECRYPT_MODE, getPrivateKey());
byte[] decode = Base64.getDecoder().decode(encryptStr);
//设置每个块的容量是128个字节
int blockSize = 128;
int currentPosition = 0;
int totalSize = decode.length;
byte[] result = {};
byte[] bytes;
while (totalSize - currentPosition > 0) {
//如果总长度减去当前位置大于0,则一直循环下去
if (totalSize - currentPosition > blockSize) {
bytes = cipher.doFinal(decode, currentPosition, blockSize);
currentPosition += blockSize;
} else {
bytes = cipher.doFinal(decode, currentPosition, totalSize - currentPosition);
currentPosition = totalSize;
}
//result扩容
result = Arrays.copyOf(result, result.length + bytes.length);
//把每次读取的内容,写到扩容后的数组中
System.arraycopy(bytes, 0, result, result.length - bytes.length, bytes.length);
}
return new String(result, StandardCharsets.UTF_8);
}
static {
PUB_PATH = RSACodeCUtil.class.getClassLoader().getResource("rsa.pub").getPath();
PRI_PATH = RSACodeCUtil.class.getClassLoader().getResource("rsa.pri").getPath();
}
/**
* 生成密钥对,并且编码为base64,然后写入到文件
*
*/
public static void writeKeyPair2LocalFile() throws Exception {
//密钥对生成器对象
KeyPairGenerator keypairgenerator = KeyPairGenerator.getInstance("RSA");
//设置密钥对长度
keypairgenerator.initialize(1024);
//生成密钥对
KeyPair keyPair = keypairgenerator.generateKeyPair();
//获取私钥对象
PrivateKey aPrivate = keyPair.getPrivate();
//获取公钥对象
PublicKey aPublic = keyPair.getPublic();
//经对象转为base64编码
String encodePrivate = Base64.getEncoder().encodeToString(aPrivate.getEncoded());
String encodePublic = Base64.getEncoder().encodeToString(aPublic.getEncoded());
//写入到文件
FileUtils.writeStringToFile(new File(PUB_PATH), encodePublic, StandardCharsets.UTF_8);
FileUtils.writeStringToFile(new File(PRI_PATH), encodePrivate, StandardCharsets.UTF_8);
}
/**
* 获取公钥
*
* @return
* @throws Exception
*/
public static PublicKey getPublicKey() throws Exception {
//从文件中加载已经base64编码过的公钥
String base64EncodedPublicKey = FileUtils.readFileToString(new File(PUB_PATH), StandardCharsets.UTF_8);
//base64解码
byte[] decodeKey = Base64.getDecoder().decode(base64EncodedPublicKey.getBytes(StandardCharsets.UTF_8));
//对于公钥来说,规则是x509
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
KeySpec keySpec = new X509EncodedKeySpec(decodeKey);
return keyFactory.generatePublic(keySpec);
}
public static PrivateKey getPrivateKey() throws Exception {
//从文件中加载已经base64编码过的公钥
String base64EncodedPrivateKey = FileUtils.readFileToString(new File(PRI_PATH), StandardCharsets.UTF_8);
//base64解码
byte[] decodeKey = Base64.getDecoder().decode(base64EncodedPrivateKey.getBytes(StandardCharsets.UTF_8));
//对于私钥来说,规则是pkcs8
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
KeySpec keySpec = new PKCS8EncodedKeySpec(decodeKey);
return keyFactory.generatePrivate(keySpec);
}
}
```