解密 Java 中的 C# AES 加密文本
Decrypt C# AES encrypted text in Java
我在 Java 第三方应用程序中实施,但应用程序的某些部分我得到了这样的加密字符串:eGlhV2xNbmdqSFBkbEhkZDNpZ3gwQT09
并且必须解密。
编写此应用程序代码的人已不在,因此我需要一些帮助来制作 Java 中的解密代码。
这是密码:CB=Z8#P@0!N2/8$%3K-9C(5S9*FDH+0Z
public static class SystemCriptografia
{
#region Atributos
private static string chave = "CB=Z8#P@0!N2/8$%3K-9C(5S9*FDH+0Z";
private static SymmetricAlgorithm algoritmo = new RijndaelManaged();
#endregion
#region Métodos
#region Métodos privados
private static string base64Encode(string data)
{
byte[] encData_byte = new byte[data.Length];
encData_byte = System.Text.Encoding.UTF8.GetBytes(data);
string encodedData = Convert.ToBase64String(encData_byte);
return encodedData;
}
private static string base64Decode(string data)
{
UTF8Encoding encoder = new UTF8Encoding();
Decoder utf8Decode = encoder.GetDecoder();
byte[] todecode_byte = Convert.FromBase64String(data);
int charCount = utf8Decode.GetCharCount(todecode_byte, 0, todecode_byte.Length);
char[] decoded_char = new char[charCount];
utf8Decode.GetChars(todecode_byte, 0, todecode_byte.Length, decoded_char, 0);
string result = new String(decoded_char);
return result;
}
private static string Criptografa(string valor, string chave)
{
byte[] ByteValor = Encoding.UTF8.GetBytes(valor);
// Seta a chave privada
algoritmo.Mode = CipherMode.CBC;
algoritmo.Key = Encoding.Default.GetBytes(chave);
algoritmo.IV = Encoding.Default.GetBytes("brasilshopsoft07");
// Interface de criptografia / Cria objeto de criptografia
ICryptoTransform cryptoTransform = algoritmo.CreateEncryptor();
MemoryStream _memoryStream = new MemoryStream();
CryptoStream _cryptoStream = new CryptoStream(_memoryStream, cryptoTransform, CryptoStreamMode.Write);
// Grava os dados criptografados no MemoryStream
_cryptoStream.Write(ByteValor, 0, ByteValor.Length);
_cryptoStream.FlushFinalBlock();
// Busca o tamanho dos bytes encriptados
byte[] cryptoByte = _memoryStream.ToArray();
// Converte para a base 64 string para uso posterior em um xml
return Convert.ToBase64String(cryptoByte, 0, cryptoByte.GetLength(0));
}
private static string Descriptografa(string valor, string chave)
{
// Converte a base 64 string em num array de bytes
byte[] cryptoByte = Convert.FromBase64String(valor);
// Seta a chave privada
algoritmo.Mode = CipherMode.CBC;
algoritmo.Key = Encoding.Default.GetBytes(chave);
algoritmo.IV = Encoding.Default.GetBytes("brasilshopsoft07");
// Interface de criptografia / Cria objeto de descriptografia
ICryptoTransform cryptoTransform = algoritmo.CreateDecryptor();
MemoryStream _memoryStream = new MemoryStream(cryptoByte, 0, cryptoByte.Length);
CryptoStream _cryptoStream = new CryptoStream(_memoryStream, cryptoTransform, CryptoStreamMode.Read);
// Busca resultado do CryptoStream
StreamReader _streamReader = new StreamReader(_cryptoStream);
return _streamReader.ReadToEnd();
}
#endregion
public static string ToCriptografa(this string valor)
{
return Criptografa(valor, chave);
}
public static string ToDescriptografa(this string valor)
{
return Descriptografa(valor, chave);
}
public static string ToCriptografaQueryString(this string valor)
{
return base64Encode(Criptografa(valor, chave));
}
public static string ToDescriptografaQueryString(this string valor)
{
return Descriptografa(base64Decode(valor), chave);
}
#endregion
}
这是我正在尝试执行的 java 代码:
public class Criptografia {
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(
"eGlhV2xNbmdqSFBkbEhkZDNpZ3gwQT09", "CB=Z8#P@0!N2/8$%3K-9C(5S9*FDH+0Z"));
}
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);
}
}
}
您的代码问题:
选择了错误的字符集。如果 Encoding.Default
在 C# 中是 UTF-8,那么 "password" 和 IV 编码在 Java.
中也必须是 "UTF-8"
IV不是从key推导出来的,也是固定值
密文其实是经过双重Base64编码的。我想有人把 "two is better than one" 看得太直白了。
完整代码:
private static final String AES_CBC_PKCS5PADDING = "AES/CBC/PKCS5PADDING";
private static final int KEY_SIZE = 256;
<b>private static String UTF_8 = "UTF-8";</b>
public static void main(final String[] args) throws Exception {
System.out.println(decryptAuthorizationString(
"eGlhV2xNbmdqSFBkbEhkZDNpZ3gwQT09", "CB=Z8#P@0!N2/8$%3K-9C(5S9*FDH+0Z"));
}
private static String decryptAuthorizationString(final String authString,
final String password) throws UnsupportedEncodingException {
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
<b>final byte[] passwordEncoded = password.getBytes(UTF_8);
final byte[] ivBytes = "brasilshopsoft07".getBytes(UTF_8);</b>
// --- init cipher
cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(<b>passwordEncoded</b>, "AES"),
new IvParameterSpec(ivBytes));
// --- decode & decrypt authentication string
final byte[] authBytes = Base64.decode(authString);
<b>final byte[] authBytes2 = Base64.decode(authBytes);</b>
final byte[] decryptedData = cipher.doFinal(<b>authBytes2</b>);
// WARNING: may still decrypt to wrong string if
// authString or password are incorrect -
// BadPaddingException may *not* be thrown
return new String(decryptedData, UTF_8);
} catch (BadPaddingException | IllegalBlockSizeException e) {
// failure to authenticate
return null;
} catch (final GeneralSecurityException e) {
throw new IllegalStateException(
"Algorithms or unlimited crypto files not available", e);
}
}
输出:
1
备注:
使用固定 IV 是不安全的。为了达到语义安全,必须随机选择 IV。它不必是秘密的,因此它可以与密文一起发送。一种常见的方法是将其添加到密文中并在解密之前将其切掉。
丢失第二个Base64编码。它只是带走了 space,但没有提供任何有用的功能。
始终使用特定的编码。 Encoding.Default
非常适合测试,但它可能会根据 运行 所在的机器而改变,并且您将失去多个 clients/servers.
之间的兼容性
验证密文!如果你不添加消息认证码或者使用像GCM或EAX这样的认证模式,那么攻击者可能会操纵密文而你将无法确定这一点。甚至可以完全恢复特定加密消息的明文(padding oracle 攻击)
我在 Java 第三方应用程序中实施,但应用程序的某些部分我得到了这样的加密字符串:eGlhV2xNbmdqSFBkbEhkZDNpZ3gwQT09 并且必须解密。
编写此应用程序代码的人已不在,因此我需要一些帮助来制作 Java 中的解密代码。 这是密码:CB=Z8#P@0!N2/8$%3K-9C(5S9*FDH+0Z
public static class SystemCriptografia
{
#region Atributos
private static string chave = "CB=Z8#P@0!N2/8$%3K-9C(5S9*FDH+0Z";
private static SymmetricAlgorithm algoritmo = new RijndaelManaged();
#endregion
#region Métodos
#region Métodos privados
private static string base64Encode(string data)
{
byte[] encData_byte = new byte[data.Length];
encData_byte = System.Text.Encoding.UTF8.GetBytes(data);
string encodedData = Convert.ToBase64String(encData_byte);
return encodedData;
}
private static string base64Decode(string data)
{
UTF8Encoding encoder = new UTF8Encoding();
Decoder utf8Decode = encoder.GetDecoder();
byte[] todecode_byte = Convert.FromBase64String(data);
int charCount = utf8Decode.GetCharCount(todecode_byte, 0, todecode_byte.Length);
char[] decoded_char = new char[charCount];
utf8Decode.GetChars(todecode_byte, 0, todecode_byte.Length, decoded_char, 0);
string result = new String(decoded_char);
return result;
}
private static string Criptografa(string valor, string chave)
{
byte[] ByteValor = Encoding.UTF8.GetBytes(valor);
// Seta a chave privada
algoritmo.Mode = CipherMode.CBC;
algoritmo.Key = Encoding.Default.GetBytes(chave);
algoritmo.IV = Encoding.Default.GetBytes("brasilshopsoft07");
// Interface de criptografia / Cria objeto de criptografia
ICryptoTransform cryptoTransform = algoritmo.CreateEncryptor();
MemoryStream _memoryStream = new MemoryStream();
CryptoStream _cryptoStream = new CryptoStream(_memoryStream, cryptoTransform, CryptoStreamMode.Write);
// Grava os dados criptografados no MemoryStream
_cryptoStream.Write(ByteValor, 0, ByteValor.Length);
_cryptoStream.FlushFinalBlock();
// Busca o tamanho dos bytes encriptados
byte[] cryptoByte = _memoryStream.ToArray();
// Converte para a base 64 string para uso posterior em um xml
return Convert.ToBase64String(cryptoByte, 0, cryptoByte.GetLength(0));
}
private static string Descriptografa(string valor, string chave)
{
// Converte a base 64 string em num array de bytes
byte[] cryptoByte = Convert.FromBase64String(valor);
// Seta a chave privada
algoritmo.Mode = CipherMode.CBC;
algoritmo.Key = Encoding.Default.GetBytes(chave);
algoritmo.IV = Encoding.Default.GetBytes("brasilshopsoft07");
// Interface de criptografia / Cria objeto de descriptografia
ICryptoTransform cryptoTransform = algoritmo.CreateDecryptor();
MemoryStream _memoryStream = new MemoryStream(cryptoByte, 0, cryptoByte.Length);
CryptoStream _cryptoStream = new CryptoStream(_memoryStream, cryptoTransform, CryptoStreamMode.Read);
// Busca resultado do CryptoStream
StreamReader _streamReader = new StreamReader(_cryptoStream);
return _streamReader.ReadToEnd();
}
#endregion
public static string ToCriptografa(this string valor)
{
return Criptografa(valor, chave);
}
public static string ToDescriptografa(this string valor)
{
return Descriptografa(valor, chave);
}
public static string ToCriptografaQueryString(this string valor)
{
return base64Encode(Criptografa(valor, chave));
}
public static string ToDescriptografaQueryString(this string valor)
{
return Descriptografa(base64Decode(valor), chave);
}
#endregion
}
这是我正在尝试执行的 java 代码:
public class Criptografia {
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(
"eGlhV2xNbmdqSFBkbEhkZDNpZ3gwQT09", "CB=Z8#P@0!N2/8$%3K-9C(5S9*FDH+0Z"));
}
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);
}
}
}
您的代码问题:
选择了错误的字符集。如果
Encoding.Default
在 C# 中是 UTF-8,那么 "password" 和 IV 编码在 Java. 中也必须是 IV不是从key推导出来的,也是固定值
密文其实是经过双重Base64编码的。我想有人把 "two is better than one" 看得太直白了。
"UTF-8"
完整代码:
private static final String AES_CBC_PKCS5PADDING = "AES/CBC/PKCS5PADDING";
private static final int KEY_SIZE = 256;
<b>private static String UTF_8 = "UTF-8";</b>
public static void main(final String[] args) throws Exception {
System.out.println(decryptAuthorizationString(
"eGlhV2xNbmdqSFBkbEhkZDNpZ3gwQT09", "CB=Z8#P@0!N2/8$%3K-9C(5S9*FDH+0Z"));
}
private static String decryptAuthorizationString(final String authString,
final String password) throws UnsupportedEncodingException {
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
<b>final byte[] passwordEncoded = password.getBytes(UTF_8);
final byte[] ivBytes = "brasilshopsoft07".getBytes(UTF_8);</b>
// --- init cipher
cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(<b>passwordEncoded</b>, "AES"),
new IvParameterSpec(ivBytes));
// --- decode & decrypt authentication string
final byte[] authBytes = Base64.decode(authString);
<b>final byte[] authBytes2 = Base64.decode(authBytes);</b>
final byte[] decryptedData = cipher.doFinal(<b>authBytes2</b>);
// WARNING: may still decrypt to wrong string if
// authString or password are incorrect -
// BadPaddingException may *not* be thrown
return new String(decryptedData, UTF_8);
} catch (BadPaddingException | IllegalBlockSizeException e) {
// failure to authenticate
return null;
} catch (final GeneralSecurityException e) {
throw new IllegalStateException(
"Algorithms or unlimited crypto files not available", e);
}
}
输出:
1
备注:
使用固定 IV 是不安全的。为了达到语义安全,必须随机选择 IV。它不必是秘密的,因此它可以与密文一起发送。一种常见的方法是将其添加到密文中并在解密之前将其切掉。
丢失第二个Base64编码。它只是带走了 space,但没有提供任何有用的功能。
始终使用特定的编码。
Encoding.Default
非常适合测试,但它可能会根据 运行 所在的机器而改变,并且您将失去多个 clients/servers. 之间的兼容性
验证密文!如果你不添加消息认证码或者使用像GCM或EAX这样的认证模式,那么攻击者可能会操纵密文而你将无法确定这一点。甚至可以完全恢复特定加密消息的明文(padding oracle 攻击)