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 hav
You don't need the BouncyCastleProvider for this, as AES is already included in Java. However PKCS#7 padding is incorrectly indicated by "PKCS5Padding"
, so "AES/CBC/PKCS7Padding"
cannot be indicated without Bouncy Castle.
The default Unicode
encoding of .NET is actually more compatible with UTF-16LE. Leave it to Microsoft to not keep to standard names (although they may have preceded it).
The Java JCE is not really build around streaming as the C# classes are, so it is better to avoid streaming altogether.
I've rewritten your sample code to show how to properly code this in Java (you'll need to be Java 7 compatible though). Don't shove exceptions under the table, turn them into AssertError
or RuntimeException
s.
I've use the Bouncy Castle Base 64 decoder, as that one was the one available both for you and for me (but otherwise this is independent of Bouncy). Java 8 has a base 64 class included.
So without further ado:
import static java.nio.charset.StandardCharsets.UTF_16LE;
import java.security.GeneralSecurityException;
import java.util.Arrays;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import org.bouncycastle.util.encoders.Base64;
public class AuthenticationStringDecrypter {
private static final String AES_CBC_PKCS5PADDING = "AES/CBC/PKCS5PADDING";
private static final int KEY_SIZE = 256;
public static void main(final String[] args) throws Exception {
System.out.println(decryptAuthorizationString(
"c1W2YO1vYQzu6czteEidrG0U4g5gT4h57vAlP7tdjcY=", "GAT"));
}
private static String decryptAuthorizationString(final String authString,
final String password) {
try {
// --- check if AES-256 is available
if (Cipher.getMaxAllowedKeyLength(AES_CBC_PKCS5PADDING) < KEY_SIZE) {
throw new IllegalStateException("Unlimited crypto files not present in this JRE");
}
// --- create cipher
final Cipher cipher = Cipher.getInstance(AES_CBC_PKCS5PADDING);
// --- create the key and initial vector bytes
final byte[] passwordEncoded = password.getBytes(UTF_16LE);
final byte[] keyData = Arrays.copyOf(passwordEncoded, KEY_SIZE
/ Byte.SIZE);
final byte[] ivBytes = Arrays.copyOf(keyData, cipher.getBlockSize());
// --- init cipher
cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(keyData, "AES"),
new IvParameterSpec(ivBytes));
// --- decode & decrypt authentication string
final byte[] authBytes = Base64.decode(authString);
final byte[] decryptedData = cipher.doFinal(authBytes);
// WARNING: may still decrypt to wrong string if
// authString or password are incorrect -
// BadPaddingException may *not* be thrown
return new String(decryptedData, UTF_16LE);
} catch (BadPaddingException | IllegalBlockSizeException e) {
// failure to authenticate
return null;
} catch (final GeneralSecurityException e) {
throw new IllegalStateException(
"Algorithms or unlimited crypto files not available", e);
}
}
}