2013-08-06 104 views
10

我被給出了由Web服務團隊編寫的這個C#代碼,該代碼公開了一些我打算使用的Web服務。我的密碼需要使用此代碼進行加密,以便Web服務知道如何對其進行解密。將C#RSACryptoServiceProvider轉換爲JAVA代碼

using(RSACryptoServiceProvider rsa = new RSACryptoServiceProvider()) 
{ 
    rsa.FromXmlString(publicKey); 
    byte[] plainBytes = Encoding.Unicode.GetBytes(clearText); 
    byte[] encryptedBytes = rsa.Encrypt(plainBytes, false); 
    return Convert.ToBase64String(encryptedBytes); 
} 

我使用Java來消費這個Web服務,現在,我有問題,翻譯是#C代碼轉換成Java代碼,因爲Web服務不能正確地解密了密碼。

這是我目前的失敗嘗試: -

// my clear text password 
String clearTextPassword = "XXXXX"; 

// these values are provided by the web service team 
String modulusString = "..."; 
String publicExponentString = "..."; 

BigInteger modulus = new BigInteger(1, Base64.decodeBase64(modulusString.getBytes("UTF-8"))); 
BigInteger publicExponent = new BigInteger(1, Base64.decodeBase64(publicExponentString.getBytes("UTF-8"))); 

KeyFactory keyFactory = KeyFactory.getInstance("RSA"); 

RSAPublicKeySpec publicKeySpec = new RSAPublicKeySpec(modulus, publicExponent); 
PublicKey publicKey = keyFactory.generatePublic(publicKeySpec); 

Cipher cipher = Cipher.getInstance("RSA/ECB/NoPadding"); 
cipher.init(Cipher.ENCRYPT_MODE, publicKey); 

String encodedEncryptedPassword = new String(Base64.encodeBase64(cipher.doFinal(clearTextPassword.getBytes("UTF-8")))); 

我做了什麼錯?非常感謝。

2013年8月7日 - UPDATE

我讀this website,我意識到,我的模值和公共指數值不是十六進制。所以,我修改了一下我的代碼,並用@Dev提到的RSA/ECB/PKCS1PADDING進行了嘗試。

// my clear text password 
String clearTextPassword = "XXXXX"; 

// these are the actual values I get from the web service team 
String modulusString = "hm2oRCtP6usJKYpq7o1K20uUuL11j5xRrbV4FCQhn/JeXLT21laKK9901P69YUS3bLo64x8G1PkCfRtjbbZCIaa1Ci/BCQX8nF2kZVfrPyzcmeAkq4wsDthuZ+jPInknzUI3TQPAzdj6gim97E731i6WP0MHFqW6ODeQ6Dsp8pc="; 
String publicExponentString = "AQAB"; 

Base64 base64Encoder = new Base64(); 

String modulusHex = new String(Hex.encodeHex(modulusString.getBytes("UTF-8"))); 
String publicExponentHex = new String(Hex.encodeHex(publicExponentString.getBytes("UTF-8"))); 

BigInteger modulus = new BigInteger(modulusHex, 16); 
BigInteger publicExponent = new BigInteger(publicExponentHex); 

KeyFactory keyFactory = KeyFactory.getInstance("RSA"); 

RSAPublicKeySpec publicKeySpec = new RSAPublicKeySpec(modulus, publicExponent); 
PublicKey publicKey = keyFactory.generatePublic(publicKeySpec); 

Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1PADDING"); 
cipher.init(Cipher.ENCRYPT_MODE, publicKey); 

String encodedEncryptedPassword = new String(base64Encoder.encode(cipher.doFinal(clearTextPassword.getBytes("UTF-8")))); 

當我打web服務,我發現了此錯誤:「要被解密的數據超出該模數的128個字節的最大」。似乎明文密碼仍未正確加密。

任何幫助或建議,非常感謝。謝謝。

2013年8月9日 - 解決方案

我下面貼我的最終工作方案。

回答

8

找到了解決方案。

String modulusString = "hm2oRCtP6usJKYpq7o1K20uUuL11j5xRrbV4FCQhn/JeXLT21laKK9901P69YUS3bLo64x8G1PkCfRtjbbZCIaa1Ci/BCQX8nF2kZVfrPyzcmeAkq4wsDthuZ+jPInknzUI3TQPAzdj6gim97E731i6WP0MHFqW6ODeQ6Dsp8pc="; 
String publicExponentString = "AQAB"; 

byte[] modulusBytes = Base64.decodeBase64(modulusString); 
byte[] exponentBytes = Base64.decodeBase64(publicExponentString); 
BigInteger modulus = new BigInteger(1, modulusBytes); 
BigInteger publicExponent = new BigInteger(1, exponentBytes); 

RSAPublicKeySpec rsaPubKey = new RSAPublicKeySpec(modulus, publicExponent); 
KeyFactory fact = KeyFactory.getInstance("RSA"); 
PublicKey pubKey = fact.generatePublic(rsaPubKey); 
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1PADDING"); 
cipher.init(Cipher.ENCRYPT_MODE, pubKey); 

byte[] plainBytes = clearTextPassword.getBytes("UTF-16LE"); 
byte[] cipherData = cipher.doFinal(plainBytes); 
String encryptedStringBase64 = Base64.encodeBase64String(cipherData); 
+0

我有一種感覺,最終會成爲登錄協議問題而不是密碼。我們幾乎涵蓋了其他一切。很高興你想出來了。 – Dev

+0

當我看到'Encoding.Unicode.GetBytes(String)'我正在考慮'UTF-8',而不是'UTF-16LE',顯然是不正確的假設,所以很好的理解你。 – Dev

+0

謝謝你 - 解決了我的問題。看起來像.NET中的人經常使用Encoding.Unicode.GetBytes/Encoding.Unicode.GetString沒有意識到它不是UTF-8。 – mvmn

1

根據有關RSACryptoServiceProvider.Encrypt的MSDN文檔,當第二個參數是false時,密碼使用PKCS#1 v1.5填充。所以,馬上你的密碼規範是不正確的。

嘗試用RSA/ECB/PKCS1PADDING代替。

您正在將您的密鑰材料轉換爲第二個代碼示例中的很多內容,並且會損壞它,結果導致您的密碼認爲您的密鑰材料比實際擁有的要多,並且使您的消息過長(這會觸發您的錯誤)以及另一端的解密密碼無法理解。直接轉換爲字節數組並將其傳遞給BigInteger

String modulusString = "..."; 
String publicExponentString = "..."; 

byte[] mod = Base64.decodeBase64(modulusString); 
byte[] e = Base64.decodeBase64(publicExponentString); 

BigInteger modulus = new BigInteger(1, mod); 
BigInteger publicExponent = new BigInteger(1, e); 
+0

我已經嘗試過「RSA/ECB/PKCS1PADDING」,還有「RSA」的密碼。兩個失敗。 – limc

+0

@limc誰在使用Base64類? – Dev

+0

我目前使用的是Commons Codec。我最初使用Spring的編解碼器,然後我認爲這會是問題,所以我切換到了Commons Codec ...但它們產生了相同的結果。 – limc