【问题标题】:Encryption/Decryption equivalents in Java for C# constructsJava 中用于 C# 构造的加密/解密等价物
【发布时间】:2012-04-10 11:22:54
【问题描述】:

我有一个使用 Rijndael 加密的 mp4,我正在 C# 中以下列方式解密。

System.Security.Cryptography.Rijndael crypt = System.Security.Cryptography.Rijndael.Create();

crypt.Key = convertedSecureString;

byte[] initializationVectorLength = new byte[sizeof(int)];
CryptoStream cryptostream = new CryptoStream(inputStream, crypt.CreateDecryptor(), CryptoStreamMode.Read);
byte[] buffer = new byte[1024];
int len;
while ((len = cryptostream.Read(buffer, 0, buffer.Length)) > 0)
{
    outputStream.Write(buffer, 0, len);
    buffer = new byte[1024];
}

outputStream.Flush();
cryptostream.Close();
inputStream.Close();

现在我需要将此代码转换为 Java/Android 等效代码。我不确定从哪里开始坦率地说。我对这么多选项感到困惑——有人说使用 Bouncy Castle,有人说 Apache Commons,还有一些本地 Java 库。我该怎么做呢。我该怎么处理 CryptoStream 等?

更新

我在 C# 中使用以下代码来分配密钥

byte[] convertedSecureString = new byte[this.key.Length];
IntPtr ptr = System.Runtime.InteropServices.Marshal.SecureStringToBSTR(this.key);

for (int i = 0, j = 0; i < this.key.Length * UnicodeByteLength; i = i + UnicodeByteLength, j++)
{
    convertedSecureString[j] = System.Runtime.InteropServices.Marshal.ReadByte(ptr, i);
}

try
{
    crypt.Key = convertedSecureString;
}

密钥是安全的。我在 Java 中有等效的不安全密钥。我如何将这段代码转换为 Java

更新

  Rfc2898DeriveBytes newKey = new Rfc2898DeriveBytes(crypt.Key.ToString(), crypt.IV);
                Array.Copy(newKey.GetBytes((int)crypt.KeySize / 8), crypt.Key, (int)crypt.KeySize / 8);
                Array.Copy(newKey.GetBytes((int)crypt.BlockSize / 8), crypt.IV, (int)crypt.BlockSize / 8);

我在 C# 中使用它来使用 Rfc 2898 修改密钥并派生字节 - 我在 Java 中找不到等效项 - 我在第二条评论中找到了 Java equivalent of C#'s Rfc2898DerivedBytes - 但是我为迭代器和 dklen 提供了哪些值?

【问题讨论】:

    标签: java android encryption


    【解决方案1】:

    你需要得到Cipher 对象。这是获取它的一种方法,使用 byte[] aesKeybyte[] iv(初始化向量,对于 AES,必须始终为 16 字节)。

    // aesKey is 128, 196 or 256-bit key (8, 12 or 16 byte array)
    SecretKeySpec key = new SecretKeySpec(aesKey, "AES");
    
    // initialization vector
    IvParameterSpec ivSpec = new IvParameterSpec(iv);
    
    // create and initialize cipher object
    Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");
    cipher.init(Cipher.DECRYPT_MODE, key, ivSpec);
    

    一旦你有Cipher 对象处于解密模式,你可以使用update 方法向它提供加密数据,它会返回纯文本数据。完成后,您必须调用 doFinal 方法之一来获取最终块。

    或者,您可以使用 Cipher 对象和提供加密数据的原始输入流创建 CipherInputStream。您从CipherInputStream 读取数据,后者又从原始输入流中读取数据,对其进行解密,然后将纯文本数据返回给您。

    对于加密,你需要将Cipher.ENCRYPT_MODE 传递给Cipher.init 方法,并改用CipherOutputStream

    更新:完整示例,或多或少等同于原始 C# 代码:

    // Algorithm, mode and padding must match encryption.
    // Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");
    
    // If you have Bouncycastle library installed, you can use
    // Rijndael/CBC/PKCS7PADDING directly.
    Cipher cipher = Cipher.getInstance("Rijndael/CBC/PKCS7PADDING");
    
    // convertedSecureString and initVector must be byte[] with correct length
    cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(convertedSecureString, "AES"),
        new IvParameterSpec(initVector));
    
    CipherInputStream cryptoStream = new CipherInputStream(inputStream, cipher);
    byte[] buffer = new byte[1024];
    int len = cryptoStream.read(buffer, 0, buffer.length);
    while (len > 0) {
        outputStream.write(buffer, 0, len);
        len = cryptoStream.read(buffer, 0, buffer.length);
    }
    
    outputStream.flush();
    cryptoStream.close();
    // no need to close inputStream here, as cryptoStream will close it
    

    默认情况下,Java 不支持 Rijndael 算法(AES 可能有效也可能无效,请参阅其他答案)和 PKCS7 填充。您需要为此安装 Bouncycastle 扩展,然后使用 Cipher.getInstance("Rijndael/CBC/PKCS7PADDING");。为什么选择 CBC 和 PKCS7 填充?这些似乎是System.Security.Cryptography.Rijndael 类的默认值。如果我弄错了,请根据您的情况使用正确的模式和填充。

    【讨论】:

    • 谢谢!但我仍然不确定如何继续 - 你在上面的评论中向我展示的内容与我在 C# 代码中所做的相同。我不确定如何将加密的数据文件转换为流,解密这些位并将其再次写回文件
    • @Vrashabh:我已经用 Java 中的等效代码更新了我的答案。
    • 感谢您的帮助!我会尝试并做更多的研究,然后提出问题或标记为正确答案:)
    • 我已编辑问题以包含更新 - 从您的示例中,我每次使用来自安全字符串的 C# 中的编组代码生成密钥。所以 SecureKey->BSTR->Marshall 到 32 个字节并分配给密钥。我在 Java 中有不安全的编码密钥 = 如何执行相同的操作来获得 32 字节的密钥用于解密?
    • @Vrashabh:Java 中没有“SecureString”之类的东西。当您说“不安全的编码密钥”时,您到底有什么,也许我可以帮忙?它是什么类型的? String 类的实例?如果是这样,您需要使用String.getBytes("UTF-8")(或其他一些编码)将其转换为字节数组。当你有字节数组时,你可以创建一个SecretKeySpec,如代码所示。
    【解决方案2】:

    不用担心 C# 中的实现。通过以下链接进行 Java 语言的加密/解密。RjIndeal Implementation in Java

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-07-30
      • 1970-01-01
      • 2019-09-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多