Cipher.init() required for each message? - java

Assume two clients are exchanging secure messages back and forth.
Must this block be run every time for each message, or can any step(s) be done just once at start:
cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, keySpec);
output = cipher.doFinal(content);
I guess to lend some context- although I don't (yet) understand the internals completely, it is my understanding that for security purposes it's important to change the IV for each message. So I think the answer to this question will depend on whether that step happens under the hood at the doFinal() stage or init()....?

You are correct: to be safe you need to use a new,random, IV for each message. This means you either need to recreate the cipher or randomly set the IV yourself for each subsequent message. The former is probably safer since if you change ciphers or modes, there maybe some other state you need to randomly set as well and reinitializing the cipher should handle all of it.
If you don't do this, you end up with the same rather bad bug SSL had with IV reuse.
Cipher.doFinal does not reset the cipher to a random IV. In fact, its far worse than that, it appears to reset the internal state to the same IV you started with. As shown by this code.
Cipher f = Cipher.getInstance("AES/CBC/PKCS5Padding");
byte[] keyBytes = new byte[] { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09,
0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f };
SecretKeySpec key = new SecretKeySpec(keyBytes, "AES");
f.init(Cipher.ENCRYPT_MODE, key);
byte[] iv = f.getIV();
System.out.println(Arrays.toString(f.doFinal("hello".getBytes())));
System.out.println(Arrays.toString(f.getIV()));
System.out.println(Arrays.toString(f.doFinal("hello".getBytes())));
System.out.println(Arrays.toString(f.getIV()));
System.out.println( Arrays.equals(f.getIV(), iv)); // true

Related

How to use SecureRandom instead of using hardcoded bytes array for Java AES Encrytion and Decryption?

In my code I am using hardcoded arrays(given below) for IV and key
**private static byte[] IVAes = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16 };
private static byte[] keyAes = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16 };
public static String encryptAes(String strPlain) {
byte[] encrypted = null;
if (StringUtils.isBlank(strPlain)) {
return strPlain;
}
byte[] toEncrypt = strPlain.getBytes();
try {
AlgorithmParameterSpec paramSpec = new IvParameterSpec(IVAes);
// Generate the key specs.
SecretKeySpec skeySpec = new SecretKeySpec(keyAes, AES_ALGORITHM);
// Instantiate the cipher
Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
cipher.init(Cipher.ENCRYPT_MODE, skeySpec, paramSpec);
encrypted = cipher.doFinal(toEncrypt);
} catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException
| InvalidAlgorithmParameterException | IllegalBlockSizeException | BadPaddingException e) {
LOGGER.error(e.getMessage(), e);
}
return new String(Base64.encodeBase64(encrypted));
}**
but using hardcoded array as IV and Key is not prefered due to security perspective. Instead of this type of Hardcoded array can I use SecureRandom() as given below-
**public static String encryptAes(String strPlain) {
byte[] encrypted = null;
if (StringUtils.isBlank(strPlain)) {
return strPlain;
}
byte[] toEncrypt = strPlain.getBytes();
try {
//---------calling generateIV method
AlgorithmParameterSpec paramSpec = generateIv();
// Instantiate the cipher
Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
cipher.init(Cipher.ENCRYPT_MODE, skeySpec, paramSpec);
encrypted = cipher.doFinal(toEncrypt);
} catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException
| InvalidAlgorithmParameterException | IllegalBlockSizeException | BadPaddingException e) {
LOGGER.error(e.getMessage(), e);
}
return new String(Base64.encodeBase64(encrypted));
}
public static IvParameterSpec generateIv() {
byte[] IVAes = new byte[16];
new SecureRandom().nextBytes(IVAes);
return new IvParameterSpec(IVAes);
}
int n = 128;
public static SecretKey generateKey(int n) throws NoSuchAlgorithmException {
KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
keyGenerator.init(n);
SecretKey key = keyGenerator.generateKey();
return key;
}**
I just wanted to know that creating array of 16 bytes for IV and key by using SecureRandom and also key generator will give same result as it was giving when I use hardcoded array as shown above??
The whole idea of a cipher is that it is indistinguishable from random (not considering the length of the ciphertext, that obviously depends on the size of the message in some way). If you have a unique key and IV then the ciphertext should be indistinguishable from random, although for CBC the IV should also be randomized. If you want to test if it "works" then you'll have to decrypt the ciphertext. Otherwise you can only check if the ciphertext size is about right.
However, if you are asking about the security of your code then sure, the use of SecureRandom and KeyGenerator seems fine. You might want to prefix the IV to the ciphertext, that's the common way to communicate a random IV. If you want to know how to distribute keys then I'd suggest reading into symmetric key management; that depends on the use case.
For my fellow crypto nerds, yes, sure related key attacks are a thing so having a unique key & IV is not entirely the whole story, but these keys are randomized, so that's fine. There are probably some other theoretical / practical issues with the answer which can usually be ignored.

Best approach to generate a dynamic key in security [duplicate]

This question already has answers here:
How to create a secure random AES key in Java?
(3 answers)
Closed 8 years ago.
A defined key is used in this example:
byte[] keyBytes = new byte[] { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09,
0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17 };
SecretKeySpec key = new SecretKeySpec(keyBytes, "AES");
I need to know what is the recommended approach to generate dynamic enhanced unpredictable key, especially when security working with JAX-WS , JAX-RS web services.
That's what the SecureRandom class in Java is for:
SecureRandom random = new SecureRandom();
byte[] key = new byte[24]; // 24 or whatever your key length is
random.nextBytes(key);
SecureRandom provides a "a cryptographically strong random number generator (RNG)" according to the Javadoc documentation.
It's often faulted for being slow, but not for being insecure.

finding a key for DES

working on a problem of encrypyting and decrypting using the DES given in java.
Ive already figured out how to encrypt and decrypt pretty easy but now im stuck.
For the current problem i am having I have the plaintext and the coorisponding cipher text (which is in the format of 8 hex pairs ex: A5 33 1F ..) but i also have the first 4 hexidecimal bits of the key. Im not really asking for code but more of an idea how i would go about tackling this problem! anything will help! this is my decryption code (just included it to show i am workin hard :) ). thanks guys!
public static void decrypt(){
Cipher cipher;
SecretKeySpec key;
byte [] keyBytes;
byte [] pt;
byte [] ct;
String plaintxt;
keyBytes = new byte [] {(byte)0xFE, (byte)0xDC, (byte)0xBA, (byte)0x98, (byte)0x76, (byte)0x54, (byte)0x32, (byte)0x10};
key = new SecretKeySpec(keyBytes, "DES");
ct = new byte [] {(byte) 0x2C, (byte) 0xE6, (byte) 0xDD, (byte) 0xA4, (byte) 0x98, (byte) 0xCA, (byte) 0xBA, (byte) 0xB9};
try{
cipher = Cipher.getInstance("DES/ECB/NoPadding");
cipher.init(Cipher.DECRYPT_MODE, key);
pt = cipher.doFinal(ct);
printByteArray(pt);
plaintxt = byteToHex(pt);
hexToAscii(plaintxt);
}
catch(Exception e){
e.printStackTrace();
}
}
Brute force.
Enumerate over every key that it could be (given the fixed bytes) until you get a decryption that makes the plaintext and ciphertext match. It'll take edit: 2^37 attempts on average, though, so don't expect it to happen fast :)
There are some properties of DES that let you crack it faster, but they're very difficult to implement and I doubt you'd be expected to learn them. But if you are interested, http://en.wikipedia.org/wiki/Data_Encryption_Standard#Security_and_cryptanalysis

encryption using provided key using DES with padding

I want to encrypt a frame using DES using a given key.
The padding style I am using is PKCS5Padding. This pads the string with 02 02 if 2 bytes are to be added and with 03 03 03 if 3 bytes are to be added to make multiple of 8.
But my requirement is to pad a string with my particular bytes. e.g if 2 bytes are to be added then 30 30 and 3 bytes are to be added then 30 30 30 (in hex 0's value is 30). Also, I must know how many padded bytes have been added.
Which padding technique should I follow and how can I use it?
Below is my code for encryption:
byte[] keyValue = new byte[]{(byte) 0x30, (byte) 0x30, (byte) 0x30, (byte) 0x30, (byte) 0x30, (byte) 0x16,(byte) 0x05, (byte) 0x12};
myKeySpec = new DESKeySpec(keyValue);
mySecretKeyFactory = SecretKeyFactory.getInstance("DES");
key = mySecretKeyFactory.generateSecret(myKeySpec);
Cipher cipher = Cipher.getInstance("DES/CBC/PKCS5Padding");
IvParameterSpec iv2 = new IvParameterSpec(new byte[8]);
cipher.init(Cipher.ENCRYPT_MODE, key, iv2);
byte[] plainText = function.HexStringToByteArray(payloadRecv);
byte[] encryptedText = cipher.doFinal(plainText);
Do not select PKCS5Padding in the cipher specification. Select NoPadding. You'll have to add the padding onto the data yourself prior to encrypting it. After decrypting it (also using no padding), you'll have to inspect the last byte to know how many bytes of padding to remove and remove it yourself.
Basically, just code exactly what you described.

Java AES encryption and decryption using a predefined 128bit key

The following code in java attempts to decrypt a string encoded in a QR code, encrypted in C# code. it seems to fail to decrypt the string. is there an easy way of doing this???
//string encrypted contains the string of the encoded characters.
String encrypted = intent.getStringExtra("SCAN_RESULT");
//converting the string into a byte array
byte[] byteEncrypted = encrypted.getBytes();
//instantiating the AES cipher object
Cipher cipher = Cipher.getInstance("AES");
//Predefined public-key
byte[] skey = new byte[] { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f };
//creating a secretKeySpec
SecretKeySpec skeyspec = new SecretKeySpec(skey, "AES");
//initializing the cipher to Decrypt
cipher.init(Cipher.DECRYPT_MODE, skeyspec);
final byte[] decrypt = cipher.doFinal(byteEncrypted);
//decrypting the string
String contents = new String(decrypt, "UTF-8");
For starters, you generally can't convert a cipher text stored as text, and convert it directly to bytes with a call to getBytes().
AES cipher text contains bytes with values from 0 to 255; I know of no character set encoding that maps all 256 values to a character, and even if there is one, it's unlikely to be your platform default encoding, and you aren't specifying it in your text-to-byte conversion.
The most common byte-to-text transformation for cipher text is Base-64 encoding. If that's what you are using here, you'll have to find or write a base-64 decoding utility.
You should also specify a complete transformation when creating the Cipher instance; otherwise, a provider specific default is used, and that might not match the sender's choices.
Since you don't show any IV, you might be using ECB as the mode. For most messages, this is insecure. It can only be safe if your message is a large random number (like a session identifier).
Most likely the padding is PKCS #5 padding (called PKCS7Padding in .NET), but you might have no padding, or some home-brew padding algorithm.
Assuming ECB and PKCS #5 padding, your cipher creation should look like this:
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");

Categories