I am new to the filed of cryptography. I was trying my hands at AES encryption in GCM mode for protecting data at rest for my application.
I went through the NIST recommendations for GCM mode. It mentions that the uniqueness of IV is very important. It says that if the (key, IV) pair is repeated, an adversary can construct cipher-text forgery. PFB the code sample
public static void main(String[] args) throws Exception {
byte[] keyBytes = MessageDigest.getInstance("MD5").digest(
"som3C0o7p@s5".getBytes());
SecretKeySpec key = new SecretKeySpec(keyBytes, "AES");
Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
IvParameterSpec ivSpec = new IvParameterSpec(new byte[96]);
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding", "BC");
byte[] block = new byte[96];
int i;
long st, et;
cipher.init(Cipher.ENCRYPT_MODE, key, ivSpec);
BufferedInputStream bIn = new BufferedInputStream(
new ProgressMonitorInputStream(null, "Encrypting ...",
new FileInputStream("input.txt")));
CipherInputStream cIn = new CipherInputStream(bIn, cipher);
BufferedOutputStream bOut = new BufferedOutputStream(
new FileOutputStream("output.txt"));
int ch;
while ((i = cIn.read(block)) != -1) {
bOut.write(block, 0, i);
}
cIn.close();
bOut.close();
Thread.sleep(5000);
cipher.init(Cipher.DECRYPT_MODE, key, ivSpec);
InputStream is = new FileInputStream("output.txt");
OutputStream os = new FileOutputStream("output2.txt");
os = new CipherOutputStream(os, cipher);
while ((i = is.read(block)) != -1)
{
os.write(block, 0, i);
}
is.close();
os.close();
}
I am able to encrypt and decrypt the text inside the input.txt file. The IV for ECM need to be unique and i wnat it to be generated using the deterministic Constrtcution of Iv specified in the NIST 800-38D.
Presently using the IV generation available in [http://docs.oracle.com/javase/7/docs/api/javax/crypto/spec/IvParameterSpec.html][1]
IvParameterSpec(byte[] iv) Creates an IvParameterSpec object using the bytes in iv as the IV.
Is there any imlemenation available in BouncyCastle or any other library to get the IV in deterministic Construction.Or do we need to need to build a custom implementaion. Also how in the implemenation for IvParameterSpec. Is it following as specification.
Also please guide in cerating a custom implemenation for IV creation using deterministic approach.
There is no NIST algorithm for creating a deterministic IV (specified in 8.2.1 Deterministic Construction). So there are no implementations either. It just defines some general procedures you need to follow to create one that would be acceptable to NIST.
If you already have something unique for the messages, then you are better off creating a hash over the unique ID and using the 8 leftmost byte as "counter" instead of using the following counter based approach.
The following is a simplistic construction that is according to NIST specs (as far as I can see). Don't forget to store the counter in such a way that it is never reused.
import java.nio.charset.StandardCharsets;
import java.security.Security;
import java.util.Arrays;
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.util.encoders.Hex;
public class CounterIVCreator {
private final int blockSizeBytes;
private final byte[] ivCounter;
public CounterIVCreator(final int blockSizeBytes) {
if (blockSizeBytes % 2 != 0 || blockSizeBytes < 16) {
// AKA don't use DES or 3DES
throw new IllegalArgumentException("Block size should be even and at least 16 bytes");
}
this.blockSizeBytes = blockSizeBytes;
this.ivCounter = new byte[blockSizeBytes / 2];
}
public CounterIVCreator(final byte[] oldCounter) {
if (oldCounter.length < 8) {
// AKA don't use DES or 3DES
throw new IllegalArgumentException("Counter should be larger than 8 bytes");
}
this.blockSizeBytes = oldCounter.length * 2;
this.ivCounter = oldCounter.clone();
}
public IvParameterSpec createIV() {
increaseCounter(ivCounter);
final byte[] iv = Arrays.copyOf(ivCounter, blockSizeBytes);
return new IvParameterSpec(iv);
}
public byte[] getCounter() {
return ivCounter.clone();
}
private static void increaseCounter(final byte[] counter) {
for (int i = counter.length - 1; i >= 0; i--) {
counter[i]++;
if (counter[i] != 0) {
break;
}
}
}
public static void main(final String ... args) throws Exception {
Security.addProvider(new BouncyCastleProvider());
byte[] oldCounter;
Cipher gcm = Cipher.getInstance("AES/GCM/NoPadding");
SecretKeySpec aesKey = new SecretKeySpec(new byte[Cipher.getMaxAllowedKeyLength("AES/GCM/NoPadding") / Byte.SIZE], "AES");
{
CounterIVCreator ivCreator = new CounterIVCreator(gcm.getBlockSize());
IvParameterSpec ivSpec = ivCreator.createIV();
gcm.init(Cipher.ENCRYPT_MODE, aesKey, ivSpec);
gcm.updateAAD(ivSpec.getIV());
byte[] ciphertext = gcm.doFinal("owlstead".getBytes(StandardCharsets.UTF_8));
System.out.println(Hex.toHexString(ciphertext));
gcm.init(Cipher.DECRYPT_MODE, aesKey, ivSpec);
gcm.updateAAD(ivSpec.getIV());
byte[] plaintext = gcm.doFinal(ciphertext);
System.out.println(new String(plaintext, StandardCharsets.UTF_8));
oldCounter = ivCreator.getCounter();
}
// part deux, creates an entirely different ciphertext
{
CounterIVCreator ivCreator = new CounterIVCreator(oldCounter);
IvParameterSpec ivSpec = ivCreator.createIV();
gcm.init(Cipher.ENCRYPT_MODE, aesKey, ivSpec);
gcm.updateAAD(ivSpec.getIV());
byte[] ciphertext = gcm.doFinal("owlstead".getBytes(StandardCharsets.UTF_8));
System.out.println(Hex.toHexString(ciphertext));
gcm.init(Cipher.DECRYPT_MODE, aesKey, ivSpec);
gcm.updateAAD(ivSpec.getIV());
byte[] plaintext = gcm.doFinal(ciphertext);
System.out.println(new String(plaintext, StandardCharsets.UTF_8));
}
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With