I'm implementing in Java the communication to a third party application. As part of the login process, the third party application is sending an encrypted string that I have to decode and send back. I have spent nearly 2 days googeling and reading posts but I can't find the right way to implement this.
I have a test case where the encrypted string is "c1W2YO1vYQzu6czteEidrG0U4g5gT4h57vAlP7tdjcY=" that decrypted with the password "GAT" must return "101714994".
The documentation I have states this: Authorization string was encrypted with the following settings:
- Padding of input data: PKCS*7
- Password byte array is 32 bytes long. Password string is converted to UTF-16 encoded byte array and byte array is then padded with zeroes up to length of 32 bytes. Longer passwords are truncated.
This is the C# example of how to decrypt the authorization string:
/// <summary> /// Decrypts a string. /// </summary> /// <param name="content">The string to decrypt.</param> /// <param name="password">The password to use.</param> /// <returns>The decrypted string.</returns> private static string DecryptString(string content, string password) { Rijndael aes; byte[] retVal = null; byte[] contentBytes; byte[] passwordBytes; byte[] ivBytes; try { //Get the content as byte[] contentBytes = Convert.FromBase64String(content); //Create the password and initial vector bytes passwordBytes = new byte[32]; ivBytes = new byte[16]; Array.Copy(Encoding.Unicode.GetBytes(password), passwordBytes, Encoding.Unicode.GetBytes(password).Length); Array.Copy(passwordBytes, ivBytes, 16); //Create the cryptograpy object aes = Rijndael.Create(); aes.Key = passwordBytes; aes.IV = ivBytes; aes.Padding = PaddingMode.PKCS7; //Decrypt retVal = aes.CreateDecryptor().TransformFinalBlock(contentBytes, 0, contentBytes.Length); } catch { } aes = null; contentBytes = null; passwordBytes = null; ivBytes = null; return Encoding.Unicode.GetString(retVal) } This is my Java procedure to decrypt the string:
private String decryptAuthorizationString(String authString, String password) { try { //Force the test string authString = "c1W2YO1vYQzu6czteEidrG0U4g5gT4h57vAlP7tdjcY="; //Force the test password password = "GAT"; //Create the password and initial vector bytes byte[] passwordBytes= new byte[32]; byte[] b= password.getBytes("UTF-8"); int len= b.length; if (len > passwordBytes.length) len = passwordBytes.length; System.arraycopy(b, 0, passwordBytes, 0, len); byte[] ivBytes= new byte[16]; System.arraycopy(passwordBytes, 0, ivBytes, 0, 16); //Get the authString as byte[] byte[] authBytes = new BASE64Decoder().decodeBuffer(authString); InputStream inputStream = new ByteArrayInputStream(authBytes); ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); // If you have Bouncycastle library installed, you can use // Rijndael/CBC/PKCS7PADDING directly. Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider()); Cipher cipher = Cipher.getInstance("Rijndael/CBC/PKCS7PADDING", "BC"); // convertedSecureString and initVector must be byte[] with correct length cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(passwordBytes, "AES"), new IvParameterSpec(ivBytes)); CipherInputStream cryptoStream = new CipherInputStream(inputStream, cipher); byte[] buffer = new byte[1024]; len = cryptoStream.read(buffer, 0, buffer.length); while (len > 0) { outputStream.write(buffer, 0, len); len = cryptoStream.read(buffer, 0, buffer.length); } outputStream.flush(); cryptoStream.close(); String resStr = outputStream.toString("UTF-8"); return resStr; //<<--- resStr must be "101714994" } catch (Throwable t) { } return null; } The procedure runs without any error but the result is not what I need it to be. Any help would be very appreciated.
sun.misc.BASE64Decoder. It's internal and unsupported.