【Java】数据加密

目录

  • 数据加密
    • 介绍
    • 使用场景
    • 密码学历史
      • 古代密码学
        • 凯撒密码
          • 例子
          • 特点
        • 维吉尼亚密码
          • 原理
          • 例子
          • 特点
      • 现代密码学
        • 介绍
  • 现代密码学的加密算法分类
    • 哈希算法
      • 优点
      • 缺点
      • 代码示例【封装写法】
    • 对称加密算法
      • 对称加密算法的加密过程
      • 解密过程
      • 对称加密算法的优点:
      • 对称加密算法的缺点:
      • 代码示例【封装写法】
    • 非对称密钥加密
      • RSA算法
      • 非对称加密算法的特点
      • 代码示例
    • 数字签名算法
      • 详细解释:
      • 优点
      • 缺点
      • 代码示例
        • 解释
    • 密钥交换算法
      • 密钥交换算法d额两个主要目标
      • 密钥交换算法方式
        • Diffie-Hellman密钥交换算法
          • 具体过程
        • 椭圆曲线Diffie-Hellman密钥交换算法(ECDH)
      • 密钥交换算法的优点
      • 密钥交换算法的局限性:
      • 代码示例
        • Diffie-Hellman算法
    • 公钥证书
      • 公钥证书内容
      • 使用公钥证书进行身份验证和加密通信的过程
      • 优点
      • 代码示例

数据加密

介绍

  • 数据加密指的是将数据转换为密文,使得非授权人员无法理解和访问数据的过程。
  • 数据加密主要通过使用算法和密钥对原始数据进行转换,从而使其变得不可读或难以理解。
  • 只有拥有正确密钥的授权人员才能解密和访问数据。

使用场景

  • 包括保护个人隐私
  • 保护商业机密
  • 确保数据的完整性和安全传输等

密码学历史

密码学是一门研究如何保护信息安全的学科。它的历史可以追溯到几千年前的古代。

古代密码学

古代人们已经开始使用各种加密技术来保护重要信息。以下是一些古代的密码学方法:

  • 凯撒密码(Caesar cipher):最早记录于古罗马时期,通过将字母按照一定规律进行替换,实现简单的加密。
  • 维吉尼亚密码(Vigenère cipher):16世纪时由法国人布利斯·德·维吉尼亚提出的多表密码,通过使用不同的密码表对明文进行加密。
凯撒密码
  • 凯撒密码(Caesar cipher)是最早的已知密码算法之一,发明于古罗马时代。它是一种简单的替换密码,通过将字母按照一定规律进行替换来实现加密。
  • 具体来说,凯撒密码采用了一种位移(shift)的方法。加密时,将明文中的每个字母按照一个固定的位移值进行移动,生成密文。解密时,将密文中的每个字母反向移动相同的位移值,就可以恢复出原始的明文。
例子
  • 将明文 “HELLO” 使用凯撒密码进行加密,假设位移值为3,则将字母按照顺序位移3位得到密文 “KHOOR”。
  • 解密时将密文字母反向位移3位,则可以得到原始的明文 “HELLO”。

上面是移位法,还有单表替换法和多表替换法。

  • 单表替换:原文和密文使用的是同一张表
    • 例如:abcde ------> sdfvs
    • 原文cdd----->密文:fvv
  • 多表替换:表示有多张表,原文和密文进行对比
    • 表单1:abcde-sdfvs、表单2:abcde-tyfgs、表单3:abcde-bdfhr
    • 原文:cdd
    • 密钥:332
    • 密文:fhg
特点
  • 凯撒密码的算法非常简单,容易理解和实现。
  • 然而,它的安全性非常低,因为密钥空间很小,只有26种可能的位移值,可以通过简单的穷举攻击破解。
  • 因此,凯撒密码在现代密码学中并不常用,但它具有教育和历史意义,是了解密码学基础的重要起点。
维吉尼亚密码

维吉尼亚密码(Vigenère cipher)是一种多表替换密码,由布鲁托·维吉尼亚(Blaise de Vigenère)在16世纪发明。相比凯撒密码,维吉尼亚密码更加复杂和安全。

原理
  • 维吉尼亚密码使用了一个关键词(key)作为密钥,用于确定每个字母的位移值。
  • 关键词中的每个字母对应一个数值,将这个数值与明文中的字母相加(取模26),得到密文中对应字母的值。
  • 如果关键词长度小于明文长度,关键词将循环使用直到加密完整的明文。
例子

例如,使用关键词 “KEY” 对明文 “HELLO” 进行加密。

  • 首先将关键词扩展到与明文相同的长度,得到 “KEYKE”。
  • 然后将明文的每个字母与关键词相应位置的字母相加,并对26取模运算,得到密文 “RIJVS”。
  • 解密时,使用相同的关键词和相反的运算,将密文中的字母与关键词对应位置的字母相减,并对26取模运算,得到原始的明文。
特点
  • 维吉尼亚密码相对于凯撒密码更加安全,因为每个字母的位移值不再恒定,而是根据关键词的每个字母决定。
  • 这使得破解更加困难,需要更复杂的分析方法。
  • 然而,维吉尼亚密码仍然可以通过一些密码分析技术进行破解,特别是在关键词较短的情况下。
  • 在现代密码学中,维吉尼亚密码通常作为基础算法进行改进或组合使用。

现代密码学

介绍

现代密码学的发展主要集中在20世纪。以下是一些重要的里程碑:

  • Enigma密码机:在第一次世界大战和第二次世界大战期间,纳粹德国使用的一种电机械密码机,被认为是最复杂和最具挑战性的密码系统之一。
  • 数据加密标准(Data Encryption Standard,DES):在20世纪70年代中期,美国国家标准局(NBS)委托IBM开发的一种对称密钥加密算法。
  • 公钥密码学:在1970年代末和1980年代初,由美国的Whitfield Diffie和Martin Hellman提出了公钥密码学概念,为密码学领域带来了重大突破。公钥密码学使用一对密钥,其中一个是公开的(公钥),另一个是私密的(私钥)。

现代密码学涉及了许多复杂的算法和协议,如RSA、AES、SHA等。随着计算机技术的发展,密码学在信息安全领域扮演着非常重要的角色,保护着个人隐私和敏感数据的安全。

现代密码学的加密算法分类

现代密码学中常用的加密算法主要包括:

  1. 哈希算法:将任意长度的数据映射为固定长度的哈希值,不可逆的算法,常见的有MD5、SHA-1、SHA-256等。
  2. 对称加密算法:使用同一个密钥进行加密和解密的算法,常见的有DES、3DES、AES等。
  3. 非对称加密算法:使用一对密钥进行加密和解密的算法,常见的有RSA、Diffie-Hellman、ECC等。
  4. 数字签名算法:使用非对称加密算法和哈希算法进行数字签名和验证,常见的有RSA、DSA等。
  5. 密钥交换算法:用于安全地交换密钥的算法,常见的有Diffie-Hellman、ECDH等。
  6. 公钥证书:用于身份验证和加密通信的数字证书,常见的有X.509证书。

这些加密算法可以应用于各种场景,如数据加密、身份验证、数字签名、安全通信等。

哈希算法

哈希算法(Hash algorithm)是一种将任意长度的数据映射为固定长度哈希值的算法。

优点

  1. 固定长度输出:哈希算法的输出通常为固定长度的哈希值。无论输入数据的大小是多少,哈希值的长度都是固定的。
  2. 不可逆性:给定一个哈希值,很难通过逆推计算出原始的输入数据。哈希算法是单向的,只能从输入计算出哈希值,而不能从哈希值还原出输入。
  3. 高效性:哈希算法的计算速度通常很快,对于任意长度的输入数据,都能够在短时间内计算出对应的哈希值。
  4. 碰撞概率很低:碰撞指的是两个不同的输入数据通过哈希算法得到了相同的哈希值。好的哈希算法应该具有非常低的碰撞概率,即使输入数据稍有变化,得到的哈希值也应该是完全不同的。

缺点

  1. 不可逆性:虽然哈希算法的不可逆性是一种优点,可以保护数据的安全性,但有时候在特定场景下需要逆向操作。例如,对于密码找回功能,用户忘记密码时,无法通过哈希值逆向计算出原始密码。
  2. 碰撞攻击:虽然优秀的哈希算法具有非常低的碰撞概率,但并非完全不可能发生碰撞。碰撞是指两个不同的输入数据通过哈希算法得到了相同的哈希值。虽然发生碰撞的概率非常低,但在密码学中,攻击者可能会专门构造数据,以达到碰撞的目的,从而破坏哈希算法的安全性。
  3. 预映射攻击:预映射攻击是指攻击者在预先计算出一些已知输入数据的哈希值,然后将这些哈希值与目标哈希值进行比较,以获得目标输入数据的可能值。这种攻击方法可以绕过对抗碰撞攻击的措施。
  4. 依赖输入数据:哈希算法的输出结果依赖于输入数据。即使输入数据发生了微小的变化,得到的哈希值也会完全不同。这可能会导致在某些情况下,进行数据比较或查找时出现困难。

代码示例【封装写法】

package com.kgc.main;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

/**
 * @author: zjl
 * @datetime: 2024/6/1
 * @desc: 复兴Java,我辈义不容辞
 */
public class HashEncryptionDemo {

    // 哈希算法
    public enum HashAlgorithm {
        MD5, SHA1, SHA256
    }

    // 哈希加密
    public static String hash(String plaintext, HashAlgorithm algorithm) throws NoSuchAlgorithmException {
        // 创建哈希算法的实例
        MessageDigest md = MessageDigest.getInstance(algorithm.toString());

        // 计算哈希值
        byte[] hashedBytes = md.digest(plaintext.getBytes(StandardCharsets.UTF_8));

        // 将哈希值转换为十六进制字符串
        StringBuilder sb = new StringBuilder();
        for (byte b : hashedBytes) {
            sb.append(String.format("%02x", b));
        }

        return sb.toString();
    }

    public static void main(String[] args) {
        try {
            String plaintext = "123456";
            HashAlgorithm algorithm = HashAlgorithm.SHA256;

            // 哈希加密
            String hashedText = hash(plaintext, algorithm);
            System.out.println("Hashed Text: " + hashedText);
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
    }
}

解密
一些简单的密码完全可以直接破解:https://www.cmd5.com/
在这里插入图片描述

对称加密算法

  • 对称加密算法是一种使用相同的密钥对明文进行加密和解密的算法。
  • 具体而言,对称加密算法通过一种数学运算将明文转换为密文,然后通过相同的数学运算将密文转换回明文。
  • 这种密钥对称的特性使得对称加密算法在数据传输和存储过程中非常高效。

对称加密算法的加密过程

  1. 首先,选取一个密钥。对称加密算法使用的密钥长度通常为128位或256位,较长的密钥长度会增加加密的安全性。
  2. 将明文划分为合适的块,并应用算法将每个块转换为相应的密文块。对称加密算法通常使用的算法有DES、AES等。
  3. 密文块通过网络或存储介质传输或保存。

解密过程

与加密过程正好相反:

  1. 接收到密文块后,使用相同的密钥和相反的算法将密文块转换为相应的明文块。
  2. 将明文块组合起来,就可以得到完整的明文。

对称加密算法的优点:

  1. 加密解密速度快。由于使用相同的密钥进行加密解密,所以运算速度很快。
  2. 实现简单。对称加密算法的实现较为简单,计算机硬件支持较好。

对称加密算法的缺点:

  1. 密钥管理困难。加密和解密的双方需要共享密钥,并且需要保证密钥的安全性,如果密钥泄露,所有的信息都会暴露。
  2. 不适合大规模网络通信。在大规模网络通信中,由于需要共享密钥,所以密钥的分发和管理会非常复杂。
  3. 缺乏不可抵御的密码。对称加密算法的密钥是对其安全性的关键,如果密钥被破解,那么加密也就没有任何意义了。

代码示例【封装写法】

package com.kgc.main;
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import java.security.Key;
import java.util.Base64;
/**
 * @author: zjl
 * @datetime: 2024/6/1
 * @desc: 复兴Java,我辈义不容辞
 */
public class SymmetricEncryptionDemo {

    // 加密算法
    public enum EncryptionAlgorithm {
        AES, DES, DESede
    }

    // 加密密码
    public static String encrypt(String plaintext, String password, EncryptionAlgorithm algorithm) throws Exception {
        // 创建加密算法的实例
        Cipher cipher = Cipher.getInstance(algorithm.toString());

        // 创建密钥对象
        Key key = new SecretKeySpec(password.getBytes(), algorithm.toString());

        // 设置为加密模式
        cipher.init(Cipher.ENCRYPT_MODE, key);

        // 进行加密计算
        byte[] encryptedBytes = cipher.doFinal(plaintext.getBytes());

        // 使用Base64进行编码
        return Base64.getEncoder().encodeToString(encryptedBytes);
    }

    // 解密密码
    public static String decrypt(String encryptedText, String password, EncryptionAlgorithm algorithm) throws Exception {
        // 创建解密算法的实例
        Cipher cipher = Cipher.getInstance(algorithm.toString());

        // 创建密钥对象
        Key key = new SecretKeySpec(password.getBytes(), algorithm.toString());

        // 设置为解密模式
        cipher.init(Cipher.DECRYPT_MODE, key);

        // 进行解密计算
        byte[] encryptedBytes = Base64.getDecoder().decode(encryptedText);
        byte[] decryptedBytes = cipher.doFinal(encryptedBytes);

        // 将解密后的字节数组转换为字符串
        return new String(decryptedBytes);
    }

    public static void main(String[] args) {
        try {
            String plaintext = "syhy_2YH";
            String password = "ThisIsTheEncryptionKey";
            EncryptionAlgorithm algorithm = EncryptionAlgorithm.AES;

            // 加密
            String encryptedText = encrypt(plaintext, password, algorithm);
            System.out.println("Encrypted Text: " + encryptedText);

            // 解密
            String decryptedText = decrypt(encryptedText, password, algorithm);
            System.out.println("Decrypted Text: " + decryptedText);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

非对称密钥加密

  • 非对称加密算法使用一对密钥来进行加密和解密操作,其中一个密钥称为公钥,另一个密钥称为私钥。
  • 公钥可以公开,而私钥必须保密。
  • 使用公钥加密的数据只能使用私钥解密,而使用私钥加密的数据只能使用公钥解密。

RSA算法

非对称加密算法的一个常见例子是RSA算法。RSA算法的加密过程如下:

  1. 选择两个不同的质数p和q,并计算出它们的乘积n。
  2. 计算n的欧拉函数φ(n) = (p-1)(q-1)。
  3. 选择一个与φ(n)互质的整数e(通常为65537),作为公钥的一部分。
  4. 计算e的模φ(n)的逆元d,作为私钥的一部分。
  5. 公钥是(n, e),私钥是(n, d)。
  6. 加密时,将明文m使用公式c = m^e mod n进行加密。
  7. 解密时,将密文c使用公式m = c^d mod n进行解密,得到原始的明文。

非对称加密算法的特点

  1. 安全性好:由于公钥是公开的,攻击者无法通过公钥推导出私钥,从而保证了数据的安全性。
  2. 适合密钥交换:非对称加密算法可以用于安全地交换密钥。例如,Alice可以使用Bob的公钥加密一条消息,只有Bob能够使用自己的私钥解密该消息。
  3. 加密速度较慢:相对于对称加密算法,非对称加密算法的加密速度较慢。因此,通常在对称加密算法中使用非对称加密算法来交换密钥,然后使用对称加密算法进行快速加密。
  4. 密钥长度较长:为了保证足够的安全性,非对称加密算法的密钥长度通常需要比对称加密算法的密钥长度长。
  5. 尽管非对称加密算法的加密速度较慢和密钥长度较长,但其安全性优势使得它在许多安全通信和加密应用中得到了广泛应用。

代码示例

package com.kgc.main;
import javax.crypto.*;
import java.security.*;
import java.util.Base64;

/**
 * @author: zjl
 * @datetime: 2024/6/1
 * @desc: 复兴Java,我辈义不容辞
 */
public class AsymmetricEncryptionDemo {

    private static final String RSA = "RSA";
    private static final String DSA = "DSA";
    private static final String EC = "EC";
    private static final int KEY_SIZE = 2048;

    public static void main(String[] args) throws Exception {
        String plainText = "syhy_2YH";
        // 生成密钥对
        KeyPair keyPair = generateKeyPair(RSA);
        // 使用公钥加密
        byte[] encryptedData = encrypt(plainText, keyPair.getPublic(), RSA);
        //一般情况下公钥和私钥会先计算出来然后保存起来


        // 使用私钥解密
        String decryptedText = decrypt(encryptedData, keyPair.getPrivate(), RSA);
        System.out.println("Encrypted Data: " + Base64.getEncoder().encodeToString(encryptedData));
        System.out.println("Decrypted Text: " + decryptedText);
    }

    public static KeyPair generateKeyPair(String algorithm) throws NoSuchAlgorithmException {
        KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(algorithm);
        keyPairGenerator.initialize(KEY_SIZE);
        return keyPairGenerator.generateKeyPair();
    }

    public static byte[] encrypt(String plainText, PublicKey publicKey, String algorithm)
            throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException, IllegalBlockSizeException, BadPaddingException {
        Cipher cipher = Cipher.getInstance(algorithm);
        cipher.init(Cipher.ENCRYPT_MODE, publicKey);
        return cipher.doFinal(plainText.getBytes());
    }

    public static String decrypt(byte[] encryptedData, PrivateKey privateKey, String algorithm)
            throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException {
        Cipher cipher = Cipher.getInstance(algorithm);
        cipher.init(Cipher.DECRYPT_MODE, privateKey);
        byte[] decryptedData = cipher.doFinal(encryptedData);
        return new String(decryptedData);
    }
}

数字签名算法

  • 数字签名是一种用于验证和保护数据完整性以及身份认证的加密技术。
  • 它涉及使用私钥对数据进行加密来创建数字签名,并使用相应的公钥对数字签名进行验证。

详细解释:

  1. 非对称密钥算法:数字签名使用非对称密钥算法,也称为公钥密码算法。这些算法使用两个密钥:一个私钥用于签名生成,另一个公钥用于验证签名。

  2. 加密和解密过程:数字签名首先对原始数据进行加密。加密过程使用私钥,它将原始数据的哈希值加密生成数字签名。数字签名本质上是原始数据的加密摘要。

  3. 验证过程:验证数字签名涉及使用相应的公钥和原始数据来解密签名。解密后的结果应与原始数据的哈希值相匹配。如果匹配成功,则表示数字签名是有效的,并且数据的完整性未被篡改。

  4. 私钥的保密性:私钥用于生成数字签名,并且必须保持机密,只有拥有私钥的实体才能对数据进行签名。私钥的机密性很重要,否则如果私钥泄露,攻击者可以伪造数字签名来进行欺骗。

  5. 公钥的分发:公钥用于验证数字签名,可以公开分发给需要验证数据完整性的人。任何人都可以使用公钥来验证数字签名,以确保数据的完整性。

  6. 数据完整性和身份验证:数字签名提供了数据完整性和身份验证。通过验证数字签名,接收方可以确信数据在传输过程中未被篡改,并且可以确定发送方的身份。

  7. 常用的数字签名算法:常见的数字签名算法包括RSA (Rivest-Shamir-Adleman)、DSA (Digital Signature Algorithm)和ECDSA (Elliptic Curve Digital Signature Algorithm)等。

优点

  1. 数据完整性:数字签名可以确保数据在传输或存储过程中未被篡改。接收方可以使用公钥来验证数字签名,如果签名验证成功,则可以确定数据的完整性。

  2. 身份认证:数字签名可以验证数据发送方的身份。通过验证数字签名,接收方可以确信数据来自于指定的发送方。

  3. 防止抵赖:数字签名可以防止发送方在数据被接收方验证之后否认其发送的数据。由于数字签名是基于私钥生成的,发送方无法否认自己生成的数字签名。

  4. 安全性:使用非对称密钥算法进行数字签名可以提供更高的安全性。私钥的保密性保证了数字签名的真实性,而公钥的公开性使得任何人都可以验证签名。

缺点

  1. 复杂性:数字签名的实现相对复杂,涉及到使用私钥加密和公钥验证的过程。正确地生成和验证数字签名需要具备相关的加密算法和密钥管理技术。
  2. 密钥管理:数字签名需要使用配对的公钥和私钥进行加密和验证。因此,密钥的生成、分发、存储和更新需要进行有效的管理,以防止私钥泄露和公钥被篡改。
  3. 性能开销:与对称密钥加密相比,非对称密钥算法具有较大的计算和存储开销。生成和验证数字签名可能需要更多的计算资源和存储空间。

代码示例

package com.kgc.main;
import java.security.*;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import javax.crypto.Cipher;
/**
 * @author: zjl
 * @datetime: 2024/6/1
 * @desc: 复兴Java,我辈义不容辞
 */
public class DigitalSignatureDemo {

    public static void main(String[] args) {
        try {
            String message = "syhy_2YH";
            KeyPair keyPair = generateKeyPair();
            // 使用私钥对消息进行签名
            byte[] signature = sign(message.getBytes(), keyPair.getPrivate());
            // 使用公钥对签名进行验证
            boolean isValid = verify(message.getBytes(), signature, keyPair.getPublic());
            System.out.println("Signature is valid: " + isValid);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    // 生成RSA密钥对
    public static KeyPair generateKeyPair() throws Exception {
        KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
        keyGen.initialize(2048);
        return keyGen.generateKeyPair();
    }

    // 使用私钥对消息进行签名
    public static byte[] sign(byte[] message, PrivateKey privateKey) throws Exception {
        Signature signature = Signature.getInstance("SHA256withRSA");
        signature.initSign(privateKey);
        signature.update(message);
        return signature.sign();
    }

    // 使用公钥对签名进行验证
    public static boolean verify(byte[] message, byte[] signature, PublicKey publicKey) throws Exception {
        Signature verifier = Signature.getInstance("SHA256withRSA");
        verifier.initVerify(publicKey);
        verifier
上一篇:python多种方式 保留小数点位数(附Demo)-2. round函数


下一篇:Elasticsearch 认证模拟题 - 5