When trying to decrypt a Hex String in Java, I am able to decrypt the string but because the original data which was encrypted is not a String but actually 32 bit hexadecimal values.
The encrypted hex string is "4ba3442d4bc3baf5126b7b271b359e42", and the key used here is "ac00ac00ac00ac00ac00ac00ac00ac00"
The output which im supposed to get as retrieve from aes.online-domain-tools.com is "× z X . b 3 ý . ä g í ý b Þ ." but as seen from this String, only zXb3gb is of a normal ASCII character and the others are the extended characters which in return becomes a � in the console which carries a int value of 65533 which in turn is not correct for my original data.
But if we see the output from aes.online-domain-tools.com, the ASCII VALUES of the extended ASCII characters IS the correct values of the original data but because it is not a normal ASCII character but an extended character, it becomes a � with value 65533 which will give me the wrong value while being casted to integer.
I was wondering rather than decrypting it to a String, am I able to directly decrypt the hex string into the hex string rather than decrypt to string and cast to int.
Currently this is my decryption code:
public static String decrypt(String strToDecrypt)
{
char[] ch=strToDecrypt.toCharArray();
System.out.println("Test: " + ch);
try
{
Cipher cipher2 = Cipher.getInstance("AES/ECB/NoPadding");
cipher2.init(Cipher.DECRYPT_MODE, secretKey);
setDecryptedString(new String(cipher2.doFinal(Hex.decodeHex(ch)))); // Output as String eg: testingone
}
catch (Exception e)
{
System.out.println("Error while decrypting: "+e.toString());
}
return null;
}
And this is the block of code I use to cast it to INT to retrieve the original value:
System.out.println("String To Decrypt : " + strToDecrypt);
final String decryptedString = getDecryptedString();
char[] asciiLine = decryptedString.toCharArray();
for (char ch:asciiLine)
{
System.out.println("Decrypted : " + (int)ch+" ");
}
System.out.println("TestDecrypted : " + test.getDecryptedString());
System.out.println("StringDecrypted : " + decryptedString);
System.out.println("DecodeDecrypted : " + Integer.decode(decryptedString));
your decryption itself seems just fine ... but your handling of the returned data is not...
doFinal returns a byte array
you are handling that by passing it to new String(...)
what you possibly want is to encode that bytearray as a hex number string
have a look here ... How to convert a byte array to a hex string in Java?
Related
I'm trying to get some encryption/decryption going using AES/CBC/PKCS5Padding and am getting a strange result. Depending on the original value I use to encrypt I get an exception:
javax.crypto.BadPaddingException: Given final block not properly padded. Such issues can arise if a bad key is used during decryption.
To test this out, I wrote a little function that starts with a string and progressively makes it bigger, trying to encrypt the string and decrypt the encrypted result in each iteration.
First iteration ==> string == "5" Encrypt and decrypt
Next iteration ==> string == "55" Encrypt and decrypt
Next iteration ==> string == "555" Encrypt and decrypt
Next iteration ==> string == "5555" Encrypt and decrypt
Next iteration ==> string == "55555" Encrypt and decrypt
If consistently fails to decrypt the encrypted values in items 0 and 4 (first and last). It successfully decrypts the other values.
Any clues what may be causing this?
Here is the output of the program:
0 **************************************
ENCRYPT Key: [00000000000000000000000000000000] value: [5]
This is the ciphertext encrypted [ÂZ??¢?»NÔå?Ó^Ç ]
Encrypted Value = [C25A863FA23FBB4ED4E53FD35E7FC7A0]
DECRYPT Key: [00000000000000000000000000000000] value: [C25A863FA23FBB4ED4E53FD35E7FC7A0]
This is the ciphertext [[B#5fdef03a]
javax.crypto.BadPaddingException: Given final block not properly padded. Such issues can arise if a bad key is used during decryption.
at java.base/com.sun.crypto.provider.CipherCore.unpad(CipherCore.java:977)
at java.base/com.sun.crypto.provider.CipherCore.fillOutputBuffer(CipherCore.java:1058)
at java.base/com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:855)
at java.base/com.sun.crypto.provider.AESCipher.engineDoFinal(AESCipher.java:446)
at java.base/javax.crypto.Cipher.doFinal(Cipher.java:2205)
at com.mgl.siebel.crypt.AES256Crypt.decrypt(AES256Crypt.java:35)
at com.mgl.siebel.crypt.AES256Crypt.test2(AES256Crypt.java:85)
at com.mgl.siebel.crypt.AES256Crypt.main(AES256Crypt.java:101)
Given final block not properly padded. Such issues can arise if a bad key is used during decryption.
1 **************************************
ENCRYPT Key: [00000000000000000000000000000000] value: [55]
This is the ciphertext encrypted []*çü×z%?eÑ¥zx~÷]
Encrypted Value = [5DAD2AE7FCD77A259665D1A57A787EF7]
DECRYPT Key: [00000000000000000000000000000000] value: [5DAD2AE7FCD77A259665D1A57A787EF7]
This is the ciphertext [[B#5ccd43c2]
Decrypted Value = [55]
2 **************************************
ENCRYPT Key: [00000000000000000000000000000000] value: [555]
This is the ciphertext encrypted [M÷o?gI¶àeØÖ8c.+]
Encrypted Value = [4DF76F916749B6E065D807D638632E2B]
DECRYPT Key: [00000000000000000000000000000000] value: [4DF76F916749B6E065D807D638632E2B]
This is the ciphertext [[B#4aa8f0b4]
Decrypted Value = [555]
3 **************************************
ENCRYPT Key: [00000000000000000000000000000000] value: [5555]
This is the ciphertext encrypted [ÖFè7tÔ·ðGÂ?WÂGs ]
Encrypted Value = [D646E83774D4B7F047C28657C24773A0]
DECRYPT Key: [00000000000000000000000000000000] value: [D646E83774D4B7F047C28657C24773A0]
This is the ciphertext [[B#7960847b]
Decrypted Value = [5555]
4 **************************************
ENCRYPT Key: [00000000000000000000000000000000] value: [55555]
This is the ciphertext encrypted [ȱiã?'èÀ0<eäy?]
Encrypted Value = [C80EB169E33F27E8C0AD303C65E4791B]
DECRYPT Key: [00000000000000000000000000000000] value: [C80EB169E33F27E8C0AD303C65E4791B]
This is the ciphertext [[B#2aae9190]
javax.crypto.BadPaddingException: Given final block not properly padded. Such issues can arise if a bad key is used during decryption.
at java.base/com.sun.crypto.provider.CipherCore.unpad(CipherCore.java:977)
at java.base/com.sun.crypto.provider.CipherCore.fillOutputBuffer(CipherCore.java:1058)
at java.base/com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:855)
at java.base/com.sun.crypto.provider.AESCipher.engineDoFinal(AESCipher.java:446)
at java.base/javax.crypto.Cipher.doFinal(Cipher.java:2205)
at com.mgl.siebel.crypt.AES256Crypt.decrypt(AES256Crypt.java:35)
at com.mgl.siebel.crypt.AES256Crypt.test2(AES256Crypt.java:85)
at com.mgl.siebel.crypt.AES256Crypt.main(AES256Crypt.java:101)
Given final block not properly padded. Such issues can arise if a bad key is used during decryption.
Here is the code being executed
public String decrypt(String key, String encryptedRawValue) throws Exception {
System.out.println("DECRYPT Key: [" + key + "] value: [" + encryptedRawValue + "]");
try {
if ((key == null) || (encryptedRawValue == null)) {
throw new Exception("key and value must not be null");
}
// convert raw value into its original encrypted sequence of bytes
byte[] ciphertext = DatatypeConverter.parseHexBinary(encryptedRawValue);
System.out.println("This is the ciphertext [" + ciphertext + "]");
byte[] raw = key.getBytes(Charset.forName("UTF-8"));
if (raw.length != 32) {
throw new IllegalArgumentException("Invalid key size.");
}
SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, skeySpec, new IvParameterSpec(new byte[16]));
byte[] original = cipher.doFinal(ciphertext);
String plainTextValue = new String(original, Charset.forName("UTF-8"));
return (plainTextValue);
} catch (Exception e) {
e.printStackTrace();
throw e;
}
}
public String encrypt(String key, String value) throws Exception {
System.out.println("ENCRYPT Key: [" + key + "] value: [" + value + "]");
try {
byte[] raw = key.getBytes(Charset.forName("UTF-8"));
if (raw.length != 32) {
throw new Exception("Invalid key size.");
}
SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, skeySpec, new IvParameterSpec(new byte[16]));
String encryptedValue = new String(cipher.doFinal(value.getBytes(Charset.forName("UTF-8"))));
System.out.println("This is the ciphertext encrypted [" + encryptedValue + "]");
String rawValue = DatatypeConverter.printHexBinary(encryptedValue.getBytes());
return (rawValue);
} catch(Exception e) {
e.printStackTrace();
throw e;
}
}
private void test2() throws Exception {
String key = "00000000000000000000000000000000";
try {
String value = "";
for (int i=0; i < 5; i++) { // loop 5 times encrypting and decrypting
System.out.println("\n" + i + " **************************************\n");
try {
value = value + "5";
String encryptedValue = this.encrypt(key, value);
System.out.println("Encrypted Value = ["+ encryptedValue + "]");
String plainTextValue = this.decrypt(key, encryptedValue);
System.out.println("Decrypted Value = ["+ plainTextValue + "]");
} catch(Exception e) {
System.out.println(e.getMessage());
}
}
} catch(Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
AES256Crypt c = new AES256Crypt();
try {
c.test2();
} catch(Exception e) {
e.printStackTrace();
}
}
}
String encryptedRawValue
This cannot work. Strings are a sequence of characters. Encrypted data is a sequence of bytes. If we live in magic unicornland where unicode, and more generally western characters, can just be waved away as being non-existent, you can write really bad code and conflate the two. This was common in ye olden days. it's so bad, it's a major reason for why python 2 decided to up and ditch it all and move to python 3.
There is only one fix. Stop doing this. The correct type is byte[]. If you then need this byte[] rendered in string form for some reason, then the only sane reason is because it needs to be rendered in a highly limited venue, such as an email. In which case, you should base64 encode it. Search the web for 'java base64' on how to do this, if you must. Those APIs get it right: The 'encode' method takes a byte[] and returns a String, and the decode method takes a String and returns a byte[].
Fix this issue and the problem goes away.
String encryptedValue = new String(cipher.doFinal(value.getBytes(Charset.forName("UTF-8"))));
Do not wrap the result of doFinal into new String. Take the byte array. That's your data.
I'm trying to test a Soap Security header in PHP with values supplied by the client.
They are supplying a value like...
wTAmCL9tmg6KNpeAQOYubw==
...and saying it's a Base64 encoded value.
However, when I run it through PHP's Base64 decode function...
base64_decode("wTAmCL9tmg6KNpeAQOYubw==");
it translates it as: �0&�m6#�.o
If I decode it in Java...
import java.util.Base64;
import java.util.Arrays;
/**
* hello
*/
public class hello {
public static void main(String[] args) {
Base64.Decoder decoder = Base64.getDecoder();
Base64.Encoder encoder = Base64.getEncoder();
String stringEncoded = "wTAmCL9tmg6KNpeAQOYubw==";
System.out.println("This is a decoded value: " + decoder.decode(stringEncoded));
System.out.println("This is a re-coded value: " + encoder.encode(decoder.decode(stringEncoded)));
}
}
I get a decoded string like this: [B#7229724f
But then if I try to re-encode that string, I get this: [B#4c873330
What am I missing here?
What you are missing is that the result of decoding the Base 64 value is not intended to be printed as a String. In fact, you see this in the output of the Java println. That [B#7229724f is not a string representation of the decoded bytes. It is the way a Java byte [] prints. The [B indicates a byte array, and the remaining characters are the hexadecimal digits of the object identity. (It will print differently for every byte array instance and has nothing to do with the contents of the array.)
If you want the String representation of the bytes you will need to construct a String from the bytes:
System.out.println("This is a decoded value: " + new String(decoder.decode(stringEncoded), StandardCharsets.UTF_8));
System.out.println("This is a re-coded value: " + new String(encoder.encode(decoder.decode(stringEncoded), StandardCharsets.UTF_8));
Based on this answer how about specify the encoding. Recommended encoding is UTF-8.
I would like to compare two byte arrays. One is calculated from plaintext with MessageDigest SHA1, the other is the hex itself in byte array, without calculation.
MessageDigest returns 20 byte long result, String.getBytes() returns 40 byte long array. bytesToHex() function is the same that was provided in this answer, used only for printing.
The question:
How can I convert a string to byte array (and then compare with one calculated with MessageDigest) without the additional overhead? String comparison with bytesToHex() and .toUppercase() is working, but not an option, since speed is cruital in the application.
The code:
MessageDigest md;
try {
md = MessageDigest.getInstance("SHA-1");
byte[] toEncode = "test".getBytes();
byte[] encoded = md.digest(toEncode);
System.out.println("String to encode:\t\t" + new String(toEncode));
System.out.println("Encoded in hex:\t\t\t" + bytesToHex(encoded));
System.out.println("Encoded length:\t\t\t" + encoded.length);
byte[] hash = new String("a94a8fe5ccb19ba61c4c0873d391e987982fbbd3").getBytes(); // "test" representation in SHA1
System.out.println("\nHash to compare with:\t\t" + new String(hash));
System.out.println("Hash length:\t\t\t" + hash.length);
System.out.println("Two byte array equals:\t\t" + Arrays.equals(hash, encoded));
System.out.println("Two equals in string:\t\t" + new String(hash).equals(bytesToHex(encoded).toLowerCase()));
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
The result:
String to encode: test
Encoded in hex: A94A8FE5CCB19BA61C4C0873D391E987982FBBD3
Encoded length: 20
Hash to compare with: a94a8fe5ccb19ba61c4c0873d391e987982fbbd3
Hash length: 40
Two byte array equals: false
Two equals in string: true
You're not decoding your hex representation to bytes. If you would, for example using the solution from this answer, the two arrays would match:
try {
byte[] encoded = MessageDigest.getInstance("SHA-1").digest("test".getBytes());
byte[] hash = DatatypeConverter.parseHexBinary("a94a8fe5ccb19ba61c4c0873d391e987982fbbd3");
System.out.println("Two byte array equals:\t\t" + Arrays.equals(hash, encoded));
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
I'm using this:
import com.sun.org.apache.xml.internal.security.utils.Base64; to encode/decode Base64 strings and byte arrays to store into a db.
I'm testing out encoding and decoding to see if I can get back the original string:
SecureRandom srand = new SecureRandom();
byte[] randomSalt = new byte[64];
srand.nextBytes(randomSalt);
System.out.println("rand salt bytes: " + randomSalt); // first line
String salt = Base64.encode(randomSalt);
try {
System.out.println(Base64.decode(salt)); // second line
}catch(Base64DecodingException e){
System.out.println(e);
}
However, this prints out:
rand salt bytes: [B#68286c59
[B#44d01f20
Why are these not the same, so that I can get back the original byte array?
What you are doing is actually dealing with the java pointer instead of the actual bytes.
This is the correct way to implement
byte[] bytesEncoded = Base64.encodeBase64(str .getBytes());
System.out.println("ecncoded value is " + new String(bytesEncoded ));
// Decode data on other side, by processing encoded data
byte[] valueDecoded= Base64.decodeBase64(bytesEncoded );
System.out.println("Decoded value is " + new String(valueDecoded));
How can I convert this byte[] to String :
byte[] mytest = new byte[] {100,25,28,-122,-26,94,-3,-26};
i get this : "d��^�" when I use :
new String( mytest , "UTF-8" )
Here is code java for creation of key :
m_key = new javax.crypto.spec.SecretKeySpec(new byte[] {100,25,28,-122,-26,94,-3,-26}, "DES");
Thanks.
In order to decode the byte array into something like ASCII, you need to know its original encoding. Otherwise you would need to treat it as binary.
Note: Base64 is intended for transferring binary data across networks.
I would suggest Base64 encoding your byte array. Then in your PHP code decoding the Base64 string back into a UTF-8 string.
In Java, here's how to Base64 encode your byte array and then decode it back to UTF-8:
import org.apache.commons.codec.binary.Base64;
public class MyTest {
public static void main(String[] args) throws Exception {
byte[] byteArray = new byte[] {100,25,28,-122,-26,94,-3,-26};
System.out.println("To UTF-8 string: " + new String(byteArray, "UTF-8"));
byte[] base64 = Base64.encodeBase64(byteArray);
System.out.println("To Base64 string: " + new String(base64, "UTF-8"));
byte[] decoded = Base64.decodeBase64(base64);
System.out.println("Back to UTF-8 string: " + new String(decoded, "UTF-8"));
/* the decoded byte array is the same as the original byte array */
for (int i = 0; i < decoded.length; i++) {
assert byteArray[i] == decoded[i];
}
}
}
The output from the above code is:
To UTF-8 string: d��^�
To Base64 string: ZBkchuZe/eY=
Back to UTF-8 string: d��^�
So if you wanted to use the same binary data in your PHP code, cut and paste the Base64 string into your PHP code and decode it back to UTF-8. Something like this:
<?php
$str = 'ZBkchuZe/eY=';
$key = base64_decode($str);
echo $key;
?>
I don't code in PHP, but you should be able to decode Base64 using this method:
http://php.net/manual/en/function.base64-decode.php
The above code should echo back the original binary data as UTF-8 (albeit with funny characters). The point is that the funny-looking string in the $key variable is representing the same binary data you had in the Java byte array:
d��^�
You should be able to pass the $key variable into your PHP encryption method.
with the way you are doing it makes no sense imo. you are creating a new string with the byte[] as an argument. i dont think that function is suppose to parse. so what you end up with is a lot of junk. but a little bit of googling got me this: http://www.mkyong.com/java/how-do-convert-byte-array-to-string-in-java/
Would m_key.getEncoded() give you the desired result.
Javadocs - SecretKeySpec
If not, you have to identify the Key provider that was used for the encoding (which resulted in the byte array that you have now) and decode.