简体   繁体   English

Java 中 C# 构造的加密/解密等价物

[英]Encryption/Decryption equivalents in Java for C# constructs

I have an encrypted mp4 using Rijndael and I am decrypting in C# in the following manner.我有一个使用 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();

Now I need to convert this code to Java/Android equivalent.现在我需要将此代码转换为 Java/Android 等效代码。 I am not sure where to start frankly.坦率地说,我不知道从哪里开始。 I am confused by so many options - some say use Bouncy Castle, some say Apache Commons, some the native Java lib.我对这么多选项感到困惑 - 有些人说使用 Bouncy Castle,有些人说 Apache Commons,有些人说原生 Java lib。 How do I do this.我该怎么做呢。 And what do I do about CryptoStream etc?我该如何处理 CryptoStream 等?

UPDATE更新

I am using the following the code in C# for assigning the key我正在使用 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;
}

where key is secure.密钥是安全的。 I have the equivalent unsecure key in Java. How do i convert this piece of code to Java我在 Java 中有等效的不安全密钥。如何将这段代码转换为 Java

UPDATE更新

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

I am using this in C# to mod the key using Rfc 2898 and derive the bytes - I cant find an equivalent in Java - I found here Java equivalent of C#'s Rfc2898DerivedBytes in the second comment - but what values do I give for iterator and dklen?我在 C# 中使用它来使用 Rfc 2898 修改密钥并派生字节 - 我在 Java 中找不到等效项 - 我在第二条评论中找到了Java 等效于 C# 的 Rfc2898DerivedBytes - 但是我为迭代器和 dklen 提供了什么值?

You need to get Cipher object. Here is one way of getting it, using byte[] aesKey , and byte[] iv (initialization vector, must always be 16 bytes for AES).您需要获取Cipher object。这是获取它的一种方法,使用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);

Once you have Cipher object in decrypt mode, you can feed it with encrypted data using update methods, and it will return you plain-text data.一旦你的Cipher object 处于解密模式,你可以使用update方法向它提供加密数据,它会返回纯文本数据。 When you are done, you must call one of doFinal methods to get final block.完成后,您必须调用其中一种doFinal方法来获取最终块。

Alternatively, you can create CipherInputStream using your Cipher object, and original input stream that supplies encrypted data.或者,您可以使用密码 object 和提供加密数据的原始输入 stream 创建CipherInputStream You read data from CipherInputStream , which in turn reads data from original input stream, decrypts it, and returns you the plain-text data.您从CipherInputStream读取数据,后者又从原始输入 stream 读取数据,对其进行解密,然后返回纯文本数据。

For encrypting, you need to pass Cipher.ENCRYPT_MODE into Cipher.init method, and use CipherOutputStream instead.对于加密,您需要将Cipher.ENCRYPT_MODE传递给Cipher.init方法,并改用CipherOutputStream

Update: full example, more or less equivalent to original C# code:更新:完整示例,或多或少等同于原始 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

By default, Java doesn't support Rijndael algorithm (AES may or may not work, see the other answer) and PKCS7 padding.默认情况下,Java 不支持 Rijndael 算法(AES 可能有效也可能无效,请参阅其他答案)和 PKCS7 填充。 You will need to install Bouncycastle extension for that and then just use Cipher.getInstance("Rijndael/CBC/PKCS7PADDING");您需要为此安装 Bouncycastle 扩展,然后只需使用Cipher.getInstance("Rijndael/CBC/PKCS7PADDING"); . . Why CBC and PKCS7 Padding?为什么使用 CBC 和 PKCS7 填充? Those seem to be defaults for System.Security.Cryptography.Rijndael class. If I got that wrong, use correct mode and padding for your situation.这些似乎是System.Security.Cryptography.Rijndael class 的默认设置。如果我弄错了,请根据您的情况使用正确的模式和填充。

Don't worry about the implementation in C#. Go through the below link for encrypting/decrypting for Java Language.不用担心 C# 中的实现。Go 通过以下链接对 Java 语言进行加密/解密。 RjIndeal Implementation in Java Java 中的 RjIndeal 实现

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM