2012-04-10 105 views
3

我有一個使用Rijndael加密的mp4,並且我正在以下面的方式在C#中解密。用於C#構造的Java中的加密/解密等效代碼

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等?

UPDATE

我正在使用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

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

我使用這個在C#國防部使用RFC 2898的關鍵和導出字節 - 我不能找到Java中的等價物 - 我在這裏發現Java equivalent of C#'s Rfc2898DerivedBytes在第二個評論 - 但我給了迭代器和dklen什麼值?

回答

6

您需要獲取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類。如果我弄錯了,請根據您的情況使用正確的模式和填充。

+0

謝謝!但是我仍然不確定如何繼續 - 你在評論中展示給我的東西超出了我在C#代碼中的作用。我不知道如何將加密的數據文件轉換爲流,解密這些位並將其重新寫回文件 – Slartibartfast 2012-04-11 05:27:11

+0

@Vrashabh:我已經用Java中的等效代碼更新了我的答案。 – 2012-04-11 07:26:43

+0

感謝您的幫助!我會嘗試一下,做更多的研究,並回答任何問題或標記爲正確的答案:) – Slartibartfast 2012-04-11 08:09:12