Question

So.. here is the class: (I use and made for AES256 encryption)

public class AES256
{
private String charSet = "UTF-8";
private String algo = "AES/CBC/PKCS5Padding";
private String baseAlgo = "AES";
private String hashAlgo = "PBKDF2WithHmacSHA1";

private String key = null;
private String salt = "defaultsaltsalt";
private String iv = "a1bC@6jZ!#sL1z0y";

private Cipher cipher;
private BufferedInputStream bIs;
private BufferedOutputStream bOs;

public AES256()
{

}

public AES256(String pass)
{
    this.key = pass;
}

public AES256(String pass, String salty)
{
    this.key = pass;
    this.salt = salty;
}

public AES256(String pass, String salty, String ivs)
{
    this.key = pass;
    this.salt = salty;
    this.iv = ivs;
}

public void setKey(String key)
{
    this.key = key;
}

public void setSalt(String salt)
{
    this.salt = salt;
}

public void setIV(String ivs)
{
    this.iv = ivs;
}

/**
 * @Method Pads and constructs the SecretKey (Padding @ 32)
 * @return Returns the padded key.
 * @throws Exception Exception is thrown if the key is null or something else wrong..
 */
public SecretKeySpec getKey() throws Exception
{
     byte[] saltBytes = salt.getBytes(charSet);

     SecretKeyFactory factory = SecretKeyFactory.getInstance(hashAlgo);
     PBEKeySpec spec = new PBEKeySpec(
             this.key.toCharArray(), 
             saltBytes, 
             300000, //make variable
             263 //default 32 bytes
     );

     SecretKey secretKey = factory.generateSecret(spec);
     SecretKeySpec secret = new SecretKeySpec(secretKey.getEncoded(), baseAlgo);

     return secret;
}

/**
 * @Method Pads and returns the IV (Padding @ 16)
 * @return
 * @throws Exception
 */
public byte[] getIV() throws Exception
{
    byte[] byteKey = iv.getBytes(charSet);
    MessageDigest sha = MessageDigest.getInstance("SHA-512");
    byteKey = sha.digest(byteKey);
    byteKey = Arrays.copyOf(byteKey, 16);
    return byteKey;
}

public byte[] encrypt(byte[] plainText) throws Exception
{
    cipher = Cipher.getInstance(algo);
    cipher.init(Cipher.ENCRYPT_MODE, getKey(), new IvParameterSpec(getIV()));

    System.out.println("Plain text length: "+plainText.length);
    byte[] enc = Base64.encodeBase64(cipher.doFinal(plainText));
    System.out.println("Encrypted text length "+enc.length);

    return  enc;
}

public byte[] decrypt(byte[] encryptedText) throws Exception
{
    cipher = Cipher.getInstance(algo);
    cipher.init(Cipher.DECRYPT_MODE, getKey(), new IvParameterSpec(getIV()));

    System.out.println("Encrypted Decrypted Text length: "+encryptedText.length);
    byte[] de = cipher.doFinal(Base64.decodeBase64(encryptedText));
    System.out.println("Decrypted Text length: "+de.length);

    return de;
}

public void encrypt(File fileToEncrypt) throws FileNotFoundException, IOException, Exception
{
    if(fileToEncrypt == null)
        throw new FileNotFoundException("File given to encrypt was not found!");
    File encrypted = new File(cutPath(fileToEncrypt.getPath()), "ENCRYPTED "+fileToEncrypt.getName());
    if(!encrypted.exists())
        encrypted.createNewFile();
    bIs = new BufferedInputStream(new FileInputStream(fileToEncrypt));
    bOs = new BufferedOutputStream(new FileOutputStream(encrypted));

    @SuppressWarnings("unused")
    int read = 0;
    byte[] buff = new byte[1024];
    while((read = bIs.read(buff)) != -1)
    {
        byte[] enc = encrypt(buff);
        bOs.write(enc, 0, enc.length);
    }
    bIs.close();
    bOs.close();
}

public void decrypt(File fileToDecrypt) throws FileNotFoundException, IOException, Exception
{
    if(fileToDecrypt == null)
        throw new FileNotFoundException("File given to decrypt was not found!");
    File decrypted = new File(cutPath(fileToDecrypt.getPath()), "DECRYPTED "+fileToDecrypt.getName().replace("ENCRYPTED ", ""));
    if(!decrypted.exists())
        decrypted.createNewFile();
    bIs = new BufferedInputStream(new FileInputStream(fileToDecrypt));
    bOs = new BufferedOutputStream(new FileOutputStream(decrypted));

    @SuppressWarnings("unused")
    int read = 0;
    byte[] buff = new byte[1388];
    while((read = bIs.read(buff)) != -1)
    {
        byte[] de = decrypt(buff);
        bOs.write(de, 0, de.length);
    }
    bIs.close();
    bOs.close();
}

private String cutPath(String path)
{
    String temp = "";
    String[] parts = path.split(Pattern.quote(File.separator));
    for(int i = 0; i < parts.length-1; i++)
        temp+=parts[i]+"/";
    return temp;
}

}

I am using this class that i wrote to encrypt and decrypt information in java using CBC/PKCS5PADDING and I am also using a hash algo in order to hash my password..

Note: I know there is some efficiency problems in this program like why do i keep computing the key ever block i get from the file.. I am fixing that later.. It was just there to test some things out.

Anyways, I am using the encrypt(File) method and when i give it a file it gets the information 1024 bytes at a time and encrypts that information then coverts to BASE64 to avoid encoding issues.. then writes it back to a different file with the same name but the words ENCRYPTED or DECRYPTED in front of it... and in the same directory as the parent file..

Now my problem is when it is encrypting the information I am sending it 1024 bytes of information to process and then using BASE64 to avoid encoding issues such as UTF and such.. but in the end of things the 1024 bytes that i am encrypting some how turns into 1388 bytes of data and that is what i get back... Now why is that?

Second problem: It somewhat works besides the problem above maybe its not a problem but I would love to learn why.. Anyways the second problem is also using the encrypt(File) method As well as decrypt(File).. When i encrypt the file it somehow adds some extra length to it (Might be directly related to the problem above...), So that when i decrypt the file the file has the text perfectly decrypted but then I get some extra repeat text at the bottom for whatever reason... Like the file will be in order until the end with some repeat information.. So i don't know where these random bytes are coming from but i would love to know..

Anyways, If you find any other problems with my encryption methods please please tell me here, Possibly weak encryption choice? Maybe it is easily being able to be brute-forced? Using an inefficient method? Don't understand something I am trying to accomplish? Possibly like saving the file with the same name and the same directory.. Is there an easier way?

Was it helpful?

Solution

Base-64 encoding a string results in a longer string than you started with.

Think of it this way. You had an array with 8 significant bits in each byte. You end up with a string with only 6 of the bits being important (hence the 64 in the name, base-64, because 2^6 = 64) so it has to be longer by roughly 1/3.

Working backwards, AES encryption using the modes you have will add 16 bytes of padding so the result will be 16 bytes longer than what you fed it. That means you give it 1024 and encryption (before the base-64 encoding) will result in a length of 1040 bytes.

The arithmetic works this way:

1024 bytes + 16 padding = 1040 bytes
1040 bytes is not divisible by 3 (as required by base-64) so add 1 byte
1041 bytes * 8 = 8328 bits / 6 = 1388
1388 base-64 characters

PART 2

The reason you have extra bytes on the end is in this code:

byte[] buff = new byte[1024];
while((read = bIs.read(buff)) != -1)
{
    byte[] enc = encrypt(buff);
    bOs.write(enc, 0, enc.length);
}

On the last read, it does not read a full 1024 bytes into the buffer. The bytes from the previous read are still there.

The variable 'read' holds the number of bytes actually read. Notice how that variable isn't used. But you are encrypting the entire buffer, not just the first 'read' number of bytes.

You can fix this by passing the value of 'read' into your 'encrypt' method and using the alternate form of the doFinal(buff, 0, read) method to just encrypt what was read.

Change this line:

    byte[] enc = encrypt(buff, read);

And this one:

public byte[] encrypt(byte[] plainText, int len) throws Exception

And this one:

byte[] enc = Base64.encodeBase64(cipher.doFinal(plainText, 0, len));

You will need to do something similar to your decrypt because it may not have 1388 bytes to read the last time and the old bytes will be in the buffer. (You don't have this problem now because you always encrypt 1024 bytes. It's just that some of them are wrong if the file has a short read on the last block.)

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top