解密Java

时间:2016-06-08 17:20:24

标签: java asp.net cryptography aes

我在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);
        }
    }
}

1 个答案:

答案 0 :(得分:1)

您的代码问题:

  • 选择了错误的字符集。如果{#1}}在C#中是UTF-8,那么Java中的“密码”和IV编码也必须是Encoding.Default

  • IV不是来自密钥,而是来自固定值。

  • 密文实际上是双重Base64编码。我猜有人认为“两个比一个好”,太过于字面化。

完整代码:

"UTF-8"

输出:

1

注意:

  • 使用固定的IV是不安全的。必须随机选择IV以达到语义安全性。它不必是秘密的,因此它可以与密文一起发送。一种常见的方法是将其添加到密文并在解密之前将其切掉。

  • 丢失第二个Base64编码。它只是占用空间,但没有提供任何有用的功能。

  • 始终使用特定编码。 private static final String AES_CBC_PKCS5PADDING = "AES/CBC/PKCS5PADDING"; private static final int KEY_SIZE = 256; private static String UTF_8 = "UTF-8"; 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 final byte[] passwordEncoded = password.getBytes(UTF_8); final byte[] ivBytes = "brasilshopsoft07".getBytes(UTF_8); // --- init cipher cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(passwordEncoded, "AES"), new IvParameterSpec(ivBytes)); // --- decode & decrypt authentication string final byte[] authBytes = Base64.decode(authString); final byte[] authBytes2 = Base64.decode(authBytes); final byte[] decryptedData = cipher.doFinal(authBytes2); // 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); } }非常适合测试,但它可能会因运行的计算机而发生变化,您将失去多个客户端/服务器之间的兼容性。

  • 验证密文!如果您不添加消息身份验证代码或使用经过身份验证的模式(如GCM或EAX),则攻击者可能会操纵密文,您将无法确定此密码。这可以完全恢复特定加密消息的明文(填充oracle攻击)。