views:

3700

answers:

2

Hi, I've read the following threads and they've helped a little, but I'm looking for a little more info.

How to write AES/CBC/PKCS5Padding encryption and decryption with Initialization Vector Parameter for BlackBerry

Java 256bit AES Encryption

Basically, what I am doing is writing a program that will encrypt a request to be sent over TCP/IP, and then decrypted by a server program. The encryption will need to be AES, and doing some research I found out I need to use CBC and PKCS5Padding. So basically I need a secret key and an IV as well.

The application I'm developing is for a phone, so I want to use the java security packages to keep the size down. I've got the design done, but unsure of the implementation of the IV and the shared key.

Here's some code:

// My user name
byte[] loginId = "login".getBytes();

byte[] preSharedKey128 = "ACME-1234AC".getBytes();
byte[] preSharedKey192 = "ACME-1234ACME-1234A".getBytes();
// 256 bit key
byte[] preSharedKey256 = "ACME-1234ACME-1234ACME-1234".getBytes();
byte[] preSharedKey = preSharedKey256;

// Initialization Vector
// Required for CBC
byte[] iv ={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
IvParameterSpec ips = new IvParameterSpec(iv);


byte[] encodedKey = new byte[loginId.length + preSharedKey.length];

System.arraycopy(loginId, 0, encodedKey, 0, loginId.length);
System.arraycopy(preSharedKey, 0, encodedKey, loginId.length, preSharedKey.length);

// The SecretKeySpec provides a mechanism for application-specific generation
// of cryptography keys for consumption by the Java Crypto classes.

// Create a key specification first, based on our key input.
SecretKey aesKey = new SecretKeySpec(encodedKey, "AES");

// Create a Cipher for encrypting the data using the key we created.
Cipher encryptCipher;

encryptCipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
// Initialize the Cipher with key and parameters
encryptCipher.init(Cipher.ENCRYPT_MODE, aesKey, ips);

// Our cleartext
String clearString = "33,8244000,9999,411,5012022517,0.00,0,1,V330";
byte[] cleartext = clearString.getBytes();

// Encrypt the cleartext
byte[] ciphertext = encryptCipher.doFinal(cleartext);

// Now decrypt back again...
// Decryption cipher
Cipher decryptCipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
// Initialize PBE Cipher with key and parameters
decryptCipher.init(Cipher.DECRYPT_MODE, aesKey, ips);

// Decrypt the cleartext
byte[] deciphertext = decryptCipher.doFinal(ciphertext);

In a nutshell what it should do is encrypt some message that can decrypted by the server without the server needing to get a key or IV from the phone. Is there a way I could do this where I could secure the IV and key on the phone, and still have the key and IV known by the server as well? Feel free to tell me to make things more clear if they're not.

+4  A: 
erickson
Right now, the design I'm being told to use says we can use the same key for every phone but don't agree with it. Is the Diffie-Hellman approach easy to implement?
Steven Wright
No, Diffie-Hellman is a bit confusing, to me at least. It uses the KeyAgreement class. RSA encryption is easier. It uses a Cipher like the AES encryption you are currently using. One thing to note with RSA is that the ciphertext will be hundreds of bytes, which is a bit of a waste if your plaintext is only a few bytes; not sure if that matters in your application. Another option to consider is that if the communication is very short messages (100 to 200 bytes) from phone to server only, you can just encrypt the message itself with RSA.
erickson
Yea I think the level of security I'm looking for doesn't involve something really complicated. Will keep it in mind though.
Steven Wright
Getting back to the Diffie-Hellman thing, is it required for the sender to first send something to the server to establish the key and then send again after encrypting with the key?
Steven Wright
I like this approach, just don't know how to handle the whole issue with securing the key by generating a password. How do I keep a person from reverse engineering the application and finding the password?
Steven Wright
Which approach do you mean? I listed a few. Also, I am suggesting you don't use a password. Use key agreement, or public key encryption to get the server and phone to exchange a key. If you are interested in one of those approaches, post another question and I'll give some code (this answer is getting a bit lengthy already).
erickson
+1  A: 

Done similar projects in a midlet before, I have following advice for you:

  1. There is no secure way to store shared secret on the phone. You can use it but this falls into a category called Security through Obscurity. It's like a "key under mat" kind of security.
  2. Don't use 256-bit AES, which is not widely available. You might have to install another JCE. 128-bit AES or TripleDES are still considered secure. Considering #1, you shouldn't worry about this.
  3. Encryption using a password (different for each user) is much more secure. But you shouldn't use password as the key like you are showing in the example. Please use PBEKeySpec (password-based encryption) to generate the keys.
  4. If you are just worried about MITM (man-in-the-middle) attacks, use SSL.
ZZ Coder
Why can't 256-bit AES be used? I can already create a 256-bit key in my test setup, but it's done manually. Mostly, management is worried about someone intercepting a transmission and either using the info in the transmission or getting a phone and reverse-engineering the algorithm and basically be an imposter in our network.
Steven Wright
Lots of phones we tried don't support it. 128-bit AES is still used by my bank. It's secure.
ZZ Coder
Actually some weaknesses have been found in AES 256. AES-128 is plenty strong, and is recommended by Bruce Schneier over AES 256 when it's not required for interoperability. (http://www.schneier.com/blog/archives/2009/07/another_new_aes.html) However, the algorithm really doesn't matter if the key isn't secure.
erickson
How do you know you use 256-bit AES? Check the value of cipher.getBlockSize(). It should return 32. Some JCE providers don't give errors when AES-256 is not supported. It simply uses first 128-bit of the key.
ZZ Coder
Ohh, with the code I have above, I did that .getBlockSize() and it returns 16, not even 32 or 64. So what do that mean? AES isn't in 64 bit is it?
Steven Wright
"256" refers only to the size of the key. The cipher block is 128 bits in either case. Rijndael has variable block sizes, but it's not AES.
erickson
Original AES is 128-bit (16 bytes). Currently, most JCE providers don't support AES. Some do it but in a very confusing way so you never know what you are using unless you check the block size.
ZZ Coder
The AES block size is always 128 bits. If the cipher reports a block size of 32 bytes, it might be Rijndael, but it's certainly not AES. See http://csrc.nist.gov/publications/fips/fips197/fips-197.pdf "The AES algorithm is capable of using cryptographic keys of 128, 192, and 256 bits to encrypt and decrypt data in blocks of 128 bits."
erickson
@erickson, you are right. Checking block size isn't the right way. I have to figure out another way ...
ZZ Coder
@Steven, forget about my findings on the AES 256 support on phones. My test was wrong. So you might want give it a shot.
ZZ Coder
Ok. But I do like what you're saying about the PBEKeySpec. @erickson I think you had this is in your example as well.
Steven Wright
You might want consider 128 bit after all :( Just bumped into the guy who did tests on phones. He said most phones are installed with a restricted (limited strength) JCE policy which restricts the key length to 128-bit.
ZZ Coder