java编码解码加密解密--md5、SHA-256、SHA-512、MAC、DES、AES

喜欢ヅ旅行 2022-09-09 06:23 1811阅读 0赞

md5

md5是一种散列算法,不可逆,是一种消息摘要算法,生成的字节数组的长度是128位,也就是等于16个字节,那么有的字节转化为字符之后,这些字符不一定是存在于ascii码之中,通常为了便于输出,我们会将每个字节转变为16进制字符串,每个16进制都是2个字符,所以md5转化之后的字符是32个字符。

这里有个技术点需要注意的是,在对每个字节进行转化为16进制的字符串的 时候,0-15这几个值的字节,转化为的字符串的长度都是1,所以需要在前面补0

jdk原生md5

  1. /**
  2. * jdk原生md5
  3. */
  4. public static void md5() throws Exception {
  5. String str = "hello聚合";
  6. String algorithm = "MD5";
  7. MessageDigest instance = MessageDigest.getInstance(algorithm);
  8. byte[] digest = instance.digest(str.getBytes(StandardCharsets.UTF_8));
  9. System.out.println(new String(digest));
  10. //如果直接输出的话,是乱码�G�s�.u�Iz�۲�
  11. //这是因为md5生成的消息摘要是128位,也就是等于16个字节,那么有的字节转化为字符之后,这些字符不一定是存在于ascii码之中的
  12. //通常为了便于输出,我们会将每个字节转变为16进制字符串,每个16进制都是2个字符,所以md5转化之后的字符是32个字符
  13. StringBuilder stringBuilder = new StringBuilder();
  14. for (byte b : digest) {
  15. //每个字节转与0xff(1111 1111)按位与,得到这个字节的补码
  16. String hex = Integer.toHexString(b & 0xff);
  17. //如果生成的16进制的字符的长度是1,那么需要在前面补0,比如
  18. //0,5,10,13,15的16进制分别是是0,5,a,d,f,长度只有1,所以需要前面补0
  19. if (hex.length() == 1) {
  20. hex = "0" + hex;
  21. }
  22. stringBuilder.append(hex);
  23. }
  24. System.out.println(stringBuilder);
  25. }
  26. }

使用commons-codec

需要引入jar包

  1. <dependency>
  2. <groupId>commons-codec</groupId>
  3. <artifactId>commons-codec</artifactId>
  4. <version>1.15</version>
  5. </dependency>
  6. /**
  7. * 使用commons-codec
  8. */
  9. public static void md5codec() {
  10. String str = "hello聚合";
  11. String encode = DigestUtils.md5Hex(str.getBytes(StandardCharsets.UTF_8));
  12. System.out.println(encode);
  13. }

全部代码

  1. package codec.md5;
  2. import org.apache.commons.codec.digest.DigestUtils;
  3. import java.nio.charset.StandardCharsets;
  4. import java.security.MessageDigest;
  5. /**
  6. * @author micro.cloud.fly
  7. * @date 2021/8/30 11:28 上午
  8. * @desc md5消息摘要算法学习笔记
  9. */
  10. public class Demo1 {
  11. public static void main(String[] args) throws Exception {
  12. md5();
  13. System.out.println();
  14. md5codec();
  15. }
  16. /**
  17. * jdk原生md5
  18. */
  19. public static void md5() throws Exception {
  20. String str = "hello聚合";
  21. String algorithm = "MD5";
  22. MessageDigest instance = MessageDigest.getInstance(algorithm);
  23. byte[] digest = instance.digest(str.getBytes(StandardCharsets.UTF_8));
  24. System.out.println(new String(digest));
  25. //如果直接输出的话,是乱码�G�s�.u�Iz�۲�
  26. //这是因为md5生成的消息摘要是128位,也就是等于16个字节,那么有的字节转化为字符之后,这些字符不一定是存在于ascii码之中的
  27. //通常为了便于输出,我们会将每个字节转变为16进制字符串,每个16进制都是2个字符,所以md5转化之后的字符是32个字符
  28. StringBuilder stringBuilder = new StringBuilder();
  29. for (byte b : digest) {
  30. //每个字节转与0xff(1111 1111)按位与,得到这个字节的补码
  31. String hex = Integer.toHexString(b & 0xff);
  32. //如果生成的16进制的字符的长度是1,那么需要在前面补0,比如
  33. //0,5,10,13,15的16进制分别是是0,5,a,d,f,长度只有1,所以需要前面补0
  34. if (hex.length() == 1) {
  35. hex = "0" + hex;
  36. }
  37. stringBuilder.append(hex);
  38. }
  39. System.out.println(stringBuilder);
  40. }
  41. /**
  42. * 使用commons-codec
  43. */
  44. public static void md5codec() {
  45. String str = "hello聚合";
  46. String encode = DigestUtils.md5Hex(str.getBytes(StandardCharsets.UTF_8));
  47. System.out.println(encode);
  48. }
  49. }

SHA-256

sha-256和md5一样,都是消息摘要算法,只不过是摘要后的长度是256位,也就是32个字节,同理,在转化为16进制的字符串之后,是64个字节,实现了md5之后,只要把算法algorithm改为SHA-256即可,以下是全部的代码

全部代码

  1. package codec.sha256;
  2. import org.apache.commons.codec.digest.DigestUtils;
  3. import java.nio.charset.StandardCharsets;
  4. import java.security.MessageDigest;
  5. /**
  6. * @author micro.cloud.fly
  7. * @date 2021/8/30 11:28 上午
  8. * @desc sha256消息摘要算法学习笔记
  9. */
  10. public class Demo {
  11. public static void main(String[] args) throws Exception {
  12. md5();
  13. System.out.println();
  14. md5codec();
  15. }
  16. /**
  17. * jdk原生md5
  18. */
  19. public static void md5() throws Exception {
  20. String str = "hello聚合";
  21. String algorithm = "SHA-256";
  22. MessageDigest instance = MessageDigest.getInstance(algorithm);
  23. byte[] digest = instance.digest(str.getBytes(StandardCharsets.UTF_8));
  24. System.out.println(new String(digest));
  25. //如果直接输出的话,是乱码�G�s�.u�Iz�۲�
  26. //这是因为md5生成的消息摘要是128位,也就是等于16个字节,那么有的字节转化为字符之后,这些字符不一定是存在于ascii码之中的
  27. //通常为了便于输出,我们会将每个字节转变为16进制字符串,每个16进制都是2个字符,所以md5转化之后的字符是32个字符
  28. StringBuilder stringBuilder = new StringBuilder();
  29. for (byte b : digest) {
  30. //每个字节转与0xff(1111 1111)按位与,得到这个字节的补码
  31. String hex = Integer.toHexString(b & 0xff);
  32. //如果生成的16进制的字符的长度是1,那么需要在前面补0,比如
  33. //0,5,10,13,15的16进制分别是是0,5,a,d,f,长度只有1,所以需要前面补0
  34. if (hex.length() == 1) {
  35. hex = "0" + hex;
  36. }
  37. stringBuilder.append(hex);
  38. }
  39. System.out.println(stringBuilder);
  40. }
  41. /**
  42. * 使用commons-codec
  43. */
  44. public static void md5codec() {
  45. String str = "hello聚合";
  46. String encode = DigestUtils.sha256Hex(str.getBytes(StandardCharsets.UTF_8));
  47. System.out.println(encode);
  48. }
  49. }

SHA-512

同sha-256原理一样,只要把algorithm算法名改为sha-512即可,以下是全部代码

  1. package codec.sha512;
  2. import org.apache.commons.codec.digest.DigestUtils;
  3. import java.nio.charset.StandardCharsets;
  4. import java.security.MessageDigest;
  5. /**
  6. * @author micro.cloud.fly
  7. * @date 2021/8/30 11:28 上午
  8. * @desc sha512消息摘要算法学习笔记
  9. */
  10. public class Demo {
  11. public static void main(String[] args) throws Exception {
  12. md5();
  13. System.out.println();
  14. md5codec();
  15. }
  16. /**
  17. * jdk原生
  18. */
  19. public static void md5() throws Exception {
  20. String str = "hello聚合";
  21. String algorithm = "SHA-512";
  22. MessageDigest instance = MessageDigest.getInstance(algorithm);
  23. byte[] digest = instance.digest(str.getBytes(StandardCharsets.UTF_8));
  24. System.out.println(new String(digest));
  25. //如果直接输出的话,是乱码�G�s�.u�Iz�۲�
  26. //这是因为md5生成的消息摘要是128位,也就是等于16个字节,那么有的字节转化为字符之后,这些字符不一定是存在于ascii码之中的
  27. //通常为了便于输出,我们会将每个字节转变为16进制字符串,每个16进制都是2个字符,所以md5转化之后的字符是32个字符
  28. StringBuilder stringBuilder = new StringBuilder();
  29. for (byte b : digest) {
  30. //每个字节转与0xff(1111 1111)按位与,得到这个字节的补码
  31. String hex = Integer.toHexString(b & 0xff);
  32. //如果生成的16进制的字符的长度是1,那么需要在前面补0,比如
  33. //0,5,10,13,15的16进制分别是是0,5,a,d,f,长度只有1,所以需要前面补0
  34. if (hex.length() == 1) {
  35. hex = "0" + hex;
  36. }
  37. stringBuilder.append(hex);
  38. }
  39. System.out.println(stringBuilder);
  40. }
  41. /**
  42. * 使用commons-codec
  43. */
  44. public static void md5codec() {
  45. String str = "hello聚合";
  46. String encode = DigestUtils.sha512Hex(str.getBytes(StandardCharsets.UTF_8));
  47. System.out.println(encode);
  48. }
  49. }

MAC

mac也是一种消息摘要,同md5、SHA256算法不同的是,它在进行消息摘要的时候,需要一个key,相同于密钥,mac算法有macMD5、macSHA256、macSHA512等多种,在实现的时候,也是只需要改一个算法名称即可,以下是实现的全部代码

  1. package codec.lesson05_mac;
  2. import org.apache.commons.codec.digest.DigestUtils;
  3. import org.apache.commons.codec.digest.HmacAlgorithms;
  4. import org.apache.commons.codec.digest.HmacUtils;
  5. import javax.crypto.Mac;
  6. import javax.crypto.spec.SecretKeySpec;
  7. import java.nio.charset.StandardCharsets;
  8. /**
  9. * @author micro.cloud.fly
  10. * @date 2021/8/30 11:28 上午
  11. * @desc mac消息摘要算法学习笔记
  12. */
  13. public class Demo1 {
  14. public static void main(String[] args) throws Exception {
  15. mac();
  16. System.out.println();
  17. maccodec();
  18. }
  19. /**
  20. * jdk原生md5
  21. */
  22. public static void mac() throws Exception {
  23. String str = "hello聚合";
  24. String key = "123";
  25. String algorithm = "HmacMD5";
  26. //使用其他算法,只需要改一下名字即可
  27. algorithm = "HmacSHA256";
  28. algorithm = "HmacSHA512";
  29. //实例化mac对象
  30. Mac mac = Mac.getInstance(algorithm);
  31. //实例化key对象
  32. SecretKeySpec secretKeySpec = new SecretKeySpec(key.getBytes(StandardCharsets.UTF_8), algorithm);
  33. //mac对象初始化
  34. mac.init(secretKeySpec);
  35. byte[] bytes = mac.doFinal(str.getBytes(StandardCharsets.UTF_8));
  36. StringBuilder stringBuilder = new StringBuilder();
  37. for (byte b : bytes) {
  38. //每个字节转与0xff(1111 1111)按位与,得到这个字节的补码
  39. String hex = Integer.toHexString(b & 0xff);
  40. //如果生成的16进制的字符的长度是1,那么需要在前面补0,比如
  41. //0,5,10,13,15的16进制分别是是0,5,a,d,f,长度只有1,所以需要前面补0
  42. if (hex.length() == 1) {
  43. hex = "0" + hex;
  44. }
  45. stringBuilder.append(hex);
  46. }
  47. System.out.println(stringBuilder);
  48. }
  49. /**
  50. * 使用commons-codec
  51. */
  52. public static void maccodec() {
  53. String str = "hello聚合";
  54. String key = "123";
  55. System.out.println("hmacMD5:"+new HmacUtils(HmacAlgorithms.HMAC_MD5, key.getBytes(StandardCharsets.UTF_8)).hmacHex(str.getBytes(StandardCharsets.UTF_8)));
  56. System.out.println("hmacSHA256:"+new HmacUtils(HmacAlgorithms.HMAC_SHA_256, key.getBytes(StandardCharsets.UTF_8)).hmacHex(str.getBytes(StandardCharsets.UTF_8)));
  57. System.out.println("hmacSHA512:"+new HmacUtils(HmacAlgorithms.HMAC_SHA_512, key.getBytes(StandardCharsets.UTF_8)).hmacHex(str.getBytes(StandardCharsets.UTF_8)));
  58. }
  59. }

DES

des是一种对称加密算法,相对于非对称加密算法来说,更快,现在des已经过时,被AES给取代了,需要注意的是,des算法的时候,key必须是8个字节,不然会报错。以下是使用des加密解密的全部代码。

  1. package codec;
  2. import javax.crypto.Cipher;
  3. import javax.crypto.spec.SecretKeySpec;
  4. import java.nio.charset.StandardCharsets;
  5. import java.util.Base64;
  6. /**
  7. * @author micro.cloud.fly
  8. * @date 2021/8/30 2:04 下午
  9. * @desc 学习des算法,des是对称加密,比起非对称加密,有点是更快,因为只使用一个key
  10. */
  11. public class lesson06_DES {
  12. public static void main(String[] args) throws Exception {
  13. String encryptedString = encrypt();
  14. String decryptedString = decrypt(encryptedString);
  15. System.out.println(decryptedString);
  16. }
  17. private static String decrypt(String encryptedString) throws Exception {
  18. String algorithm = "DES";
  19. Cipher cipher = Cipher.getInstance(algorithm);
  20. String key = "12345678";//这里必须是8个字节
  21. SecretKeySpec secretKeySpec = new SecretKeySpec(key.getBytes(StandardCharsets.UTF_8), algorithm);
  22. cipher.init(Cipher.DECRYPT_MODE, secretKeySpec);
  23. //传参过来的明文,是base64编码后的内容,所以,需要先进行base64解码
  24. byte[] bytes = cipher.doFinal(Base64.getDecoder().decode(encryptedString.getBytes(StandardCharsets.UTF_8)));
  25. return new String(bytes, StandardCharsets.UTF_8);
  26. }
  27. /**
  28. * 使用DES加密
  29. *
  30. * @return 加密后的内容
  31. */
  32. public static String encrypt() throws Exception {
  33. String algorithm = "DES";
  34. String str = "hello聚合";
  35. //cipher是密码的意思,这里是实例化一个cipher对象,
  36. //这里ECB是指加密的模式,是java的默认加密模式,PKCS7Padding是指填充模式,加密模式和填充模式也可以不进行指定
  37. Cipher cipher = Cipher.getInstance("DES/ECB/PKCS5Padding");
  38. String key = "12345678";//这里必须是8个字节
  39. //实例化一个密钥,第一个参数是密钥,第二个参数是算法
  40. SecretKeySpec secretKeySpec = new SecretKeySpec(key.getBytes(StandardCharsets.UTF_8), algorithm);
  41. //cipher初始化,第一个参数是加解密模式,即,cipher是为了加密,还是用来解密,第二个参数是密钥对象
  42. cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec);
  43. byte[] bytes = cipher.doFinal(str.getBytes(StandardCharsets.UTF_8));
  44. //得到的是字节数组,通常的做法是把此处的字节数组转为base64进行展示
  45. byte[] encode = Base64.getEncoder().encode(bytes);
  46. System.out.println(new String(encode, StandardCharsets.UTF_8));
  47. return new String(encode);
  48. }
  49. }

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个字节。
以下是完整的代码展示

  1. package codec.lesson07_AES;
  2. import javax.crypto.Cipher;
  3. import javax.crypto.KeyGenerator;
  4. import javax.crypto.SecretKey;
  5. import javax.crypto.spec.IvParameterSpec;
  6. import javax.crypto.spec.SecretKeySpec;
  7. import java.nio.charset.StandardCharsets;
  8. import java.security.SecureRandom;
  9. import java.util.Base64;
  10. /**
  11. * @author micro.cloud.fly
  12. * @date 2021/8/30 2:04 下午
  13. * @desc 学习aes算法,aes是对称加密,比起非对称加密,有点是更快,因为只使用一个key
  14. */
  15. public class Demo02 {
  16. public static void main(String[] args) throws Exception {
  17. //常规加密
  18. String encryptedString = encrypt();
  19. //常规解密
  20. String decryptedString = decrypt(encryptedString);
  21. System.out.println(decryptedString);
  22. System.out.println();
  23. //优化后的加密
  24. String s = encryptOptimise();
  25. //优化后的解密
  26. String s1 = decryptOptimise(s);
  27. System.out.println(s1);
  28. }
  29. /**
  30. * 使用AES加密
  31. *
  32. * @return 加密后的内容
  33. */
  34. public static String encrypt() throws Exception {
  35. String algorithm = "AES";
  36. String str = "hello聚合";
  37. //cipher是密码的意思,这里是实例化一个cipher对象,
  38. //这里ECB是指加密的模式,是java的默认加密模式,
  39. // PKCS5Padding是指填充模式,也是java默认的填充方式,
  40. Cipher cipher = Cipher.getInstance(algorithm);
  41. //这里与des区别的地方是,des必须是8个字节,而aes必须是16,24,32个字节
  42. /*在接口AESConstants中明确规定了长度
  43. interface AESConstants {
  44. int AES_BLOCK_SIZE = 16;
  45. int[] AES_KEYSIZES = new int[]{16, 24, 32};
  46. }*/
  47. String key = "1234567812345678";
  48. //实例化一个密钥,第一个参数是密钥,第二个参数是算法
  49. SecretKeySpec secretKeySpec = new SecretKeySpec(key.getBytes(StandardCharsets.UTF_8), algorithm);
  50. //cipher初始化,第一个参数是加解密模式,即,cipher是为了加密,还是用来解密,第二个参数是密钥对象
  51. //默认的是ECB加密模式,如果使用的CBC模式的话,需要多传一个IV向量,即initialization vector
  52. String iv = "12345678abcdabcd";
  53. IvParameterSpec ivParameterSpec = new IvParameterSpec(iv.getBytes(StandardCharsets.UTF_8));
  54. cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec);
  55. //CBC模式下,必须有第三个参数IV
  56. //cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec,ivParameterSpec);
  57. byte[] bytes = cipher.doFinal(str.getBytes(StandardCharsets.UTF_8));
  58. //得到的是字节数组,通常的做法是把此处的字节数组转为base64进行展示
  59. byte[] encode = Base64.getEncoder().encode(bytes);
  60. System.out.println(new String(encode, StandardCharsets.UTF_8));
  61. return new String(encode);
  62. }
  63. private static String decrypt(String encryptedString) throws Exception {
  64. String algorithm = "AES";
  65. Cipher cipher = Cipher.getInstance(algorithm);
  66. String key = "1234567812345678";//这里必须是8个字节
  67. SecretKeySpec secretKeySpec = new SecretKeySpec(key.getBytes(StandardCharsets.UTF_8), algorithm);
  68. cipher.init(Cipher.DECRYPT_MODE, secretKeySpec);
  69. //传参过来的明文,是base64编码后的内容,所以,需要先进行base64解码
  70. byte[] bytes = cipher.doFinal(Base64.getDecoder().decode(encryptedString.getBytes(StandardCharsets.UTF_8)));
  71. return new String(bytes, StandardCharsets.UTF_8);
  72. }
  73. /**
  74. * 优化后的aes加密算法,这是因为默认key的长度只能是16, 24, 32个字节,此处使用key工厂,可以传递任意字节的密钥
  75. *
  76. * @return 加密后的内容
  77. */
  78. public static String encryptOptimise() throws Exception {
  79. String algorithm = "AES";
  80. String str = "hello聚合";
  81. //cipher是密码的意思,这里是实例化一个cipher对象,
  82. Cipher cipher = Cipher.getInstance(algorithm);
  83. //实例化key工厂
  84. KeyGenerator keyGenerator = KeyGenerator.getInstance(algorithm);
  85. //初始化secureRandom,并指定生成key的算法
  86. SecureRandom secureRandom = SecureRandom.getInstance("SHA1PRNG");
  87. String key = "1234567812345";
  88. //设置key工厂的种子
  89. secureRandom.setSeed(key.getBytes(StandardCharsets.UTF_8));
  90. //第一个参数是生成原始key的长度,第二个参数是SecureRandom对象
  91. keyGenerator.init(128, secureRandom);
  92. SecretKey secretKey = keyGenerator.generateKey();
  93. //获取到新的密钥的字节数组
  94. byte[] encodedKey = secretKey.getEncoded();
  95. //实例化一个密钥,第一个参数是密钥,第二个参数是算法
  96. SecretKeySpec secretKeySpec = new SecretKeySpec(encodedKey, algorithm);
  97. //cipher初始化,第一个参数是加解密模式,即,cipher是为了加密,还是用来解密,第二个参数是密钥对象
  98. cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec);
  99. byte[] bytes = cipher.doFinal(str.getBytes(StandardCharsets.UTF_8));
  100. //得到的是字节数组,通常的做法是把此处的字节数组转为base64进行展示
  101. byte[] encode = Base64.getEncoder().encode(bytes);
  102. System.out.println(new String(encode, StandardCharsets.UTF_8));
  103. return new String(encode);
  104. }
  105. /**
  106. * 优化后的aes解密算法,这是因为默认key的长度只能是16, 24, 32个字节,此处使用key工厂,可以传递任意字节的密钥
  107. *
  108. * @return 加密后的内容
  109. */
  110. public static String decryptOptimise(String encryptStr) throws Exception {
  111. String algorithm = "AES";
  112. //cipher是密码的意思,这里是实例化一个cipher对象,
  113. Cipher cipher = Cipher.getInstance(algorithm);
  114. //实例化key工厂
  115. KeyGenerator keyGenerator = KeyGenerator.getInstance(algorithm);
  116. //初始化secureRandom,并指定生成key的算法
  117. SecureRandom secureRandom = SecureRandom.getInstance("SHA1PRNG");
  118. String key = "1234567812345";
  119. //设置key工厂的种子
  120. secureRandom.setSeed(key.getBytes(StandardCharsets.UTF_8));
  121. //第一个参数是生成原始key的长度,第二个参数是SecureRandom对象
  122. keyGenerator.init(128, secureRandom);
  123. SecretKey secretKey = keyGenerator.generateKey();
  124. //获取到新的密钥的字节数组
  125. byte[] encodedKey = secretKey.getEncoded();
  126. //实例化一个密钥,第一个参数是密钥,第二个参数是算法
  127. SecretKeySpec secretKeySpec = new SecretKeySpec(encodedKey, algorithm);
  128. //cipher初始化,第一个参数是加解密模式,即,cipher是为了加密,还是用来解密,第二个参数是密钥对象
  129. cipher.init(Cipher.DECRYPT_MODE, secretKeySpec);
  130. byte[] bytes = cipher.doFinal(Base64.getDecoder().decode(encryptStr.getBytes(StandardCharsets.UTF_8)));
  131. return new String(bytes);
  132. }
  133. }

发表评论

表情:
评论列表 (有 0 条评论,1811人围观)

还没有评论,来说两句吧...

相关阅读