java编码解码加密解密--md5、SHA-256、SHA-512、MAC、DES、AES
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);
}
}
还没有评论,来说两句吧...