java - Java 中用于 C# 构造的加密/解密等价物

标签 java android encryption

我有一个使用 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,有人说使用 native Java 库。我该怎么做呢。我该如何处理 CryptoStream 等?

更新

我在 C# 中使用以下代码分配 key

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;
}

key 是安全的。我在 Java 中有等效的不安全 key 。我如何将这段代码转换为 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 修改 key 并派生字节 - 我找不到 Java 中的等效项 - 我在这里找到 Java equivalent of C#'s Rfc2898DerivedBytes在第二条评论中——但是我为迭代器和 dklen 赋予了什么值?

最佳答案

你需要得到 Cipher目的。这是获取它的一种方法,使用 byte[] aesKeybyte[] iv(初始化 vector ,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 之一获取最终区 block 的方法。

或者,您可以创建 CipherInputStream使用您的 Cipher 对象和提供加密数据的原始输入流。您从 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 的默认值类(class)。如果我弄错了,请根据您的情况使用正确的模式和填充。

关于java - Java 中用于 C# 构造的加密/解密等价物,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10087794/

相关文章:

iPhone 测试自动化 - 基准工具?

java - Android SQLite 行不更新

java - MS SQL服务器: Securing column level data

c++ - 在 Crypto++ 中加载 PEM 编码的私有(private) RSA key

java - 如何在 LIBGDX 中检查曲线的碰撞检测?

java - 编写一个方法来查找 ArrayList 中最大整数的索引时遇到问题

android - 无法在内部存储中创建文件

java - 过度绘制 Eclipse RCP 应用程序的主 shell

java - 使用 Java 编辑 Flash

Java AES 无法解密阿拉伯语