加密与安全_探索对称加密算法

文章目录


概述

对称加密算法是一种加密技术,使用相同的密钥来进行加密和解密数据。在这种算法中,发送方使用密钥将明文(未加密的数据)转换为密文(加密的数据),而接收方使用相同的密钥将密文还原为明文。

对称加密算法的安全性依赖于密钥的保密性,因为任何持有相同密钥的人都能够解密数据。

常见的对称加密算法包括AES(高级加密标准)和DES(数据加密标准)。虽然对称加密算法在性能上通常比非对称加密算法更高效,但在密钥管理和分发方面存在挑战。

通俗来讲,可以这么理解: 对称加密算法就像是一把钥匙可以打开一个锁。在这里,你有一个钥匙(密钥),用它来锁住(加密)你的信息,然后你可以用同样的钥匙(密钥)来解锁(解密)它。这意味着发送方和接收方都使用相同的密钥来加密和解密信息。


常用的对称加密算法

常用的对称加密算法包括:

  1. AES(Advanced Encryption Standard):这是目前最常用的对称加密算法之一。它使用128、192或256位密钥来加密数据,并已被广泛采用于许多安全应用中。

  2. DES(Data Encryption Standard):虽然已被AES所取代,但仍然在一些遗留系统中使用。DES使用56位密钥对数据进行加密。

  3. 3DES(Triple Data Encryption Standard):3DES是DES的改进版本,它对数据应用三次DES算法,提高了安全性。但由于计算成本高昂,现在已经不太常用。

  4. Blowfish:这是一个可扩展的对称加密算法,可以使用变长密钥,从32位到448位。它曾经很流行,但由于一些安全性方面的考虑,现在使用较少。

  5. RC4(Rivest Cipher 4):尽管曾被广泛使用,但由于存在一些严重的安全漏洞,现在已经不建议使用。


从程序的角度看,所谓加密,就是这样一个函数,它接收密码和明文,然后输出密文:

java 复制代码
secret = encrypt(key, message);

而解密则相反,它接收密码和密文,然后输出明文:

java 复制代码
plain = decrypt(key, secret);  

从程序的角度看,所谓加密,就是这样一个函数,它接收密码和明文,然后输出密文:

java 复制代码
secret = encrypt(key, message);

而解密则相反,它接收密码和密文,然后输出明文:

java 复制代码
plain = decrypt(key, secret);  

加密和解密确实可以被视为类似上面的函数,但实际上,它们可能会更为复杂一些,尤其是在实现对称加密算法时。
在使用对称加密算法时,这两个函数通常被称为加密函数和解密函数。例如,在使用AES算法时,加密函数会接收密钥(key)和明文(message),然后输出密文(ciphertext)。而解密函数则接收密钥(key)和密文(ciphertext),然后输出明文(message)

算法 密钥长度 工作模式 填充模式
AES 128/192/256 ECB/CBC/PCBC/CTR/... NoPadding/PKCS5Padding/PKCS7Padding/...
DES 56/64 ECB/CBC/PCBC/CTR/... NoPadding/PKCS5Padding/...
... ... ... ...

密钥长度直接决定加密强度,而工作模式和填充模式可以看成是对称加密算法的参数和格式选择。


这些对称加密算法在不同的场景中都有各自的优缺点,选择合适的算法取决于安全性需求、性能和应用环境。AES通常被认为是最安全和高效的对称加密算法之一,因此在许多情况下被首选使用


AES

AES算法是目前应用最广泛的加密算法。

ECB模式

先用ECB模式加密并解密. 代码如下

java 复制代码
package com.artisan.securityalgjava.aes;

import java.security.*;
import java.util.Base64;

import javax.crypto.*;
import javax.crypto.spec.*;

/**
 * @author 小工匠
 * @version 1.0
 * @mark: show me the code , change the world
 */
public class AesECBExample {

    public static void main(String[] args) throws Exception {
        // 原文:
        String message = "Hello, Artisan!";
        System.out.println("Message: " + message);

        // 128位密钥 = 16 bytes Key:
        byte[] key = "1234567890abcdef".getBytes("UTF-8");

        // 加密:
        byte[] data = message.getBytes("UTF-8");
        byte[] encrypted = encrypt(key, data);
        System.out.println("Encrypted: " + Base64.getEncoder().encodeToString(encrypted));

        // 解密:
        byte[] decrypted = decrypt(key, encrypted);
        System.out.println("Decrypted: " + new String(decrypted, "UTF-8"));
    }

    // 加密方法
    public static byte[] encrypt(byte[] key, byte[] input) throws GeneralSecurityException {
        // 创建加密对象
        Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
        // 创建密钥规范
        SecretKey keySpec = new SecretKeySpec(key, "AES");
        // 初始化加密对象
        cipher.init(Cipher.ENCRYPT_MODE, keySpec);
        // 执行加密操作
        return cipher.doFinal(input);
    }

    // 解密方法
    public static byte[] decrypt(byte[] key, byte[] input) throws GeneralSecurityException {
        // 创建解密对象
        Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
        // 创建密钥规范
        SecretKey keySpec = new SecretKeySpec(key, "AES");
        // 初始化解密对象
        cipher.init(Cipher.DECRYPT_MODE, keySpec);
        // 执行解密操作
        return cipher.doFinal(input);
    }
}
    

ECB模式是最简单的AES加密模式,它只需要一个固定长度的密钥,固定的明文会生成固定的密文,这种一对一的加密方式会导致安全性降低

CBC模式 (推荐)

java 复制代码
package com.artisan.securityalgjava.aes;

import java.security.*;
import java.util.Base64;

import javax.crypto.*;
import javax.crypto.spec.*;

/**
 * @author 小工匠
 * @version 1.0
 * @mark: show me the code , change the world
 * @desc: AES CBC模式加解密示例
 */
public class AesCBCExample {

    public static void main(String[] args) throws Exception {
        // 原文:
        String message = "Hello, Artisan!";
        System.out.println("Message: " + message);
        // 256位密钥 = 32 bytes Key:
        byte[] key = "1234567890abcdef1234567890abcdef".getBytes("UTF-8");
        // 加密:
        byte[] data = message.getBytes("UTF-8");
        byte[] encrypted = encrypt(key, data);
        System.out.println("Encrypted: " + Base64.getEncoder().encodeToString(encrypted));
        // 解密:
        byte[] decrypted = decrypt(key, encrypted);
        System.out.println("Decrypted: " + new String(decrypted, "UTF-8"));
    }

    /**
     * 加密
     * @param key
     * @param input
     * @return
     * @throws GeneralSecurityException
     */
    public static byte[] encrypt(byte[] key, byte[] input) throws GeneralSecurityException {
        // 创建AES加密器
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        // 创建密钥规范
        SecretKeySpec keySpec = new SecretKeySpec(key, "AES");
        // CBC模式需要生成一个16 bytes的初始化向量
        SecureRandom sr = SecureRandom.getInstanceStrong();
        byte[] iv = sr.generateSeed(16);
        IvParameterSpec ivps = new IvParameterSpec(iv);
        // 初始化加密器
        cipher.init(Cipher.ENCRYPT_MODE, keySpec, ivps);
        // 执行加密操作
        byte[] data = cipher.doFinal(input);
        // IV不需要保密,把IV和密文一起返回
        return join(iv, data);
    }

    /**
     * 解密
     * @param key
     * @param input
     * @return
     * @throws GeneralSecurityException
     */
    public static byte[] decrypt(byte[] key, byte[] input) throws GeneralSecurityException {
        // 把input分割成IV和密文
        byte[] iv = new byte[16];
        byte[] data = new byte[input.length - 16];
        System.arraycopy(input, 0, iv, 0, 16);
        System.arraycopy(input, 16, data, 0, data.length);
        // 创建AES解密器
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        // 创建密钥规范
        SecretKeySpec keySpec = new SecretKeySpec(key, "AES");
        IvParameterSpec ivps = new IvParameterSpec(iv);
        // 初始化解密器
        cipher.init(Cipher.DECRYPT_MODE, keySpec, ivps);
        // 执行解密操作
        return cipher.doFinal(data);
    }

    /**
     * 拼接两个字节数组
     * @param bs1
     * @param bs2
     * @return
     */
    public static byte[] join(byte[] bs1, byte[] bs2) {
        byte[] r = new byte[bs1.length + bs2.length];
        System.arraycopy(bs1, 0, r, 0, bs1.length);
        System.arraycopy(bs2, 0, r, bs1.length, bs2.length);
        return r;
    }

}

CBC模式下,需要一个随机生成的16字节IV参数,必须使用SecureRandom生成。因为多了一个IvParameterSpec实例,因此,初始化方法需要调用Cipher的一个重载方法并传入IvParameterSpec

观察输出,可以发现每次生成的IV不同,密文也不同, 如下图所示



代码实现了AES CBC模式的加密和解密功能。在加密过程中,生成了一个16字节的初始化向量(IV),在解密时使用了这个IV来确保安全性。

因此,CBC模式,它需要一个随机数作为IV参数,这样对于同一份明文,每次生成的密文都不同 .


ECB VS CBC

AES有几种不同的模式,其中最常见的两种是ECB(Electronic Codebook)模式和CBC(Cipher Block Chaining)模式。

  1. ECB模式(电子密码本模式)
  • 特点
    • 将明文分成块,每个块使用相同的密钥进行加密。
    • 相同的明文块在加密后会得到相同的密文块。
    • 每个块的加密是独立的,不受其他块的影响。
  • 优点
    • 简单,容易并行化处理。
    • 适用于对称加密需求较简单的场景。
  • 缺点
    • 容易受到重放攻击的影响,因为相同的明文块会产生相同的密文块,没有隐藏明文块之间的关系。
    • 不适合加密大量数据或需要保护隐私的数据,因为无法隐藏明文块之间的模式。
  1. CBC模式(密码块链接模式)
  • 特点
    • 在加密前,会对明文块进行异或运算,并与前一个密文块进行混合,然后再加密。
    • 需要一个初始化向量(IV)来增加随机性,防止重放攻击。
    • 密文块的加密依赖于前一个密文块,因此密文块之间存在依赖关系。
  • 优点
    • 对于相同的明文块,使用不同的IV会产生不同的密文块,增加了安全性。
    • 可以加密大量数据,并且可以隐藏明文块之间的模式。
  • 缺点
    • 加密速度较ECB模式慢,因为需要依赖前一个密文块。
    • 不太容易并行化处理,因为每个块的加密都依赖于前一个块的加密结果。

综上所述,ECB模式简单快速,适合简单的加密需求,但安全性较差,不适合加密大量数据或需要保护隐私的数据。而CBC模式相对更安全,能够隐藏明文块之间的模式,适合加密大量数据或需要保护隐私的数据,但加密速度较慢


附:AES工具类

java 复制代码
package com.artisan.securityalgjava.aes;

import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.SecretKeySpec;
import java.security.SecureRandom;
import java.security.spec.KeySpec;
import java.util.Arrays;
import java.util.Base64;

/**
 * @author 小工匠
 * @version 1.0
 * @mark: show me the code , change the world
 * @desc: AES加密解密工具类, 提供了AES加密解密的功能,使用了CBC模式和PBKDF2算法生成密钥
 */
public class AESCipher {

    /**
     * 密钥生成算法
     */
    private static final String SECRET_KEY_ALGORITHM = "PBKDF2WithHmacSHA256";
    /**
     * 加密算法
     */
    private static final String ENCRYPTION_ALGORITHM = "AES/CBC/PKCS5Padding";
    /**
     * 密钥长度
     */
    private static final int KEY_SIZE = 256;
    /**
     * 迭代次数
     */
    private static final int ITERATION_COUNT = 65536;
    /**
     * 初始化向量长度
     */
    private static final int IV_SIZE = 16;

    /**
     * 生成密钥
     *
     * @param password
     * @param salt
     * @return
     * @throws Exception
     */
    private static SecretKeySpec generateKey(String password, byte[] salt) throws Exception {
        SecretKeyFactory factory = SecretKeyFactory.getInstance(SECRET_KEY_ALGORITHM);
        KeySpec spec = new PBEKeySpec(password.toCharArray(), salt, ITERATION_COUNT, KEY_SIZE);
        SecretKey tmp = factory.generateSecret(spec);
        return new SecretKeySpec(tmp.getEncoded(), "AES");
    }

    /**
     * 加密
     *
     * @param plaintext
     * @param password
     * @return
     * @throws Exception
     */
    public static String encrypt(String plaintext, String password) throws Exception {
        // 生成盐
        byte[] salt = new byte[16];
        // 生成初始化向量
        byte[] iv = new byte[IV_SIZE];
        byte[] encryptedBytes;

        // 生成盐和初始化向量
        SecureRandom random = new SecureRandom();
        random.nextBytes(salt);
        random.nextBytes(iv);

        // 生成密钥
        SecretKeySpec keySpec = generateKey(password, salt);
        Cipher cipher = Cipher.getInstance(ENCRYPTION_ALGORITHM);
        cipher.init(Cipher.ENCRYPT_MODE, keySpec, new IvParameterSpec(iv));

        // 执行加密操作
        encryptedBytes = cipher.doFinal(plaintext.getBytes());

        // 将盐、初始化向量和密文拼接并返回Base64编码字符串
        byte[] combined = new byte[salt.length + iv.length + encryptedBytes.length];
        System.arraycopy(salt, 0, combined, 0, salt.length);
        System.arraycopy(iv, 0, combined, salt.length, iv.length);
        System.arraycopy(encryptedBytes, 0, combined, salt.length + iv.length, encryptedBytes.length);

        return Base64.getEncoder().encodeToString(combined);
    }

    /**
     * 解密
     *
     * @param encryptedText
     * @param password
     * @return
     * @throws Exception
     */
    public static String decrypt(String encryptedText, String password) throws Exception {
        // 解析Base64编码字符串并分离盐、初始化向量和密文
        byte[] combined = Base64.getDecoder().decode(encryptedText);
        byte[] salt = Arrays.copyOfRange(combined, 0, 16);
        byte[] iv = Arrays.copyOfRange(combined, 16, 32);
        byte[] encryptedBytes = Arrays.copyOfRange(combined, 32, combined.length);

        // 生成密钥
        SecretKeySpec keySpec = generateKey(password, salt);
        Cipher cipher = Cipher.getInstance(ENCRYPTION_ALGORITHM);
        cipher.init(Cipher.DECRYPT_MODE, keySpec, new IvParameterSpec(iv));

        // 执行解密操作并返回明文字符串
        byte[] decryptedBytes = cipher.doFinal(encryptedBytes);
        return new String(decryptedBytes);
    }

    /**
     * 测试方法
     *
     * @param args
     * @throws Exception
     */
    public static void main(String[] args) throws Exception {
        // 测试加密解密功能
        String encrypted = encrypt("组热么共和国的啥范德萨", "dddd");
        System.out.println("Encrypted: " + encrypted);
        String decrypted = decrypt(encrypted, "dddd");
        System.out.println("Decrypted: " + decrypted);
    }
}

总结

对称加密算法使用同一个密钥进行加密和解密,适用于需要高效加解密的场景。常见的对称加密算法包括DES、AES和3DES等。

对称加密算法使用同一个密钥进行加密和解密,常用的算法包括DES、AES和3DES等。

  • DES(Data Encryption Standard):DES是一种较早的对称加密算法,使用56位密钥进行加密和解密。由于密钥长度较短,DES已经不再被推荐使用,因为它容易受到穷举攻击。

  • AES(Advanced Encryption Standard):AES是目前广泛使用的对称加密算法之一。它使用128位、192位或256位密钥进行加密和解密。AES算法的安全性和性能较高,因此被广泛应用于各种安全领域。

  • 3DES(Triple Data Encryption Standard):3DES是对DES算法的改进,通过对数据应用三次DES算法来提高安全性。3DES使用的密钥长度为56位,因此它的安全性较DES提高了很多。但由于AES的出现和3DES的计算复杂性,3DES的使用逐渐减少。

密钥长度由算法设计决定。对于AES算法,它支持的密钥长度为128位、192位和256位。一般来说,密钥长度越长,加密的安全性越高,但同时也带来了更高的计算成本。

在使用对称加密算法时,需要指定以下参数:

  • 算法名称:即使用的加密算法,例如DES、AES和3DES等。
  • 工作模式:指定了加密算法在加密大块数据时的工作模式,常见的工作模式包括ECB、CBC、CFB、OFB等。
  • 填充模式:指定了在加密数据块大小不足时如何填充数据,常见的填充模式包括PKCS5Padding、NoPadding等。

选择合适的算法名称、工作模式和填充模式,可以根据具体的安全需求和性能要求进行调整。

相关推荐
装不满的克莱因瓶7 分钟前
【Redis经典面试题六】Redis的持久化机制是怎样的?
java·数据库·redis·持久化·aof·rdb
n北斗14 分钟前
常用类晨考day15
java
骇客野人17 分钟前
【JAVA】JAVA接口公共返回体ResponseData封装
java·开发语言
Clockwiseee38 分钟前
php伪协议
windows·安全·web安全·网络安全
黑客Ash1 小时前
安全算法基础(一)
算法·安全
云云3211 小时前
搭建云手机平台的技术要求?
服务器·线性代数·安全·智能手机·矩阵
云云3211 小时前
云手机有哪些用途?云手机选择推荐
服务器·线性代数·安全·智能手机·矩阵
yuanbenshidiaos1 小时前
c++---------数据类型
java·jvm·c++
向宇it1 小时前
【从零开始入门unity游戏开发之——C#篇25】C#面向对象动态多态——virtual、override 和 base 关键字、抽象类和抽象方法
java·开发语言·unity·c#·游戏引擎
Lojarro2 小时前
【Spring】Spring框架之-AOP
java·mysql·spring