簡體   English   中英

JAVA通過加密過程中使用的這3種組合將加密文件中的AES密鑰,初始化向量和數據分開

[英]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開始)來使用更少的類。

請注意,您通常希望使用較小的緩沖區來流式傳輸文件。 由於當前正在緩沖整個純文本密文,因此您的應用程序使用的內存比所需的要多得多。 要使用流加密數據,可以依賴CipherInputStreamCipherOutputStream

不用說,異常處理需要改進,我只是研究了解決當前問題的最佳方法。 當您使事情正常運行時(請使工作正常,使事情正確,使事情最優化),請重新看一下。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM