I have a c# code which does the encryption and a java code which decrypt, but in Java I get
"Given final block not properly padded. Such issues can arise if a bad key is used during decryption".
But if I encrypt in JAVA and decrypt in JAVA , it works fine. Please help I am stuck since a week.
I read PKCS5Padding and PKCS7Padding both are same in JAVA, is it true?
to try with PKCS7Padding in Java, I used bouncy Castle but that gave below error
" BadPaddingException: pad block corrupted"
C# Encryption Logic:
string Encrypt(string textToEncrypt, string key)
{
RijndaelManaged rijndaelCipher = new RijndaelManaged();
rijndaelCipher.Mode = CipherMode.CBC;
rijndaelCipher.Padding = PaddingMode.PKCS7;
rijndaelCipher.KeySize = 0x80;
rijndaelCipher.BlockSize = 0x80;
byte[] pwdBytes = Encoding.UTF8.GetBytes(key);
byte[] keyBytes = new byte[0x10];
int len = pwdBytes.Length;
if (len > keyBytes.Length)
{
len = keyBytes.Length;
}
Array.Copy(pwdBytes, keyBytes, len);
rijndaelCipher.Key = keyBytes;
rijndaelCipher.IV = keyBytes;
ICryptoTransform transform = rijndaelCipher.CreateEncryptor();
byte[] plainText = Encoding.UTF8.GetBytes(textToEncrypt);
return Convert.ToBase64String(transform.TransformFinalBlock(plainText, 0, plainText.Length));
}
Java Decryption Logic
public String decryptInputData(String encryptedRequest, String key1) {
byte[] cipherData = Base64.getDecoder().decode(encryptedRequest);
byte[] keyByte = key1.getBytes(StandardCharsets.UTF_8);
byte[] IV=new byte[16];
SecretKeySpec key = new SecretKeySpec(keyByte, "AES");
IvParameterSpec iv = new IvParameterSpec(IV);
Cipher aesCBC;
try {
aesCBC = Cipher.getInstance("AES/CBC/PKCS5Padding");
aesCBC.init(Cipher.DECRYPT_MODE, key, iv);
byte[] decryptedData = aesCBC.doFinal(cipherData);
return new String(decryptedData, StandardCharsets.UTF_8);
} catch (NoSuchAlgorithmException | NoSuchPaddingException |InvalidKeyException | InvalidAlgorithmParameterException |IllegalBlockSizeException | BadPaddingException e) {
e.printStackTrace();
return null;
}
}
Test Data:
arxtiUWLzv5W74mDyRDxIWGM5C40kTiHocBYD9xfpvqYi7bkWIfO7jba1PdRaSCN31CwD18UGVRa2WVGDlt9LCkFuU2ErWFrboKC11OHFuozznF8ZAm1e6kSiSR/QfH1bhLONkClWruzDcTONA7BobZQd86LuPJe5BlAqYcaZq2DTXRmP11IZFzZP7+3cnk+oxF/H15hz+ypw7u0JMHQirg5C8aGD5DjmuLcsGcMjHNoaQ9cOrzjCOK8zpgGGDo9T5libP1h1GsaBYmdNp21auwLbebO8BzwFJGzD2fiybT5MswZpdtxE4Hh9OtgjZwSRFeBW10e2v/EQR6Qeffumgp93u109gOtYdc+HmAjFeu645JsNHON2EpqBJ/I8tfcdYWpJMVkS8h0nEd5QbWMN1/B+Rk42UmAAFoeyo2YgVHJLDNAe2HnjiQv/RKuL/zjJEtTOdZZKIdHduPT32GtZGHzqCK3Gy/MlTd37zgSeUahE6pe3Zp0Cu+pinQgOY9oCaTdhVmH8xiYv33plcbsElXDW4zTusj68jkeCBpPFeW9DRxWLngooPqszCKrZ6EJFgdbpCdEanU79mJCflg8d7uqwntwTw6gGgOLNqK+OpvVTtvoZ9oBeIBOjB0NroP9edQkSbJw7vSdGMMiQODOqIosgXrecdmvpja3hoZ3RuHGkkieIwNm4CSoSrDQdDwSIMW5CXY9r5UZ8+Pf5KHx2UYU7RqcZa44Z32mP7n10g6gjCHYTi0FCf0HpFx7ykFHC8qEEptI+ywRm6Y+WR6NEO284UILOvwmJb7iyB3N8i32jYq+CIH7h8jYePHkX+eVdfiaC6JGWC5nrM+6pUB2tOMN4LIu+4Lvy9OIPCFAw/U+ze2B23t/SfUae7peKu3SeczQrP7BGAk4s5PYAh1gncZmNhmhVviqN8KkO44bH7eqGXpnIUqeswYRu4pJYFhfNkqtaSSWSD4q/slycVORyMjPKSDDp5shm1qIdui6lGI=
Key:TL3U2HAQJZ79F8O5X4CNW6S10IEKGPYB
PlainText:
Salutation=MRS|Customer_Name=ITMSYAR EBMEEN|Address=ABCD EFG~WERT|City=GHTTG|Pin_Code=310012|State=WERY|DOB=1900-02-19|Gender=F|Mobile_Number=010007000007|Nationality=IN|Email_Address=ABCDEFG#GMAIL.COM|Marital_Status=Y|Occupation_Type=Housewife|PAN_Number=AOIPM1619P|Nominee_Name=|Nominee_DOB=|Relationship_of_Nominee=|Timestamp=7/26/2022 11:06:16 AM|Website_Ref_No=1zEeSs97MAao5UIi|CRM_Lead_Id=9121421421|Source_Id=MB_LoggedIn|Referral_Code=123456|utm_source=|utm_medium=|utm_campaign=|Product_Name=Group Active Health Plan|Partner_Name=ABCD|SP_Code=|LG_SOL_ID=002|Producer_Code=202324134|EBCC_Flag=N|Scheme_Code=FSGSW|CKYC_NO=|Acc_No=1234567889|Acc_Type=Main|
Related
I trying to implement this same code to encrypt on c# but always i get some different encrypted code :
This is my Java class :
public class AES256 {
private static final String SECRET_KEY = "my_super_secret_key_ho_ho_ho";
private static final String SALT = "ssshhhhhhhhhhh!!!!";
public static String encrypt(String strToEncrypt) {
try {
byte[] iv = "1234567891234567".getBytes("UTF-8");
IvParameterSpec ivspec = new IvParameterSpec(iv);
SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256");
KeySpec spec = new PBEKeySpec(SECRET_KEY.toCharArray(), SALT.getBytes(), 65536, 256);
SecretKey tmp = factory.generateSecret(spec);
SecretKeySpec secretKey = new SecretKeySpec(tmp.getEncoded(), "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, secretKey, ivspec);
return Base64.getEncoder()
.encodeToString(cipher.doFinal(strToEncrypt.getBytes(StandardCharsets.UTF_8)));
} catch (Exception e) {
System.out.println("Error while encrypting: " + e.toString());
}
return null;
}
}
How can i implement the same on c#? i usig this as a model -> c# AES Encrypt but the result is diffetent even using the same secret , salt ,interaction hash count
This what i have on c# :
var passPhrase = "my_super_secret_key_ho_ho_ho";
// Initialization Vector (16 bit length)
var iv = "1234567891234567";
// Encrypt & Decrypt (with advanced settings)
var opts = new AESCryptOptions()
{
PasswordHash = AESPasswordHash.SHA1,
PasswordHashIterations = 65536,
PasswordHashSalt = "ssshhhhhhhhhhh!!!!",
PaddingMode = PaddingMode.PKCS7,
MinSaltLength = 4,
MaxSaltLength = 16,
FixedKeySize=256
};
var encryptedText = new AESCrypt(passPhrase, iv, opts).Encrypt(text);
And the encrypt Method, i changed the hash to sha256, the only change made from the implement from gitHub:
PasswordDeriveBytes password = new PasswordDeriveBytes(
passPhrase,
saltValueBytes,
("SHA256"),
Options.PasswordHashIterations);
// Convert key to a byte array adjusting the size from bits to bytes.
keyBytes = password.GetBytes(keySize / 8);
I have Java code sitting on a server for decrypting data that I am trying to run locally for some testing. The code runs fine on the server but throws an error in my local build.
ECB mode cannot use IV
public static String triple_des_decrypt(String key, String data)
{
try
{
//needs to have an even number of digits
if (key.length() % 2 == 1)
{
key = "0" + key;
}
byte[] desKey = Hex.decodeHex(key.toCharArray());
// pad out key for cipher routine
int deskeyLength = desKey.length;
byte[] desKey24 = new byte[24];
int copySize = 16;
if (copySize > deskeyLength)
{
copySize = deskeyLength;
}
System.arraycopy(desKey, 0, desKey24, 0, copySize);
copySize = 8;
if (copySize > deskeyLength)
{
copySize = deskeyLength;
}
System.arraycopy(desKey, 0, desKey24, 16, 8);
DESedeKeySpec keySpec = new DESedeKeySpec(desKey24);
Cipher cipher = Cipher.getInstance("DESede/ECB/NoPadding");
String algo = "DESede";
SecretKey secretKey = SecretKeyFactory.getInstance(algo).generateSecret(keySpec);
IvParameterSpec iv = new IvParameterSpec(new byte[8]);
cipher.init(Cipher.DECRYPT_MODE, secretKey, iv); //Error thrown here
byte[] byteData = Hex.decodeHex(data.toCharArray());
byte[] decryptedData = cipher.doFinal(byteData);
char tempString[] = Hex.encodeHex(decryptedData);
String decryptedString = new String(tempString).toUpperCase();
return decryptedString;
}
catch (Exception e)
{
throw new RuntimeException(e);
}
}
I'm not familiar with encryption and I'm at a loss as to why this error is thrown.
Edit Removing the IV parameter from cipher.init fixes the issue, but I'm still curious as to why no error is thrown in a different environment.
ECB doesn't perform chaining between blocks so there is no way to use initialization vector (wiki). Therefore, you get the error message that ECB mode cannot use IV
I'm currently running into an issue where our decryption portion of our C# site is having trouble with the padding with the encrypted string from java. The .Net code throws this error "Padding is invalid and cannot be removed". The _signKey and _encKey are both 64 bytes.
public String encryptString(String plainText) {
byte[] ciphertext;
byte[] iv = new byte[16];
byte[] plainBytes = plainText.getBytes(StandardCharsets.UTF_8);
String _signKey = "****************************************************************";
String _encKey = "****************************************************************";
try {
Mac sha256 = Mac.getInstance("HmacSHA256");
SecretKeySpec shaKS = new SecretKeySpec(_signKey.getBytes(StandardCharsets.UTF_8), "HmacSHA256");
sha256.init(shaKS);
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
SecureRandom randomSecureRandom = SecureRandom.getInstance("SHA1PRNG");
iv = new byte[cipher.getBlockSize()];
randomSecureRandom.nextBytes(iv);
IvParameterSpec ivParams = new IvParameterSpec(iv);
byte[] sessionKey = sha256.doFinal((_encKey + iv).getBytes(StandardCharsets.UTF_8));
// Perform Encryption
SecretKeySpec eks = new SecretKeySpec(sessionKey, "AES");
cipher.init(Cipher.ENCRYPT_MODE, eks, ivParams);
ciphertext = cipher.doFinal(plainBytes);
System.out.println("ciphertext= " + new String(ciphertext));
// Perform HMAC using SHA-256 on ciphertext
SecretKeySpec hks = new SecretKeySpec(_signKey.getBytes(StandardCharsets.UTF_8), "HmacSHA256");
Mac mac = Mac.getInstance("HmacSHA256");
mac.init(hks);
ByteArrayOutputStream outputStream2 = new ByteArrayOutputStream();
outputStream2.write(iv);
outputStream2.write(ciphertext);
outputStream2.flush();
outputStream2.write(mac.doFinal(outputStream2.toByteArray()));
return Base64.encodeBase64String(outputStream2.toByteArray());
} catch (Exception e) {
e.printStackTrace();
}
return plainText;
}
Does does encrypt the string properly as far as I can tell. We cannot change any code on the .Net side to decrypt this because this is being used today.
public static string DecryptString(string ciphertext)
{
using (HMACSHA256 sha256 = new HMACSHA256(Encoding.UTF8.GetBytes(_signKey)))
{
// Convert message to bytes
byte[] encBytes = Convert.FromBase64String(ciphertext);
// Get arrays for comparing HMAC tags
byte[] sentTag = new byte[sha256.HashSize / 8];
byte[] calcTag = sha256.ComputeHash(encBytes, 0, (encBytes.Length - sentTag.Length));
// If message length is too small return null
if (encBytes.Length < sentTag.Length + _ivLength) { return null; }
// Copy tag from end of encrypted message
Array.Copy(encBytes, (encBytes.Length - sentTag.Length), sentTag, 0, sentTag.Length);
// Compare tags with constant time comparison, return null if no match
int compare = 0;
for (int i = 0; i < sentTag.Length; i++) { compare |= sentTag[i] ^ calcTag[i]; }
if (compare != 0) { return null; }
using (AesCryptoServiceProvider csp = new AesCryptoServiceProvider())
{
// Set parameters
csp.BlockSize = _blockBits;
csp.KeySize = _keyBits;
csp.Mode = CipherMode.CBC;
csp.Padding = PaddingMode.PKCS7;
// Copy init vector from message
var iv = new byte[_ivLength];
Array.Copy(encBytes, 0, iv, 0, iv.Length);
// Derive session key
byte[] sessionKey = sha256.ComputeHash(Encoding.UTF8.GetBytes(_encKey + iv));
// Decrypt message
using (ICryptoTransform decrypt = csp.CreateDecryptor(sessionKey, iv))
{
return Encoding.UTF8.GetString(decrypt.TransformFinalBlock(encBytes, iv.Length, encBytes.Length - iv.Length - sentTag.Length));
}
}
}
}
If there is anything that sticks out it would be appreciated for the reply.
I didn't read all your code, but this line in Java:
byte[] sessionKey = sha256.doFinal((_encKey + iv).getBytes(StandardCharsets.UTF_8));
does nothing useful or sensible. The "+" operator does string concatenation, but iv is a byte[], not a String. So java uses iv.toString(), which simply returns a String containing something like [B#1188e820 which is meaningless in this context.
Refer four java code and DotNet code:
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); //Java
csp.Padding = PaddingMode.PKCS7; //.Net
You are essentially using different padding, that is the probable source of error; however, there is an alternate view, Refer this great post and this for general fundamentals on padding
The cipher suites supported by deafult Oracle JVM implementation are here
If you notice it does not have 'AES/CBC/PKCS7Padding', a PKCS#7 padding implementation is available in sun.security package, refer this, otherwise you could use Bouncy Castle packages. It would be recommendable to use Bouncy Castle as com.sun package are generally considered unsupported.
There are a lot of threads on stack overflow with this topic, and always the same solutions, but these doesn't work for me. I am looking for a way to decrypt the value byte[] encrypted and return byte[] decodedBytes.
With the method AESCrypt. I use compile 'com.scottyab:aescrypt:0.0.1'
private void testAES() {
try {
final byte[] encrypted = Base64.decode("R3JhbmRlIFZpY3RvaXJlICE=", Base64.NO_WRAP);
byte[] keyBytes = Base64.decode("L/91ZYrliXvmhYt9FKEkkDDni+PzcnOuV9cikm188+4=", Base64.NO_WRAP);
final byte[] ivBytes = Base64.decode("gqjFHI+YQiP7XYEfcIEJHw==".getBytes(), Base64.NO_WRAP);
final SecretKeySpec keySpec = new SecretKeySpec(keyBytes, "AES");
byte[] decodedBytes = AESCrypt.decrypt(keySpec, ivBytes, encrypted);
} catch (Exception e) {
e.printStackTrace();
}
}
With the value Cipher, i use it like that.
private static byte[] testCipher() {
try {
final byte[] encrypted = Base64.decode("R3JhbmRlIFZpY3RvaXJlICE=", Base64.NO_WRAP);
byte[] keyBytes = Base64.decode("L/91ZYrliXvmhYt9FKEkkDDni+PzcnOuV9cikm188+4=", Base64.NO_WRAP);
byte[] ivBytes = Base64.decode("gqjFHI+YQiP7XYEfcIEJHw==".getBytes(), Base64.NO_WRAP);
final IvParameterSpec ivSpecForData = new IvParameterSpec(ivBytes);
SecretKeySpec decodedKeySpec = new SecretKeySpec(keyBytes, "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, decodedKeySpec, ivSpecForData);
byte[] decodedBytes = cipher.doFinal(encrypted); // I have the error here //
return decodedBytes;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
Whatever i do, i allways have the same error :
error:1e06b07b:Cipher functions:EVP_DecryptFinal_ex:WRONG_FINAL_BLOCK_LENGTH
I try to put in Cipher.getInstance (AES/CBC/NoPadding, AES/CBC/PKCS5Padding, AES/CBC/PKCS7Padding) but nothing change.
Do you have any idea to help me ?
"R3JhbmRlIFZpY3RvaXJlICE=" decoded to 17 hex bytes 4772616E646520566963746F6972652021 which is the ASCII text: "Grande Victoire !".
17 bytes is not a valid size for AES which is a block cipher that requires encrypted data to be a multiple of the block size of 16-bytes.
There is no encryption just Base64 encoding.
I want a secure solution for caching a user's password on their PC during their session.
I have trawled numerous AES examples and know that this has been answered elsewhere but I must say it is a little confusing. My aesSecretKey or aesInitialisationVector are not working in the decryption correctly but not sure where the issue lies.
Decrypting results in a javax.crypto.BadPaddingException: Given final block not properly padded exception.
My class looks like this
public class LockManagerTest {
// Need to share the IV and key between encode and decode
private static byte[] aesInitialisationVector;
private static SecretKey aesSecretKey;
private static Cipher aesCipher;
public LockManagerTest(String sessionKey) {
try {
byte[] key = getSecretKey(sessionKey.toCharArray(), getSalt(32),
65536, 128);
aesSecretKey = new SecretKeySpec(key, "AES");
aesCipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
aesCipher.init(Cipher.ENCRYPT_MODE, aesSecretKey);
AlgorithmParameters params = aesCipher.getParameters();
aesInitialisationVector =
params.getParameterSpec(IvParameterSpec.class).getIV();
} catch (Exception e) {
Util.handleException(e);
}
}
private static byte[] getSecretKey(char[] plaintext,
byte[] salt,
int iterations,
int keySize)
throws Exception {
PBEKeySpec spec = new PBEKeySpec(plaintext, salt, iterations, keySize);
SecretKeyFactory skf = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
return skf.generateSecret(spec).getEncoded();
}
private static byte[] getSalt(int keyLength) throws Exception {
SecureRandom random = SecureRandom.getInstance("SHA1PRNG", "SUN");
byte[] salt = new byte[keyLength];
random.nextBytes(salt);
return salt;
}
public byte[] encryptedAes(char[] input) throws Exception {
// WRONG
// aesCipher.init(Cipher.ENCRYPT_MODE, aesSecretKey);
//
aesCipher.init(Cipher.ENCRYPT_MODE, aesSecretKey,
new IvParameterSpec(aesInitialisationVector);
CharBuffer cBuf = CharBuffer.wrap(input);
byte[] normalised = Charset.forName("UTF-8").encode(cBuf).array();
byte[] ciphertext = aesCipher.doFinal(normalised);
return ciphertext;
}
public byte[] decryptAes(byte[] ciphertext) throws Exception {
aesCipher.init(Cipher.DECRYPT_MODE,
aesSecretKey, new IvParameterSpec(aesInitialisationVector));
byte[] plaintext = aesCipher.doFinal(ciphertext);
return plaintext;
}
}
Comments regarding the level of security appreciated also.
You need to pass the IV when calling init() in encryptedAes().
AES is a CBC algorithm and divides input into blocks. These blocks must be of a specific size. In the case of AES, I believe it is 16 bytes. If the input is not a multiple of 16 bytes, it must be padded with nulls before encryption.
Instead of generating new IV while decrypting, you need to pass same IV which you use for encrypting. Remember AES is Symmetric Cipher.
Edit:
What you are doing is:
public byte[] encryptedAes(char[] input) throws Exception {
// WRONG
// aesCipher.init(Cipher.ENCRYPT_MODE, aesSecretKey);
//
aesCipher.init(Cipher.ENCRYPT_MODE, aesSecretKey,
new IvParameterSpec(aesInitialisationVector);
CharBuffer cBuf = CharBuffer.wrap(input);
byte[] normalised = Charset.forName("UTF-8").encode(cBuf).array();
byte[] ciphertext = aesCipher.doFinal(normalised);
return ciphertext;
}
Instead store the IvParameterSpec as a static, as per below (u can do proper variable declaration in your program)
public byte[] encryptedAes(char[] input) throws Exception {
//declare as static so initVector can be reused when decrypting
IvParamterSpec initVector = new IvParameterSpec(aesSecretKey);
aesCipher.init(Cipher.ENCRYPT_MODE, aesSecretKey, initVector);
CharBuffer cBuf = CharBuffer.wrap(input);
byte[] normalised = Charset.forName("UTF-8").encode(cBuf).array();
byte[] ciphertext = aesCipher.doFinal(normalised);
return ciphertext;
}
make the changes and then run your program. make sure you use the same initVector while decrypting. in your program you are creating new IvParameterSpec(...)