Java AES加密和解密教程

在本教程中,我们将看到如何使用JDK中的Java密码体系结构(JCA)来实现AES加密和解密。对称密钥块密码在数据加密中起重要作用。这意味着同一密钥可用于加密和解密。高级加密标准(AES)是一种广泛使用的对称密钥加密算法。

AES算法是一种迭代的对称密钥块密码,它支持128、192和256位的加密密钥(秘密密钥),以对128位的块中的数据进行加密和解密。

在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秘密密钥。下面方法可通过65,536次迭代和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;
}

加密字符串

要实现输入字符串加密,我们首先需要根据上一节生成密钥和初始化向量IV:

IV是伪随机值,其大小与加密的块相同。我们可以使用SecureRandom类生成随机IV。

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

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

下一步,我们使用getInstance()方法从Cipher类创建一个实例。

此外,我们使用带有秘密密钥,IV和加密模式的init()方法配置密码实例。最后,我们通过调用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);
}

加密文件

现在,让我们使用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);
}

基于密码加密解密

我们可以使用从给定密码派生的密钥进行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);
}

加密对象

为了加密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);
}

可以在GitHub上获得本文的完整源代码 。

以上就是Java AES加密和解密教程的详细内容,更多关于Java AES加密和解密的资料请关注我们其它相关文章!

(0)

相关推荐

  • java 实现DES 加密解密的示例

    package com.cn.peitest; import javax.crypto.Cipher; import javax.crypto.SecretKey; import javax.crypto.SecretKeyFactory; import javax.crypto.spec.DESKeySpec; import javax.crypto.spec.IvParameterSpec; /** * @功能说明: <BR> * @创建日期:2016年9月21日<BR> *

  • java使用RSA与AES加密解密的实例代码详解

    首先了解下,什么是堆成加密,什么是非对称加密? 对称加密:加密与解密的密钥是相同的,加解密速度很快,比如AES 非对称加密:加密与解密的秘钥是不同的,速度较慢,比如RSA •先看代码(先会用在研究) 相关依赖: <dependency> <groupId>org.bouncycastle</groupId> <artifactId>bcprov-jdk15on</artifactId> <version>1.58</versio

  • Java实现md5和base64加密解密的示例代码

    import java.io.IOException; import java.security.MessageDigest; import sun.misc.BASE64Encoder; import sun.misc.BASE64Decoder; public class MD5Util { /** * MD5加密 */ public static String md5Encryption(String str) { MessageDigest md5 = null; try { md5 =

  • java实现微信小程序加密数据解密算法

    一.概述 微信推出了小程序,很多公司的客户端应用不仅具有了APP.H5.还接入了小程序开发.但是,小程序中竟然没有提供Java版本的加密数据解密算法.这着实让广大的Java开发人员蛋疼. 微信小程序提供的加密数据解密算法链接 我们下载的算法示例如下: 木有Java!! 木有Java!! 木有Java!! 那么如何解决这个问题,我们一起来实现Java版本的微信小程序加密数据解密算法. 二.实现Java版本的微信小程序加密数据解密算法 1.创建项目 这里,我们创建一个Maven工程,具体创建步骤略.

  • Java可视化之实现文本的加密和解密

    一.题目 编写一个Java程序,实现一个文本信息的加密. 二.要求 可视化界面,友好的输入和输出,文件的存取. 三.分析 所谓数据加密(Data Encryption)技术是指将一个信息(或称明文,plain text)经过加密钥匙(Encryption key)及加密函数转换,变成无意义的密文(cipher text),而接收方则将此密文经过解密函数.解密钥匙(Decryption key)还原成明文. 四.界面规划 登录验证界面 建立基本框架,基于Swing中Frame 各组件的属性 组件编

  • java必懂的冷知识点之Base64加密与解密

    为了安全地进行数据传输,就需要对数据进行加密与解密操作,Base64就是Java提供的加密处理器.本博客主要讲解Base64工具类的使用以及加密和解密信息操作实现. Base64是一种直接利用64个可打印字符来表示二进制数据的算法,也是网络传输中较为常见的一种加密算法.从JDK1.8版本开始提供java.util.Base64的工具类,同时提供了两个Base64的内部类实现数据加密与解密操作. [数据加密]java.util.Base64.Encoder, 对象获取方法:public stati

  • java使用异或对文件进行加密解密

    本文实例为大家分享了java使用异或对文件进行加密解密的具体代码,供大家参考,具体内容如下 1.使用异或的方式加密文件的原理 一个数异或另一个数两次,结果一定是其本身 2.使用异或的原理加密文件 /** * 将文件内容加密 * 使用异或的方式将a.txt加密复制出一个b.txt,放到同一个文件夹下 */ @Test public void encryptFile(){ FileInputStream in = null; FileOutputStream out = null; try { St

  • java使用Base64实现文件加密解密

    本文实例为大家分享了Java实现Base64给文件加密.解密的具体代码,供大家参考,具体内容如下 package test.base64; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import sun.misc.BASE64Decoder;

  • Java上传下载文件并实现加密解密

    使用 Jersey 服务器实现上传,使用 HTTP 请求实现下载 引入依赖 在 pom.xml 中添加 Jersey 相关依赖 <dependency> <groupId>com.sun.jersey</groupId> <artifactId>jersey-client</artifactId> <version>1.18.1</version> </dependency> 创建工具类 import com.

  • 如何通过Java实现加密、解密Word文档

    前言 对一些重要文档,我们为保证其文档内容不被泄露,常需要对文件进行加密,查看文件时,需要正确输入密码才能打开文件.下面介绍了一种比较简单的方法给Word文件加密以及如何给已加密的Word文件解除密码保护. 使用工具:Free Spire.Doc for Java 2.0.0(免费版) Jar文件导入: 方法1:通过官网下载控件包.在程序下新建一个directory目录,并命名(本示例中命名为lib):将控件包lib文件夹下的jar(如下图1)拷贝到程序中新建的目录下.复制jar文件后,鼠标右键

  • plsql实现DES对称加密 Java解密

    背景 某项目接口采用plsql开发,接口返回用户密码,但要求密码不能是明文返回,因为程序内部需要用到明文密码,所以只能在plsql中对密码进行对称加密,在程序内部进行解密,程序采用java开发. 实现 dbms_crypto是oracle自带的加密包,包含多种加密解密方法,非dba用户需要授权才能进行使用 grant execute on dbms_crypto to xxx;   下面是一个通过DES算法加密的function function encrypt_password(p_passw

  • java使用RSA加密方式实现数据加密解密的代码

    RSA的应用 RSA是一种非对称加密算法.现在,很多登陆表单的密码的都采用RSA加密,例如京东中的登陆使用公钥对密码进行加密 java使用RSA加密方式实现数据加密解密,需要首先产生私钥和公钥 测试代码 public static void main(String args[]) { try { RSADemo rsa=new RSADemo(); rsa.generateKey(); byte[] data=rsa.encrypt("luanpeng".getBytes()); by

  • Java AES256加密解密示例代码

    Java支持许多安全的加密算法,但是其中一些功能较弱,无法在安全性要求很高的应用程序中使用.例如,数据加密标准(DES)加密算法被认为是高度不安全的.今天介绍一下AES 256加密解密. 什么是 AES 256? 高级加密标准 (英语:Advanced Encryption Standard,缩写:AES ),在密码学中又称Rijndael加密法,是美国联邦政府采用的一种区块加密标准.这个标准用来替代原先的DES,已经被多方分析且广为全世界所使用. AES是一种对称加密算法.它旨在易于在硬件和软

随机推荐