Java AES加密和解密教程
在本教程中,我们将看到如何使用JDK中的Java密码体系结构(JCA)来实现AES加密和解密。对称密钥块密码在数据加密中起重要作用。这意味着同一密钥可用于加密和解密。高级加密标准(AES)是一种广泛使用的对称密钥加密算法。
AES算法是一种迭代的对称密钥块密码,它支持128、192和256位的加密密钥(秘密密钥),以对128位的块中的数据进行加密和解密。
在AES中生成密钥的方法有两种:从随机数生成或从给定密码生成。
在第一种方法中,应该从像SecureRandom类这样的加密安全(伪)随机数生成器生成秘密密钥。为了生成密钥,我们可以使用KeyGenerator类。让我们定义一种用于生成大小为n(128、192和256)位的AES密钥的方法:
publicstaticSecretKeygenerateKey(intn)throwsNoSuchAlgorithmException{ KeyGeneratorkeyGenerator=KeyGenerator.getInstance("AES"); keyGenerator.init(n); SecretKeykey=keyGenerator.generateKey(); returnkey; }
在第二种方法中,可以使用基于密码的密钥派生功能(例如PBKDF2)从给定的密码派生AES秘密密钥。下面方法可通过65,536次迭代和256位密钥长度从给定密码生成AES密钥:
publicstaticSecretKeygetKeyFromPassword(Stringpassword,Stringsalt) throwsNoSuchAlgorithmException,InvalidKeySpecException{ SecretKeyFactoryfactory=SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256"); KeySpecspec=newPBEKeySpec(password.toCharArray(),salt.getBytes(),65536,256); SecretKeysecret=newSecretKeySpec(factory.generateSecret(spec) .getEncoded(),"AES"); returnsecret; }
加密字符串
要实现输入字符串加密,我们首先需要根据上一节生成密钥和初始化向量IV:
IV是伪随机值,其大小与加密的块相同。我们可以使用SecureRandom类生成随机IV。
让我们定义一种生成IV的方法:
publicstaticIvParameterSpecgenerateIv(){ byte[]iv=newbyte[16]; newSecureRandom().nextBytes(iv); returnnewIvParameterSpec(iv); }
下一步,我们使用getInstance()方法从Cipher类创建一个实例。
此外,我们使用带有秘密密钥,IV和加密模式的init()方法配置密码实例。最后,我们通过调用doFinal()方法对输入字符串进行加密。此方法获取输入字节并以字节为单位返回密文:
publicstaticStringencrypt(Stringalgorithm,Stringinput,SecretKeykey, IvParameterSpeciv)throwsNoSuchPaddingException,NoSuchAlgorithmException, InvalidAlgorithmParameterException,InvalidKeyException, BadPaddingException,IllegalBlockSizeException{ Ciphercipher=Cipher.getInstance(algorithm); cipher.init(Cipher.ENCRYPT_MODE,key,iv); byte[]cipherText=cipher.doFinal(input.getBytes()); returnBase64.getEncoder() .encodeToString(cipherText); }
为了解密输入字符串,我们可以使用DECRYPT_MODE初始化密码来解密内容:
publicstaticStringdecrypt(Stringalgorithm,StringcipherText,SecretKeykey, IvParameterSpeciv)throwsNoSuchPaddingException,NoSuchAlgorithmException, InvalidAlgorithmParameterException,InvalidKeyException, BadPaddingException,IllegalBlockSizeException{ Ciphercipher=Cipher.getInstance(algorithm); cipher.init(Cipher.DECRYPT_MODE,key,iv); byte[]plainText=cipher.doFinal(Base64.getDecoder() .decode(cipherText)); returnnewString(plainText); }
编写一个用于加密和解密字符串输入的测试方法:
@Test voidgivenString_whenEncrypt_thenSuccess() throwsNoSuchAlgorithmException,IllegalBlockSizeException,InvalidKeyException, BadPaddingException,InvalidAlgorithmParameterException,NoSuchPaddingException{ Stringinput="baeldung"; SecretKeykey=AESUtil.generateKey(128); IvParameterSpecivParameterSpec=AESUtil.generateIv(); Stringalgorithm="AES/CBC/PKCS5Padding"; StringcipherText=AESUtil.encrypt(algorithm,input,key,ivParameterSpec); StringplainText=AESUtil.decrypt(algorithm,cipherText,key,ivParameterSpec); Assertions.assertEquals(input,plainText); }
加密文件
现在,让我们使用AES算法加密文件。步骤是相同的,但是我们需要一些IO类来处理文件。让我们加密一个文本文件:
publicstaticvoidencryptFile(Stringalgorithm,SecretKeykey,IvParameterSpeciv, FileinputFile,FileoutputFile)throwsIOException,NoSuchPaddingException, NoSuchAlgorithmException,InvalidAlgorithmParameterException,InvalidKeyException, BadPaddingException,IllegalBlockSizeException{ Ciphercipher=Cipher.getInstance(algorithm); cipher.init(Cipher.ENCRYPT_MODE,key,iv); FileInputStreaminputStream=newFileInputStream(inputFile); FileOutputStreamoutputStream=newFileOutputStream(outputFile); byte[]buffer=newbyte[64]; intbytesRead; 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 voidgivenFile_whenEncrypt_thenSuccess() throwsNoSuchAlgorithmException,IOException,IllegalBlockSizeException, InvalidKeyException,BadPaddingException,InvalidAlgorithmParameterException, NoSuchPaddingException{ SecretKeykey=AESUtil.generateKey(128); Stringalgorithm="AES/CBC/PKCS5Padding"; IvParameterSpecivParameterSpec=AESUtil.generateIv(); Resourceresource=newClassPathResource("inputFile/baeldung.txt"); FileinputFile=resource.getFile(); FileencryptedFile=newFile("classpath:baeldung.encrypted"); FiledecryptedFile=newFile("document.decrypted"); AESUtil.encryptFile(algorithm,key,ivParameterSpec,inputFile,encryptedFile); AESUtil.decryptFile( algorithm,key,ivParameterSpec,encryptedFile,decryptedFile); assertThat(inputFile).hasSameTextualContentAs(decryptedFile); }
基于密码加密解密
我们可以使用从给定密码派生的密钥进行AES加密和解密。
为了生成密钥,我们使用getKeyFromPassword()方法。加密和解密步骤与字符串输入部分中显示的步骤相同。然后,我们可以使用实例化的密码和提供的密钥来执行加密。
让我们写一个测试方法:
@Test voidgivenPassword_whenEncrypt_thenSuccess() throwsInvalidKeySpecException,NoSuchAlgorithmException, IllegalBlockSizeException,InvalidKeyException,BadPaddingException, InvalidAlgorithmParameterException,NoSuchPaddingException{ StringplainText="www.baeldung.com"; Stringpassword="baeldung"; Stringsalt="12345678"; IvParameterSpecivParameterSpec=AESUtil.generateIv(); SecretKeykey=AESUtil.getKeyFromPassword(password,salt); StringcipherText=AESUtil.encryptPasswordBased(plainText,key,ivParameterSpec); StringdecryptedCipherText=AESUtil.decryptPasswordBased( cipherText,key,ivParameterSpec); Assertions.assertEquals(plainText,decryptedCipherText); }
加密对象
为了加密Java对象,我们需要使用SealedObject类。该对象应可序列化。让我们从定义学生类开始:
publicclassStudentimplementsSerializable{ privateStringname; privateintage; //standardsettersandgetters }
接下来,让我们加密Student对象:
publicstaticSealedObjectencryptObject(Stringalgorithm,Serializableobject, SecretKeykey,IvParameterSpeciv)throwsNoSuchPaddingException, NoSuchAlgorithmException,InvalidAlgorithmParameterException, InvalidKeyException,IOException,IllegalBlockSizeException{ Ciphercipher=Cipher.getInstance(algorithm); cipher.init(Cipher.ENCRYPT_MODE,key,iv); SealedObjectsealedObject=newSealedObject(object,cipher); returnsealedObject; }
稍后可以使用正确的密码解密加密的对象:
publicstaticSerializabledecryptObject(Stringalgorithm,SealedObjectsealedObject, SecretKeykey,IvParameterSpeciv)throwsNoSuchPaddingException, NoSuchAlgorithmException,InvalidAlgorithmParameterException,InvalidKeyException, ClassNotFoundException,BadPaddingException,IllegalBlockSizeException, IOException{ Ciphercipher=Cipher.getInstance(algorithm); cipher.init(Cipher.DECRYPT_MODE,key,iv); SerializableunsealObject=(Serializable)sealedObject.getObject(cipher); returnunsealObject; }
让我们写一个测试用例:
@Test voidgivenObject_whenEncrypt_thenSuccess() throwsNoSuchAlgorithmException,IllegalBlockSizeException,InvalidKeyException, InvalidAlgorithmParameterException,NoSuchPaddingException,IOException, BadPaddingException,ClassNotFoundException{ Studentstudent=newStudent("Baeldung",20); SecretKeykey=AESUtil.generateKey(128); IvParameterSpecivParameterSpec=AESUtil.generateIv(); Stringalgorithm="AES/CBC/PKCS5Padding"; SealedObjectsealedObject=AESUtil.encryptObject( algorithm,student,key,ivParameterSpec); Studentobject=(Student)AESUtil.decryptObject( algorithm,sealedObject,key,ivParameterSpec); assertThat(student).isEqualToComparingFieldByField(object); }
可以在GitHub上获得本文的完整源代码 。
以上就是JavaAES加密和解密教程的详细内容,更多关于JavaAES加密和解密的资料请关注毛票票其它相关文章!