Java AES-128 ECB encryption - java

I have received a message from AT5 (Atrack) unite encoded with AES-128 ECB encryption and this is the key in hex (33333838000000000000000000000000)
the original key is in string "3388"
and this is the cipher that i received but i convert it to hex
Whenever I try to decrypt the message, I face this exception:
Error while decrypting: javax.crypto.IllegalBlockSizeException: Input length must be multiple of 16 when decrypting with padded cipher
Here is my code:
orginalString
?U??????}MgD?R???`????
#?j????g:N???#???$=???r?u?>~??Qh,?N?????3?8:?-E??;?b<J??I?v{?'o?m[?|?CY?n????K????>?ã??<?,???? ??f?'???}&?}?7r%??93??!u?0D?3Ig|??%'????*??`?Y^?M?4J?I?>?tIu???;?RR;2??{nrl??us
?R?F?oi????
String strToDecrypt = "E255898281B7C0B67D4D6744DB52FA1789F760B99B86A40A1F238B6ABCC690C1C9673A4E07EA03F79B40B2ACC8243DD098F4B10E72BA75CE3E7EE50F935168042CC74EA2F4BBE3D833F4383AE02D45C0119C3BC8623C4AD5189249FAB0BB767BA2276FB56D5BF27CE017435901DD8F6EC9DECD05B74BF51A99B1933E89C3A3AD06CA893CE72CDDEAE5F509E2D01B66A02717AADD0C917D26BA7DB1377225CCF23933E5F92175BD3044C63349677CEBC6251B27BE1FC9FD7FC32A0785F36019C2595E1EE783B64DB2344A14CE49C63EAB74174975FCE1C53BD95252113B0332CBD7A37B6E726CCFF675730DB052B14605E36F69AF11E8F3D2002D8BABEFFF508187E4C176329A3ABE08CF2B9A9F4812CF4084BACE87AD116F49C2ACD449767E758CE9184C60268AE3AAEADA052C91BF16241682E333671AC209D5BDC34CFD2B2D0C8D6D795D36A5FBD707FB56F71B3740BA86B1CEAC6E784E8E2B999CC6C9260A13F697A115C80F29C5AA38E95964731073CB051BB8A201EBAE6443A057AA69CFF41C9A593F88E2D6A712107EABCDE7042134F818268BF31896072C1B399B878BACCECC096F79A8D1835C2766EA639341E4AB22820D5AAD0F202BC896BD6C6F4D1FB1873C5BE06278D11E67F577D0120E054971088E7DB7E3A8139B20C6E22B86205BC0F4778A1DA0D6E50416FCE55DBC576A9F907FC706148204CA3C79993A4F37756427871C12EB379B4BFA0A518FFCA2BC698B1CA68AC9B3548B241C12669CEFAC9C8ECDB7B5A8149B";
secretKey = new SecretKeySpec("33333838000000000000000000000000".getBytes("UTF-8"), "AES");
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5PADDING");
cipher.init(Cipher.DECRYPT_MODE, secretKey);
byte[] cipherResult = cipher.doFinal(Base64.decodeBase64(strToDecrypt));

Your strToDecrypt seems to be hex encoded, not base64 encoded .. so you need to hex decode it before decrypting, instead of base64 decoding. But actually you encrypted data if hex decoded, would also end up having an invalid size. Your hex string is 1200 hex chars = 600 bytes = 37.5 AES blocks of 16 bytes .. Something seems to be wrong with your data ..
Also, your key is also Hex encoded, so you need to hex decode it .. not just do a getBytes(..).

Related

JAVA - AES Decryption - Input length must be multiple of 16 when decrypting with padded cipher

I am trying to decrypt the ResponseText variable which i get from an API. I am getting the following error.
Exception in thread "main" javax.crypto.IllegalBlockSizeException: Input length must be
multiple of 16 when decrypting with padded cipher
Below is my code snippet for decrypting the response. The Decrytpt method is throwing the error.
public static String decrypt(String encryptedText) throws Exception
{
Key key = generateKey();
Cipher chiper = Cipher.getInstance("AES/CBC/PKCS5Padding");
IvParameterSpec ivspec = new IvParameterSpec(iv);
chiper.init(Cipher.DECRYPT_MODE, key, ivspec);
byte[] encVal = chiper.doFinal(encryptedText.getBytes("UTF-8"));
Base64.Encoder base64Encoder = Base64.getEncoder();
String decryptedValue = base64Encoder.encodeToString(encVal);
String decryptedString= new String("");
return decryptedString;
}
I have not posted the actual encrypted value here as the length of the encrypted value is too high. I am new to Java. Thanks in advance.
You should probably base 64 decode the ciphertext, decrypt the binary ciphertext and then decode the resulting plaintext to UTF-8.
You haven't correctly reversed the encryption routine (encode UTF-8, encrypt, encode base64), in other words.
There is a generateKey() for the decryption; unless it returns a static value (and doesn't generate one, as the method name implies) decryption will likely fail. So either the name is wrong, or the decryption.
The IV doesn't seem to be included with the ciphertext either, which will mean that that's the next problem to deal with.
Finally, you will want to know how to handle exceptions for encryption / decryption routines.

'javax.crypto.BadPaddingException' while using cipherInputStream

I'm writing a program to encrypt and decrypt data.
for encrypting,
I created a symmetric key using keyGenerator.
I transferred the key to the cipher, and created a string version of the key:
String keyString = Base64.getEncoder().encodeToString(symmetricKey.getEncoded());
in order to store it in a configuration file (so I can retrieve the key in the decrypt function).
Now, in the decrypt function I need to get that string back to key format, so I can send it as a parameter to the cipher in dercypt mode.
I convert it back to key this way:
byte[] keyBytes = key.getBytes(Charset.forName("UTF-8"));
Key newkey = new SecretKeySpec(keyBytes,0,keyBytes.length, "AES");
And I transffer it to the cipher and write the output (the decrypted data) using CipherInputStream:
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, newkey, newiv, SecureRandom.getInstance("SHA1PRNG"));
CipherInputStream cipherInputStream = new CipherInputStream(
new ByteArrayInputStream(encryptedBytes), cipher);
ArrayList<Byte> decryptedVal = new ArrayList<>();
int nextByte;
while ((nextByte = cipherInputStream.read()) != -1) {
decryptedVal.add((byte) nextByte);
}
byte[] bytes = new byte[decryptedVal.size()];
for (int i = 0; i < bytes.length; i++) {
bytes[i] = decryptedVal.get(i);
}
String decryptedData = new String(bytes);
cipherInputStream.close();
System.out.println("decryptedData: " + decryptedData);
I get this error:
Exception in thread "main" java.io.IOException: javax.crypto.BadPaddingException: Given final block not properly padded. Such issues can arise if a bad key is used during decryption.
So I suspect that there might be a problem with the way I treat the key.
Any suggestions? help would be appreciated!
I think you have not sent IV to decryption function. For decryption in CBC mode, you must provide an IV which is used in encryption process.
Update:
IV will affect only first block in CBC decryption mode. So my answer may affect the unpadding if your data is less than 1 block. It will just change the decrypted plaintext of the first block otherwise.
Of course you get this error: first you apply base 64 encoding:
String keyString = Base64.getEncoder().encodeToString(symmetricKey.getEncoded());
and then you use character-encoding to turn it back into bytes:
byte[] keyBytes = key.getBytes(Charset.forName("UTF-8"));
which just keeps be base64 encoding, probably expanding the key size from 16 bytes to 24 bytes which corresponds with a 192 bit key instead of a 128 bit key. Or 24 bytes key to a 32 bytes key of course - both seem to work.
To solve this you need to use Base64.getDecoder() and decode the key.
Currently you get a key with a different size and value. That means that each block of plaintext, including the last one containing the padding, will decrypt to random plaintext. As random plaintext is unlikely to contain valid padding, you will be greeted with a BadPaddingException.
Reminder:
encoding, e.g. base 64 or hex: encoding bytes to a text string
character-encoding, e.g. UTF-8 or ASCII: encoding a text string into bytes
They are not opposites, that would be decoding and character-decoding respectively.
Remarks:
yes, listen to Ashfin; you need to use a random IV during encryption and then use it during decryption, for instance by prefixing it to the ciphertext (unencrypted);
don't use ArrayList<Byte>; that stores a reference to each separate byte (!) - use ByteArrayOutputStream or any other OutputStream instead;
you can better use a byte buffer and use that to read / write to the streams (note that the read function may not fill the buffer, even if at the start or in the middle of the stream) - reading a single byte at the time is not performant;
lookup try-with-resources for Java;
using a KeyStore may be better than storing in a config file;
GCM mode (AES/GCM/NoPadding) also authenticates data and should be preferred over CBC mode.

Java can't decrypt string encrypted in PHP

Hello everyone i have string encrypted in PHP by openssl_encrypt with algorithm 'aes-256-cbc'
Key: C4E30455853D4949A8E91B2C366BE9DE
Vector: 5686044872102713
Encrypted string: ak9YSTd6RXU5TENocUxQUGxieVhpZ3VqSlFiQUdndGZrbVJvbEliTGZjZz0=
And here is my Java function for decrypt:
public static String Decrypt_AES_FromBase64(String AEncryptedText, String AKey32Bytes, String AVectorNum16Bytes) {
try {
byte[] vEncryptedBytes = Base64.getDecoder().decode(AEncryptedText);
Key SecretKey = new SecretKeySpec(AKey32Bytes.getBytes(), "AES");
IvParameterSpec vSpec = new IvParameterSpec(AVectorNum16Bytes.getBytes());
Cipher vCipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
vCipher.init(Cipher.DECRYPT_MODE, SecretKey, vSpec);
return new String(vCipher.doFinal(vEncryptedBytes));
} catch (Exception e) {
Common.mContext.getLogger().log(e.toString());
return "";
}
}
When i try to decrypt i have error:
javax.crypto.IllegalBlockSizeException: Input length must be multiple of 16 when decrypting with padded cipher
Can somebody tell what the wrong?
The encrypted string AKey32Bytes is double Base64 encoded.
Instead of AKey32Bytes.getBytes() you need to double Base64 decode the encrypted data to binary.
Encrypted string:
ak9YSTd6RXU5TENocUxQUGxieVhpZ3VqSlFiQUdndGZrbVJvbEliTGZjZz0=
After one Base64 decode:
jOXI7zEu9LChqLPPlbyXigujJQbAGgtfkmRolIbLfcg=
After a second Base64 decode (displayed in hex because it is not binary):
8CE5C8EF312EF4B0A1A8B3CF95BC978A0BA32506C01A0B5F9264689486CB7DC8
That is what needs to be provided to the decryption function.
The decrypted result is:
(in hex) 257531362A2179704B40577255516272
(in ASCII): "%u16*!ypK#WrUQbr" (all valid ASCII characters)
Note: there is a full block of PKCS#7 padding (in hex): 10101010101010101010101010101010
As much as it pains me to say this, from the correct padding I can assume the decryption was successful.
See Cryptomathic AES CALCULATOR

Generating a Key from the first 10 Characters of a Base64 String

Let's say I have a Base64 String:
data = AOUTl5C2QV2xFRPlzKR0Ag==
I want to generate a Key in Java (Android) from the first 10 characters of this Base64 String and then use it to AES-Decrypt a Message sent from the Server. To do this, I use the below code:
String firstTen = data.substring(0, 10);
byte[] decodedBytes = Base64.decode(firstTen, Base64.DEFAULT);
SecretKeySpec key = new SecretKeySpec(decodedBytes, "AES");
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.DECRYPT_MODE, key);
byte[] original = cipher.doFinal(Message_to_Decrypt, Base64.DEFAULT));
But then I can a Java.security.Exception:
java.security.InvalidKeyException: Key length not 128/192/256 bits.
Is there a way that I can get a valid Key which I can use for AES decryption from the first 10 Characters of a Base64String?
Extend the 10 characters with a hash function or better yet PBKDF2 (Password Based Key Derivation Function 2).
You really need to provide a key of an expected length, AES keys can be 128, 192 or 256 bytes long. While some AED implementations may null pad the key do not rely on that, it is not part of the standard.
The error message says: Key length not 128/192/256 bits.
You are using 10 Characters, each char is 8 bits. So 10*8=80. Try with 16 characters (128/8=16).

why decrypted data is different from original data which was encrypted using java?

I am using AES encryption and decryption using java. And I use Appache commons library for conversion from string to byte and vice versa. But when I decrypt data then it is different from the input data that was encrypted using same key? why is so
Here is my code:
public static void main(String[] args) throws Exception {
String key="this is key";
String message="This is just an example";
KeyGenerator kgen = KeyGenerator.getInstance("AES");
kgen.init(128, new SecureRandom(Base64.decodeBase64(key)));
// Generate the secret key specs.
SecretKey skey = kgen.generateKey();
byte[] raw = skey.getEncoded();
SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.ENCRYPT_MODE, skeySpec);
byte[] encrypted= cipher.doFinal(Base64.decodeBase64(message));
String encryptedString=Base64.encodeBase64String(encrypted);
cipher.init(Cipher.DECRYPT_MODE, skeySpec);
byte[] original =
cipher.doFinal(Base64.decodeBase64(encryptedString));
System.out.println(Base64.encodeBase64String(original));
}
I get the output "Thisisjustanexamplc=" where it should have been "This is just an example". what I need to change in my code. Thanks in advance
You are base-64–decoding your plain text message. You should use message.getBytes(StandardCharsets.UTF_8) (or some other encoding) to convert to bytes instead. Base-64 encode the result of the encryption operation, then base-64 decode it before decrypting. Use new String(original, StandardCharsets.UTF_8) to convert the result of the decryption operation back to text.
In other words, use a character encoding to convert between text and bytes. Use base-64 encoding and decoding to encode binary data in a text form.

Categories