I'm trying to decrypt a server response using AES (256/ECB) but getting a wrong result. When I try the same inputs with this online tool I get the right result but running my code is giving a wrong result. Here's my decryption code
//input is a Hex encoded String of the response
public String decryptString(String input){
SecretKeySpec keySpec = new SecretKeySpec(Hex.decodeHex(key),"AES");
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.DECRYPT_MODE,keySpec);
byte[] output = cipher.doFinal(Hex.decodeHex(input));
String outputString = Base64.encodeBase64String(output);
return outputString;
}
The parameters I entered into the online tool are :
key = 57e17ae84ceb2938c1f464e902f004919ea08fa7de5e358d1df028fde98d456d
input = 1c6f645bed9019332e94b69bd0152015b41dfce6c7f83046a59e1f80bce302a1ea59ccd15adbd7fcd5e7579cdaea1178fa9540ff0afa74cfe85c4e3244f9255f6dc3808b76088203bf28af25191d9d79487a2f7fb3a53bf7ee50d735d748dd16fbc3f19f9ebcf33a44d95bb221ef47fb577450d207ce6c5b762dc70142c9b7c1d815137ce24bf34fd0f5d2e0ab618c9087ef62327657f1f6c31f164109a4d190973c998e02971e6438dfc1af8dffc28cad0aa9a91a62f57d15200934cd18935b93d7327f7f8a41498ac416d90316a963cc736ce5d4fcde8401ec2f83714c4b202ddb69ce5fde1b61d69caadc2c7a162d7e88f2c5c671832f0bc4f14c98a4e2b9c4c84666a60530623f17c2f960b60c4a7242e10752cb863d41153c451dfc7d5cc4e2e9a8f8c0641764c8fca05f7db2b6
Just wanted to share the answer in case anyone stumbles into the same problem.
The result was actually the right result, the missing part was encoding the resulting byte array as a string using UTF-8 charset. The function becomes
public String decryptString(String input){
SecretKeySpec keySpec = new SecretKeySpec(Hex.decodeHex(key),"AES");
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.DECRYPT_MODE,keySpec);
byte[] output = cipher.doFinal(Hex.decodeHex(input));
String outputString = new String(output,"UTF-8");
return outputString;
}
Related
I have been using the following two methods to encrypt and decrypt sensitive info.
public static String encryptSensitiveInfo(String strToEncrypt,
String saltToEncrypt) throws Exception {
String encryptedString = "";
byte[] encryptedValue;
Key key = new SecretKeySpec(saltToEncrypt.getBytes(), "AES");
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.ENCRYPT_MODE, key);
encryptedValue = cipher.doFinal(strToEncrypt.getBytes());
encryptedString = new String(Base64.encodeBase64(encryptedValue));
encryptedValue = null;
return encryptedString;
}
public static String decryptSensitiveInfo(String strToDecrypt,
String saltToDecrypt) throws Exception {
String decryptedString = "";
byte[] decryptedValue;
Key key = new SecretKeySpec(saltToDecrypt.getBytes(), "AES");
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.DECRYPT_MODE, key);
decryptedValue = cipher.doFinal(Base64.decodeBase64(strToDecrypt
.getBytes()));
decryptedString = new String(decryptedValue);
decryptedValue = null;
return decryptedString;
}
At the time of decryption I get "pad block corrupted" execption. Any help to resolve this issue would be very much appreciated. Thanks in advance.
You're correctly performing base 64 on the ciphertext because the ciphertext consists of random looking bytes. However, you forget to do the same with your key (which, inexplicably, is called saltToDecrypt in your code). If the keys do not match or if the ciphertext has become corrupted then you will almost certainly run into a BadPaddingException.
If the amount of ciphertext has changed an IllegalBlockSizeException is more likely and if the key isn't of the right size for AES, an InvalidKeyException.
i already wandered in many stackoverflows post but still cant figured out whats wrong with my code.
public class KripAsim {
String hasil;
public String encrypt(String text) {
try {
String PUBLIC_KEY="MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvCNqSslgCndo8vfNrkXFDLXmst024Oi8D7LEiJFjYBva4kBKKISe8rKp58kCLLHjv90RN+Dy2KWcf0eFkKaqc3zILBI99JhV1z8TFOzmt5dfgW6fD1ucBfsK6pWxK84DddyOqKldwHlReqjuDHT2jLue51vpXaCa12WV5bMnGsfy3vZKnp699YCguqRpTR1MijZ9pz8WqldrR0a/DCaq5YxZ7lvjwuWIodQy3S3XRHAaeaUrFHFFLumzXAGuP447oRYR0p+1qsy8+wOtrsGm8m8bMg+C1XGMblkODtOFHz3wtrRZ5OwzgEm7J7odmSX8mSYBZYLcnUVqIFRsQkZLiwIDAQAB";
byte [] decoded = Base64.decode(PUBLIC_KEY,Base64.NO_WRAP);
KeyFactory keyFac = KeyFactory.getInstance("RSA");
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(decoded);
PublicKey pubkey = keyFac.generatePublic(keySpec);
Cipher rsa;
rsa = Cipher.getInstance("RSA");
rsa.init(Cipher.ENCRYPT_MODE, pubkey);
hasil = Base64.encodeToString(rsa.doFinal(text.getBytes("UTF-8")),Base64.NO_WRAP);
return hasil;
} catch (Exception e) {
e.printStackTrace();
}
return hasil;
}
}
it returns null. please help. thanks in advance
The line PublicKey pubkey = keyFac.generatePublic(keySpec); throws an InvalidKeySpecException because you have incorrectly supplied a PKCS8EncodedKeySpec when you should have supplied an X509EncodedKeySpec.
You should also completely specify the transformation string in the Cipher.getInstance() method. The following fragment taken from your code illustrates this:
byte[] decoded = Base64.decode(PUBLIC_KEY, Base64.DEFAULT);
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(decoded);
PublicKey pubkey = KeyFactory.getInstance("RSA").generatePublic(keySpec);
Cipher rsa = Cipher.getInstance("RSA/ECB/OAEPwithSHA-256andMGF1Padding");
rsa.init(Cipher.ENCRYPT_MODE, pubkey);
String hasil = Base64.encodeToString(rsa.doFinal(text.getBytes("UTF-8")),
Base64.NO_WRAP);
return hasil;
Finally, you should avoid encrypting data directly with RSA. The correct method is to use a hybrid encryption scheme in which the data is encrypted with a block cipher, say AES in GCM mode, using a randomly generated AES key, and then this key is encrypted using RSA. There are many examples of this around for reference.
I just want AES/CBC 128 bit encryption decryption in openSSl c and Android with identical result.
I have to send encrypted data using pre defined 16 bytes key from android to c via bluetooth.
So is there any common mechanism which i can use in both to produce identical result of encryption and decryption.
Any help would be appreciate.
Thank you.
I found a solution which work perfectly for Android.
I am going to post the answer if it would help anyone.
static String IV = "AAAAAAAAAAAAAAAA";
static String encryptionKey = "0123456789ABCDEF";
public static String decrypt(byte[] cipherText, String encryptionKey) throws Exception{
Cipher cipher = Cipher.getInstance("AES/CBC/ZeroBytePadding"/*, "SunJCE"*/);
SecretKeySpec key = new SecretKeySpec(encryptionKey.getBytes("UTF-8"), "AES");
cipher.init(Cipher.DECRYPT_MODE, key,new IvParameterSpec(IV.getBytes("UTF-8")));
return new String(cipher.doFinal(cipherText),"UTF-8");
}
public static byte[] encrypt(String plainText, String encryptionKey) throws Exception {
Cipher cipher = Cipher.getInstance("AES/CBC/ZeroBytePadding"/*, "SunJCE"*/);
SecretKeySpec key = new SecretKeySpec(encryptionKey.getBytes("UTF-8"), "AES");
cipher.init(Cipher.ENCRYPT_MODE, key,new IvParameterSpec(IV.getBytes("UTF-8")));
return cipher.doFinal(plainText.getBytes("UTF-8"));
}
//To Encrypt
byte[] cipher = encrypt(plaintext, encryptionKey);
System.out.print("cipher: ");
//To Decrypt
String decrypted = decrypt(cipher, encryptionKey);
System.out.println("decrypt: " + decrypted);
The following method does not work. decodedMessage ends up with garbage in it instead of the expected results.
I'm following an example here that supposedly works.
public static void POCSimple()
{
String secretMessage = "short message";
PublicKey publicKey = null;
PrivateKey privateKey = null;
String encodedMessage = "";
byte[] encodedBytes = null;
String decodedMessage ="";
byte[] decodedBytes = null;
try
{
KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
kpg.initialize(1024);
KeyPair kp = kpg.genKeyPair();
publicKey = kp.getPublic();
privateKey = kp.getPrivate();
Cipher c1 = Cipher.getInstance("RSA");
c1.init(Cipher.ENCRYPT_MODE, publicKey);
encodedBytes = c1.doFinal(secretMessage.getBytes());
encodedMessage = Base64.encodeToString(encodedBytes, Base64.DEFAULT);
Cipher c2 = Cipher.getInstance("RSA");
c2.init(Cipher.DECRYPT_MODE, privateKey);
decodedBytes = c2.doFinal(encodedBytes);
decodedMessage = Base64.encodeToString(decodedBytes, Base64.DEFAULT);
String mystring = "look at results";
}
catch (Exception e)
{
String status = e.toString();
}
}
Any help would be most appreciated.
Thanks,
Dean
Of course you are getting garbage, this is your sequence:
Plaintext message -> Encrypt -> Encode -> Encoded message
Encoded message -> Decrypt -> Decode -> GARBAGE
You need to undo the Base64 encoding before you can decrypt the message, you are doing the reverse process in the incorrect order!
Edit
Actually its worse, this is your sequence:
Plaintext message -> Encrypt -> Encode -> Encoded message
Encrypted message -> Decrypt -> Encode -> GARBAGE
Try this:
Cipher c1 = Cipher.getInstance("RSA");
c1.init(Cipher.ENCRYPT_MODE, publicKey);
encodedBytes = c1.doFinal(secretMessage.getBytes());
encodedMessage = Base64.encodeToString(encodedBytes, Base64.DEFAULT);
Cipher c2 = Cipher.getInstance("RSA");
c2.init(Cipher.DECRYPT_MODE, privateKey)
decodedBytes = Base64.decode(encodedMessage.toByteArray(), Base64.DEFAULT);
decryptedMessage = c2.doFinal(decodedBytes);
It turns out that in my original code, decodedBytes contained the properly decrypted bytes. The following command was turning decodedBytes into junk characters ...
decodedMessage = Base64.encodeToString(decodedBytes, Base64.DEFAULT);
I replaced that code with ...
String str = new String(decodedBytes, "UTF-8");
And this solved the problem probably because decodedBytes had never been Base64 encoded in the first place.
I also found that using straight RSA I can only encrypt a maximum of 245 bytes if I use a 2048 bit key. less if I use a 1024 bit key.
If larger strings need to be encrypted using asymmetric Public/Private keys then I need to first encrypt a string using symmetric AES and then encrypt the AES key with the public RSA key and send both the encrypted AES key and the encrypted message over the wire where the receiver can decrypt the AES key using their private RSA key. The AES key can be randomly generated in the sending code.
I am working on SOAP parsing sending request to Dot.net server.
Response is Encrypted on the server side by AES 256 algorithm. the response from the server is
k/tMHkiyWgoof8FAsTJttWZT7sku5QcJe6iZsWjkPXS+xE7ujjPn/f0E8sqWkXLH0jiXXHYwrV1SdJjbnXsiXxitfnAB83uIOr3VunB3fMVCOxTHk+Ej4mx+hBNB9pkJlgOJfTPX666fn6mwbkmFE4uqhTVbdGjm9HiSAW0mm91UANu3EERLS8g0UUPNdHn1
Now I am using the decryption method in java files as:
**public class SimpleCrypto {
public static String decrypt(String seed, String encrypted) throws Exception {
byte[] keyb = seed.getBytes("UTF-8");
MessageDigest md = MessageDigest.getInstance("MD5");
byte[] thedigest = md.digest(keyb);
SecretKeySpec skey = new SecretKeySpec(thedigest, "AES/ECB/PKCS7Padding");
Cipher dcipher = Cipher.getInstance("AES/ECB/PKCS7Padding");
dcipher.init(Cipher.DECRYPT_MODE, skey);
byte[] clearbyte = dcipher.doFinal(toByte(encrypted));
return new String(clearbyte);
}
public static byte[] toByte(String hexString) {
int len = hexString.length()/2;
byte[] result = new byte[len];
for (int i = 0; i < len; i++)
result[i] = Integer.valueOf(hexString.substring(2*i, 2*i+2), 16).byteValue();
return result;
}
}**
Your toByte function doesn't make any sense. Encrypted response is not a Hex String(A hex String has only 0123456789ABCDEF characters). So you treat your response as if it is a hex String and convert it to byte[].
You need to know the encoding used on the server when it converts encrypted data to String and you should use the same encoding to get the byte[] back from the response String. So try
encrypted.getBytes(YOUR_RESPONSE_ENCODING);
EDIT
Also your cipher should use the same algorithm used on the server to encrypt, in my case I'm using:
new SecretKeySpec(thedigest, "AES/CBC/ZeroBytePadding");
Note: We also use AES 256 encryption. But there are many ways to encrypt data using AES 256. You need to know the exact algorithm and padding method used on your server.
If you get BadPaddingException that means your data length is not an exact multiple of your key length. So in your case, encrypted.getBytes(YOUR_RESPONSE_ENCODING).length % thedigest.length must be equal to 0. You should add zero bytes to the end of your data so that this constraint is satisfied.
There is a excellent guide to cryptography here:
http://www.javamex.com/tutorials/cryptography/index.shtml