[英]JAVA separate AES key, initilization vector and data from encrypted file with these 3 combinations used during encryption
我創建了結合了AES加密,引入向量和原始數據的加密文件。 因此,我的加密文件包含上述3個加密形式的元素。 現在,在解密過程中,我被困在再次分離所有這三個元素的過程中,此外,我還必須使用在加密過程中生成的在解密過程中硬編碼的AES密鑰長度。
public static void encrypt() throws Exception {
// RSA with ECB mode
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher.init(Cipher.ENCRYPT_MODE, generatePublicKey(readKeysFromFile("My_public.pub")));
// AES key generator
KeyGenerator kgen = KeyGenerator.getInstance("AES");
kgen.init(128, srandom);
SecretKey skey = kgen.generateKey();
// Initialization vector 16 byte
byte[] iv = new byte[128/8];
srandom.nextBytes(iv);
IvParameterSpec ivspec = new IvParameterSpec(iv);
try (FileOutputStream out = new FileOutputStream("dataFile" + ".enc")) {
{
byte[] b = cipher.doFinal(skey.getEncoded());
out.write(b);
System.err.println("AES Key Length: " + b.length);
}
out.write(iv);
System.err.println("IV Length: " + iv.length);
Cipher ci = Cipher.getInstance("AES/CBC/PKCS5Padding");
ci.init(Cipher.ENCRYPT_MODE, skey, ivspec);
File inputDataFile = new File("dataFile.xml");
try (DataInputStream in = new DataInputStream(new FileInputStream(inputDataFile))) {
byte[] buffer = new byte[(int)inputDataFile.length()];
in.readFully(buffer);
in.close();
byte[] encryptedData = ci.doFinal(buffer);
out.write(encryptedData);
out.close();
}
}
}
public static void decryptRSAAES() throws Exception {
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher.init(Cipher.DECRYPT_MODE, generatePrivateKey(readKeysFromFile("My_private.key")));
File file2 = new File("dataFile.enc");
RandomAccessFile raf = new RandomAccessFile(file2, "r");
// length of AES key
byte[] c = new byte[384];
// read the AES key from file
raf.read(c, 0 , 384);
byte[] fileContent = Files.readAllBytes(file2.toPath());
byte[] keyb = cipher.doFinal(c);
SecretKeySpec skey = new SecretKeySpec(keyb, "AES");
// read the initializatoin vector
byte[] iv = new byte[128/8];
raf.seek(384);
raf.read(iv);
IvParameterSpec ivspec = new IvParameterSpec(iv);
raf.seek(400);
Cipher ci = Cipher.getInstance("AES/CBC/PKCS5Padding");
ci.init(Cipher.DECRYPT_MODE, skey, ivspec);
try (FileOutputStream out = new FileOutputStream("decryptedFileTest"+".xml")){
byte[] decryptedData = ci.doFinal(fileContent);
out.write(decryptedData);
out.close();
//processDecryptFile(ci, in, out);
}
}
實際結果:使用AES密鑰和原始純數據創建解密的文件
預期結果:僅在輸出中寫入原始原始數據,以除去AES和初始化向量。
讓我們簡化一下,並使用Java的InputStream
類中新提供的函數:
public static void encrypt(RSAPublicKey publicKey) throws Exception {
try (FileOutputStream out = new FileOutputStream("dataFile" + ".enc")) {
// --- RSA using PKCS#1 v1.5 padding
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
// --- AES key generator
KeyGenerator kgen = KeyGenerator.getInstance("AES");
kgen.init(128);
SecretKey skey = kgen.generateKey();
// --- write encrypted AES key
byte[] encryptedSKey = cipher.doFinal(skey.getEncoded());
out.write(encryptedSKey);
// --- Initialization vector 16 byte
SecureRandom srandom = new SecureRandom();
byte[] iv = new byte[128/8];
srandom.nextBytes(iv);
IvParameterSpec ivspec = new IvParameterSpec(iv);
// --- write IV
out.write(iv);
// --- initialize AES cipher
Cipher ci = Cipher.getInstance("AES/CBC/PKCS5Padding");
ci.init(Cipher.ENCRYPT_MODE, skey, ivspec);
// --- convert file by copying to memory
try (FileInputStream in = new FileInputStream("dataFile.xml")) {
byte[] buffer = in.readAllBytes();
byte[] encryptedData = ci.doFinal(buffer);
out.write(encryptedData);
}
}
}
public static void decrypt(RSAPrivateKey privateKey) throws Exception {
try (FileInputStream in = new FileInputStream("dataFile" + ".enc")) {
// --- RSA using PKCS#1 v1.5 padding
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher.init(Cipher.DECRYPT_MODE, privateKey);
// --- read encrypted AES key
byte[] encryptedSKey = in.readNBytes(determineEncryptionSizeInBytes(privateKey));
byte[] decryptedSKey = cipher.doFinal(encryptedSKey);
SecretKey skey = new SecretKeySpec(decryptedSKey, "AES");
// --- Initialization vector 16 byte
byte[] iv = in.readNBytes(128 / Byte.SIZE);
IvParameterSpec ivspec = new IvParameterSpec(iv);
// --- initialize AES cipher
Cipher ci = Cipher.getInstance("AES/CBC/PKCS5Padding");
ci.init(Cipher.DECRYPT_MODE, skey, ivspec);
// --- convert file by copying to memory
File outputDataFile = new File("dataFile.xml2");
try (FileOutputStream out = new FileOutputStream(outputDataFile)) {
byte[] buffer = in.readAllBytes();
byte[] decryptedData = ci.doFinal(buffer);
out.write(decryptedData);
}
}
}
private static int determineEncryptionSizeInBytes(RSAPrivateKey privateKey) {
return (privateKey.getModulus().bitLength() + Byte.SIZE - 1) / Byte.SIZE;
}
public static void main(String[] args) throws Exception {
KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
kpg.initialize(384 * Byte.SIZE);
KeyPair pair = kpg.generateKeyPair();
encrypt((RSAPublicKey) pair.getPublic());
decrypt((RSAPrivateKey) pair.getPrivate());
}
如您所見,代碼現在非常像是鏡像。 我只復制了加密代碼,然后對其進行了更改。 如您所見,它現在依靠InputStream#readAllBytes()
(從Java 9開始)和InputStream#readNBytes()
(從Java 11開始)來使用更少的類。
請注意,您通常希望使用較小的緩沖區來流式傳輸文件。 由於當前正在緩沖整個純文本和密文,因此您的應用程序使用的內存比所需的要多得多。 要使用流加密數據,可以依賴CipherInputStream
和CipherOutputStream
。
不用說,異常處理需要改進,我只是研究了解決當前問題的最佳方法。 當您使事情正常運行時(請使工作正常,使事情正確,使事情最優化),請重新看一下。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.