[英]Java AES / GCM decryption fails
我正在尝试使用GCM模式进行加密和解密。 不幸的是,解密不起作用。
加密和解密类都必须使用相同的初始化向量吗? 我已经尝试过了,但是没有成功...
问题可能是keyGen.init(128, random)
的random参数吗?
加密码:
public class AES128SymmetricEncryption {
private static final int GCM_NONCE_LENGTH = 12; // in bytes
private static final int GCM_TAG_LENGTH = 16; // in bytes
public static void encode (FileInputStream ciphertextSource, FileOutputStream plaintextDestination)
{
try {
int numRead;
SecureRandom random = SecureRandom.getInstanceStrong();
KeyGenerator keyGen = KeyGenerator.getInstance("AES");
keyGen.init(128, random);
SecretKey key = keyGen.generateKey();
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding", "BC");
GCMParameterSpec spec = new GCMParameterSpec(GCM_TAG_LENGTH * 8, getIV(random));
cipher.init(Cipher.ENCRYPT_MODE, key, spec);
byte[] buf = new byte[2048];
while ((numRead = ciphertextSource.read(buf)) > 0) {
byte[] decryptedBlock = cipher.update(buf, 0, numRead);
plaintextDestination.write(decryptedBlock);
}
}
catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (plaintextDestination != null) {
ciphertextSource.close();
}
if (plaintextDestination != null) {
plaintextDestination.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
public static byte[] getIV(SecureRandom random) {
final byte[] nonce = new byte[GCM_NONCE_LENGTH];
random.nextBytes(nonce);
System.out.println(nonce);
return nonce;
}
public static void main(String[] args) throws GeneralSecurityException, IOException
{
Security.addProvider(new BouncyCastleProvider());
FileInputStream fis = new FileInputStream("C:/Users/roehrlef/Desktop/Test Data/Source Data/100KB.jpg");
FileOutputStream fos = new FileOutputStream("C:/Users/roehrlef/Desktop/Test Data/Encrypted Data/encrypted.jpg");
encode(fis, fos);
}
}
解密代码:
public class AES128SymmetricDecryption {
private static final int GCM_NONCE_LENGTH = 12; // in bytes
private static final int GCM_TAG_LENGTH = 16; // in bytes
public static void decode (FileInputStream ciphertextSource, FileOutputStream plaintextDestination)
{
try {
int numRead = 0;
SecureRandom random = SecureRandom.getInstanceStrong();
KeyGenerator keyGen = KeyGenerator.getInstance("AES");
keyGen.init(128, random);
SecretKey key = keyGen.generateKey();
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding", "BC");
GCMParameterSpec spec = new GCMParameterSpec(GCM_TAG_LENGTH * 8, getIV(random));
cipher.init(Cipher.DECRYPT_MODE, key, spec);
CipherInputStream cis = new CipherInputStream(ciphertextSource, cipher);
byte[] buf = new byte[2048];
while ((numRead = cis.read(buf)) > 0) {
byte[] decryptedBlock = cipher.update(buf, 0, numRead);
plaintextDestination.write(decryptedBlock);
}
}
catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (plaintextDestination != null) {
ciphertextSource.close();
}
if (plaintextDestination != null) {
plaintextDestination.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
public static byte[] getIV(SecureRandom random) {
final byte[] nonce = new byte[GCM_NONCE_LENGTH];
random.nextBytes(nonce);
System.out.println(nonce);
return nonce;
}
public static void main(String[] args) throws GeneralSecurityException, IOException
{
Security.addProvider(new BouncyCastleProvider());
FileInputStream fis = new FileInputStream("C:/Users/roehrlef/Desktop/Test Data/Encrypted Data/encrypted.jpg");
FileOutputStream fos = new FileOutputStream("C:/Users/roehrlef/Desktop/Test Data/Decrypted Data/decrypted.jpg");
decode(fis, fos);
}
}
您两次使用KeyGenerator
; 一次用于加密,一次用于解密。 此类生成一个新的随机密钥。 对于对称密码,您需要使用相同的密钥进行加密和解密(因此得名)。
通常,出于以下目的,应使用以下类:
对于对称密钥(例如,AES,HMAC):
KeyGenerator
:全新的秘密(对称)密钥; SecretKeyFactory
:解码秘密(对称)密钥,例如,由大多数密钥类实现的Key#getEncoded()方法生成; 对于非对称公钥/私钥对(例如RSA):
KeyPairGenerator
:全新的公共/私有非对称密钥对; KeyFactory
:从存储的密钥格式中解码公共/私有(非对称)密钥,例如,由大多数密钥类实现的Key#getEncoded()
方法生成; 对称密钥和非对称密钥都可以存储在密钥存储区中:
KeyStore
:将密钥/证书存储在诸如PKCS#12密钥库之类的密钥容器中; 最后,还有其他一些用于创建密钥的选项:
KeyAgreement
:建立由密钥协商功能,如Diffie-Hellman密钥交换的关键; Cipher#unwrap
: Cipher#unwrap
(解密)使用Cipher#wrap
(或另一个平台上的类似功能)和另一个密钥创建的密钥。 您可能应该在KeyStore
存储和检索密钥-您可以将其加载/保存到文件中。 请注意,并非所有密钥库都被创建为相等。 Java 9扩展了PKCS#12密钥存储区的功能,并将其设置为默认值。 您还对代码进行编码,然后使用SecretKeyFactory
再次对其进行解码。
或者,您可以仅作弊并重复使用在加密过程中生成的SecretKey
实例,并在以后实现密钥存储。 这对于测试目的将是很好的。 最后,您需要共享对称加密的密钥。
是的,双方的IV必须相同。 通常,它只是存储在密文的前面。 IV对于每种加密来说应该是唯一的,因此您必须在那使用随机数生成器。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.