2014-07-25 55 views
0

我正在使用RSA加密來加密C#中的一些數據。現在我想用Java解密加密的數據。 但我遇到了一些問題。在Java中解密來自C#的RSA加密數據。加密數據的格式?

主要的問題可能是從c#到Java的加密消息。 在C#中我們無符號字節,字節序是不同

因此,爲了測試我轉換byte陣列加密的數據在C#中的sbyte陣列,並得到它的字符串表示。 然後我將字節數組的字符串表示複製到我的java代碼中,並將其轉換回'byte'數組。在那之後,我將數組倒過來以匹配java的字節順序。

但是,如果我嘗試這是像上面所傳送的數據進行解碼,我得到以下異常:

javax.crypto.BadPaddingException: Message is larger than modulus

加密和C#到C#解密工作,以及從Java到Java。只有C#到java將無法工作。 (要加密的字符串長度爲7個字符,所以它不是很長)

我將c#中的公鑰轉換爲BigInteger。公共密鑰從RSAParameters交付:

public byte[] RSAEncrypt(byte[] data, RSAParameters param, bool padding) { 
     using (RSACryptoServiceProvider rsaProvider = new RSACryptoServiceProvider(1024)) { 
      rsaProvider.ImportParameters(param); 

      byte[] modulusArray = param.Modulus; 
      byte[] exponentArray = param.Exponent; 

      BigInteger modulusBigInt = new BigInteger(modulusArray); 

      BigInteger exponentBigInt = new BigInteger(exponentArray); 

      encryptedData = rsaProvider.Encrypt(data, false); 

      return encryptedData; 
     } 
    } 

之後,我複製模的字符串表示和指數到我的Java代碼,創建從他們新BigInteger並創建公共密鑰:

BigInteger modulusBigInt = new BigInteger(modulusBytesStr); 
    BigInteger exponentBigInt = getBigIntFromByteString(exponentBytesStr); 

    Key pK = getPublicKey(modulusBigInt, exponentBigInt); 

然後我嘗試對數據進行解密(其中數據是予從C#傳遞到Java等中描述上面的字節數組):

 Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding"); 

     cipher.init(Cipher.DECRYPT_MODE, pK); 

     decryptedData = cipher.doFinal(data); 

但是,如果我嘗試這樣做,我會得到上述異常。我想,公鑰應該是對的。至少我有相同的BigInteger模數和指數在c#和java中的值。填充也是相同的。 所以我假設我的加密數據的格式有問題。它應該具有哪些fromat?

我也看到了這個問題:RSA .NET encryption Java decryption 但即使是我不知道是什麼格式我的數據到encryspt /解密應該有

編輯:嘗試在C#中的加密字節轉換爲Base64 String和java將其轉換回字節。也不能正常工作

編輯2:如果我使用var key = rsaProvider.ToXmlString(true);來獲取公共密鑰的xml represantation並將模數和指數的xml字符串放入我的java代碼中,將它們從Base64字符串轉換爲字節數組和字節數組到BigInteger的,然後我得到的BigInteger的曾在C#中的模數的BigInteger的另一個價值,但我得到follwing這個值異常:javax.crypto.BadPaddingException: Decryption error

EDIT3:發現我的錯誤:對於簡單的測試我只是使用的私有我在C#代碼中生成的密鑰在java中解密。但在我的java代碼中,我試圖從私鑰生成公鑰。

 RSAPublicKeySpec keySpec = new RSAPublicKeySpec(modulus, exponent); 

     KeyFactory kf = KeyFactory.getInstance("RSA"); 
     PublicKey pK = kf.generatePublic(keySpec); 

這顯然是錯誤的。所以我改變了這個:

RSAPrivateKeySpec keySpec = new RSAPrivateKeySpec(modulusBigInt, exponentBigInt); 

     KeyFactory kf = KeyFactory.getInstance("RSA"); 
     Key key = kf.generatePrivate(keySpec); 

它的工作。那也是爲什麼GregS的方法處理(有沒有「公鑰」 /「專用密鑰」生成和解密是不是在方法的Java編譯使用)

+0

建議:不要嘗試加密和解密開始。找出一種將C#中的二進制數據傳輸到Java的方法,然後一旦這部分工作,就在它上面加密。 – zebediah49

+0

想出了一個辦法:使用base64字符串(就像我第一次嘗試,在我嘗試直接傳輸字節之前,因爲沒有任何工作)。所以,正如你可以在我的EDIT2中看到的,base64字符串也不起作用。基於base64字符串,模數的BigInteger值在c#和java中是不同的。 – Rul3r

回答

0

我有點不清楚你到底錯在哪裏。這是一個適用於我的例子,我基於你的代碼。我沒有Windows機器,所以我在Mono中進行了測試。

C#:

using System; 
using System.Security.Cryptography; 
using System.Text; 

namespace RsaDotNetToJava 
{ 
    class MainClass 
    { 
     public byte[] RSAEncrypt(byte[] data, RSAParameters param, bool padding) { 
      using (RSACryptoServiceProvider rsaProvider = new RSACryptoServiceProvider(1024)) { 
       rsaProvider.ImportParameters(param); 

       var encryptedData = rsaProvider.Encrypt(data, false); 

       return encryptedData; 
      } 
     } 

     public static void W(string label, byte [] x) { 
      var b64 = Convert.ToBase64String (x); 
      Console.WriteLine ("{0} = {1}", label, b64); 
     } 

     public static void Main (string[] args) 
     { 
      var x = new MainClass(); 
      var rsa = new RSACryptoServiceProvider (1024); 
      var data = Encoding.ASCII.GetBytes("Hello world"); 
      var parms = rsa.ExportParameters(true); 
      W ("Modulus", parms.Modulus); 
      W ("P", parms.P); 
      W ("DecryptExponent", parms.D); 
      W ("EncryptExponent", parms.Exponent); 
      var cipher = x.RSAEncrypt(data, parms, false); 
      W ("Cipher", cipher); 
     } 
    } 
} 

接着,一些Java,在BASE64字符串用( 「標籤=」 剝離)的命令行和做一些操作讀。這使用java 7類javax.xml.bind.DatatypeConverter作爲其base64解析器。

import java.math.BigInteger; 
import javax.xml.bind.DatatypeConverter; 

public class RsaJavaToDotNet { 


    private static BigInteger b64ToBigInteger(String b64) { 
     byte [] bigEndianBytes = DatatypeConverter.parseBase64Binary(b64); 
     return new BigInteger(1, bigEndianBytes); 
    } 

    /** 
    * @param args base64 encoded .NET big-endian integer arrays 
    * args[0] = modulus 
    * args[1] = prime 
    * args[2] = decrypt exponent 
    * args[3] = encrypt exponent 
    * args[4] = cipher 
    * @throws Exception 
    */ 
    public static void main(String[] args) throws Exception { 

     BigInteger modulus = b64ToBigInteger(args[0]); 
     final int modulusByteLength = (modulus.bitLength() + 7)/8; 
     BigInteger prime = b64ToBigInteger(args[1]); 
     BigInteger d = b64ToBigInteger(args[2]); 
     BigInteger e = b64ToBigInteger(args[3]); 
     BigInteger cipherInt = b64ToBigInteger(args[4]); 

     // Decrypt the cipher 

     BigInteger plainInt = cipherInt.modPow(d, modulus); 
     byte [] plain = plainInt.toByteArray(); 

     // Verify the format and extract the message. 

     if (plain.length != (modulusByteLength - 1) || plain[0] != 2) { 
      throw new Exception("Something is wrong"); 
     } 

     // Find the zero byte delimited the payload from the padding 

     int zeroPos = 1; 
     while (zeroPos < plain.length && plain[zeroPos] != 0) { 
      ++zeroPos; 
     } 

     String plainStr = new String(plain, zeroPos + 1, plain.length - zeroPos - 1, "UTF-8"); 
     System.out.println(plainStr); 
    } 

} 
+0

您的代碼正在工作。在我嘗試將其調整爲我的代碼並失敗後,我只是將其複製以進行測試,並且工作正常。所以,現在我試圖找出我的代碼中的錯誤。 – Rul3r

-1

So, for testing I am converting the byte array of the encrypted data in c# to a sbyte array and get a string representation of it. Then I copy the string representation of the byte array into my java code and convert it back to an 'byte' array. After that, I reverse the array to match the endianess of java.

我不太明白爲什麼「字節順序」這裏是個問題。 Endianism是你正在運行的CPU的函數,而不是編程語言。

+0

如果我有follwing字節數組; 'byte [] b = new byte [] {120,110,100}'並且想要將它轉換成java和c#中的BigInteger,而不是我在c#中的值爲6581880,而在java中的值爲7892580.只能顛倒java或在C#中)將得到相同的結果。 我現在的問題是:是否有必要在Java和C#中的公鑰的BigIntegers相同的值,或者我可以忽略字節數組的順序? – Rul3r

+0

但它並不重要,因爲即使我使用base64字符串獲取公鑰(模數,指數)和加密的消息給java(並將模數和指數字符串轉換爲BigIntegers),我也會遇到異常。 – Rul3r

+1

字節順序不僅僅是一個CPU功能。每當有一個大小的二進制整數序列與較小的二進制整數的較長序列之間存在映射時,字節順序就很重要。當CPU以不同大小的塊訪問內存時,可能發生這種映射。它也可能是網絡協議和文件格式中的一個問題。在具有「聯合」數據類型(例如C/C++)的編程語言中,這是一個問題,並且在圖書館中「串行化」對象是一個問題。協議/語言/庫可以指定字節序,或者它們可以允許它依賴於底層硬件。 –