Java加密和C#解密问题

发布于 2024-12-09 10:39:23 字数 6426 浏览 0 评论 0原文

我在 C# 中有一个 DLL,可以加密和解密字符串文本(一些基本的东西),但现在我需要在 Java 中实现相同的加密方法,以便某些应用程序可以加密数据并将其发送到库。

我无法修改 C# 代码,因为它已经投入生产,但 Java 还没有,所以请任何建议都必须在 Java 端完成。

基本上我正在尝试在 Java 中实现相同的 C# 加密方法。以下是我的 C# 代码:

注意:密码、盐等值显然只是参考性的。

    const string PassPhrase = "IhDyHz6bgQyS0Ff1/1s="; 
    const string SaltValue = "0A0Qvv09OXd3GsYHVrA=";   
    const string HashAlgorithm = "SHA1";                
    const int PasswordIterations = 3;                 
    const string InitVector = "GjrlRZ6INgNckBqv";      
    const int KeySize = 256;


public static string Encrypt(string plainText)
    {

        byte[] initVectorBytes = Encoding.ASCII.GetBytes(InitVector);
        byte[] saltValueBytes = Encoding.ASCII.GetBytes(SaltValue);


        byte[] plainTextBytes = Encoding.UTF8.GetBytes(plainText);


        PasswordDeriveBytes password = new PasswordDeriveBytes(
                                                        PassPhrase,
                                                        saltValueBytes,
                                                        HashAlgorithm,
                                                        PasswordIterations);


        byte[] keyBytes = password.GetBytes(KeySize / 8);


        RijndaelManaged symmetricKey = new RijndaelManaged();


        symmetricKey.Mode = CipherMode.CBC;


        ICryptoTransform encryptor = symmetricKey.CreateEncryptor(
                                                         keyBytes,
                                                         initVectorBytes);


        MemoryStream memoryStream = new MemoryStream();


        CryptoStream cryptoStream = new CryptoStream(memoryStream,
                                                     encryptor,
                                                     CryptoStreamMode.Write);

        cryptoStream.Write(plainTextBytes, 0, plainTextBytes.Length);


        cryptoStream.FlushFinalBlock();


        byte[] cipherTextBytes = memoryStream.ToArray();


        memoryStream.Close();
        cryptoStream.Close();


        string cipherText = Convert.ToBase64String(cipherTextBytes);


        return cipherText;
    }


public static string Decrypt(string cipherText)
    {

        byte[] initVectorBytes = Encoding.ASCII.GetBytes(InitVector);
        byte[] saltValueBytes = Encoding.ASCII.GetBytes(SaltValue);


        byte[] cipherTextBytes = Convert.FromBase64String(cipherText);

        PasswordDeriveBytes password = new PasswordDeriveBytes(
                                                        PassPhrase,
                                                        saltValueBytes,
                                                        HashAlgorithm,
                                                        PasswordIterations);


        byte[] keyBytes = password.GetBytes(KeySize / 8);


        RijndaelManaged symmetricKey = new RijndaelManaged();


        symmetricKey.Mode = CipherMode.CBC;


        ICryptoTransform decryptor = symmetricKey.CreateDecryptor(
                                                         keyBytes,
                                                         initVectorBytes);


        MemoryStream memoryStream = new MemoryStream(cipherTextBytes);


        CryptoStream cryptoStream = new CryptoStream(memoryStream,
                                                      decryptor,
                                                      CryptoStreamMode.Read);


        byte[] plainTextBytes = new byte[cipherTextBytes.Length];


        int decryptedByteCount = cryptoStream.Read(plainTextBytes,
                                                   0,
                                                   plainTextBytes.Length);


        memoryStream.Close();
        cryptoStream.Close();


        string plainText = Encoding.UTF8.GetString(plainTextBytes,
                                                   0,
                                                   decryptedByteCount);


        return plainText;
    }

这是我的 java 代码,它加密数据,但与 C# 加密代码的方式不同,因此当我尝试使用 C# 库解密它时,它会抛出异常:“要解密的数据长度无效”

    static final String PassPhrase = "IhDyHz6bgQyS0Ff1/1s=";   
    static final String SaltValue = "0A0Qvv09OXd3GsYHVrA=";    
    static final String HashAlgorithm = "SHA1";               
    static final int PasswordIterations = 3;                   
    static final String InitVector = "GjrlRZ6INgNckBqv";       
    static final int KeySize = 256;

public static String encrypt(String plainText)
{
    char[] password = PassPhrase.toCharArray();
    byte[] salt = SaltValue.getBytes();
    byte[] iv = InitVector.getBytes();
    byte[] ciphertext = new byte[0];

    SecretKeyFactory factory;
    try {
        factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");

        KeySpec spec = new PBEKeySpec(password, salt, PasswordIterations, 256);
        SecretKey tmp;

        tmp = factory.generateSecret(spec);

        SecretKey secret = new SecretKeySpec(tmp.getEncoded(), "AES");

        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        cipher.init(Cipher.ENCRYPT_MODE, secret);
        AlgorithmParameters params = cipher.getParameters();
        //iv = params.getParameterSpec(IvParameterSpec.class).getIV();
        ciphertext = cipher.doFinal(plainText.getBytes("UTF-8"));

    } catch (NoSuchAlgorithmException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (InvalidKeySpecException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (NoSuchPaddingException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (InvalidKeyException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } 
    //catch (InvalidParameterSpecException e) {
    //  // TODO Auto-generated catch block
    //  e.printStackTrace();
    //} 
    catch (IllegalBlockSizeException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (BadPaddingException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (UnsupportedEncodingException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }

    return Base64.encode(new String(ciphertext));
}

< strong>编辑1:我修复了Java代码中最终字节数组转换为String的问题,正如Jon Skeet建议的那样。

I have a DLL in C# that encrypts and decrypts string texts (something basic), but now I need to implement the same encryption method in Java, so that some applications can encrypt data and send it to the library.

I can't modify the C# code, because it's already in production, but the Java don't, so please, any suggestion must be done at the Java side.

Basically I'm trying to implement the same C# encryption method in Java. Here are my C# codes:

NOTE: the passphrase, salt, etc. values obviously are just referential.

    const string PassPhrase = "IhDyHz6bgQyS0Ff1/1s="; 
    const string SaltValue = "0A0Qvv09OXd3GsYHVrA=";   
    const string HashAlgorithm = "SHA1";                
    const int PasswordIterations = 3;                 
    const string InitVector = "GjrlRZ6INgNckBqv";      
    const int KeySize = 256;


public static string Encrypt(string plainText)
    {

        byte[] initVectorBytes = Encoding.ASCII.GetBytes(InitVector);
        byte[] saltValueBytes = Encoding.ASCII.GetBytes(SaltValue);


        byte[] plainTextBytes = Encoding.UTF8.GetBytes(plainText);


        PasswordDeriveBytes password = new PasswordDeriveBytes(
                                                        PassPhrase,
                                                        saltValueBytes,
                                                        HashAlgorithm,
                                                        PasswordIterations);


        byte[] keyBytes = password.GetBytes(KeySize / 8);


        RijndaelManaged symmetricKey = new RijndaelManaged();


        symmetricKey.Mode = CipherMode.CBC;


        ICryptoTransform encryptor = symmetricKey.CreateEncryptor(
                                                         keyBytes,
                                                         initVectorBytes);


        MemoryStream memoryStream = new MemoryStream();


        CryptoStream cryptoStream = new CryptoStream(memoryStream,
                                                     encryptor,
                                                     CryptoStreamMode.Write);

        cryptoStream.Write(plainTextBytes, 0, plainTextBytes.Length);


        cryptoStream.FlushFinalBlock();


        byte[] cipherTextBytes = memoryStream.ToArray();


        memoryStream.Close();
        cryptoStream.Close();


        string cipherText = Convert.ToBase64String(cipherTextBytes);


        return cipherText;
    }


public static string Decrypt(string cipherText)
    {

        byte[] initVectorBytes = Encoding.ASCII.GetBytes(InitVector);
        byte[] saltValueBytes = Encoding.ASCII.GetBytes(SaltValue);


        byte[] cipherTextBytes = Convert.FromBase64String(cipherText);

        PasswordDeriveBytes password = new PasswordDeriveBytes(
                                                        PassPhrase,
                                                        saltValueBytes,
                                                        HashAlgorithm,
                                                        PasswordIterations);


        byte[] keyBytes = password.GetBytes(KeySize / 8);


        RijndaelManaged symmetricKey = new RijndaelManaged();


        symmetricKey.Mode = CipherMode.CBC;


        ICryptoTransform decryptor = symmetricKey.CreateDecryptor(
                                                         keyBytes,
                                                         initVectorBytes);


        MemoryStream memoryStream = new MemoryStream(cipherTextBytes);


        CryptoStream cryptoStream = new CryptoStream(memoryStream,
                                                      decryptor,
                                                      CryptoStreamMode.Read);


        byte[] plainTextBytes = new byte[cipherTextBytes.Length];


        int decryptedByteCount = cryptoStream.Read(plainTextBytes,
                                                   0,
                                                   plainTextBytes.Length);


        memoryStream.Close();
        cryptoStream.Close();


        string plainText = Encoding.UTF8.GetString(plainTextBytes,
                                                   0,
                                                   decryptedByteCount);


        return plainText;
    }

Here is my java code, it encrypts the data, but not at the same way as the C# encryption code, so when I try to decrypt it using the C# library it throws the exception: "Length of the data to decrypt is invalid"

    static final String PassPhrase = "IhDyHz6bgQyS0Ff1/1s=";   
    static final String SaltValue = "0A0Qvv09OXd3GsYHVrA=";    
    static final String HashAlgorithm = "SHA1";               
    static final int PasswordIterations = 3;                   
    static final String InitVector = "GjrlRZ6INgNckBqv";       
    static final int KeySize = 256;

public static String encrypt(String plainText)
{
    char[] password = PassPhrase.toCharArray();
    byte[] salt = SaltValue.getBytes();
    byte[] iv = InitVector.getBytes();
    byte[] ciphertext = new byte[0];

    SecretKeyFactory factory;
    try {
        factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");

        KeySpec spec = new PBEKeySpec(password, salt, PasswordIterations, 256);
        SecretKey tmp;

        tmp = factory.generateSecret(spec);

        SecretKey secret = new SecretKeySpec(tmp.getEncoded(), "AES");

        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        cipher.init(Cipher.ENCRYPT_MODE, secret);
        AlgorithmParameters params = cipher.getParameters();
        //iv = params.getParameterSpec(IvParameterSpec.class).getIV();
        ciphertext = cipher.doFinal(plainText.getBytes("UTF-8"));

    } catch (NoSuchAlgorithmException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (InvalidKeySpecException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (NoSuchPaddingException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (InvalidKeyException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } 
    //catch (InvalidParameterSpecException e) {
    //  // TODO Auto-generated catch block
    //  e.printStackTrace();
    //} 
    catch (IllegalBlockSizeException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (BadPaddingException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (UnsupportedEncodingException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }

    return Base64.encode(new String(ciphertext));
}

EDIT 1: I fixed the final byte array conversion to String in the Java code, as Jon Skeet suggested.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

凉栀 2024-12-16 10:39:23

这就是 Java 代码中的错误:

return Base64.encode(ciphertext.toString());

您在字节数组上调用 toString(),这将总是给出一个字符串,例如 [B@ 3e25a5。

编辑:哦,刚刚注意到您可以更改Java方面。万岁。

基本上,您需要使用 Base64 API,它允许:

return Base64.encode(ciphertext);

说实话,我总是对 Base64 API 感到失望,它们允许您“编码”字符串...... Base64 从根本上将二进制数据编码为文本,并将文本数据解码为二进制。哦,好吧......

无论如何,使用这个APIencodeBytes 方法),如果您需要一个允许您传入字节数组的方法。

我还没有详细检查实际的加密部分,但 C# 代码至少看起来在编码方面做得正确。不过,它可以用 using 语句来完成:)

This is what's wrong, in the Java code:

return Base64.encode(ciphertext.toString());

You're calling toString() on the byte array, which will always give a string such as [B@3e25a5.

EDIT: Ooh, just noticed that you can change the Java side. Hooray.

Basically, you need to use a Base64 API which allows:

return Base64.encode(ciphertext);

I'm always disappointed in Base64 APIs which allow you to "encode" a string, to be honest... base64 fundamentally encodes binary data to text, and decodes text data to binary. Oh well...

Anyway, use this API (the encodeBytes method) if you need one which allows you to pass in a byte array.

I haven't checked over the actual encryption part in detail, but the C# code at least looks like it's doing the right thing in terms of encodings. It could do with using statements though :)

饭团 2024-12-16 10:39:23

这是一个 C# 示例,您需要 IterationCount 和 PaddingMode.None

protected void Page_Load(object sender, EventArgs e)
{
    string value = "";
    string password = "";
    string salt = "";
    string iv = "";


    byte[] vectorBytes = Convert.FromBase64String(Server.UrlDecode(iv)); 
    byte[] cipherText = Convert.FromBase64String(Server.UrlDecode(value));

    Rfc2898DeriveBytes key1 = new Rfc2898DeriveBytes(password, StringToByteArray(salt)); //same as PBKDF2WithHmacSHA1
    key1.IterationCount = 32;
    byte[] keyBytes = key1.GetBytes(16);

    string Answer = DecryptDataAES(cipherText, keyBytes, vectorBytes); //vectorBytes is good

    //litAnswer.Text = Answer;
}

public static string DecryptDataAES(byte[] cipherText, byte[] key, byte[] iv)
{
    string plaintext = null;

    using (Rijndael rijndael = Rijndael.Create())
    {
        rijndael.Key = key;
        rijndael.IV = iv;
        rijndael.Padding = PaddingMode.None;

        ICryptoTransform decryptor = rijndael.CreateDecryptor(rijndael.Key, rijndael.IV);

        // Create the streams used for decryption. 
        using (MemoryStream msDecrypt = new MemoryStream(cipherText))
        {
            using (CryptoStream csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read))
            {
                using (StreamReader srDecrypt = new StreamReader(csDecrypt))
                {
                    plaintext = srDecrypt.ReadToEnd();
                }
            }
        }
    }
    return plaintext;
}

public static byte[] StringToByteArray(String hex)
{
    int NumberChars = hex.Length / 2;
    byte[] bytes = new byte[NumberChars];
    using (var sr = new StringReader(hex))
    {
        for (int i = 0; i < NumberChars; i++)
            bytes[i] =
              Convert.ToByte(new string(new char[2] { (char)sr.Read(), (char)sr.Read() }), 16);
    }
    return bytes;
}

Here is a C# example, you need the IterationCount and PaddingMode.None

protected void Page_Load(object sender, EventArgs e)
{
    string value = "";
    string password = "";
    string salt = "";
    string iv = "";


    byte[] vectorBytes = Convert.FromBase64String(Server.UrlDecode(iv)); 
    byte[] cipherText = Convert.FromBase64String(Server.UrlDecode(value));

    Rfc2898DeriveBytes key1 = new Rfc2898DeriveBytes(password, StringToByteArray(salt)); //same as PBKDF2WithHmacSHA1
    key1.IterationCount = 32;
    byte[] keyBytes = key1.GetBytes(16);

    string Answer = DecryptDataAES(cipherText, keyBytes, vectorBytes); //vectorBytes is good

    //litAnswer.Text = Answer;
}

public static string DecryptDataAES(byte[] cipherText, byte[] key, byte[] iv)
{
    string plaintext = null;

    using (Rijndael rijndael = Rijndael.Create())
    {
        rijndael.Key = key;
        rijndael.IV = iv;
        rijndael.Padding = PaddingMode.None;

        ICryptoTransform decryptor = rijndael.CreateDecryptor(rijndael.Key, rijndael.IV);

        // Create the streams used for decryption. 
        using (MemoryStream msDecrypt = new MemoryStream(cipherText))
        {
            using (CryptoStream csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read))
            {
                using (StreamReader srDecrypt = new StreamReader(csDecrypt))
                {
                    plaintext = srDecrypt.ReadToEnd();
                }
            }
        }
    }
    return plaintext;
}

public static byte[] StringToByteArray(String hex)
{
    int NumberChars = hex.Length / 2;
    byte[] bytes = new byte[NumberChars];
    using (var sr = new StringReader(hex))
    {
        for (int i = 0; i < NumberChars; i++)
            bytes[i] =
              Convert.ToByte(new string(new char[2] { (char)sr.Read(), (char)sr.Read() }), 16);
    }
    return bytes;
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文