首页 > 编程语言 >java 实现AES的CBC、CFB、OFB加解密

java 实现AES的CBC、CFB、OFB加解密

时间:2024-09-24 13:50:49浏览次数:10  
标签:OFB CBC AES 加密 String 密钥流 IV 密文 明文

1. CBC(Cipher Block Chaining,密码分组链接模式)

概述

CBC 模式是一种常见的块密码工作模式,通过将每个明文块与前一个密文块进行异或操作,再进行加密,从而增强数据的安全性。

工作原理

  1. 初始向量(IV,Initialization Vector)

    • CBC 模式需要一个随机生成的 IV 来确保相同明文在不同加密过程中的密文不同。
  2. 加密过程

    • 步骤 1:将第一个明文块与 IV 进行异或(XOR)操作。
    • 步骤 2:将异或后的结果通过块密码算法(如 AES)加密,生成第一个密文块。
    • 步骤 3:将第一个密文块与第二个明文块进行异或,再加密生成第二个密文块。
    • 步骤 4:重复上述步骤,直到所有明文块都被加密。
  3. 解密过程

    • 步骤 1:将第一个密文块解密,得到异或后的数据。
    • 步骤 2:将解密后的数据与 IV 进行异或,恢复出第一个明文块。
    • 步骤 3:将解密后的密文块与下一个密文块进行异或,恢复出下一个明文块。
    • 步骤 4:重复上述步骤,直到所有密文块都被解密。

特点

  • 依赖性:每个密文块都依赖于前一个密文块,增强了安全性。
  • 随机性:使用 IV 增加了加密的随机性,防止相同明文生成相同密文。
  • 错误传播:在解密过程中,如果某个密文块损坏,将导致该块和下一个块的解密失败。

优点

  • 增强安全性:通过链接操作,使得相同的明文块在不同的加密过程中生成不同的密文块。
  • 简单易实现:实现相对简单,广泛支持于各种加密库和标准中。

缺点

  • 无法并行处理:由于每个密文块依赖于前一个密文块,加密和解密过程无法并行化,影响性能。
  • 错误传播:解密过程中,某个密文块的错误会影响到当前块和下一个块的解密结果。

适用场景

  • 文件加密:如加密文件系统中的数据。
  • 通信加密:如 SSL/TLS 的部分加密阶段。
  • 通用数据保护:适用于需要高度安全性的场合。

2. CFB(Cipher Feedback,密码反馈模式)

概述

CFB 模式将块密码转换为一种类似流密码的工作模式,可以处理任意长度的数据流。它通过将前一个密文块反馈到加密过程中,实现对明文的加密。

工作原理

  1. 初始向量(IV)

    • CFB 模式同样需要一个随机生成的 IV 来确保加密的随机性。
  2. 加密过程

    • 步骤 1:将 IV 加密,得到一个密钥流块。
    • 步骤 2:将密钥流块与第一个明文块进行异或,生成第一个密文块。
    • 步骤 3:将第一个密文块作为下一个加密过程的输入,加密后得到下一个密钥流块。
    • 步骤 4:将第二个密钥流块与第二个明文块进行异或,生成第二个密文块。
    • 步骤 5:重复上述步骤,直到所有明文块被加密。
  3. 解密过程

    • 步骤 1:将 IV 加密,得到密钥流块。
    • 步骤 2:将密钥流块与第一个密文块进行异或,恢复出第一个明文块。
    • 步骤 3:将第一个密文块作为下一个加密过程的输入,加密后得到下一个密钥流块。
    • 步骤 4:将第二个密钥流块与第二个密文块进行异或,恢复出第二个明文块。
    • 步骤 5:重复上述步骤,直到所有密文块被解密。

特点

  • 反馈机制:密文块反馈到加密过程,增强了安全性。
  • 类似流密码:能够处理任意长度的数据,与流密码类似。

优点

  • 灵活性高:可以处理任意长度的数据,而不仅限于块大小的整数倍。
  • 无需填充:不需要像 CBC 模式那样进行填充操作,简化了实现。
  • 错误局部化:单个密文块的错误只会影响对应的明文块,错误不会传播到其他块。

缺点

  • 无法并行处理:与 CBC 模式类似,加密和解密过程需要串行进行,影响性能。
  • 安全性依赖于反馈:需要确保反馈机制的安全性,否则可能导致攻击风险。

适用场景

  • 流式通信:如实时数据传输、网络通信加密。
  • 无线通信:适用于需要快速响应和低延迟的场合。
  • 即时消息传输:如聊天应用中的数据加密。

3. OFB(Output Feedback,输出反馈模式)

概述

OFB 模式也是将块密码转换为一种流密码的模式,通过不断生成密钥流来与明文进行异或,从而实现加密。与 CFB 不同的是,OFB 模式使用块密码的输出作为密钥流的生成源,而不依赖于密文。

工作原理

  1. 初始向量(IV)

    • 与 CBC 和 CFB 模式类似,OFB 也需要一个随机的 IV。
  2. 密钥流生成

    • 步骤 1:将 IV 输入块密码算法,得到第一个密钥流块。
    • 步骤 2:将第一个密钥流块再次输入块密码算法,生成第二个密钥流块。
    • 步骤 3:重复上述步骤,持续生成密钥流块,直到覆盖所有明文数据。
  3. 加密过程

    • 步骤 1:将生成的密钥流块与明文数据进行异或(XOR)操作,生成密文块。
    • 步骤 2:重复以上步骤,直到所有数据块都被加密。
  4. 解密过程

    • 由于 XOR 操作的对称性,解密过程与加密过程相同,将密钥流块与密文块进行异或,恢复出明文。

特点

  • 独立性:密钥流的生成独立于明文和密文,只依赖于初始向量和密钥。
  • 同步流密码:可以预先生成密钥流,适用于需要同步流密码的场合。

优点

  • 并行性高:密钥流可以提前生成或并行处理,提高加密和解密性能。
  • 无错误传播:单个密文块的错误只会影响对应的明文块,错误不会传播到其他块。
  • 无需填充:无需像 CBC 模式那样进行填充操作,简化了实现。

缺点

  • 无内建认证:OFB 模式仅提供加密功能,不提供数据完整性和认证保障,容易受到重放攻击等威胁。
  • IV 重复风险:如果 IV 被重复使用,可能导致密钥流重复,破坏安全性。因此,必须确保 IV 的唯一性。

适用场景

  • 广播通信:如加密广播数据流。
  • 实时系统:需要快速生成密钥流并进行加密的场合。
  • 高性能应用:如视频流、音频流加密。

CBC、CFB 和 OFB 模式的比较

特性CBCCFBOFB
加密类型块加密模式混合块加密和流加密流加密模式
初始向量(IV)需要需要需要
并行处理不支持加密,支持解密的部分并行不支持并行支持加密和解密的并行
错误传播解密时错误会影响当前和下一个块错误只影响对应的块错误只影响对应的块
适用场景文件加密、通信加密流式传输、实时通信高性能流加密、广播通信
安全性高,但依赖于 IV 的唯一性和安全性高,但依赖于 IV 的唯一性和安全性高,但需要防止 IV 重复使用
需要填充需要不需要不需要

总结

  • CBC 模式:适用于需要高度安全性但对性能要求不高的场景,如文件加密和常规通信加密。其串行依赖性限制了并行处理能力,且错误传播可能影响到多个密文块。

  • CFB 模式:适用于流式数据加密,如实时通信和无线通信。虽然提供了类似流密码的灵活性,但同样存在无法并行处理的限制。

  • OFB 模式:适用于需要高性能和并行处理的场景,如视频流和音频流加密。其密钥流的独立性使得加密和解密过程可以并行进行,但缺乏内建的认证机制,需要额外的手段来保证数据完整性。

在实际应用中,选择哪种加密模式取决于具体的需求,包括数据类型、性能要求、安全性需求以及系统的特性。对于需要同时保证数据机密性和完整性的场景,可能需要结合使用认证机制(如 HMAC)或选择带认证功能的加密模式(如 GCM)。


示例代码(Java)

以下是使用 Java 实现 CBC、CFB 和 OFB 模式的示例代码

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.util.Base64;

/**
 *
 * 支持 CBC CFB OFB
 */

public class AES {

    private static Logger log = LoggerFactory.getLogger(AES.class);
    //默认模式
    private static String DEFAULT_MODE = "AES/CBC/PKCS5Padding";
    //默认key
    private static final String DEFAULT_KEY = "hqsywqVnGKaEYka1";
    //默认初始向量
    private static final String DEFAULT_IV = "TlP5B1wg7zMnmQHT";

    public static Build build(String key, String mode) {
        return new Build(key, mode);
    }

    public static Build build() {
        return new Build();
    }

    public static class Build {

        private Cipher cipher;
        private String key = DEFAULT_KEY;
        private String mode = DEFAULT_MODE;
        private String result;
        private String iv = DEFAULT_IV;
        private String padding;

        public Build() {
        }

        public Build(String key, String mode) {
            if (StringUtils.isNotBlank(key)) {
                this.key = key;
            }
            if (StringUtils.isNotBlank(mode)) {
                this.mode = mode;
            }
        }

        /**
         * 初始化
         * @return
         */
        public Build init() {
            try {
                cipher = Cipher.getInstance(mode);
            } catch (Exception e) {
                log.error("初始化aes失败:", e);
            }
            return this;
        }

        /**
         * 加密
         * @param enc
         * @return
         */
        public Build encrypt(String enc) {
            if (cipher == null) {
                init();
            }
            try {
                cipher.init(Cipher.ENCRYPT_MODE, getSecretKey(key), getIvParameterSpec(iv));
                byte[] bytes = cipher.doFinal(enc.getBytes(StandardCharsets.UTF_8));
                result = Base64.getEncoder().encodeToString(bytes);
            } catch (Exception e) {
                log.error("aes加密失败:", e);
            }
            return this;
        }

        /**
         * 解密
         * @param dec
         * @return
         */
        public Build decrypt(String dec) {
            if (cipher == null) {
                init();
            }
            try {
                cipher.init(Cipher.DECRYPT_MODE, getSecretKey(key), getIvParameterSpec(iv));
                byte[] bytes = cipher.doFinal(Base64.getDecoder().decode(dec));
                result = new String(bytes);
            } catch (Exception e) {
                log.error("aes解密失败:", e);
            }
            return this;
        }

        public String build() {
            return result;
        }
    }

    // 将字符串转换为初始化向量
    public static IvParameterSpec getIvParameterSpec(String ivStr) {
        return new IvParameterSpec(ivStr.getBytes(StandardCharsets.UTF_8));
    }

    /**
     * 生成密钥
     * @param key
     * @return
     */
    public static SecretKey getSecretKey(String key) {
        byte[] bytes = key.getBytes(StandardCharsets.UTF_8);
        return new SecretKeySpec(bytes, 0, key.length(), "AES");
    }

    public static void main(String[] args) {
        //支持 CBC CFB OFB
        Build init = AES.build("1232QWE131ASD2Q2","AES/CBC/PKCS5Padding").init();
        String enc = init.encrypt("123").build();
        System.out.println(enc);
        String dec = init.decrypt(enc).build();
        System.out.println(dec);
    }
}

注意事项

  1. 密钥管理

    • 密钥必须安全地存储和管理,避免泄露。可以使用 Java 的 KeyStore 来管理密钥。
    • 不建议在代码中硬编码密钥。
  2. 初始化向量(IV)

    • 每次加密操作应使用不同且随机生成的 IV,以确保密文的唯一性。
    • IV 本身不需要保密,但必须与密文一起存储或传输,以便解密时使用。
  3. 填充方式

    • 在 CBC 模式下,需要填充(如 PKCS5Padding)以确保明文长度是块大小的整数倍。
  4. 安全性

    • 确保使用最新的 Java 版本和安全库,以防止已知的安全漏洞。
    • 考虑结合使用认证机制(如 HMAC)以增强数据完整性和防御主动攻击。
  5. 异常处理

    • 加密和解密过程中可能会抛出各种异常,应妥善处理,确保系统的稳定性和安全性。

标签:OFB,CBC,AES,加密,String,密钥流,IV,密文,明文
From: https://blog.csdn.net/wenlai123456/article/details/142485474

相关文章

  • RSA加密 AES加密 py c#
    网上提供的方案描述都不太清晰,主要需要注意的是Py中使用的是pkcs1标准,注意这一点即可使用AES加密时候需要注意填充模式pyimportosimportuuidimportbase64importwmiimportjsonfromdatetimeimportdatetimeimportrandomimportrsaimportbinasciifromrsaimpo......
  • 【加密算法基础——AES解密实践】
    AES解密实践AES解密是对使用AES加密算法加密的数据进行恢复的过程。常用的解密方式有三种:在线解密工具:格式比较好控制,但是有些在线工具兼容性不好,有时候无法解出,不知道是自己的密文密钥没找对,还是因为未知原因,比较难判断。而且无法处理key的截断问题。命令行解密:Open......
  • 【加密算法基础——AES CBC模式代码解密实践】
    AES解密实践之代码实现AES解密使用python脚本比较灵活,但是一定要保证脚本是调试过的,才能在找到正确的密文,密钥,初始向量的情况下,解出正确的明文。但是对于AES解密,命令行无法处理key截断的问题。实际测试了一下,CBC模式,对于key截断的问题可以解决,但是CFB模式,目前还无法实验......
  • php AES/ECB/PKCS7Padding 加密
    在PHP中,直接使用 openssl_encrypt 函数时,它并不直接支持PKCS7Padding,特别是当使用ECB模式时,因为ECB模式本身并不关心数据填充(每个块都是独立加密的,且块大小固定为AES的块大小,即128位或16字节)。然而,由于AES的块大小与PKCS#7填充的最小单位(1字节)相同,在ECB模式......
  • AES加密 & RSA签名
    publicclassMain{publicstaticvoidmain(String[]args)throwsException{//生成RSA密钥对KeyPairGeneratorkeyGen=KeyPairGenerator.getInstance("RSA");keyGen.initialize(1024);KeyPairkeyPair=keyGen.genera......
  • AES加密解密全流程演示__api基础使用
    publicstaticvoidmain(String[]args)throwsException{//共同约定秘钥和加密算法Stringcontent="你好,世界";//AES密钥长度通常为128、192或256位Stringkey="1234567812345678";//16字节*8Stringalgorithm="AE......
  • Python 和 Go 实现 AES 加密算法的技术详解
    AES(AdvancedEncryptionStandard,高级加密标准)是一种对称密钥加密算法,广泛应用于各种安全通信场景中。AES使用128、192或256位的密钥,能够提供不同级别的安全性。本文将详细讲解如何使用Python和Go来实现AES加密算法,提供代码示例并对其进行逐步解析。1.什么是AES加密......
  • Apache OFBiz远程代码执行漏洞(CVE-2024-38856)
    漏洞简介ApacheOFBiz是一个开源的企业资源规划系统,提供了一整套企业管理解决方案,涵盖了许多领域,包括财务管理、供应链管理、客户关系管理、人力资源管理和电子商务等。ApacheOFBiz基于Java开发,采用灵活的架构和模块化设计,使其可以根据企业的需求进行定制和扩展,它具有强大的......
  • Goby 漏洞发布|(CVE-2024-45195)Apache OFBiz /viewdatafile 代码执行漏洞【已复现】
    漏洞名称:ApacheOFBiz/viewdatafile代码执行漏洞(CVE-2024-45195)EnglishName:ApacheOFBiz/viewdatafileCodeExecutionVulnerability(CVE-2024-45195)CVSScore: 8.0漏洞描述:ApacheOFBiz是一个开源企业资源规划(ERP)系统。它提供了一套企业应用程序,集成并自动化企业的......
  • Java 后端接口入参 - 联合前端VUE 使用AES完成入参出参加密&解密
    加密效果:解密后的数据就是正常数据:后端:使用的是spring-cloud框架,在gateway模块进行操作<dependency><groupId>com.google.guava</groupId><artifactId>guava</artifactId><version>30.0-jre</version>......