mcorley
mcorley

Reputation: 767

Implementing Bouncy Castle Cipher Algorithms with Android

How can I use the Bouncy Castle provider to implement algorithms such as Serpent and Twofish, because Sun's providers don't implement these at all. I know when multiple providers can implement the same algorithm, you get the implementation form the highest ranking provider which is going to be the Sun provider. If for some reason you want to use the implementation from a specific provider (perhaps because you know it is faster), you can specify the provider in two-arg version of getInstance(). In my case, the Sun provider doesn't implement the algorithms I'm interested in at all.

I have attempted to implement Serpent:

    public static final String FILE_EXTENSION = ".serpent";
    public static final String PROVIDER = "BC"; // Bouncy Castle
    public static final String BLOCK_CIPHER = "Serpent";
    public static final String TRANSFORMATION = "Serpent/CBC/PKCS7Padding";
    public static final String KEY_ALGORITHM = "PBKDF2WithHmacSHA1";
    public static final String PRNG_ALGORITHM = "SHA1PRNG";

    public static final int BLOCK_SIZE = 128; // bits
    public static final int KEY_SIZE = 256; // bits
    public static final int ITERATION_COUNT = 1024; // for PBE

    /** Performs the encryption of a file. */
    public void encrypt(String pathname, char[] password, byte[] salt) {
        // Use bouncy castle as our provider
        Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());

        // Convert the file into a byte array
        byte[] plaintext = fileToBytes(new File(pathname));

        // Generate a 256-bit key
        SecretKey key = generateSecretKey(password,salt);

        // Generate a 128-bit secure random IV
        byte[] iv = generateIV();

        // Setup the cipher and perform the encryption
        Cipher cipher = null;
        byte[] ciphertext = null;
        try {
            cipher = Cipher.getInstance(TRANSFORMATION, PROVIDER);
            cipher.init(Cipher.ENCRYPT_MODE, key, new IvParameterSpec(iv));
            ciphertext = cipher.doFinal(plaintext);
        } catch (Exception e) {
            e.printStackTrace();
        }

        // Append the IV to the ciphertext
        byte[] temp = new byte[iv.length+ciphertext.length];
        System.arraycopy(iv, 0, temp, 0, iv.length);
        System.arraycopy(ciphertext, 0, temp, iv.length, ciphertext.length);
        ciphertext = temp;

        // Store the encrypted file in the same directory we found it
        if (Environment.getExternalStorageDirectory().canWrite()) {
            bytesToFile(ciphertext, pathname+FILE_EXTENSION);
            File file = new File(pathname);
            file.delete();
        }       
    }

This however throws a

java.security.NoSuchAlgorithmException: Serpent/CBC/PKCS7Padding

on the line where I call

cipher = Cipher.getInstance(TRANSFORMATION, PROVIDER);

Running

$ adb shell
# logcat

I get tons of

not resolving ambiguous class
not verifying
multiple definitions

errors being outputted. Any idea what can be causing this to happen and how I can resolve the issue?

Upvotes: 4

Views: 7489

Answers (2)

Roberto Tyley
Roberto Tyley

Reputation: 25304

You probably want Spongy Castle - a repackage I made of Bouncy Castle specifically targeted for Android.

Spongy Castle is a full replacement for the crippled versions of the Bouncy Castle cryptographic libraries which ship with Android. There are a couple of small changes to make it work on Android:

  • all package names have been moved from org.bouncycastle.* to org.spongycastle.* - so no classloader conflicts
  • the Java Security API Provider name is now SC rather than BC

"Spongy Castle saved my ass." - feedback from one happy user :)

Upvotes: 6

Anya Shenanigans
Anya Shenanigans

Reputation: 94584

What does javap org.bouncycastle.jce.provider.symmetric.Serpent yield? If it doesn't yield a class being found, then it indicates that there is something missing in the bouncy castle package, or you may be using an incorrect class.

if you're using the 1.4 VM, then the jar file needs to be installed in $JAVA_HOME/jre/lib/ext, as otherwise it will not work correctly IIRC.

Check the output of zipinfo bcprov-jdk16-146.jar | grep '/symmetric/' for the Serpent class. Again, this is to cross-check the correct installation of the package and the presence of the Serpent symmetric algorithm.

I did a simple test, using quite similar code to your own, and it did not generate an exception.

Ok, the provider is present in the system, but what is happening is that the internal bouncy castle implementation is being loaded before the one you have linked in. The internal implementation does not contain the Serpent/CBC/PKCS7Padding code, and even though you add the bouncycastle provider, it does not replace the ones that have already been registered.

The internal provider only implements a handful of ciphers, viz. AES, ARC4, Blowfish and DESede

I used the following stub activity to determine this:

public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
    Cipher cipher = null;
    TextView tv = new TextView(this);
    setContentView(tv);

    for (String name : SYMMETRIC_CIPHERS) {
    try {
        cipher = Cipher.getInstance(name, "BC");
        tv.append(name);
        tv.append("\n");
    } catch (Exception e) {
    }
    }
}

with the list of providers from the BouncyCastleProvider source code:

private static final String[] SYMMETRIC_CIPHERS =
{
    "AES", "ARC4", "Blowfish", "Camellia", "CAST5", "CAST6", "DESede", "Grainv1", "Grain128", "HC128", "HC256", "IDEA",
    "Noekeon", "RC5", "RC6", "Rijndael", "Salsa20", "SEED", "Serpent", "Skipjack", "TEA", "Twofish", "VMPC", "VMPCKSA3", "XTEA"
};

I know it doesn't really help you, but why aren't you using AES?

Upvotes: 3

Related Questions