查看原文
其他

少年,Java 中的加密与签名知道否?

超级小豆丁 SpringForAll社区 2021-05-27
点击上方☝SpringForAll社区 轻松关注!
及时获取有趣有料的技术文章

本文来源:http://www.mydlq.club/article/57/


. 一、加密简介

. 1、背景

. 2、目的

. 3、加密类型

. 二、Java 中的加密方法示例

. 1、Maven 引入 Hutool 工具依赖

. 2、对称加密示例

. 3、非对称加密示例

. 4、签名示例

. 5、摘要加密示例


环境配置:

  • JDK 版本:1.8

参考地址:

  • 百度百科-加密算法

  • 示例项目 Github 地址:https://github.com/my-dlq/blog-example/tree/master/java/java-encrypt-example

一、加密简介

1、背景

数据加密的基本过程就是对原来为明文的文件或数据按某种算法进行处理,使其成为不可读的一段代码为“密文”,使其只能在输入相应的密钥之后才能显示出原容,通过这样的途径来达到保护数据不被非法人窃取、阅读的目的。该过程的逆过程为解密,即将该编码信息转化为其原来数据的过程。

2、目的

使用密码学可以达到以下目的:

  • 保密性: 防止用户的标识或数据被读取。

  • 数据完整性: 防止数据被更改。

  • 身份验证: 确保数据发自特定的一方。

3、加密类型

加密技术通常分为两大类“对称加密”和“非对称加密”。

  • 对称式加密: 对称式加密就是加密和解密使用同一个密钥。

  • 非对称式加密: 非对称式加密就是加密和解密所使用的不是同一个密钥,通常有两个密钥,称为“公钥”和“私钥”,私钥自己拥有,不能给别人,公钥公开。根据应用的不同,我们可以选择使用不同的密钥加密。

二、Java 中的加密方法示例

1、Maven 引入 Hutool 工具依赖

这里主要是使用 Hutool 工具,该工具封装了 Java 大多数加密方式,使用起来非常方便。

  1. <?xml version="1.0" encoding="UTF-8"?>

  2. <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

  3. xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">

  4. <modelVersion>4.0.0</modelVersion>


  5. <groupId>com.aspire</groupId>

  6. <artifactId>java-encrypt</artifactId>

  7. <version>0.0.1</version>

  8. <name>java-encrypt</name>

  9. <description>java encrypt demo</description>


  10. <properties>

  11. <java.version>1.8</java.version>

  12. </properties>


  13. <dependencies>

  14. <dependency>

  15. <groupId>cn.hutool</groupId>

  16. <artifactId>hutool-all</artifactId>

  17. <version>5.1.0</version>

  18. </dependency>

  19. </dependencies>


  20. </project>

2、对称加密示例

(1)、简介

对称加密(也叫私钥加密)指加密和解密使用相同密钥的加密算法。有时又叫传统密码算法,就是加密密钥能够从解密密钥中推算出来,同时解密密钥也可以从加密密钥中推算出来。而在大多数的对称算法中,加密密钥和解密密钥是相同的,所以也称这种加密算法为秘密密钥算法或单密钥算法。它要求发送方和接收方在安全通信之前,商定一个密钥。对称算法的安全性依赖于密钥,泄漏密钥就意味着任何人都可以对他们发送或接收的消息解密,所以密钥的保密性对通信的安全性至关重要。

(2)、示例

  1. import cn.hutool.crypto.SecureUtil;

  2. import cn.hutool.crypto.symmetric.SymmetricAlgorithm;

  3. import cn.hutool.crypto.symmetric.SymmetricCrypto;

  4. import java.io.UnsupportedEncodingException;


  5. /**

  6. * 对称加密

  7. */

  8. public class SymmetricalEncryptionExample {


  9. /**

  10. * AES 加密、解密

  11. *

  12. * @param data 加密数据

  13. */

  14. public static void aesEncrypt(String data) {

  15. // 随机生成密钥

  16. byte[] key = SecureUtil.generateKey(SymmetricAlgorithm.AES.getValue()).getEncoded();

  17. // 创建 AES 对象

  18. SymmetricCrypto aes = new SymmetricCrypto(SymmetricAlgorithm.AES, key);

  19. // 加密

  20. byte[] encrypt = aes.encrypt(data);

  21. // 解密

  22. byte[] decrypt = aes.decrypt(encrypt);

  23. System.out.println("AES 解密的数据:" + new String(decrypt));

  24. }


  25. /**

  26. * DES 加密、解密

  27. *

  28. * @param data 加密数据

  29. */

  30. public static void desEncrypt(String data) {

  31. // 随机生成密钥

  32. byte[] key = SecureUtil.generateKey(SymmetricAlgorithm.DES.getValue()).getEncoded();

  33. // 创建 DES 对象

  34. SymmetricCrypto des = new SymmetricCrypto(SymmetricAlgorithm.DES, key);

  35. // 加密

  36. byte[] encrypt = des.encrypt(data);

  37. // 解密

  38. byte[] decrypt = des.decrypt(encrypt);

  39. System.out.println("DES 解密的数据:" + new String(decrypt));

  40. }


  41. /**

  42. * DESede 加密、解密

  43. *

  44. * @param data 加密数据

  45. */

  46. public static void desedeEncrypt(String data) {

  47. // 随机生成密钥

  48. byte[] key = SecureUtil.generateKey(SymmetricAlgorithm.DESede.getValue()).getEncoded();

  49. // 创建 DESede 对象

  50. SymmetricCrypto desede = new SymmetricCrypto(SymmetricAlgorithm.DESede, key);

  51. // 加密

  52. byte[] encrypt = desede.encrypt(data);

  53. // 解密

  54. byte[] decrypt = desede.decrypt(encrypt);

  55. System.out.println("DESede 解密的数据:" + new String(decrypt));

  56. }


  57. /**

  58. * Blowfish 加密、解密

  59. *

  60. * @param data 加密数据

  61. */

  62. public static void blowfishEncrypt(String data) {

  63. // 随机生成密钥

  64. byte[] key = SecureUtil.generateKey(SymmetricAlgorithm.Blowfish.getValue()).getEncoded();

  65. // 创建 Blowfish 对象

  66. SymmetricCrypto blowfish = new SymmetricCrypto(SymmetricAlgorithm.Blowfish, key);

  67. // 加密

  68. byte[] encrypt = blowfish.encrypt(data);

  69. // 解密

  70. byte[] decrypt = blowfish.decrypt(encrypt);

  71. System.out.println("Blowfish 解密的数据:" + new String(decrypt));

  72. }


  73. /**

  74. * RC2 加密、解密

  75. *

  76. * @param data 加密数据

  77. */

  78. public static void rc2Encrypt(String data) {

  79. // 随机生成密钥

  80. byte[] key = SecureUtil.generateKey(SymmetricAlgorithm.RC2.getValue()).getEncoded();

  81. // 创建 RC2 对象

  82. SymmetricCrypto rc2 = new SymmetricCrypto(SymmetricAlgorithm.RC2, key);

  83. // 加密

  84. byte[] encrypt = rc2.encrypt(data);

  85. // 解密

  86. byte[] decrypt = rc2.decrypt(encrypt);

  87. System.out.println("RC2 解密的数据:" + new String(decrypt));

  88. }


  89. /**

  90. * ARCFOUR 加密、解密

  91. *

  92. * @param data 加密数据

  93. */

  94. public static void arcfourEncrypt(String data) {

  95. // 随机生成密钥

  96. byte[] key = SecureUtil.generateKey(SymmetricAlgorithm.ARCFOUR.getValue()).getEncoded();

  97. // 创建 ARCFOUR 对象

  98. SymmetricCrypto arcfour = new SymmetricCrypto(SymmetricAlgorithm.ARCFOUR, key);

  99. // 加密

  100. byte[] encrypt = arcfour.encrypt(data);

  101. // 解密

  102. byte[] decrypt = arcfour.decrypt(encrypt);

  103. System.out.println("ARCFOUR 解密的数据:" + new String(decrypt));

  104. }


  105. public static void main(String[] args) throws UnsupportedEncodingException {

  106. /* 设置要加密的内容 */

  107. String data = "测试数据";

  108. /* AES加密 */

  109. aesEncrypt(data);

  110. /* DES加密 */

  111. desEncrypt(data);

  112. /* RC2加密 */

  113. rc2Encrypt(data);

  114. /* Blowfish加密 */

  115. blowfishEncrypt(data);

  116. /* DESede加密 */

  117. desedeEncrypt(data);

  118. /* ARCFOUR加密 */

  119. arcfourEncrypt(data);

  120. }


  121. }

3、非对称加密示例

(1)、简介

非对称式加密就是加密和解密所使用的不是同一个密钥,通常有两个密钥,称为“公钥”和“私钥”,它们两个必需配对使用,否则不能打开加密文件。这里的“公钥”是指可以对外公布的,“私钥”则不能,只能由持有人一个人知道。它的优越性就在这里,因为对称式的加密方法如果是在网络上传输加密文件就很难不把密钥告诉对方,不管用什么方法都有可能被别窃听到。而非对称式的加密方法有两个密钥,且其中的“公钥”是可以公开的,也就不怕别人知道,收件人解密时只要用自己的私钥即可以,这样就很好地避免了密钥的传输安全性问题。

(2)、示例

  1. import cn.hutool.core.codec.Base64;

  2. import cn.hutool.crypto.SecureUtil;

  3. import cn.hutool.crypto.asymmetric.KeyType;

  4. import cn.hutool.crypto.asymmetric.RSA;

  5. import java.io.UnsupportedEncodingException;

  6. import java.security.KeyPair;

  7. import java.security.PrivateKey;

  8. import java.security.PublicKey;


  9. /**

  10. * 非对称加密

  11. */

  12. public class AsymmetricEncryptionExample {


  13. /**

  14. * RSA 公钥加密,私钥解密

  15. *

  16. * @param data 加密数据

  17. * @param privateKeyString 私钥字符串

  18. * @param publicKeyString 公钥字符串

  19. * @throws UnsupportedEncodingException

  20. */

  21. public static void rsaEncrypt1(String data, String privateKeyString, String publicKeyString) throws UnsupportedEncodingException {

  22. // 将公、私钥字符串转换成公、私钥对象

  23. PrivateKey privateKey = SecureUtil.generatePrivateKey("RSA", Base64.decode(privateKeyString));

  24. PublicKey publicKey = SecureUtil.generatePublicKey("RSA", Base64.decode(publicKeyString));

  25. // 获取字符串byte数组

  26. byte[] bytes = data.getBytes("UTF-8");

  27. // 创建 RSA 对象

  28. RSA rsa = new RSA();

  29. // 设置公钥,然后执行公钥加密

  30. rsa.setPublicKey(publicKey);

  31. byte[] encrypt = rsa.encrypt(bytes, KeyType.PublicKey);

  32. // 设置私钥,然后执行私钥解密

  33. rsa.setPrivateKey(privateKey);

  34. byte[] decrypt = rsa.decrypt(encrypt, KeyType.PrivateKey);

  35. // 输出解密的内容

  36. System.out.println("公钥加密,私钥解密,解密内容:" + new String(decrypt));

  37. }


  38. /**

  39. * RSA 私钥加密,公钥解密

  40. *

  41. * @param data 加密数据

  42. * @param privateKeyString 私钥字符串

  43. * @param publicKeyString 公钥字符串

  44. * @throws UnsupportedEncodingException

  45. */

  46. public static void rsaEncrypt2(String data, String privateKeyString, String publicKeyString) throws UnsupportedEncodingException {

  47. // 将公、私钥字符串转换成公、私钥对象

  48. PrivateKey privateKey = SecureUtil.generatePrivateKey("RSA", Base64.decode(privateKeyString));

  49. PublicKey publicKey = SecureUtil.generatePublicKey("RSA", Base64.decode(publicKeyString));

  50. // 获取字符串byte数组

  51. byte[] bytes = data.getBytes("UTF-8");

  52. // 创建 RSA 对象

  53. RSA rsa = new RSA();

  54. // 设置私钥,然后执行私钥加密

  55. rsa.setPrivateKey(privateKey);

  56. byte[] encrypt = rsa.encrypt(bytes, KeyType.PrivateKey);

  57. // 设置公钥,然后执行公钥解密

  58. rsa.setPublicKey(publicKey);

  59. byte[] decrypt = rsa.decrypt(encrypt, KeyType.PublicKey);

  60. // 输出解密的内容

  61. System.out.println("私钥加密,公钥解密,解密内容:" + new String(decrypt));

  62. }


  63. public static void main(String[] args) throws UnsupportedEncodingException {

  64. /* 生成钥匙对 */

  65. KeyPair pair = SecureUtil.generateKeyPair("RSA");

  66. PrivateKey privateKey = pair.getPrivate();

  67. PublicKey publicKey = pair.getPublic();

  68. // 将公钥私钥转换成 Base64 字符串

  69. String privateKeyString = Base64.encode(privateKey.getEncoded());

  70. String publicKeyString = Base64.encode(publicKey.getEncoded());

  71. /* 设置要加密的内容 */

  72. String data = "测试数据";

  73. /* RSA 公钥加密,私钥解密 */

  74. rsaEncrypt1(data, privateKeyString, publicKeyString);

  75. /* RSA 私钥加密,公钥解密 */

  76. rsaEncrypt2(data, privateKeyString, publicKeyString);

  77. }


  78. }

4、签名示例

(1)、简介

在两个人进行通信,需要确保收到的内容不被劫取篡改,这里就用到签名来确保发消息的人确实是指定的人。

比如说,A 准备给 B 发送一段信息,A 先将消息进行散列运算,得到消息摘要 MD5,然后用自己的私匙对摘要进行加密,然后发送给 B,B 得到消息内容和加密的信息摘要,再用 A 的公匙和发送的内容来验证这段加密摘要(如果验证成功,则证明是 A 发送的消息),如果验证成则说明数据没有被篡改过。(信息摘要是根据对消息内容进行散列运算得到一个唯一的标识码,除非数据相同,否则几乎不可能由其他数据运算得到此标识码,所以它是唯一的,只要信息内容有一点改变,再次进行散列运算时得到标识码就会改变,所以可以对解密后的信息进行散列运算得到摘要然后和发送过来的信息摘要进行对比判断数据是否被修改)。

(2)、示例

  1. import cn.hutool.core.codec.Base64;

  2. import cn.hutool.crypto.SecureUtil;

  3. import cn.hutool.crypto.asymmetric.Sign;

  4. import cn.hutool.crypto.asymmetric.SignAlgorithm;

  5. import java.security.KeyPair;

  6. import java.security.PrivateKey;

  7. import java.security.PublicKey;


  8. /**

  9. * 签名

  10. */

  11. public class SignExample {


  12. /**

  13. * RSA 私钥签名

  14. *

  15. * @param data 签名数据

  16. * @param privateKeyString 私钥字符串

  17. */

  18. public static String rsaSign(String data, String privateKeyString) {

  19. // 将私钥字符串转换成私钥对象

  20. PrivateKey privateKey = SecureUtil.generatePrivateKey("RSA", Base64.decode(privateKeyString));

  21. // 设置签名对象以及加密算法

  22. Sign sign = SecureUtil.sign(SignAlgorithm.MD5withRSA);

  23. // 设置私钥,然后执行签名

  24. sign.setPrivateKey(privateKey);

  25. byte[] bytes = sign.sign(data.getBytes());

  26. // 将签名转换为 Base64 字符串,然后返回

  27. return Base64.encode(bytes);

  28. }


  29. /**

  30. * RSA 公钥验签

  31. *

  32. * @param data 签名数据

  33. * @param publicKeyString 公钥

  34. * @param signString 签名

  35. * @return 是否验证成功

  36. */

  37. public static boolean rsaSignVerify(String data, String publicKeyString, String signString) {

  38. // 将公钥字符串转换成公钥对象

  39. PublicKey publicKey = SecureUtil.generatePublicKey("RSA", Base64.decode(publicKeyString));

  40. // 设置签名对象以及加密算法

  41. Sign sign = SecureUtil.sign(SignAlgorithm.MD5withRSA);

  42. // 将签名字符串转换成 byte 数组

  43. byte[] bytes = Base64.decode(signString);

  44. // 设置公钥,然后执行验签

  45. sign.setPublicKey(publicKey);

  46. return sign.verify(data.getBytes(), bytes);

  47. }


  48. public static void main(String[] args) {

  49. /* 生成钥匙对 */

  50. KeyPair pair = SecureUtil.generateKeyPair("RSA");

  51. PrivateKey privateKey = pair.getPrivate();

  52. PublicKey publicKey = pair.getPublic();

  53. // 将公钥私钥转换成 Base64 字符串

  54. String privateKeyString = Base64.encode(privateKey.getEncoded());

  55. String publicKeyString = Base64.encode(publicKey.getEncoded());

  56. /* 设置要加密的内容 */

  57. String data = "测试数据";

  58. /* RSA 私钥签名,公钥验签 */

  59. String sign = rsaSign(data, privateKeyString);

  60. boolean verify = rsaSignVerify(data, publicKeyString, sign);

  61. System.out.println("签名验证结果:" + verify);

  62. }


  63. }

5、摘要加密示例

(1)、简介

摘要算法是一种能产生特殊输出格式的算法,这种算法的特点是无论用户输入什么长度的原始数据,经过计算后输出的密文都是固定长度的,这种算法的原理是根据一定的运算规则对原数据进行某种形式的提取,这种提取就是摘要,被摘要的数据内容与原数据有密切联系,只要原数据稍有改变,输出的“摘要”便完全不同,因此,基于这种原理的算法便能对数据完整性提供较为健全的保障。

但是,由于输出的密文是提取原数据经过处理的定长值,所以它已经不能还原为原数据,即消息摘要算法是不可逆的,理论上无法通过反向运算取得原数据内容,因此它通常只能被用来做数据完整性验证。

(2)、示例

  1. import cn.hutool.crypto.digest.DigestUtil;


  2. /**

  3. * 摘要加密

  4. */

  5. public class DigesterEncryption {


  6. /**

  7. * MD2 加密

  8. * @param data 加密内容

  9. */

  10. public static void md2Encrypt(String data) {

  11. String md2String = DigestUtil.md5Hex(data);

  12. System.out.println("MD2加密后的字符串:" + md2String);

  13. }


  14. /**

  15. * MD5 加密

  16. * @param data 加密内容

  17. */

  18. public static void md5Encrypt(String data) {

  19. String md5String = DigestUtil.md5Hex(data);

  20. System.out.println("MD5加密后的字符串:" + md5String);

  21. }


  22. /**

  23. * SHA-1 加密

  24. * @param data 加密内容

  25. */

  26. public static void sha1Encrypt(String data) {

  27. String sha1String = DigestUtil.sha1Hex(data);

  28. System.out.println("SHA1加密后的字符串:" + sha1String);

  29. }


  30. /**

  31. * SHA-256 加密

  32. * @param data 加密内容

  33. */

  34. public static void sha256Encrypt(String data) {

  35. String sha256String = DigestUtil.sha256Hex(data);

  36. System.out.println("SHA256加密后的字符串:" + sha256String);

  37. }


  38. public static void main(String[] args) {

  39. /* 设置要加密的内容 */

  40. String data = "测试数据";

  41. /* MD2加密 */

  42. md2Encrypt(data);

  43. /* MD5加密 */

  44. md5Encrypt(data);

  45. /* SHA1加密 */

  46. sha1Encrypt(data);

  47. /* SHA256加密 */

  48. sha256Encrypt(data);

  49. }


  50. }




 SpringBoot 中优雅处理参数验证,到底发生了什么?

● Java人应该知道的SpringBoot For Kafka (上)

● Java人应该知道的SpringBoot For Kafka (下)

● SpringBoot 多种读取配置文件中参数的方式

● SpringBoot 操作 ElasticSearch 详解

● SpringBoot 使用 Caffeine 本地缓存

● Github推出了GitHub CLI

● (很全面)SpringBoot 集成 Apollo 配置中心

● 你知道如何成为一名靠谱的架构师不?

● Tomcat 在 SpringBoot 中是如何启动的?

● SpringBoot 深度调优,让你的项目飞起来!

● 8种经常被忽视的SQL错误用法,你有没有踩过坑?

● Java面试应该知道之深入理解Java的接口和抽象类


    您可能也对以下帖子感兴趣

    文章有问题?点此查看未经处理的缓存