C中AES_cbc_encrypt加密对应java中的解密

news2024/10/2 16:19:56

前言知识:

1.AES(Advanced Encryption Standard)高级加密标准,作为分组密码(把明文分成一组一组的,每组长度相等每次加密一组数据,直到加密完整个明文)。

2.在AES标准规范中,分组长度只能是128位,也就是说,每个分组为16个字节(每个字节8位)8的倍数密钥的长度可以使用128位、192位或256位,分别对应的就是AES128AES192AES256,密钥的长度不同,推荐加密轮数也不同,从安全性来看,AES256安全性最高。从性能看,AES128性能最高。本质原因就是它们的加密处理轮数不同

3.AES属于对称加密算法,是因为加解密使用同一个秘钥

4.AES支持三种长度的密钥: 128位,192位,256位,一般有至少4种模式,即ECB、CBC、CFB、OFB等

 

5.AES算法在对明文加密的时候,并不是把整个明文一股脑的加密成一整段密文,而是把明文拆分成一个个独立的明文块,每一个明文块长度128bit

这些明文块经过AES加密器复杂处理,生成一个个独立的密文块,这些密文块拼接在一起,就是最终的AES加密的结果。

但这里涉及到一个问题,假如一段明文长度是196bit,如果按每128bit一个明文块来拆分的话,第二个明文块只有64bit,不足128bit。这时候怎么办呢?就需要对明文块进行填充(Padding) 。

6.几种典型的填充方式

NoPadding: 不做任何填充,但是要求明文必须是16字节的整数倍。
PKCS5Padding(Java默认): 如果明文块少于16个字节(128bit),在明文块末尾补足相应数量的字符,且每个字节的值等于缺少的字符数。 比如明文:{1,2,3,4,5,a,b,c,d,e},缺少6个字节,则补全为{1,2,3,4,5,a,b,c,d,e,6,6,6,6,6,6 }
ISO10126Padding:如果明文块少于16个字节(128bit),在明文块末尾补足相应数量的字节,最后一个字符值等于缺少的字符数,其他字符填充随机数。比如明文:{1,2,3,4,5,a,b,c,d,e},缺少6个字节,则可能补全为{1,2,3,4,5,a,b,c,d,e,5,c,3,G,$,6}
PKCS7Padding原理与PKCS5Padding相似,区别是PKCS5Paddingblocksize为8字节,而PKCS7Paddingblocksize可以为1到255字节

需要注意的是,如果在AES加密的时候使用了某一种填充方式,解密的时候也必须采用同样的填充方式,ZeroPadding(C++默认,java没有次填充方式):java操作的话,明文不足16位则手动补零,然后调用NoPadding

AES四种工作模式原理

1、ECB模式:

ECB (电子密码本)模式是最简单的块密码加密模式,加密前根据数据块大小(如AES为128位,每组大小跟加密秘钥长度相同)分成若干块,之后将每块使用相同的密钥单独通过块加密器密器。这种加密模式的优点就是简单,不需要初始化向量(IV) ,每个数据块独立进行加/解密,利于并行计算,加/解密效率很高。但这种模式中,所有数据都采用相同密钥进行加/解密,也没有经过任何逻辑运算,相同明文得到相同的密文,所以可能导致“选择明文攻击”的发生。(最早采用和最简单的模式

优点:   1.简单;   2.有利于并行计算;  3.误差不会被扩散; 

缺点:   1.不能隐藏明文的模式;  2.可能对明文进行主动攻击; 因此,此模式适于加密小消息

2、CBC模式: 参考

CBC (密码分组链接)模式是先将明文切分成若干小块,然后每个小块与初始块或者上一段的密文段进行逻辑异或运算后,再用密钥进行加密。第一个明文块与一个叫初始化向量的数据块进行逻辑异或运算。这样就有效的解决了ECB模式所暴露出来的问题,即使两个明文块相同,加密后得到的密文块也不相同。但是缺点也相当明显,如加密过程复杂,效率低等。 

优点:  不容易主动攻击,安全性好于ECB,适合传输长度长的报文,是SSL、IPSec的标准。 

缺点:  1.不利于并行计算;  2.误差传递;  3.需要初始化向量IV 

3、CFB模式:

与ECB和CBC模式只能够加密块数据不同,CFB模式能够将密文转化成为流密文。这种加密模式中,由于加密流程和解密流程中被块加密器加密的数据是前块的密文,因此即使本块明文数据的长度不是数据块大小的整数倍也是不需要填充的,这保证了数据长度在加密前后是相同的。

优点:  1.隐藏了明文模式;  2.分组密码转化为流模式;  3.可以及时加密传送小于分组的数据; 

缺点:  1.不利于并行计算;  2.误差传送:一个明文单元损坏影响多个单元;  3.唯一的IV; 

4、OFB模式:

不再直接加密明文块,其加密过程是先使用块加密器生成密钥流,然后再将密钥流和明文流进行逻辑异或运算得到密文流。

优点:  1.隐藏了明文模式;  2.分组密码转化为流模式;  3.可以及时加密传送小于分组的数据; 

缺点:  1.不利于并行计算;  2.对明文的主动攻击是可能的;  3.误差传送:一个明文单元损坏影响多个单元;

AES的算法原理


加密算法的一般设计准则

混淆 (Confusion) 最大限度地复杂化密文、明文与密钥之间的关系,通常用非线性变换算法达到最大化的混淆。

扩散 (Diffusion) 明文或密钥每变动一位将最大化地影响密文中的位数,通常采用线性变换算法达到最大化的扩散。

对Rijndael算法来说解密过程就是加密过程的逆向过程。下图为AES加解密的流程,从图中可以看出:1)解密算法的每一步分别对应加密算法的逆操作,2)加解密所有操作的顺序正好是相反的。正是由于这几点(再加上加密算法与解密算法每步的操作互逆)保证了算法的正确性。具体参考1 参考2

正文(C中AES_cbc_encrypt加密对应java中的解密)

//C中的加密方式
AES_cbc_encrypt((const unsigned char*)in.data(),
                    (unsigned char*)out.data(),
                    len,
                    &aes,
                    (unsigned char*)ivec.data(),
                    AES_ENCRYPT);

AES_cbc_encrypt:这是C++中AES中的CBC加密方式,可以对任意长度的输入数据进行加密,若输入数据不为16字节整数倍时,该函数内部会使用ZeroPadding自动对输入数据,进行填充,再进行加密。然后我查了一下,java中没有ZeroPadding,都是手动实现补零然后调用NoPadding的,我的具体实现:

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import javax.xml.bind.DatatypeConverter;
import java.nio.charset.StandardCharsets;

/**
 * @ClassName AESCBCUtil
 * @Description TODO
 * @Author wanghaha
 * @Date 2023/3/1
 **/
public class AESCBCUtil {


    /*
     * @Description: 满足pc的加密方式 生成128位
     * @Author: wanghaha
     * @Date: 2023/3/1
     * @param: data
     * @param: iv
     * @return: java.lang.String
     **/
    public static String encrypt128(String data, String iv) {
        byte[] key = new byte[16];
        for (int i = 0; i < 16; i++) {
            key[i] = (byte) (29 + i * 3);
        }
        try {
            Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
            byte[] dataBytes = data.getBytes();
            byte[] plaintext = new byte[128];
            //填充
            System.arraycopy(dataBytes, 0, plaintext, 0, dataBytes.length);
            SecretKeySpec keySpec = new SecretKeySpec(key, "AES");
            //设置偏移量参数
            IvParameterSpec ivSpec = new IvParameterSpec(iv.getBytes(StandardCharsets.UTF_8));
            cipher.init(Cipher.ENCRYPT_MODE, keySpec, ivSpec);
            byte[] encryped = cipher.doFinal(plaintext);

            return DatatypeConverter.printBase64Binary(encryped);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    /* 加密 正常长度
     * @Description:
     * @Author: wanghaha
     * @Date: 2023/3/1
     * @param: null
     * @return: null
     **/
    public static String encrypt(String data, String iv) {
        byte[] key = new byte[16];
        for (int i = 0; i < 16; i++) {
            key[i] = (byte) (29 + i * 3);
        }
        try {
            Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
            byte[] dataBytes = data.getBytes();
            int blockSize = cipher.getBlockSize();
            int length = dataBytes.length;
            //计算需填充长度
            if (length % blockSize != 0) {
                length = length + (blockSize - (length % blockSize));
            }
            byte[] plaintext = new byte[length];
            //填充
            System.arraycopy(dataBytes, 0, plaintext, 0, dataBytes.length);
            SecretKeySpec keySpec = new SecretKeySpec(key, "AES");
            //设置偏移量参数
            IvParameterSpec ivSpec = new IvParameterSpec(iv.getBytes(StandardCharsets.UTF_8));
            cipher.init(Cipher.ENCRYPT_MODE, keySpec, ivSpec);
            byte[] encryped = cipher.doFinal(plaintext);

            return DatatypeConverter.printBase64Binary(encryped);

        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    //解密
    public static String desEncrypt(String data, String iv) {
        byte[] key = new byte[16];
        for (int i = 0; i < 16; i++) {
            key[i] = (byte) (29 + i * 3);
        }
        try {
            byte[] encryp = DatatypeConverter.parseBase64Binary(data);
            Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
            SecretKeySpec keySpec = new SecretKeySpec(key, "AES");
            IvParameterSpec ivSpec = new IvParameterSpec(iv.getBytes(StandardCharsets.UTF_8));
            cipher.init(Cipher.DECRYPT_MODE, keySpec, ivSpec);
            byte[] original = cipher.doFinal(encryp);
            //因为pc端使用加密的是zeroPadding: 后补0的Nopadding方式 且 都是字符unsigned限制的 char正数 可以通过判断第一个0的位置判断字符长度
            int end=0;
            while(end < original.length && original[end] != 0){
                end++;
            }
            return new String(original,0, end);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }


    //测试
    public static void main(String[] args) {
        String data = "232342342342342";
        String iv = "2334022720230227";
        String encrypt= encrypt(data ,iv);

        String desencrypt = desEncrypt(encrypt,iv);
        System.out.println("长加密后:"+encrypt);
        System.out.println("长解密后:"+desencrypt);


    }
}

遇到的bug解决方法:

bug1:在做AES解密的时候,碰到了"Given final block not properly padded. Such issues can arise if a bad key is used during decryption"报错,意思就是加密和加密所所对应的秘钥不同

bug2:在使用java的Cipher类进行AES加密时,报错:IllegalBlockSizeException: Input length not multiple of 16 bytes 

报错的代码 Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding")

填充方式如果是Nopadding,那么加密的明文就得是8的倍数,或者是密钥必须是16位的
待加密内容的长度必须是16的倍数,如果不是16的倍数

总结:Java虽然支持AES的CBC模式,但是填充方式不支持ZeroPadding。

原理:ZeroPadding就是用'\0'将加密内容填充至BlockSize(CBC一般是16)的整数倍,再用NoPadding方式填充即可。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/397562.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

C#基础教程12 数组

文章目录 C# 数组(Array)C# 中的数组声明数组初始化数组赋值给数组访问数组元素C# 数组细节C# 数组(Array) 数组是一个存储相同类型元素的固定大小的顺序集合。数组是用来存储数据的集合,通常认为数组是一个同一类型变量的集合。 声明数组变量并不是声明 number0、number1…

【设计模式】工厂模式

工厂模式 所谓工厂&#xff0c;顾名思义&#xff0c;就是创建出一类相似的产品的&#xff0c;工厂模式可以帮我们创建各个复杂/简单对象。属于创建型模式。 工厂模式分为三类: 简单工厂工厂方法抽象工厂 简单工厂 比方说我们需要根据配置文件去解析配置&#xff0c;不同后…

html5播放器禁止拖拽、视频禁止拖动的实例

阿酷TONY / 2023-3-8 / 长沙html5播放器禁止拖拽功能,常用于场景&#xff1a;企业培训、在线教学内容禁止学员拖动视频进行观看。应用代码实例&#xff1a;<div id"player"></div> <script src"//player.polyv.net/script/player.js">&l…

pytest初识

一、单元测试框架 &#xff08;1&#xff09;什么是单元测试框架&#xff1f; 单元测试是指在软件开发中&#xff0c;针对软件的最小单元&#xff08;函数、方法&#xff09;进行正确性的检查测试 &#xff08;2&#xff09;单元测试框架 java&#xff1a;junit和testng pytho…

Windows SSH 配置和SCP的使用

使用用户界面安装 ssh 功能 要在 Windows 10/11 上启用 SSH 服务器&#xff0c;请按照以下步骤操作&#xff1a; 按“Windows 键 I”打开“设置”菜单&#xff0c;然后选择“应用程序”。在左侧菜单栏中选择“应用和功能”。从列表中选择“可选功能”。 点击“添加功能”按钮…

[数据结构]:15-堆排序(顺序表指针实现形式)(C语言实现)

目录 前言 已完成内容 堆排序实现 01-开发环境 02-文件布局 03-代码 01-主函数 02-头文件 03-PSeqListFunction.cpp 04-SortCommon.cpp 05-SortFunction.cpp 结语 前言 此专栏包含408考研数据结构全部内容&#xff0c;除其中使用到C引用外&#xff0c;全为C语言代码…

android h5考勤管理系统myeclipse开发mysql数据库编程服务端java计算机程序设计

一、源码特点 android h5考勤管理系统是一套完善的WEBandroid设计系统&#xff0c;对理解JSP java&#xff0c;安卓app编程开发语言有帮助&#xff08;系统采用web服务端APP端 综合模式进行设计开发&#xff09;&#xff0c;系统具有完整的源代 码和数据库&#xff0c;系统主…

平板触控笔要原装的吗?开学季必备电容笔推荐

如今对那些把ipad当做学习工具的用户而言&#xff0c;Apple Pencil就显得尤为重要了。但由于Apple Pencil的售价实在太高&#xff0c;让学生党望而却步。因此&#xff0c;最好的办法就是选择平替电容笔。我是一个ipad设备的忠实用户&#xff0c;同时也是一个数码热衷者&#xf…

MySQL增量备份和全量备份

1 全量备份 1.1 创建用于备份的目录 mkdir /root/mysql.backup1.2 创建存入备份文件的目录 mkdir /root/mysql.backup/data1.3 进入备份目录&#xff0c;创建备份脚本 cd /root/mysql.backupvim mysqlBackuoShell.sh#!/bin/bash #保存备份个数,31条 number31 #备份保存路…

Infineon Aurix 系列网络安全概述

目录 硬件安全 其它 1999年&#xff0c;英飞凌推出了第一代AUDO(汽车统一处理器)系列。基于统一的以RISC/MCU/DSP处理器为核心&#xff0c;这款32位TriCore™微控制器是一款强大的计算机器。其不断改进和优化TriCore的概念&#xff0c;最终形成了现在的第六代TriCore™,由于其…

ACWING蓝桥杯每日一题python(持续更新

ACWing蓝桥杯每日一题 一直没时间去总结算法&#xff0c;终于有空可以总结一下刷的acwing了&#xff0c;因为没时间所以最近只刷了ACWING的蓝桥杯每日一题。。。真是该死 1.截断数组 首先我们要知道&#xff0c;如果sum(a)不能被3整除或者len(a) < 3 &#xff0c;那么他肯…

Android使用移动智能终端补充设备标识获取OAID

官网http://www.msa-alliance.cn/col.jsp?id120首先到官网注册账号&#xff0c;申请下载相关sdk和授权证书2.把 oaid_sdk_x.x.x.aar 拷贝到项目的 libs 目录&#xff0c;并设置依赖&#xff0c;其中x.x.x 代表版本号3.supplierconfig.json 拷贝到项目 assets 目录下&#xff0…

keepalived实现nginx高可用

文章目录前言keepalived简介软件架构简单理解环境准备一、keepalived安装1.1 下载keepalived 安装包1.2 解压/下载依赖1.3 编译1.4 创建软连接1.5 增加系统服务1.6 启动keepalived二、实现Nginx高可用2.1 创建keepalived配置文件2.2 Nginx监控脚本2.4 重启keepalived2.5 查看虚…

自己DIY装机后,如何使用U盘装系统

最近自己整了一台主机&#xff0c;然后需要装一下系统&#xff0c;这边就讲一下如何用U盘给新电脑装系统。 安装Windows 10 光盘映像 首先你需要一个内存大于8GB的U盘&#xff0c;并且是纯净的&#xff0c;里面没有东西。 这边以Windows 10 为例&#xff1a; 百度搜索 下载…

IMX6ULL 启动方式之启动设备的选择

一. 硬件启动方式选择 汇编程序启动 LED 灯实验&#xff0c;是从SD卡读取 bin 文件并启动&#xff0c;说明 IMX6ULL 支持从 SD 卡启动。 IMX6ULL 支持多种启动方式。 注意&#xff1a;硬件原理图中&#xff0c;标注 DNP ( do not pupulate) 的意思是不焊接&#xff0c;即没…

【AcWing】归并排序及其应用

&#x1f386;音乐分享 &#xff08;点击链接可以听哦&#x1f60e;&#xff09; 无名之辈 - 陈雪燃 目录 归并排序 归并排序应用 文章中的图片来源&#xff1a; (2条消息) 归并排序&#xff08;分治法&#xff09;_分治法 归并排序_小小的香辛料的博客-CSDN博客 AcWing…

Springboot怎么实现WebSocket通信(二)

前言上一篇文章分享了单机模式下&#xff0c;websocket的基本使用方法&#xff0c;但在实际的业务中&#xff0c;通常是不会这样使用的&#xff0c;大部项目都是分布式部署的&#xff0c;一个工程布署了多个服务节点&#xff0c;前端并不直接请求具体服务节点&#xff0c;而是先…

C51---PWM 脉冲宽度调制

1.PWM:脉冲宽度调制,它是通过一系列脉冲宽度进行调制&#xff0c;等效出所需要的波形&#xff08;包含形状以及幅值&#xff09;。对模拟信号电平进行数字编码。也就是说通过调节占空比的变化来调节信号、能量等的变化&#xff0c;占空比就是指在一个周期内&#xff0c;信号处于…

第九届省赛——6打印大X

题目&#xff1a;本题目要求你在控制台输出一个由数字组成的等腰三角形。具体的步骤是&#xff1a;1. 先用1,2,3&#xff0c;...的自然数拼一个足够长的串2. 用这个串填充三角形的三条边。从上方顶点开始&#xff0c;逆时针填充。比如&#xff0c;当三角形高度是8时&#xff1a…

【Java开发】JUC进阶 06:异步回调、JMM、Volatile

1 异步回调异步是多线程的一种特殊实现方式&#x1f4cc; 举例我需要一个计算时间5秒方法的返回值我不想等这5秒钟&#xff0c;我想要继续执行下面的代码&#xff0c;那就异步执行这个方法当我通过get去获取这个返回值时&#xff0c;如果已经过了5秒&#xff0c;也就是方法执行…