5

I'm making an app that encrypts some files. I want to use gnu's cryptix library. It says it is no longer developed since 2005, but I guess it has everything I need... should I use something else?

And I have a question about encrypting a single file. Right now I do it with a loop like this:

for(int i=0; i+block_size < bdata.length; i += block_size)
    cipher.encryptBlock(bdata, i, cdata, i);

So my question is how to encrypt the last block that may not have the same size as the block_size. I was thinking maybe a should add some extra data to the last block, but than I don't know how to decrypt that...

user568021
  • 1,426
  • 5
  • 28
  • 55
  • There is really no need to encrypt each block separately yourself, that kind of stuff is already in the API's, nor do you need to develop your own padding mechanism ("...add some extra data to the last block"). – Maarten Bodewes Jul 29 '12 at 17:45

4 Answers4

7

I would strongly suggest using AES encryption and it too comes with the JAVA SDK. Have a look at: Using AES with Java Technology which will give you some great example. To read up more on AES see: Advanced Encryption Standard - Wikipedia.

Never use your own encryption scheme or an older form of an encryption scheme. AES has been tried and tested by people with far greater knowledge in that field then us, so you know it will work. Where as with your own or an old encryption scheme we might miss a fatal loop hole that will leave our data open to attacks.

See this question here to see the difference in the encryption schemes: Comparison of DES, Triple DES, AES, blowfish encryption for data

Addendum:

AES in java will work flawlessly for 192 and 256bit keys but you will have to install the newer JCE Policy Files. See here and here. You should also place the files in your JDK or else it wont work when executed from your IDE.

Note: Make sure you download the correct JCE policy files, depending on your Java version i.e 1.4, 1.5 1.6 or 7.

However if you use 128bit keys no need to install the newer JCE files.

Here is a template of some secure AES usage in java it use CBC/AES/PKCS5Padding and a random IV using RandomSecure.

Note you need both the key and IV for decrypting:

import java.io.UnsupportedEncodingException;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import javax.crypto.*;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

/**
 * This program generates a AES key, retrieves its raw bytes, and then
 * reinstantiates a AES key from the key bytes. The reinstantiated key is used
 * to initialize a AES cipher for encryption and decryption.
 */
public class AES {

    /**
     * Encrypt a sample message using AES in CBC mode with a random IV genrated
     * using SecyreRandom.
     *
     */
    public static void main(String[] args) {
        try {
            String message = "This string contains a secret message.";
            System.out.println("Plaintext: " + message + "\n");

            // generate a key
            KeyGenerator keygen = KeyGenerator.getInstance("AES");
            keygen.init(128);  // To use 256 bit keys, you need the "unlimited strength" encryption policy files from Sun.
            byte[] key = keygen.generateKey().getEncoded();
            SecretKeySpec skeySpec = new SecretKeySpec(key, "AES");

            // build the initialization vector (randomly).
            SecureRandom random = new SecureRandom();
            byte iv[] = new byte[16];//generate random 16 byte IV AES is always 16bytes
            random.nextBytes(iv);
            IvParameterSpec ivspec = new IvParameterSpec(iv);

            // initialize the cipher for encrypt mode
            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
            cipher.init(Cipher.ENCRYPT_MODE, skeySpec, ivspec);

            System.out.println("Key: " + new String(key, "utf-8") + " This is important when decrypting");
            System.out.println("IV: " + new String(iv, "utf-8") + " This is important when decrypting");
            System.out.println();

            // encrypt the message
            byte[] encrypted = cipher.doFinal(message.getBytes());
            System.out.println("Ciphertext: " + asHex(encrypted) + "\n");

            // reinitialize the cipher for decryption
            cipher.init(Cipher.DECRYPT_MODE, skeySpec, ivspec);

            // decrypt the message
            byte[] decrypted = cipher.doFinal(encrypted);
            System.out.println("Plaintext: " + new String(decrypted) + "\n");
        } catch (IllegalBlockSizeException | BadPaddingException | UnsupportedEncodingException | InvalidKeyException | InvalidAlgorithmParameterException | NoSuchPaddingException | NoSuchAlgorithmException ex) {
            ex.printStackTrace();
        }
    }

    /**
     * Turns array of bytes into string
     *
     * @param buf   Array of bytes to convert to hex string
     * @return  Generated hex string
     */
    public static String asHex(byte buf[]) {
        StringBuilder strbuf = new StringBuilder(buf.length * 2);
        int i;
        for (i = 0; i < buf.length; i++) {
            if (((int) buf[i] & 0xff) < 0x10) {
                strbuf.append("0");
            }
            strbuf.append(Long.toString((int) buf[i] & 0xff, 16));
        }
        return strbuf.toString();
    }
}
Community
  • 1
  • 1
David Kroukamp
  • 36,155
  • 13
  • 81
  • 138
  • I will try this ... but probably tomorrow. I tried 3 or 4 different approaches today and you just get tired of this... Every approach has some issue I can't go around. – user568021 Jul 29 '12 at 11:58
  • 5
    That uses "ECB" mode and "PKCS5Padding" padding mechanism (the defaults). Although PKCS5Padding is fine, ECB is not. You should at least use CBC with a random IV: `"AES/CBC/PKCS5Padding"` or GCM mode: `"AES/GCM/NoPadding"` during `Cipher.getInstance(String): Cipher`. – Maarten Bodewes Jul 29 '12 at 17:43
  • @user568021 glad you got it working. And take note if the above comment its very much correct. – David Kroukamp Jul 29 '12 at 18:06
  • That's very interesting but with AES/GCM/NoPadding I get "No such algorithm exception"... and using AES/CBC/PKCS5Padding there's a problem with decryption - it's strange: here it says "invalid key exception"... – user568021 Jul 29 '12 at 18:47
  • @user568021 See my edited post. I found the template I usually use its pretty secure, though I havent added the salt part but its not necessary. – David Kroukamp Jul 29 '12 at 19:39
  • @user568021 yes but the IV does not necessarily have to be kept by the user, because without the key the IV is useless, and vice versa, so you could write the IV to you file which will then be read and decrypted using the key given (also best stored in a seperate file which user keeps, as it might be to long to remember) – David Kroukamp Jul 30 '12 at 12:11
5

I always use BouncyCastle

I also use the streaming framework instead of the for loop you were describing: it deals with the issue raised. Mostly I use that because when it comes to cryptography (and threading) I rarely trust my own code, I trust the people that live eat and breath it. Here is the code I use when I want "gash" cryptography. i.e. I have no particular threat model, and just want something "a little secure".

The hex encoding of the keys makes them much easier to manipulate / store and so on. I use "makeKey" to ... well ... make a key, then I can use the key in the encrypt and decrypt methods. You can obviously go back to using byte[] instead of hex strings for the keys.

    private static boolean initialised;
    private static void init() {
      if (initialised)
        return;
      Security.addProvider(new BouncyCastleProvider());
      initialised = true;
    }
    public static String makeKey() {
        init();
        KeyGenerator generator = KeyGenerator.getInstance(algorithm, provider);
        generator.init(keySize);
        Key key = generator.generateKey();
        byte[] encoded = key.getEncoded();
        return Strings.toHex(encoded);
}

public static String aesDecrypt(String hexKey, String hexCoded) {
        init();
        SecretKeySpec key = new SecretKeySpec(Strings.fromHex(hexKey), algorithm);
        Cipher cipher = Cipher.getInstance(algorithm + "/ECB/PKCS5Padding", provider);
        cipher.init(Cipher.DECRYPT_MODE, key);
        byte[] codedBytes = Strings.fromHex(hexCoded);
        CipherInputStream inputStream = new CipherInputStream(new ByteArrayInputStream(codedBytes), cipher);
        byte[] bytes = getBytes(inputStream, 256);
        String result = new String(bytes, "UTF-8");
        return result;
}

public static String aesEncrypt(String hexKey, String input) {
        init();
        SecretKeySpec key = new SecretKeySpec(Strings.fromHex(hexKey), algorithm);

        Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding", "BC");
        cipher.init(Cipher.ENCRYPT_MODE, key);
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(input.length());
        CipherOutputStream outputStream = new CipherOutputStream(byteArrayOutputStream, cipher);
        setText(outputStream, input);
        byte[] outputBytes = byteArrayOutputStream.toByteArray();
        String output = new String(Strings.toHex(outputBytes));
        return output;
}
public static void setText(OutputStream outputStream, String text, String encoding) {
    try {
        outputStream.write(text.getBytes(encoding));
        outputStream.flush();
    } finally {
            outputStream.close();
    }
}
public static byte[] getBytes(InputStream inputStream, int bufferSize) {
    try {
        List<ByteArrayAndLength> list = Lists.newList();
        while (true) {
            byte[] buffer = new byte[bufferSize];
            int count = inputStream.read(buffer);
            if (count == -1) {
                byte[] result = new byte[ByteArrayAndLength.length(list)];
                int index = 0;
                for (ByteArrayAndLength byteArrayAndLength : list) {
                    System.arraycopy(byteArrayAndLength.bytes, 0, result, index, byteArrayAndLength.length);
                    index += byteArrayAndLength.length;
                }
                assert index == result.length;
                return result;
            }
            list.add(new ByteArrayAndLength(buffer, count));
        }
    } finally {
            inputStream.close();
    }
}
    static class ByteArrayAndLength {
    byte[] bytes;
    int length;

    public ByteArrayAndLength(byte[] bytes, int length) {
        super();
        this.bytes = bytes;
        this.length = length;
    }

    static int length(List<ByteArrayAndLength> list) {
        int result = 0;
        for (ByteArrayAndLength byteArrayAndLength : list) {
            result += byteArrayAndLength.length;
        }
        return result;
    }
}

I've taken out some of the exception catching to reduce the size of the code, and Strings.fromHex turns the string back into a byte[]

David Kroukamp
  • 36,155
  • 13
  • 81
  • 138
Phil Rice
  • 151
  • 1
  • 6
  • +1 for mentioning AES. Though I'd be skeptical of turning to a 3rd party library when it can be done in native java libraries (although of course it does make it easier) – David Kroukamp Jul 29 '12 at 10:39
  • 1
    Using ECB mode is not recommended (see my other comment). Furthermore it should be noted that using the BouncyCastle provider is definitively not needed in J2SE, and that `CipherInputStream` may remove any `BadPaddingException`s that may be thrown. – Maarten Bodewes Jul 29 '12 at 17:58
  • 1
    +1 for BouncyCastle. One reason to use BC: http://stackoverflow.com/questions/2927952/why-do-people-use-bouncycastle-instead-of-java-cryptography-extension-what-is-t – Jeremy Brooks Apr 10 '13 at 22:56
2

Maybe you should consider using a javax.crypto package. Here is an example of how to use Ciphers:

DES encryption

Hope this helps

Community
  • 1
  • 1
Mark Bramnik
  • 39,963
  • 4
  • 57
  • 97
  • 1
    DES is the old "data encryption standard" from the seventies. Its key size is too short for proper security (56 effective bits; this can be brute-forced, as has been demonstrated more than ten years ago). Also, DES uses 64-bit blocks, which raises some potential issues when encrypting several gigabytes of data with the same key (a gigabyte is not that big nowadays). – David Kroukamp Jul 29 '12 at 10:38
  • Sorry, but my point was to not encourage to use DES specifically, but instead point on javax.crypto package as a valid substitution to cryptix mentioned by user568021. DES was only an example, and user568021 didn't ask about the specific method of encryption. Sorry for misunderstanding here. – Mark Bramnik Jul 29 '12 at 11:26
0

I would seriously think twice before going this route. The development of the software was halted because standard alternatives exist, and have a look at the mailing list, there's been no significant activity since 2009. In my book that means that the software is abandoned, and abandoned software means you're more or less on your own.

Have a look here on SO, there are several questions and answers that may help you like this one. An at first sight interesting package that could simplify things for you (but still using the standard JCE infrastructure) is jasypt

Community
  • 1
  • 1
fvu
  • 32,488
  • 6
  • 61
  • 79
  • Yeah I tried jasypt but it has some bug in the binary decryption, I really don't want to deal with them right now. – user568021 Jul 29 '12 at 11:24
  • please note that **jasypt** relies on **bouncycastle** - at least for recent versions (I know this question and answer are old) – diginoise Oct 09 '17 at 16:39
  • @diginoise the [features page](http://www.jasypt.org/features.html#) still says `Open API for use with any JCE provider, and not only the default Java VM one. Jasypt can be easily used with well-known providers like Bouncy Castle`. Note, **can**, not **must**. On the other hand, with a last update 3.5 years ago and mostly dead support links this project may quite be EOL too. – fvu Oct 09 '17 at 22:38
  • @fvu fair point. jasypt's pom lists bouncycastle as dependency perhaps for default implementations – diginoise Oct 10 '17 at 08:25