Rekha Ahir
Rekha Ahir

Reputation: 13

File Encryption Decryption with AES

public long copyStreamsLong(InputStream in, OutputStream out, long sizeLimit) throws IOException {

        long byteCount = 0;
        IOException error = null;
        long totalBytesRead = 0;
        try {
            String key = "C4F9EA21977047D6"; // user value (16/24/32 bytes)
            // byte[] keyBytes = DatatypeConverter.parseHexBinary(aesKey);
            SecretKeySpec secretKey = new SecretKeySpec(key.getBytes(), "AES");
            System.out.println(secretKey.toString());
            Cipher cipher = Cipher.getInstance("AES");
            cipher.init(Cipher.ENCRYPT_MODE, secretKey);
            byte[] buffer = new byte[CustomLimitedStreamCopier.BYTE_BUFFER_SIZE];
            // in.read(buffer);
            int bytesRead = -1;
            while ((bytesRead = in.read(buffer)) != -1) {
                // We are able to abort the copy immediately upon limit violation.
                totalBytesRead += bytesRead;
                if (sizeLimit > 0 && totalBytesRead > sizeLimit) {
                    StringBuilder msg = new StringBuilder();
                    msg.append("Content size violation, limit = ").append(sizeLimit);
                    throw new ContentLimitViolationException(msg.toString());
                }
                byte[] obuf = cipher.update(buffer, 0, bytesRead);
                if (obuf != null) {
                    out.write(obuf);
                }
                    byteCount += bytesRead;
            }
            byte[] obuf = cipher.doFinal();
            if (obuf != null) {
                out.write(obuf);
            }
                    out.flush();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                in.close();
            } catch (IOException e) {
                error = e;
                CustomLimitedStreamCopier.logger.error("Failed to close input stream: " + this, e);
            }
            try {
                out.close();
            } catch (IOException e) {
                error = e;
                CustomLimitedStreamCopier.logger.error("Failed to close output stream: " + this, e);
            }
        }
        if (error != null)
            throw error;
        return byteCount;
    }
     public InputStream getContentInputStream() throws ContentIOException {
        ReadableByteChannel channel = getReadableChannel();
        InputStream is = Channels.newInputStream(channel);
        try {    
            final String ALGORITHM = "AES";
            final String TRANSFORMATION = "AES";
            String key = "C4F9EA21977047D6";
            Key secretKey = new SecretKeySpec(key.getBytes(), ALGORITHM);
            Cipher cipher = Cipher.getInstance(TRANSFORMATION);
            cipher.init(Cipher.DECRYPT_MODE, secretKey);
            byte[] buffer = ByteStreams.toByteArray(is);
            System.out.println("in read" + buffer.length);
            is.read(buffer);
            byte[] outputBytes = cipher.doFinal(buffer);            
            is = new ByteArrayInputStream(outputBytes);
}

When i m trying to encrypt input stream i will get increased byte array and after that when i will decrypt that input stream at that time in decryption it will take original byte size .so,when i tried to open that file it will give error that premature end tag so i want same file size after encryption ,and this method is part of java class.

What will be the solution for this problem?

Upvotes: 1

Views: 500

Answers (1)

Michael Fehr
Michael Fehr

Reputation: 6414

You initialize the cipher with the TRANSFORMATION = "AES" and that means that your Java implementation will choose a default AES mode, usually it is "AES/ECB/PKCS5Padding". Beneath the fact that ECB-mode is unsecure and should not any longer used for plaintext/streams longer than 16 bytes the padding will add additional bytes up to a (multiple) blocklength of 16.

So running my small program you see that in your implementation an inputLen of "10" (means a plaintext/stream of 10 byte length) will result in an outputSize of "16".

To avoid this you do need another AES mode and that the output is of the same length as the input on encryption side. You can use AES CTR mode for this - you just need an additional parameter (initialization vector, 16 byte long). It is very important that you never ever use the same iv for more than 1 encryption so it should get generated as random value. For decryption the recipient of the message ("the decryptor") needs to know what initvector was used on encryption side.

cipher algorithm: AES                  inputLen  10 outputSize  16
cipher algorithm: AES/CTR/NOPADDING    inputLen  10 outputSize  10

Edit (security warning): As reminded by President James K. Polk "CTR mode makes it trivial to modify individual bytes of the attacker's choosing, so it needs to be coupled with an authentication tag.". It depends on the kind of data that are going to get encrypted if they need a authentication (e.g. if you are encrypting music files then any modifying will result in a "piep" or "krk", changing of financial data will end catastrophical).

code:

import javax.crypto.Cipher;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.security.*;

public class Main {
    public static void main(String[] args) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, InvalidAlgorithmParameterException {
        System.out.println("");
        int inputLen = 10;
        final String ALGORITHM = "AES";

        // aes ecb mode
        final String TRANSFORMATION = "AES";
        //final String TRANSFORMATION = "AES/ECB/PKCS5PADDING";
        String key = "C4F9EA21977047D6";
        Key secretKey = new SecretKeySpec(key.getBytes(), ALGORITHM);
        Cipher cipher = Cipher.getInstance(TRANSFORMATION);
        cipher.init(Cipher.ENCRYPT_MODE, secretKey);
        System.out.format("cipher algorithm: %-20s inputLen %3d outputSize %3d%n", cipher.getAlgorithm(), inputLen, cipher.getOutputSize(inputLen));

        // aes ctr mode
        String TRANSFORMATION2 = "AES/CTR/NOPADDING";
        // you need an unique (random) iv for each encryption
        SecureRandom secureRandom = new SecureRandom();
        byte[] iv = new byte[16];
        secureRandom.nextBytes(iv);
        IvParameterSpec ivParameterSpec = new IvParameterSpec(iv);
        Cipher cipher2 = Cipher.getInstance(TRANSFORMATION2);
        cipher2.init(Cipher.ENCRYPT_MODE, secretKey, ivParameterSpec);
        System.out.format("cipher algorithm: %-20s inputLen %3d outputSize %3d%n", cipher2.getAlgorithm(), inputLen, cipher2.getOutputSize(inputLen));
    }
}

A running implementation of the AES CTR-mode can be found here: https://stackoverflow.com/a/62662276/8166854

Upvotes: 1

Related Questions