Search code examples
javaencryptionbouncycastle

Can I use BouncyCastle's Tweakable Block Ciphers using the standard Java Cipher API?


BouncyCastle provides an implementation of Threefish, which can take a tweak as a parameter:

ThreeFishEngine engine = new ThreeFishEngine(256);
engine.init(true, new TweakableBlockCipherParams(...));

However, TweakableBlockCipherParams is not compatible with the AlgorithmParameter type that is used by instances of Java's default Cipher.

Is there a way to initialize this cipher with a tweak?

Cipher cipher = Cipher.getInstance("Threefish-256/CBC/NoPadding");
cipher.init(???);

Solution

  • You can only use Bouncy Castle's Threefish algorithm through Java's cryptography API if you don't want to use a tweak parameter during ciphering. Through Java's API you can only introduce a key and an initialization vector parameter, but this won't be used as a tweak parameter (I explained why after the code example, see below).

    Also, for the below example to work you have to update your JRE/JDK with the Java Cryptography Extension (JCE) Unlimited Strength Jurisdiction Policy Files which you can download from here. There are different versions for Java 7 and 8.

    If you don't want to use a tweak parameter you can use the Threefish algorithm through the standard crypto API like this.

    static final BouncyCastleProvider PROVIDER = new BouncyCastleProvider();
    
    public static void main(String[] args) throws Exception {
        KeyGenerator kg = KeyGenerator.getInstance("Threefish-1024", PROVIDER);
        kg.init(1024);
        SecretKey key = kg.generateKey();
    
        byte[] plaintext = "Hi! I'm cat!".getBytes();
        byte[] ciphertext = encrypt(key, plaintext);
        System.out.println(new String(decrypt(key, ciphertext)));
        // prints "Hi! I'm cat!"
    }
    
    static byte[] encrypt(SecretKey key, byte[] plaintext) throws Exception {
        return encryptOrDecrypt(true, key, plaintext);
    }
    
    static byte[] decrypt(SecretKey key, byte[] ciphertext) throws Exception {
        return encryptOrDecrypt(false, key, ciphertext);
    }
    
    static byte[] encryptOrDecrypt(boolean encrypt, SecretKey key, byte[] bytes) throws Exception {
        Cipher cipher = Cipher.getInstance("Threefish-1024/CBC/PKCS5Padding", PROVIDER);
        // note that we are creating a dummy iv parameter, in this case it
        // should be 128 bytes long, because if it's not an exception is raised
        cipher.init(encrypt ? Cipher.ENCRYPT_MODE : Cipher.DECRYPT_MODE, key, new IvParameterSpec(new byte[128]));
        return cipher.doFinal(bytes);
    }
    

    I've downloaded a Bouncy Castle JAR with debug symbols from here and debugged the above code. The call to Cipher.init lands in Threefish.init and the variable params will be an instance of KeyParameter and not TweakableBlockCipherParameters in our case. So, tweakBytes will be null and won't be used during ciphering.

    Knowing this, right now it's impossible to use the Java API to supply the tweak parameter to the underlying Threefish cipher engine.

    Link to another very similar question