【数据安全】Java AES加密和解密

自我介绍

  • 做一个简单介绍,酒架年近48 ,有20多年IT工作经历,目前在一家500强做企业架构.因为工作需要,另外也因为兴趣涉猎比较广,为了自己学习建立了三个博客,分别是【全球IT瞭望】,【架构师酒馆】和【开发者开聊】,有更多的内容分享,谢谢大家收藏。
  • 企业架构师需要比较广泛的知识面,了解一个企业的整体的业务,应用,技术,数据,治理和合规。之前4年主要负责企业整体的技术规划,标准的建立和项目治理。最近一年主要负责数据,涉及到数据平台,数据战略,数据分析,数据建模,数据治理,还涉及到数据主权,隐私保护和数据经济。 因为需要,比如数据资源入财务报表,另外数据如何估值和货币化需要财务和金融方面的知识,最近在学习财务,金融和法律。打算先备考CPA,然后CFA,如果可能也想学习法律,备战律考。
  • 欢迎爱学习的同学朋友关注,也欢迎大家交流。微信小号【ca_cea】

1.概述

对称密钥分组密码在数据加密中起着重要作用。这意味着加密和解密都使用相同的密钥。高级加密标准(AES)是一种广泛使用的对称密钥加密算法。

在本教程中,我们将学习如何在JDK中使用Java Cryptography Architecture(JCA)实现AES加密和解密。

2.AES算法

AES算法是一种迭代的对称密钥块密码,它支持128、192和256位的密钥(秘密密钥)来加密和解密128位块中的数据。下图显示了高级AES算法:

Encryption

如果要加密的数据不满足128位的块大小要求,则必须对其进行填充。填充是将最后一个块填充为128位的过程。

3.AES变化

AES算法有六种操作模式:

  • ECB(电子代码簿)
  • CBC(密码块链接)
  • CFB(密码反馈)
  • OFB(输出反馈)
  • CTR(计数器)
  • GCM(伽罗瓦/计数器模式)

我们可以应用这种操作模式来加强加密算法的效果。此外,操作模式可以将分组密码转换为流密码。每种模式都有其长处和短处。让我们快速回顾每一个。

3.1. ECB

这种操作模式是最简单的。明文被划分为大小为128位的块。然后用相同的密钥和算法对每个块进行加密。因此,它对同一块产生相同的结果。这是该模式的主要弱点,不建议用于加密。它需要填充数据。

3.2.CBC

为了克服ECB的弱点,CBC模式使用初始化向量(IV)来增强加密。首先,CBC使用带有IV的明文块xor。然后将结果加密到密文块。在下一个块中,它使用加密结果与明文块异或,直到最后一个块。

在这种模式下,加密不能并行化,但解密可以并行化。它还需要填充数据。

3.3.CFB

此模式可以用作流密码。首先,它对IV进行加密,然后与明文块进行异或以获得密文。然后CFB对加密结果进行加密以异或明文。它需要IV。

在这种模式下,解密可以并行化,但加密不能并行化。

3.4.OFB

此模式可以用作流密码。首先对IV进行加密,然后利用加密结果对明文进行异或运算,得到密文。

它不需要填充数据,也不会受到嘈杂块的影响。

3.5.CTR

这种模式使用计数器的值作为IV。它与OFB非常相似,但每次都使用计数器而不是IV进行加密。

这种模式有两个优点,包括加密/解密并行化,并且一个块中的噪声不会影响其他块。

3.6.GCM

此模式是CTR模式的扩展。GCM受到了极大的关注,并得到了NIST的推荐。GCM模型输出密文和认证标签。与算法的其他操作模式相比,该模式的主要优点是其效率。

在本教程中,我们将使用AES/CCBC/PKCS5Padding算法,因为它在许多项目中被广泛使用。

3.7.加密后的数据大小

如前所述,AES具有128位或16字节的块大小。AES不会改变大小,密文大小等于明文大小。此外,在ECB和CBC模式中,我们应该使用类似PKCS 5的填充算法。因此,加密后的数据大小为:

ciphertext_size (bytes) = cleartext_size + (16 - (cleartext_size % 16))

为了用密文存储IV,我们需要再添加16个字节。

4.AES参数

在AES算法中,我们需要三个参数:输入数据、密钥和IV。IV在ECB模式中不使用。

4.1.输入数据

AES的输入数据可以是基于字符串、文件、对象和密码的。

4.2.密钥

AES中有两种生成密钥的方法:从随机数生成密钥,或者从给定的密码派生密钥。

在第一种方法中,密钥应该由加密安全(伪)随机数生成器(如SecureRandom类)生成。

为了生成密钥,我们可以使用KeyGenerator类。让我们定义一种生成大小为n(128、192和256)位的AES密钥的方法:

public static SecretKey generateKey(int n) throws NoSuchAlgorithmException {KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");keyGenerator.init(n);SecretKey key = keyGenerator.generateKey();return key;
}

在第二种方法中,可以使用类似PBKDF2的基于密码的密钥推导函数从给定密码推导AES密钥。我们还需要一个salt值来将密码转换为密钥。盐也是一个随机值。

我们可以将SecretKeyFactory类与PBKDF2WithHmacSHA256算法一起使用,从给定的密码生成密钥。

让我们定义一种方法,通过65536次迭代和256位的密钥长度从给定密码生成AES密钥:

public static SecretKey getKeyFromPassword(String password, String salt)throws NoSuchAlgorithmException, InvalidKeySpecException {SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256");KeySpec spec = new PBEKeySpec(password.toCharArray(), salt.getBytes(), 65536, 256);SecretKey secret = new SecretKeySpec(factory.generateSecret(spec).getEncoded(), "AES");return secret;
}

4.3.初始化矢量(四)

IV是一个伪随机值,并且具有与加密的块相同的大小。我们可以使用SecureRandom类生成随机IV。

让我们定义一种生成IV的方法:

public static IvParameterSpec generateIv() {byte[] iv = new byte[16];new SecureRandom().nextBytes(iv);return new IvParameterSpec(iv);
}

5.加密和解密

5.1.字符串

要实现输入字符串加密,我们首先需要根据上一节生成密钥和IV。下一步,我们使用getInstance()方法从Cipher类创建一个实例。

此外,我们使用init()方法配置了一个密码实例,该方法具有密钥IV和加密模式。最后,我们通过调用doFinal()方法来加密输入字符串。此方法获取输入的字节数,并以字节为单位返回密文:

public static String encrypt(String algorithm, String input, SecretKey key,IvParameterSpec iv) throws NoSuchPaddingException, NoSuchAlgorithmException,InvalidAlgorithmParameterException, InvalidKeyException,BadPaddingException, IllegalBlockSizeException {Cipher cipher = Cipher.getInstance(algorithm);cipher.init(Cipher.ENCRYPT_MODE, key, iv);byte[] cipherText = cipher.doFinal(input.getBytes());return Base64.getEncoder().encodeToString(cipherText);
}

为了解密输入字符串,我们可以使用DECRYPT_MODE初始化我们的密码来解密内容:

public static String decrypt(String algorithm, String cipherText, SecretKey key,IvParameterSpec iv) throws NoSuchPaddingException, NoSuchAlgorithmException,InvalidAlgorithmParameterException, InvalidKeyException,BadPaddingException, IllegalBlockSizeException {Cipher cipher = Cipher.getInstance(algorithm);cipher.init(Cipher.DECRYPT_MODE, key, iv);byte[] plainText = cipher.doFinal(Base64.getDecoder().decode(cipherText));return new String(plainText);
}

让我们编写一个用于加密和解密字符串输入的测试方法:

@Test
void givenString_whenEncrypt_thenSuccess()throws NoSuchAlgorithmException, IllegalBlockSizeException, InvalidKeyException,BadPaddingException, InvalidAlgorithmParameterException, NoSuchPaddingException { String input = "baeldung";SecretKey key = AESUtil.generateKey(128);IvParameterSpec ivParameterSpec = AESUtil.generateIv();String algorithm = "AES/CBC/PKCS5Padding";String cipherText = AESUtil.encrypt(algorithm, input, key, ivParameterSpec);String plainText = AESUtil.decrypt(algorithm, cipherText, key, ivParameterSpec);Assertions.assertEquals(input, plainText);
}Copy

5.2. File

现在让我们使用AES算法对文件进行加密。步骤是相同的,但我们需要一些IO类来处理这些文件。让我们加密一个文本文件:

public static void encryptFile(String algorithm, SecretKey key, IvParameterSpec iv,File inputFile, File outputFile) throws IOException, NoSuchPaddingException,NoSuchAlgorithmException, InvalidAlgorithmParameterException, InvalidKeyException,BadPaddingException, IllegalBlockSizeException {Cipher cipher = Cipher.getInstance(algorithm);cipher.init(Cipher.ENCRYPT_MODE, key, iv);FileInputStream inputStream = new FileInputStream(inputFile);FileOutputStream outputStream = new FileOutputStream(outputFile);byte[] buffer = new byte[64];int bytesRead;while ((bytesRead = inputStream.read(buffer)) != -1) {byte[] output = cipher.update(buffer, 0, bytesRead);if (output != null) {outputStream.write(output);}}byte[] outputBytes = cipher.doFinal();if (outputBytes != null) {outputStream.write(outputBytes);}inputStream.close();outputStream.close();
}

请注意,不建议尝试将整个文件读取到内存中,尤其是在文件很大的情况下。相反,我们一次加密一个缓冲区。

对于解密文件,我们使用类似的步骤,并使用DECRYPT_MODE初始化密码,如前所述。

再次,让我们定义一个用于加密和解密文本文件的测试方法。在这种方法中,我们从测试资源目录中读取baeldung.txt文件,将其加密到一个名为baeldung.encrypted的文件中,然后将该文件解密到一个新文件中:

@Test
void givenFile_whenEncrypt_thenSuccess() throws NoSuchAlgorithmException, IOException, IllegalBlockSizeException, InvalidKeyException, BadPaddingException, InvalidAlgorithmParameterException, NoSuchPaddingException {SecretKey key = AESUtil.generateKey(128);String algorithm = "AES/CBC/PKCS5Padding";IvParameterSpec ivParameterSpec = AESUtil.generateIv();Resource resource = new ClassPathResource("inputFile/baeldung.txt");File inputFile = resource.getFile();File encryptedFile = new File("classpath:baeldung.encrypted");File decryptedFile = new File("document.decrypted");AESUtil.encryptFile(algorithm, key, ivParameterSpec, inputFile, encryptedFile);AESUtil.decryptFile(algorithm, key, ivParameterSpec, encryptedFile, decryptedFile);assertThat(inputFile).hasSameTextualContentAs(decryptedFile);
}

5.3.基于密码

我们可以使用从给定密码派生的密钥进行AES加密和解密。

为了生成密钥,我们使用getKeyFromPassword()方法。加密和解密步骤与字符串输入部分中所示的步骤相同。然后,我们可以使用实例化的密码和提供的密钥来执行加密。

让我们写一个测试方法:

@Test
void givenPassword_whenEncrypt_thenSuccess() throws InvalidKeySpecException, NoSuchAlgorithmException, IllegalBlockSizeException, InvalidKeyException, BadPaddingException, InvalidAlgorithmParameterException, NoSuchPaddingException {String plainText = "www.baeldung.com";String password = "baeldung";String salt = "12345678";IvParameterSpec ivParameterSpec = AESUtil.generateIv();SecretKey key = AESUtil.getKeyFromPassword(password,salt);String cipherText = AESUtil.encryptPasswordBased(plainText, key, ivParameterSpec);String decryptedCipherText = AESUtil.decryptPasswordBased(cipherText, key, ivParameterSpec);Assertions.assertEquals(plainText, decryptedCipherText);
}

5.4.对象

为了加密Java对象,我们需要使用SealedObject类。对象应该是可序列化的。让我们从定义学生类开始:

public class Student implements Serializable {private String name;private int age;// standard setters and getters
}

接下来,让我们加密Student对象:

public static SealedObject encryptObject(String algorithm, Serializable object,SecretKey key, IvParameterSpec iv) throws NoSuchPaddingException,NoSuchAlgorithmException, InvalidAlgorithmParameterException, InvalidKeyException, IOException, IllegalBlockSizeException {Cipher cipher = Cipher.getInstance(algorithm);cipher.init(Cipher.ENCRYPT_MODE, key, iv);SealedObject sealedObject = new SealedObject(object, cipher);return sealedObject;
}

加密的对象稍后可以使用正确的密码进行解密:

public static Serializable decryptObject(String algorithm, SealedObject sealedObject,SecretKey key, IvParameterSpec iv) throws NoSuchPaddingException,NoSuchAlgorithmException, InvalidAlgorithmParameterException, InvalidKeyException,ClassNotFoundException, BadPaddingException, IllegalBlockSizeException,IOException {Cipher cipher = Cipher.getInstance(algorithm);cipher.init(Cipher.DECRYPT_MODE, key, iv);Serializable unsealObject = (Serializable) sealedObject.getObject(cipher);return unsealObject;
}

现在让我们编写一个测试用例:

@Test
void givenObject_whenEncrypt_thenSuccess() throws NoSuchAlgorithmException, IllegalBlockSizeException, InvalidKeyException,InvalidAlgorithmParameterException, NoSuchPaddingException, IOException, BadPaddingException, ClassNotFoundException {Student student = new Student("Baeldung", 20);SecretKey key = AESUtil.generateKey(128);IvParameterSpec ivParameterSpec = AESUtil.generateIv();String algorithm = "AES/CBC/PKCS5Padding";SealedObject sealedObject = AESUtil.encryptObject(algorithm, student, key, ivParameterSpec);Student object = (Student) AESUtil.decryptObject(algorithm, sealedObject, key, ivParameterSpec);assertThat(student).isEqualToComparingFieldByField(object);
}

6.结论

在本文中,我们学习了如何在Java中使用AES算法对字符串、文件、对象和基于密码的数据等输入数据进行加密和解密。此外,我们还讨论了AES的变化和加密后数据的大小。

和往常一样,文章的完整源代码是可用的

 over on GitHub.

本文:【数据安全】Java AES加密和解密 | 开发者开聊

欢迎收藏  【全球IT瞭望】,【架构师酒馆】和【开发者开聊】.

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

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

相关文章

Kubernetes 架构原则和对象设计

什么是 Kubernetes Kubernetes 是谷歌开源的容器集群管理系统 • 基于容器的应用部署、维护和滚动升级; • 负载均衡和服务发现; • 跨机器和跨地区的集群调度; • 自动伸缩; • 无状态服务和有状态服务; • 插件机制…

fba海派和传统海运的区别,亚马逊 FBA货物包装技巧—站斧浏览器

fba海派和传统海运的区别 1、美国FBA海派是什么? 美国FBA海派即将商品通过海洋运输的方式运送到美国亚马逊FBA仓库的服务。这种方式主要适用于大批量或大件商品,因为相比其他物流方式,海派具备成本低和运载量大的优势。 2、传统海运是什么…

编译opencv和opencv_contrib

1 下载源码 下载opencv源码https://github.com/opencv/opencv 下载opencv源码https://github.com/opencv/opencv_contrib 2 开始编译 构建需要下载ffmpeg的包,cmake构建时会自动下载,但是比较满,这里可以从下面链接直接下载 https://downloa…

ECMAScript基础入门:从语法到应用

在此之前我以及发布过关于JavaScript基础知识点大家也可以参考 大家有关于JavaScript知识点不知道可以去 🎉博客主页:阿猫的故乡 🎉系列专栏:JavaScript专题栏 🎉ajax专栏:ajax知识点 🎉欢迎关注…

C++ Qt开发:Charts折线图绘制详解

Qt 是一个跨平台C图形界面开发库,利用Qt可以快速开发跨平台窗体应用程序,在Qt中我们可以通过拖拽的方式将不同组件放到指定的位置,实现图形化开发极大的方便了开发效率,本章将重点介绍QCharts折线图的常用方法及灵活运用。 折线图…

C++ map和vector向量使用方法

C map用法 C 中 map 提供的是一种键值对容器,里面的数据都是成对出现的,如下图:每一对中的第一个值称之为关键字(key),每个关键字只能在 map 中出现一次;第二个称之为该关键字的对应值。 map的使用 需要导入头文件 #include …

采用线性插值的方法 在n个坐标点的基础上 准备添加一个坐标点p 根据给出p的横坐标 计算出p的纵坐标 np.interp()

【小白从小学Python、C、Java】 【计算机等考500强证书考研】 【Python-数据分析】 采用线性插值的方法 在n个坐标点的基础上 准备添加一个坐标点p 根据给出p的横坐标 计算出p的纵坐标 np.interp() [太阳]选择题 下列选项正确的是: import numpy as np x np.arra…

[架构之路-264]:个性特征 - 到底什么才是工程师文化?

目录 前言: 一、三种类型的商业公司与生存法则 (1)运营或销售驱动型公司 (2)产品驱动型公司 (3)技术驱动型公司 二、工程师文化特征解读1 三、工程师文化特征解读2 (1&#…

解决Unity物体速度过快无法进行碰撞检测(碰撞检测穿透)

解决Unity物体速度过快无法进行碰撞检测(碰撞检测穿透) 一、解决碰撞检测穿透方法一Collision Detection碰撞检测总结: 二、解决碰撞检测穿透方法二 一、解决碰撞检测穿透方法一 首先我们知道只要是跟碰撞相关的基本都是离不开刚体 Rigidbod…

八大排序算法@直接插入排序(C语言版本)

目录 直接插入排序概念算法思想代码实现核心算法:直接插入排序的算法实现: 特性总结 直接插入排序 概念 算法思想 把待排序的记录按其关键码值的大小逐个插入到一个已经排好序的有序序列中,直到所有的记录插入完为止,得到一个新…

「C/C++ 01」 深拷贝和浅拷贝

目录 一、概念 1. 浅拷贝 2. 深拷贝 3. 深浅拷贝问题 4. 总结 二、在C的类中实现深拷贝 1. 拷贝构造函数 中实现深拷贝 a. 自己开辟一个新空间,然后将内容拷贝到新空间 b. 借助构造函数来实现深拷贝 2. operator 中实现深拷贝 a. 自己开辟一个新空间,…

One Wire协议应用篇(c语言板)

一.项目简介 利用DS18B20实时检测温度并显示在LCD1602显示屏上,同时可以通过K1,K2,K3,K4设置最高温度和最低温度利用AT24C02可以实现掉电不丢失,最后当检测温度大于或小于最高温时,会在LCD1602显示屏上显示OV:H或OV:L。 二.准备材料 AT89C52、…

ESP32+LVGL笔记(6)-把712k的一二级汉字字库放在SPIRAM

文章目录 1.字库制作2.字库烧录到ESP32-S3的flash2.1 配置好分区文件2.2 汉字库文件烧录到ESP32的flash 3.将字库从 flash 拷贝到 SPIRAM3.1 工程配置中有关 SPIRAM 部分3.2 将汉字库从flash拷贝到SPIRAM的代码3.3 在进入lvgl之前调用函数 copyHZK_from_flash_to_SPIRAM 在前面…

Python入门知识点分享——(八)文件的open方法

学完了Python当中的数据类型,下一步我们来了解如何用Python语言打开文件并添加内容。 目录 file mode buffering encoding errors newline closefd opener 函数 打开文件需要用到open函数,完整的语法格式如下所示,为了演示方便&…

【Linux系统基础】(1)Linux基础命令全面详解

在计算机世界中,Linux操作系统以其稳定性、安全性和开源性而受到广大程序员和系统管理员的喜爱。然而,对于初学者来说,Linux的命令行界面可能会显得有些复杂和难以理解。本文将详细介绍一些常用的Linux基础命令,帮助你更好地理解和…

TLC2543(12位A/D转换器)实现将输入的模拟电压显示到数码管上

代码&#xff1a; #include <reg51.h> #define uchar unsigned char #define uint unsigned int// 数码管0-9 unsigned char seg[] {0x3F, 0x06, 0x5B, 0x4F, 0x66, 0x6D, 0x7D, 0x07, 0x7F, 0x6F}; sbit SDO P1^0; sbit SDI P1^1; sbit CS P1^2; sbit CLK P1^3; s…

【C语言】打印内存数据

C语言&#xff0c;用函数封装&#xff1a;16进制打印unsigned char *p指向的内存&#xff0c;长度为int l。16个字节&#xff0c;换一次行。16个字节用一个字符串缓存&#xff0c;一次打印。 以下是一个使用函数封装的C语言代码&#xff0c;用于以16进制格式打印unsigned char …

MyBatis——MyBatis的延迟加载

MyBatis的延迟加载&#xff08;一对多查询案例&#xff09; 1.什么是延迟加载&#xff1f; 开启延迟加载后&#xff0c;在真正使用数据的时候才发起级联查询&#xff0c;不用的时候不查询。 2.pojo User类&#xff1a; package com.wt.pojo;import java.io.Serializable; …

计算机毕业设计------JSP教务处学生成绩管理系统

项目介绍 本项目包含管理员、教师、学生三种角色&#xff1b; 用户角色包含以下功能&#xff1a; 修改密码,查看自己的信息,查看自己的成绩,登录界面等功能。 管理员角色包含以下功能&#xff1a; 修改示例,增删改查学生信息,增删改查教师信息,增删改查课程信息,管理员修改…

电机控制 相关基础概念

基本概念: 定子或者转子上有铁心或者绕铜线的地方,绕铜线的地方叫槽,而将槽分开的叫齿,将所有的齿连起来的部位较轭部。 磁感应强度与磁场强度之间的关系可以通过以下公式表示: B=μH 其中,B 是磁感应强度,H 是磁场强度,μ 是磁导率。这个关系表明,在给定磁场强度下…