So, we are using AES GCM encryption & decryption in nodejs as follows, We need to use this in Java. So one can encrypt in Java and decrypt in nodeJs and vice versa.
here is encrypt decrypt function in node
const encrypt = (text, masterkey) => {
// random initialization vector
const iv = crypto.randomBytes(16);
// random salt
const salt = crypto.randomBytes(64);
// derive encryption key: 32 byte key length
// in assumption the masterkey is a cryptographic and NOT a password there is no need for
// a large number of iterations. It may can replaced by HKDF
// the value of 2145 is randomly chosen!
const key = crypto.pbkdf2Sync(masterkey, salt, 2145, 32, 'sha512');
// AES 256 GCM Mode
const cipher = crypto.createCipheriv('aes-256-gcm', key, iv);
// encrypt the given text
const encrypted = Buffer.concat([
cipher.update(text, 'utf8'),
cipher.final()
]);
// extract the auth tag
const tag = cipher.getAuthTag();
// generate output
return Buffer.concat([salt, iv, tag, encrypted]).toString('base64');
};
const decrypt = (encdata, masterkey) => {
// base64 decoding
const bData = Buffer.from(encdata, 'base64');
// convert data to buffers
const salt = bData.slice(0, 64);
const iv = bData.slice(64, 80);
const tag = bData.slice(80, 96);
const text = bData.slice(96);
// derive key using; 32 byte key length
const key = crypto.pbkdf2Sync(masterkey, salt, 2145, 32, 'sha512');
// AES 256 GCM Mode
const decipher = crypto.createDecipheriv('aes-256-gcm', key, iv);
decipher.setAuthTag(tag);
// encrypt the given text
return decipher.update(text, 'binary', 'utf8') + decipher.final('utf8');
};
Here's What I have done in Java, but getting input too short
exception.
I have also tried to mock above nodeJs encrypt function, but it seems to be not working.
I have got initialization vector(IV), salt, key as same as nodejs (in java it is signed 128 bits)
public static String decrypt(String encData, String masterKey)
{
var cipherText = Base64.getDecoder().decode(encData.getBytes(StandardCharsets.UTF_8));
var salt = Arrays.copyOfRange(cipherText, 0, 64);
var iv = Arrays.copyOfRange(cipherText, 64, 80);
var tag = Arrays.copyOfRange(cipherText, 80, 96);
var ciphertext = Arrays.copyOfRange(cipherText, 96, cipherText.length);
var key = getKeyFromPassword(masterKey, salt);
//GCM_TAG_LENGTH = 16
return helper("AES/GCM/NoPadding", ciphertext, tag, key, new GCMParameterSpec(GCM_TAG_LENGTH * 8, iv));
}
public static SecretKey getKeyFromPassword(String masterKey, byte[] salt) {
SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA512");
KeySpec spec = new PBEKeySpec(masterKey.toCharArray(), salt, 2145, 256);
SecretKey secret = new SecretKeySpec(factory.generateSecret(spec)
.getEncoded(), "AES");
return secret;
}
public static String helper(String algorithm, byte[] cipherText, SecretKey key,
GCMParameterSpec gcmParameterSpec){
Cipher cipher = Cipher.getInstance(algorithm);
cipher.init(Cipher.DECRYPT_MODE, key, gcmParameterSpec);
cipher.update(cipherText);
byte[] plainText = cipher.doFinal(tag);
return new String(plainText, StandardCharsets.UTF_8);
}
UPDATE: above code works for decryption in java
But now need to encrypt in java
here's what i am doing, but getting Tag mismatch!
exception while decryption.I also change the order of tag & cipherText but still same error occured.
public static String encrypt(String text, String masterKey)
{
var iv = generateIv(16);
var salt = generateIv(64);
var key = getKeyFromPassword(masterKey, salt);
var cipher = helper1("AES/GCM/NoPadding", text, key, new GCMParameterSpec(GCM_TAG_LENGTH * 8, iv));
var outputStream = new ByteArrayOutputStream();
var tag = Arrays.copyOfRange(cipher, 0, 16);
var ciphertext = Arrays.copyOfRange(cipher, 16, cipher.length);
outputStream.write(salt);
outputStream.write(iv);
outputStream.write(tag);
outputStream.write(ciphertext);
return Base64.getEncoder().encodeToString(outputStream.toByteArray());
}
public static byte[] generateIv(int N) {
byte[] iv = new byte[N];
new SecureRandom().nextBytes(iv);
return iv;
}
public static byte[] helper1(String algorithm, String input, SecretKey key,
GCMParameterSpec gcmParameterSpec){
Cipher cipher = Cipher.getInstance(algorithm);
cipher.init(Cipher.ENCRYPT_MODE, key, gcmParameterSpec);
return cipher.doFinal(input.getBytes());
}
public static SecretKey getKeyFromPassword(String masterKey, byte[] salt) {
SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA512");
KeySpec spec = new PBEKeySpec(masterKey.toCharArray(), salt, 2145, 256);
SecretKey secret = new SecretKeySpec(factory.generateSecret(spec)
.getEncoded(), "AES");
return secret;
}