c语言sscanf函数的用法是什么
285
2023-02-15
Java AES加密和解密教程
在本教程中,我们将看到如何使用JDK中的java密码体系结构(JCA)来实现AES加密和解密。对称密钥块密码在数据加密中起重要作用。这意味着同一密钥可用于加密和解密。高级加密标准(AES)是一种广泛使用的对称密钥加密算法。
AES算法是一种迭代的对称密钥块密码,它支持128、192和256位的加密密钥(秘密密钥),以对128位的块中的数据进行加密和解密。
在AES中生成密钥的方法有两种:从随机数生成或从给定密码生成。
在第一种方法中,应该从像SecureRandom类这样的加密安全(伪)随机数生成器生成秘密密钥。hdhhYJT为了生成密钥,我们可以使用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();
ResohdhhYJTurce 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 = "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 sthttp://atic 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加密和解密的资料请关注我们其它相关文章!
版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。
发表评论
暂时没有评论,来抢沙发吧~