|
Bouncy Castle Crypto API is a lightweight cryptography API in Java. It also have a J2ME version.
This tip will give you an example of encryption and decryption of messages using Bouncy Castle Crypto
API.
Let’s start with the utility class we will use in our midlet to encrypt/decrypt arbitrary text
messages. Encryptor class below allows you to encrypt and decrypt arbitrary messages using
encryptString and decryptString methods:
import org.bouncycastle.crypto.*;
import org.bouncycastle.crypto.engines.*;
import org.bouncycastle.crypto.modes.*;
import org.bouncycastle.crypto.params.*;
// A simple example that uses the Bouncy Castle
// lightweight cryptography API to perform DES
// encryption of arbitrary data.
public class Encryptor {
private BufferedBlockCipher cipher;
private KeyParameter key;
// Initialize the cryptographic engine.
// The key array should be at least 8 bytes long.
public Encryptor( byte[] key ){
/*
cipher = new PaddedBlockCipher(
new CBCBlockCipher(
new DESEngine() ) );
*/
cipher = new PaddedBlockCipher(
new CBCBlockCipher(
new BlowfishEngine() ) );
this.key = new KeyParameter( key );
}
// Initialize the cryptographic engine.
// The string should be at least 8 chars long.
public Encryptor( String key ){
this( key.getBytes() );
}
// Private routine that does the gritty work.
private byte[] callCipher( byte[] data )
throws CryptoException {
int size =
cipher.getOutputSize( data.length );
byte[] result = new byte[ size ];
int olen = cipher.processBytes( data, 0,
data.length, result, 0 );
olen += cipher.doFinal( result, olen );
if( olen < size ){
byte[] tmp = new byte[ olen ];
System.arraycopy(
result, 0, tmp, 0, olen );
result = tmp;
}
return result;
}
// Encrypt arbitrary byte array, returning the
// encrypted data in a different byte array.
public synchronized byte[] encrypt( byte[] data )
throws CryptoException {
if( data == null || data.length == 0 ){
return new byte[0];
}
cipher.init( true, key );
return callCipher( data );
}
// Encrypts a string.
public byte[] encryptString( String data )
throws CryptoException {
if( data == null || data.length() == 0 ){
return new byte[0];
}
return encrypt( data.getBytes() );
}
// Decrypts arbitrary data.
public synchronized byte[] decrypt( byte[] data )
throws CryptoException {
if( data == null || data.length == 0 ){
return new byte[0];
}
cipher.init( false, key );
return callCipher( data );
}
// Decrypts a string that was previously encoded
// using encryptString.
public String decryptString( byte[] data )
throws CryptoException {
if( data == null || data.length == 0 ){
return "";
}
return new String( decrypt( data ) );
}
}
|
And here is the source of our midlet which uses
Encryptor class described above to encrypt/decrypt
messages entered by the user:
import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;
import javax.microedition.rms.*;
import org.bouncycastle.crypto.*;
import java.math.BigInteger;
public class CryptoTest extends MIDlet {
private Display display;
private Command exitCommand = new Command( "Exit", Command.EXIT, 1 );
private Command okCommand = new Command( "OK", Command.OK, 1 );
private Encryptor encryptor;
private RecordStore rs;
/** Creates a new instance of CryptoTest */
public CryptoTest() {
}
/**
* This method initializes UI of the application.
*/
private void initialize() {
}
public void startApp() {
initialize();
if( display == null ){ // first time called...
initMIDlet();
}
}
public void pauseApp() {
}
public void destroyApp(boolean unconditional) {
exitMIDlet();
}
private void initMIDlet(){
display = Display.getDisplay( this );
// Open a record store here
try {
// This need to be changed to start with a clean reocrd
rs = RecordStore.openRecordStore( "test3",
true );
} catch( RecordStoreException e ){
// put in error handling here
}
display.setCurrent( new AskForKey() );
}
public void exitMIDlet(){
try {
if( rs != null ){
rs.closeRecordStore();
}
} catch( RecordStoreException e ){
}
notifyDestroyed();
}
private void displayException( Exception e ){
Alert a = new Alert( "Exception" );
a.setString( e.toString() );
a.setTimeout( Alert.FOREVER );
display.setCurrent( a, new AskForKey() );
}
class AskForKey extends TextBox
implements CommandListener {
public AskForKey(){
super( "Enter a secret key:", "", 8, 0 );
setCommandListener( this );
addCommand( okCommand );
addCommand( exitCommand );
}
public void commandAction( Command c,
Displayable d ){
if( c == exitCommand ){
exitMIDlet();
}
String key = getString();
if( key.length() < 8 ){
Alert a = new Alert( "Key too short" );
a.setString( "The key must be " +
"8 characters long" );
setString( "" );
display.setCurrent( a, this );
return;
}
encryptor = new Encryptor( key );
try {
if( rs.getNextRecordID() == 1 ){
display.setCurrent(
new EnterMessage() );
} else {
byte[] data = rs.getRecord( 1 );
String str =
encryptor.decryptString( data );
Alert a =
new Alert( "Decryption" );
a.setTimeout( Alert.FOREVER );
a.setString(
"The decrypted string is '" +
str + "'" );
display.setCurrent( a, this );
}
} catch( RecordStoreException e ){
displayException( e );
} catch( CryptoException e ){
displayException( e );
}
}
}
class EnterMessage extends TextBox
implements CommandListener {
public EnterMessage(){
super( "Enter a message to encrypt:", "",
100, 0 );
BigInteger bigInt = new BigInteger("199999");
setCommandListener( this );
addCommand( okCommand );
}
public void commandAction( Command c,
Displayable d ){
String msg = getString();
try {
byte[] data =
encryptor.encryptString( msg );
rs.addRecord( data, 0, data.length );
} catch( RecordStoreException e ){
displayException( e );
} catch( CryptoException e ){
displayException( e );
}
display.setCurrent( new AskForKey() );
}
}
}
|
Also note at the time of this writing that some version of Bouncy Castle Crypto API is not
compiled for MIDP 2.0. When you tried to compile this example with Bouncy Castle Crypto API, you may
get errors. (Some of the test classes use some classes not available to J2ME which is only available
to J2SE) In that case, you may try other versions of the API to eliminate this problem.
If the above method still does not work for you, we recommend you to add full source code of the
API to your project and eliminate problems one by one by removing some test classes and removing
unnecessary but problematic parts of the library. (Note that you should also check the license before
distributing the changes you made!)
References
- The Legion of the Bouncy Castle
Related Tips
|
You can share your information about this topic using the form below!
Please do not post your questions with this form! Thanks.