【问题标题】:AES Negative bytesAES 负字节
【发布时间】:2025-11-30 05:05:02
【问题描述】:

以下是在 Java 中使用 AES 加密的摘录:

  encryptedData =   encryptCipher.doFinal(strToEncrypt.getBytes());

以下是c#中的摘录

 DecryptStringFromBytes_Aes(encrypted, myAes.Key, myAes.IV);

两者都使用一个字节数组加密另一个解密,Java中的加密会产生一些存储在字节数组中的负值。

C# 使用字节数组进行解密,但 C# 中的字节被定义为仅包含 0..255 之间的数字 - Java 将其字节类型定义为 -128 到 127。

因此,我无法将加密数据发送到用 C# 编写的远程应用程序,因为它无法使用从 Java 应用程序发送的字节数组进行解密。

有没有人想出一个解决方案,让我告诉 java 在加密时不要产生负数?

代码来自 Micrsoft,MemoryStream 需要 byte[] 来为加密代码创建流... 不管有没有提到,我用 sbyte 替换了 byte[] 但无济于事,因为 MemoryStream 需要 byte[]

static string DecryptStringFromBytes_Aes(sbyte[] cipherText, byte[] Key, byte[] IV)
    {
        // Check arguments. 
        if (cipherText == null || cipherText.Length <= 0)
            throw new ArgumentNullException("cipherText");
        if (Key == null || Key.Length <= 0)
            throw new ArgumentNullException("Key");
        if (IV == null || IV.Length <= 0)
            throw new ArgumentNullException("Key");

        // Declare the string used to hold 
        // the decrypted text. 
        string plaintext = null;

        // Create an Aes object 
        // with the specified key and IV. 
        using (Aes aesAlg = Aes.Create())
        {
            aesAlg.Key = Key;
            aesAlg.IV = IV;

            // Create a decrytor to perform the stream transform.
            ICryptoTransform decryptor = aesAlg.CreateDecryptor(aesAlg.Key, aesAlg.IV);

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


                        // Read the decrypted bytes from the decrypting stream
                        // and place them in a string.
                        plaintext = srDecrypt.ReadToEnd();
                    }
                }
            }

        }

        return plaintext;


    }

【问题讨论】:

    标签: c# java aes


    【解决方案1】:

    Java 的字节是有符号的,C# 的字节是无符号的(C# 中还有一个sbyte 类型,没有人使用,就像 Java 的字节一样)。

    没关系。它们在某些方面是不同的,即

    • 当转换为int 时,C# 的字节将被零扩展,Java 的字节将被符号扩展(这就是为什么在 Java 中使用字节时您几乎总是会看到 &amp; 0xFF
    • 当转换为字符串时,Java 的字节将它们的 128 - 255 范围映射到 -128 - -1。忽略它。

    这些字节的实际值(即它们的位模式)才是真正重要的,0xAA 的字节将是 0xAA,无论您将其解释为 170(如 C#)还是 -86(如爪哇)。是一样的,只是打印成字符串的方式不同。


    new MemoryStream((byte)cipherText)) 绝对没有做正确的事情(或任何事情,它甚至不应该编译)。相关的new MemoryStream((byte[])cipherText)) 也不起作用,您不能在这样的原始数组之间进行转换。 cipherText 应该只是一个 byte[] 开头。

    【讨论】:

    • 我明白你的意思,但是,当字节数据被发送到 c# 应用程序时,传递给加密函数的数据(来自 c# 库)抛出一个异常,抱怨它需要一个无符号字节数组?感谢您的帮助等人
    • @Perry 这真的没有意义,没有办法给它其他任何东西 - 它需要一个字节数组,根据定义它是无符号的
    • Harold、Java 和 Objective-C 使用有符号字节数组。因此,当我为这些语言调用各自的加密函数时,它们返回一个有符号字节数组,而 C# 使用无符号字节数组,同样使用 C# 加密和解密的函数使用无符号字节数组 - 我已经尝试了所有 3 个,这就是我所拥有的成立。我可以在IOS和Java之间发送和接收加密数据然后解密,但是调用C#上的方法来解密是有问题的。
    • @Perry 你能发布更多代码吗?对于 C# 方面。我仍然不明白这怎么可能出错。
    • 看来我无法通过 whoe 的东西所以这是 ti 调用的标题: static string DecryptStringFromBytes_Aes(byte[] cipherText, byte[] Key, byte[] IV) // 调用其中是内存流,它采用字节 []。在这个函数中,它调用 MemoryStream,它使用 byte[] 为加密代码创建一个流。加密数据为:{ 89, -62, -75, 88, 113, 93, -57, 47, -18, 14, -26, -57, 49, 13, -73, -42, -103, 109 , -75, 22, 62, -117, -33, 81, 56, -3, -124, -13, -128, 103, -27, 42 };
    【解决方案2】:

    你可以把它变成一个带有某种编码的字符串,比如:

    encryptedData =   encryptCipher.doFinal(strToEncrypt.getBytes());
    String s = new String(encryptedData, "Base-64");
    

    使用相同的标准化编码,C# 和 Java 都应该能够从该字符串重建彼此的加密数据。

    【讨论】:

    • 很好的例子,答案也很合适。我也考虑过标准化编码。
    • 简而言之,如果加密产生负值,则解密必须将这些负值转换回普通文本。 C# 中使用的默认说明 MemoryStream 采用无符号字节,这意味着您不能仅反转两者对负值的互补,这样做会改变最终结果。到目前为止,我发现的唯一方法是不使用 Microsoft 的默认 Crypto - 而是选择采用负值的 3rd 方解密方法。还是谢谢你。