How to decrypt result of cipher CBC encryption using cipher GCM? - encryption

Because of cipher CBC is vulnerability, the solution is to change using cipher GCM, but the problem there is old result of cipher CBC encryption exist. So the question is how to decrypt the result of cipher CBC encryption using cipher GCM?
Cipher CBC encryption:
private static final String AES_ALGORITHM = "AES";
private static final Integer BLOCK_SIZE = 16;
private static final String CIPHER_ALGORITHM = "AES/CBC/PKCS5Padding";
public String generateMerchantToken(String internalToken, String merchantSecretKey) throws Exception{
SecretKeySpec secretKeySpec = new SecretKeySpec(merchantSecretKey.getBytes(), AES_ALGORITHM);
byte[] iv = new byte[BLOCK_SIZE];
secureRandom.nextBytes(iv);
IvParameterSpec ivParameterSpec = new IvParameterSpec(iv);
Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, ivParameterSpec);
byte[] cipherEncodedBytes = cipher.doFinal(internalToken.getBytes());
byte[] combinedBytes = ArrayUtils.addAll(iv, cipherEncodedBytes);
byte[] encodedBytes = Base64.encodeBase64(combinedBytes);
return new String(encodedBytes);
}
Here is GCM decrypt but found error "javax.crypto.AEADBadTagException: Tag mismatch!"
private static final String AES_ALGORITHM = "AES";
private static final Integer BLOCK_SIZE = 16;
private static final Integer GCM_TAG_SIZE = 16 * Byte.SIZE;
private static final String CIPHER_ALGORITHM = "AES/GCM/NoPadding";
public String decryptMerchantToken(String token, String merchantSecretKey) throws Exception {
byte[] decodeBase64 = Base64.decodeBase64(token);
byte[] ivString = Arrays.copyOfRange(decodeBase64,0, BLOCK_SIZE);
SecretKeySpec secretKeySpec = new SecretKeySpec(merchantSecretKey.getBytes(), AES_ALGORITHM);
GCMParameterSpec iv = new GCMParameterSpec(GCM_TAG_SIZE ,ivString);
Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
cipher.init(Cipher.DECRYPT_MODE, secretKeySpec, iv);
byte[] original = cipher.doFinal(Arrays.copyOfRange(decodeBase64, BLOCK_SIZE, decodeBase64.length));
String decryptedString = new String(original);
return decryptedString;
}
The expectation is success to decrypt cipher CBC encryption result using cipher GCM

Related

AES 256 Encryption Decryption,

Decryption logic is missing something can you please assist.
Output is not completely decrypted.
Java Encryption Logic:
public static void main(String[] args) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, ShortBufferException, IllegalBlockSizeException, BadPaddingException {
try {
String in ="This is a text message";
byte[] input = in.toString().getBytes("utf-8");
String ENCRYPTION_KEY = "RW50ZXIgS2V5IEhlcmU=";
MessageDigest md = MessageDigest.getInstance("SHA-256");
byte[] thedigest = md.digest(ENCRYPTION_KEY.getBytes("UTF-8"));
// SecretKeySpec skc = new SecretKeySpec(thedigest, "AES/ECB/PKCS5Padding");
SecretKeySpec skc = new SecretKeySpec(thedigest, "AES");
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.ENCRYPT_MODE, skc);
byte[] cipherText = new byte[cipher.getOutputSize(input.length)];
int ctLength = cipher.update(input, 0, input.length, cipherText, 0);
ctLength += cipher.doFinal(cipherText, ctLength);
// String query = Base64.encodeToString(cipherText, Base64.DEFAULT);
String query = new String(java.util.Base64.getEncoder().encode(cipherText));
System.out.println("query " + query);
// String query = new String(encode(cipherText), StandardCharsets.ISO_8859_1);
} catch(UnsupportedEncodingException e) { // TODO Auto-generated catch block
e.printStackTrace();
}
}
Nodejs Decryption Logic:
let crypto = require('crypto');
var decipher = crypto.createDecipher('aes-256-ecb', "RW50ZXIgS2V5IEhlcmU=");
decipher.setAutoPadding(false);
console.log(decipher.update("EncyptedText", 'base64', 'utf8') + decipher.final('utf8'));

Ruby OpenSSL::Cipher::CipherError (key not set)

I am trying to port an existing .net encryption code to ruby. But stuck with the key not set error.
Bellow is the .net code to encrypt a string.
private static string Encrypt(string strToEncrypt, string saltValue, string password)
{
using (var csp = new AesCryptoServiceProvider())
{
ICryptoTransform e = GetCryptoTransform(csp, true, saltValue, password);
byte[] inputBuffer = Encoding.UTF8.GetBytes(strToEncrypt);
byte[] output = e.TransformFinalBlock(inputBuffer, 0, inputBuffer.Length);
string encrypted = Convert.ToBase64String(output);
return encrypted;
}
}
private static ICryptoTransform GetCryptoTransform(AesCryptoServiceProvider csp, bool encrypting, string saltValue, string password)
{
csp.Mode = CipherMode.CBC;
csp.Padding = PaddingMode.PKCS7;
var passWord = password;
var salt = saltValue;
//a random Init. Vector. just for testing
String iv = "e675f725e675f123";
var spec = new Rfc2898DeriveBytes(Encoding.UTF8.GetBytes(passWord), Encoding.UTF8.GetBytes(salt), 1000);
byte[] key = spec.GetBytes(16);
csp.IV = Encoding.UTF8.GetBytes(iv);
csp.Key = key;
if (encrypting)
{
return csp.CreateEncryptor();
}
return csp.CreateDecryptor();
}
I have used Ruby's OpenSSL::PKCS5 library to generate key and OpenSSL::Cipher to encrypt using AES algorithm like bellow.
def aes_encrypt(input_string)
cipher = OpenSSL::Cipher.new('AES-128-CBC')
cipher.encrypt
key = encryption_key
iv = cipher.random_iv
cipher.update(input_string) + cipher.final
end
def encryption_key
OpenSSL::PKCS5.pbkdf2_hmac_sha1(PASSWORD, SALT, 1000, 16)
end
Can anyone let know where I am missing? (Padding ?)

Invalid Key Exception

I am retrieving a text password as input from a file and applying AES encryption over that and later on, decrypting that.
When I did it for the first time, every 4 out of 5 times it was running correctly (encryption decryption successful) but 1 time, it was throwing BadPaddingException. Following is what I wrote :
//ABCD is class name
public static void enc(String fileName, String pwd) {
try {
Properties prop = new Properties();
InputStream input = ABCD.class.getClassLoader().getResourceAsStream(fileName);
prop.load(input);
input.close();
URL url = ABCD.class.getClassLoader().getResource(fileName);
FileOutputStream outputStream = new FileOutputStream(url.getPath());
KeyGenerator key = KeyGenerator.getInstance("AES");
key.init(128);
SecretKey aesKey = key.generateKey();
String newkey = new String(Base64.encode(aesKey.getEncoded()).getBytes("UTF-8"));
Cipher aesCipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
aesCipher.init(Cipher.ENCRYPT_MODE, aesKey);
byte[] clear = pwd.getBytes("UTF-8");
byte[] cipher = aesCipher.doFinal(clear);
String encPwd = new String(cipher);
prop.setProperty("password", encPwd);
prop.setProperty("secKey", newkey);
prop.store(outputStream, null);
outputStream.close();
} catch (Exception e) {
System.out.println(e);
}
}
public static String dec(Properties prop, String fileName) {
String decPwd = ABCD.map.get(fileName);
try {
String newkey = prop.getProperty("secKey");
StringBuilder pwd;
byte[] newkeybuff = Base64.decode(newkey.getBytes("UTF-8"));
SecretKey key = new SecretKeySpec(newkeyuff, "AES");
Cipher aesCipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
aesCipher.init(Cipher.DECRYPT_MODE, key);
pwd = new StringBuilder(prop.getProperty("password"));
byte[] cipher = aesCipher.doFinal(pwd.toString().getBytes());
decPwd = new String(cipher);
} catch (Exception e) {
System.out.println(e);
}
ABCD.map.put(fileName, decPwd);
return decPwd;
}
I needed to fix this. Somewhere, I read that BadPaddingExcpetion occurs since of the operations done with String, in place of where actually byte should be used. Hence, I changed my code to the following :
public static void enc(String fileName, String pwd) {
try {
Properties prop = new Properties();
InputStream input = ABCD.class.getClassLoader().getResourceAsStream(fileName);
prop.load(input);
input.close();
URL url = ABCD.class.getClassLoader().getResource(fileName);
FileOutputStream outputStream = new FileOutputStream(url.getPath());
KeyGenerator key = KeyGenerator.getInstance("AES");
key.init(128);
SecretKey aesKey = key.generateKey();
byte[] newkey=(Base64.encode(aesKey.getEncoded())).getBytes("UTF-8");
Cipher aesCipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
aesCipher.init(Cipher.ENCRYPT_MODE, aesKey,new IvParameterSpec(new byte[16]));
byte[] clear = pwd.getBytes("UTF-8");
byte[] cipher = aesCipher.doFinal(clear);
prop.setProperty("password", Arrays.toString(cipher));
prop.setProperty("secKey", Arrays.toString(newkey));
prop.store(outputStream, null);
outputStream.flush();
outputStream.close();
} catch (Exception e) {
System.out.println(e);
}
}
public static String dec(Properties prop, String fileName) {
String decPwd = ABCD.map.get(fileName);
try {
byte[] newkey=prop.getProperty("secKey").getBytes("UTF-8");
byte[] pwd;
byte[] newkeybuff = Base64.decode(newkey);
SecretKeySpec key = new SecretKeySpec(newkeybuff, "AES");
Cipher aesCipher=Cipher.getInstance("AES/CBC/PKCS5Padding");
aesCipher.init(Cipher.DECRYPT_MODE, key,new IvParameterSpec(new byte[16]));
pwd = prop.getProperty("password").getBytes();
byte[] cipher = aesCipher.doFinal(pwd);
decPwd=new String(cipher);
System.out.println("Decrypted pwd " + decPwd);
}
catch (Exception e) {
System.out.println(e);
}
ABCD.map.put(fileName, decPwd);
return decPwd;
}
Now, I am getting InvalidKeyException. This time, I read that the size of the key should be 16 bytes. But I don't know how to apply this. Need a fix for this!
You should check your IV (Initialization Vector) which must be the same for encryption and decryption.
A padding error usually means the decryption failed.
Check that the key is a full length (16, 24 or 32 bytes), the IV is full length (16-bytes). If the key or IV is to short it will be padded with "something"and that man not be consistent, there is no standard for such padding.
getBytes("UTF-8") may return different length of bytes depending on the characters used.
Using new IvParameterSpec(new byte[16]) for the IV is incorrect, the IV should be a random bytes. A usual method of handling the IV is to create a random IV on encryption and prepend it to the encrypted data, it does not need to be secret and by prepending it will be available for decryption.

Datatype of encrypted password

I want to encrypt my password and store to my DB, SQL Server 2008 R2.
For that I took the password from text box and encrypted using proper function and want to store in back end.
Tell me which datatype I have to use for encrypted password column.
Namespace:
using System.Security.Cryptography;
Encrypt Function:
public static string Encrypt(string Message)
{
string Password = Message;
byte[] Results;
System.Text.UTF8Encoding UTF8 = new System.Text.UTF8Encoding();
MD5CryptoServiceProvider HashProvider = new MD5CryptoServiceProvider();
byte[] TDESKey = HashProvider.ComputeHash(UTF8.GetBytes(Password));
TripleDESCryptoServiceProvider TDESAlgorithm = new TripleDESCryptoServiceProvider();
TDESAlgorithm.Key = TDESKey;
TDESAlgorithm.Mode = CipherMode.ECB;
TDESAlgorithm.Padding = PaddingMode.PKCS7;
byte[] DataToEncrypt = UTF8.GetBytes(Message);
try
{
ICryptoTransform Encryptor = TDESAlgorithm.CreateEncryptor();
Results = Encryptor.TransformFinalBlock(DataToEncrypt, 0, DataToEncrypt.Length);
}
finally
{
TDESAlgorithm.Clear();
HashProvider.Clear();
}
return Convert.ToBase64String(Results);
}
Decrypt Function:
public static string Decrypt(string Message)
{
string Password = Message;
byte[] Results;
System.Text.UTF8Encoding UTF8 = new System.Text.UTF8Encoding();
MD5CryptoServiceProvider HashProvider = new MD5CryptoServiceProvider();
byte[] TDESKey = HashProvider.ComputeHash(UTF8.GetBytes(Password));
TripleDESCryptoServiceProvider TDESAlgorithm = new TripleDESCryptoServiceProvider();
TDESAlgorithm.Key = TDESKey;
TDESAlgorithm.Mode = CipherMode.ECB;
TDESAlgorithm.Padding = PaddingMode.PKCS7;
byte[] DataToDecrypt = Convert.FromBase64String(Message);
try
{
ICryptoTransform Decryptor = TDESAlgorithm.CreateDecryptor();
Results = Decryptor.TransformFinalBlock(DataToDecrypt, 0, DataToDecrypt.Length);
}
finally
{
TDESAlgorithm.Clear();
HashProvider.Clear();
}
return UTF8.GetString(Results);
}
How to use??
For Encrypt:
string encryptpassword=Encrypt(txtPassword.Text.Trim());
For Decrypt:
string decryptpassword=Decrypt(txtPassword.Text.Trim());
NOTE : txtPassword is a textbox where you can enter a password

doFinal() javax.crypto.IllegalBlockSizeException: last block incomplete in decryption

Sorry if this has been answered. I see several similar but not one I can identify as my issue.
I am getting the following error:
javax.crypto.IllegalBlockSizeException: last block incomplete in decryption
at org.bouncycastle.jce.provider.JCEBlockCipher.engineDoFinal(Unknown Source)
at javax.crypto.Cipher.doFinal
public static String encryptAES(String key, String source) {
String encrypted = "";
try {
SecretKeySpec keySpec = new SecretKeySpec(key.getBytes(), "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
IvParameterSpec iv = new IvParameterSpec(new byte[16]);
cipher.init(Cipher.ENCRYPT_MODE, keySpec, iv);
byte[] bXml = source.getBytes("UTF8");
byte[] enc = cipher.doFinal(bXml);
encrypted = new sun.misc.BASE64Encoder().encode(enc);
} catch (Exception e) { /** removed **/ }
return encrypted;
}
public static String decryptAES(String key, String source) {
String decrypted = "";
try {
SecretKeySpec keySpec = new SecretKeySpec(key.getBytes(), "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
IvParameterSpec iv = new IvParameterSpec(new byte[16]);
cipher.init(Cipher.DECRYPT_MODE, keySpec, iv);
byte[] dec = new sun.misc.BASE64Decoder().decodeBuffer(source);
byte[] bDecrypted = cipher.doFinal(dec); /** Error occurs here **/
decrypted = new String(bDecrypted, "UTF8");
} catch (Exception e) { /** removed **/ }
return decrypted;
}

Resources