Reputation: 767
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
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:
"Spongy Castle saved my ass." - feedback from one happy user :)
Upvotes: 6
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