Ted*_*pin 110 java encryption aes
以下示例有什么问题?
问题是解密字符串的第一部分是无意义的.但是,剩下的很好,我明白了......
Run Code Online (Sandbox Code Playgroud)Result: `£eB6O?geS??i are you? Have a nice day.
@Test
public void testEncrypt() {
try {
String s = "Hello there. How are you? Have a nice day.";
// Generate key
KeyGenerator kgen = KeyGenerator.getInstance("AES");
kgen.init(128);
SecretKey aesKey = kgen.generateKey();
// Encrypt cipher
Cipher encryptCipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
encryptCipher.init(Cipher.ENCRYPT_MODE, aesKey);
// Encrypt
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
CipherOutputStream cipherOutputStream = new CipherOutputStream(outputStream, encryptCipher);
cipherOutputStream.write(s.getBytes());
cipherOutputStream.flush();
cipherOutputStream.close();
byte[] encryptedBytes = outputStream.toByteArray();
// Decrypt cipher
Cipher decryptCipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
IvParameterSpec ivParameterSpec = new IvParameterSpec(aesKey.getEncoded());
decryptCipher.init(Cipher.DECRYPT_MODE, aesKey, ivParameterSpec);
// Decrypt
outputStream = new ByteArrayOutputStream();
ByteArrayInputStream inStream = new ByteArrayInputStream(encryptedBytes);
CipherInputStream cipherInputStream = new CipherInputStream(inStream, decryptCipher);
byte[] buf = new byte[1024];
int bytesRead;
while ((bytesRead = cipherInputStream.read(buf)) >= 0) {
outputStream.write(buf, 0, bytesRead);
}
System.out.println("Result: " + new String(outputStream.toByteArray()));
}
catch (Exception ex) {
ex.printStackTrace();
}
}
Run Code Online (Sandbox Code Playgroud)
Cha*_*ara 244
包括我在内的很多人在制作这项工作时面临很多问题,因为缺少一些信息,例如忘记转换为Base64,初始化向量,字符集等等.所以我想要制作一个功能齐全的代码.
希望这对大家都有用:要编译,你需要额外的Apache Commons Codec jar,可以在这里找到:http: //commons.apache.org/proper/commons-codec/download_codec.cgi
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import org.apache.commons.codec.binary.Base64;
public class Encryptor {
public static String encrypt(String key, String initVector, String value) {
try {
IvParameterSpec iv = new IvParameterSpec(initVector.getBytes("UTF-8"));
SecretKeySpec skeySpec = new SecretKeySpec(key.getBytes("UTF-8"), "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");
cipher.init(Cipher.ENCRYPT_MODE, skeySpec, iv);
byte[] encrypted = cipher.doFinal(value.getBytes());
System.out.println("encrypted string: "
+ Base64.encodeBase64String(encrypted));
return Base64.encodeBase64String(encrypted);
} catch (Exception ex) {
ex.printStackTrace();
}
return null;
}
public static String decrypt(String key, String initVector, String encrypted) {
try {
IvParameterSpec iv = new IvParameterSpec(initVector.getBytes("UTF-8"));
SecretKeySpec skeySpec = new SecretKeySpec(key.getBytes("UTF-8"), "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");
cipher.init(Cipher.DECRYPT_MODE, skeySpec, iv);
byte[] original = cipher.doFinal(Base64.decodeBase64(encrypted));
return new String(original);
} catch (Exception ex) {
ex.printStackTrace();
}
return null;
}
public static void main(String[] args) {
String key = "Bar12345Bar12345"; // 128 bit key
String initVector = "RandomInitVector"; // 16 bytes IV
System.out.println(decrypt(key, initVector,
encrypt(key, initVector, "Hello World")));
}
}
Run Code Online (Sandbox Code Playgroud)
Bul*_*aza 40
这里没有办法解决Apache Commons Codec
的Base64
:
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
public class AdvancedEncryptionStandard
{
private byte[] key;
private static final String ALGORITHM = "AES";
public AdvancedEncryptionStandard(byte[] key)
{
this.key = key;
}
/**
* Encrypts the given plain text
*
* @param plainText The plain text to encrypt
*/
public byte[] encrypt(byte[] plainText) throws Exception
{
SecretKeySpec secretKey = new SecretKeySpec(key, ALGORITHM);
Cipher cipher = Cipher.getInstance(ALGORITHM);
cipher.init(Cipher.ENCRYPT_MODE, secretKey);
return cipher.doFinal(plainText);
}
/**
* Decrypts the given byte array
*
* @param cipherText The data to decrypt
*/
public byte[] decrypt(byte[] cipherText) throws Exception
{
SecretKeySpec secretKey = new SecretKeySpec(key, ALGORITHM);
Cipher cipher = Cipher.getInstance(ALGORITHM);
cipher.init(Cipher.DECRYPT_MODE, secretKey);
return cipher.doFinal(cipherText);
}
}
Run Code Online (Sandbox Code Playgroud)
用法示例:
byte[] encryptionKey = "MZygpewJsCpRrfOr".getBytes(StandardCharsets.UTF_8);
byte[] plainText = "Hello world!".getBytes(StandardCharsets.UTF_8);
AdvancedEncryptionStandard advancedEncryptionStandard = new AdvancedEncryptionStandard(
encryptionKey);
byte[] cipherText = advancedEncryptionStandard.encrypt(plainText);
byte[] decryptedCipherText = advancedEncryptionStandard.decrypt(cipherText);
System.out.println(new String(plainText));
System.out.println(new String(cipherText));
System.out.println(new String(decryptedCipherText));
Run Code Online (Sandbox Code Playgroud)
打印:
Hello world!
?;??LA+??b*
Hello world!
Run Code Online (Sandbox Code Playgroud)
GPI*_*GPI 23
在我看来,你没有正确处理初始化向量(IV).自从我上次阅读有关AES,IV和块链接以来,已经有很长一段时间了
IvParameterSpec ivParameterSpec = new IvParameterSpec(aesKey.getEncoded());
Run Code Online (Sandbox Code Playgroud)
似乎没有问题.在AES的情况下,您可以将初始化向量视为密码实例的"初始状态",并且此状态是您无法从密钥获得的一些信息,而是来自加密密码的实际计算.(有人可能会争辩说,如果可以从密钥中提取IV,那么它就没有用了,因为密钥已经在密钥实例的初始阶段给出了).
因此,您应该在加密结束时从密码实例获取IV作为byte []
cipherOutputStream.close();
byte[] iv = encryptCipher.getIV();
Run Code Online (Sandbox Code Playgroud)
你应该用这个字节[] 初始化你的Cipher
in DECRYPT_MODE
:
IvParameterSpec ivParameterSpec = new IvParameterSpec(iv);
Run Code Online (Sandbox Code Playgroud)
然后,你的解密应该没问题.希望这可以帮助.
k17*_*170 17
您用于解密的IV不正确.替换此代码
//Decrypt cipher
Cipher decryptCipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
IvParameterSpec ivParameterSpec = new IvParameterSpec(aesKey.getEncoded());
decryptCipher.init(Cipher.DECRYPT_MODE, aesKey, ivParameterSpec);
Run Code Online (Sandbox Code Playgroud)
有了这段代码
//Decrypt cipher
Cipher decryptCipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
IvParameterSpec ivParameterSpec = new IvParameterSpec(encryptCipher.getIV());
decryptCipher.init(Cipher.DECRYPT_MODE, aesKey, ivParameterSpec);
Run Code Online (Sandbox Code Playgroud)
那应该可以解决你的问题.
下面包含Java中简单AES类的示例.我不建议在生产环境中使用此类,因为它可能无法满足您的应用程序的所有特定需求.
import java.nio.charset.StandardCharsets;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.util.Base64;
public class AES
{
public static byte[] encrypt(final byte[] keyBytes, final byte[] ivBytes, final byte[] messageBytes) throws InvalidKeyException, InvalidAlgorithmParameterException
{
return AES.transform(Cipher.ENCRYPT_MODE, keyBytes, ivBytes, messageBytes);
}
public static byte[] decrypt(final byte[] keyBytes, final byte[] ivBytes, final byte[] messageBytes) throws InvalidKeyException, InvalidAlgorithmParameterException
{
return AES.transform(Cipher.DECRYPT_MODE, keyBytes, ivBytes, messageBytes);
}
private static byte[] transform(final int mode, final byte[] keyBytes, final byte[] ivBytes, final byte[] messageBytes) throws InvalidKeyException, InvalidAlgorithmParameterException
{
final SecretKeySpec keySpec = new SecretKeySpec(keyBytes, "AES");
final IvParameterSpec ivSpec = new IvParameterSpec(ivBytes);
byte[] transformedBytes = null;
try
{
final Cipher cipher = Cipher.getInstance("AES/CTR/NoPadding");
cipher.init(mode, keySpec, ivSpec);
transformedBytes = cipher.doFinal(messageBytes);
}
catch (NoSuchAlgorithmException | NoSuchPaddingException | IllegalBlockSizeException | BadPaddingException e)
{
e.printStackTrace();
}
return transformedBytes;
}
public static void main(final String[] args) throws InvalidKeyException, InvalidAlgorithmParameterException
{
//Retrieved from a protected local file.
//Do not hard-code and do not version control.
final String base64Key = "ABEiM0RVZneImaq7zN3u/w==";
//Retrieved from a protected database.
//Do not hard-code and do not version control.
final String shadowEntry = "AAECAwQFBgcICQoLDA0ODw==:ZtrkahwcMzTu7e/WuJ3AZmF09DE=";
//Extract the iv and the ciphertext from the shadow entry.
final String[] shadowData = shadowEntry.split(":");
final String base64Iv = shadowData[0];
final String base64Ciphertext = shadowData[1];
//Convert to raw bytes.
final byte[] keyBytes = Base64.getDecoder().decode(base64Key);
final byte[] ivBytes = Base64.getDecoder().decode(base64Iv);
final byte[] encryptedBytes = Base64.getDecoder().decode(base64Ciphertext);
//Decrypt data and do something with it.
final byte[] decryptedBytes = AES.decrypt(keyBytes, ivBytes, encryptedBytes);
//Use non-blocking SecureRandom implementation for the new IV.
final SecureRandom secureRandom = new SecureRandom();
//Generate a new IV.
secureRandom.nextBytes(ivBytes);
//At this point instead of printing to the screen,
//one should replace the old shadow entry with the new one.
System.out.println("Old Shadow Entry = " + shadowEntry);
System.out.println("Decrytped Shadow Data = " + new String(decryptedBytes, StandardCharsets.UTF_8));
System.out.println("New Shadow Entry = " + Base64.getEncoder().encodeToString(ivBytes) + ":" + Base64.getEncoder().encodeToString(AES.encrypt(keyBytes, ivBytes, decryptedBytes)));
}
}
Run Code Online (Sandbox Code Playgroud)
请注意,AES与编码无关,这就是我选择单独处理它而不需要任何第三方库的原因.
pat*_*ckf 15
在这个答案中,我选择接近"简单Java AES加密/解密示例"主题,而不是具体的调试问题,因为我认为这将使大多数读者受益.
这是关于Java中AES加密的博客文章的简单摘要,所以我建议在实现任何内容之前先阅读它.但是,我仍然会提供一个简单的示例来使用并给出一些指示,注意什么.
在这个例子中,我会选择使用经过验证的加密与伽罗瓦/计数器模式或GCM模式.原因是在大多数情况下,您需要 完整性和真实性以及机密性(在博客中阅读更多内容).
以下是使用Java密码体系结构(JCA)使用AES-GCM加密/解密所需的步骤.不要与其他示例混在一起,因为细微差别可能会使您的代码完全不安全.
由于它取决于您的用例,我将假设最简单的情况:随机密钥.
SecureRandom secureRandom = new SecureRandom();
byte[] key = new byte[16];
secureRandom.nextBytes(key);
SecretKey secretKey = SecretKeySpec(key, "AES");
Run Code Online (Sandbox Code Playgroud)
重要:
SecureRandom
byte[] IV = new byte[12]; //NEVER REUSE THIS IV WITH SAME KEY
secureRandom.nextBytes(IV);
Run Code Online (Sandbox Code Playgroud)
重要:
SecureRandom
final Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
GCMParameterSpec parameterSpec = new GCMParameterSpec(128, IV); //128 bit auth tag length
cipher.init(Cipher.ENCRYPT_MODE, secretKey, parameterSpec);
byte[] cipherText = cipher.doFinal(plainText);
Run Code Online (Sandbox Code Playgroud)
重要:
CipherInputStream
加密大量数据时cipher.updateAAD(associatedData);
.只需附加iv和密文.如上所述,iv不需要保密.
ByteBuffer byteBuffer = ByteBuffer.allocate(4 + IV.length + cipherText.length);
byteBuffer.putInt(IV.length);
byteBuffer.put(IV);
byteBuffer.put(cipherText);
byte[] cipherMessage = byteBuffer.array();
Run Code Online (Sandbox Code Playgroud)
如果需要字符串表示,可以选择使用Base64进行编码.使用Android或Java 8的内置实现(不要使用Apache Commons Codec - 这是一个糟糕的实现).编码用于将字节数组"转换"为字符串表示,以使其安全,例如:
String base64CipherMessage = Base64.getEncoder().encodeToString(cipherMessage);
Run Code Online (Sandbox Code Playgroud)
如果您已对消息进行编码,请先将其解码为字节数组:
byte[] cipherMessage = Base64.getDecoder().decode(base64CipherMessage)
Run Code Online (Sandbox Code Playgroud)
然后解构消息
ByteBuffer byteBuffer = ByteBuffer.wrap(cipherMessage);
int ivLength = byteBuffer.getInt();
if(ivLength < 12 || ivLength >= 16) { // check input parameter
throw new IllegalArgumentException("invalid IV length");
}
byte[] IV = new byte[ivLength];
byteBuffer.get(IV);
byte[] cipherText = new byte[byteBuffer.remaining()];
byteBuffer.get(cipherText);
Run Code Online (Sandbox Code Playgroud)
重要:
初始化密码并设置与加密相同的参数:
final Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(key, "AES"), new GCMParameterSpec(128, IV));
byte[] plainText= cipher.doFinal(cipherText);
Run Code Online (Sandbox Code Playgroud)
重要:
请注意,最新的Android(SDK 21+)和Java(7+)实现应该具有AES-GCM.较旧的版本可能缺乏它.我仍然选择这种模式,因为与类似的Encrypt-then-Mac模式(例如AES-CBC + HMAC)相比,它更容易实现.请参阅此文章,了解如何使用HMAC实施AES-CBC.
归档时间: |
|
查看次数: |
460819 次 |
最近记录: |