2017-07-16 349 views
0

我加密在網絡服務器鳳凰城的一些數據:的Java解密RSA加密的數據ArrayIndexOutOfBoundsException異常:太多的數據,RSA塊

private_key = ExPublicKey.load!("private.pem") 
token = %{username: user.username, mobile_phone: user.mobile_phone, email: user.email} 
payload = Poison.encode!(token) 
{:ok, signature} = ExPublicKey.encrypt_private(payload, private_key) 

和解密它的Java(實際上安卓)客戶端如下:

try { 
    byte[] keyBytes = Base64.decode(Constants.RSA_PUBLIC_KEY.getBytes(), Base64.DEFAULT); 
    X509EncodedKeySpec encodedKeySpec = new X509EncodedKeySpec(keyBytes); 
    KeyFactory keyFactory = KeyFactory.getInstance("RSA"); 
    PublicKey publicKey = keyFactory.generatePublic(encodedKeySpec) ; 
    Cipher cipher = Cipher.getInstance("RSA") ; 
    cipher.init(Cipher.DECRYPT_MODE, publicKey) ; 
    // 
    Log.e(DEBUG_TAG, jwt) ; // received token 
    String payload = new String(Base64.decode(jwt, Base64.DEFAULT), "UTF-8") ; // java does UTF16, elixir does UTF8 
    Log.e(DEBUG_TAG, payload) ; // base64 decoded token 
    byte[] cipherText = cipher.doFinal(payload.getBytes("UTF-8")) ; // decrypt 
    String token = new String(Base64.decode(cipherText, Base64.URL_SAFE), "UTF-8") ; // cipher text is urlencoded 
    Log.e(DEBUG_TAG, token) ; 
    return null ; 
} catch (Exception e) { 
    e.printStackTrace(); 
} 

上有鳳凰一側沒有異常,但試圖解密關於java導致異常的標記:

java.lang.ArrayIndexOutOfBoundsException: too much data for RSA block 
    at com.android.org.bouncycastle.jcajce.provider.asymmetric.rsa.CipherSpi.engineDoFinal(CipherSpi.java:459) 
    at javax.crypto.Cipher.doFinal(Cipher.java:1502 

如果輸入對於RSA模數過大,它應該導致網絡服務器出錯。所以我想知道什麼是錯誤的。

更新:好像有一個問題與庫。通過簽署一些數據的SHA256摘要產生的輸出返回344字節,而對於所使用的密鑰長度,其輸出應該是256字節。恢復使用Erlang的public_key模塊,現在工作正常。

+1

1.什麼是數據和密鑰大小?數據長度必須小於密鑰大小。 2.除非您使用非對稱加密(RSA),否則可以使用AES來處理您需要的任何大小的數據。 – zaph

+2

在我看來,你沒有加密任何東西。用私鑰「加密」稱爲*簽名*和用公鑰解密,並比較結果稱爲*驗證*。你想達到什麼目標?通常,散列是有符號的,而不是實際的數據。 –

+0

我最初計劃使用RSA密鑰進行加密(而不是簽名),以避免管理AES密鑰的麻煩。但這裏的問題在於此。即使只將2048位私鑰應用於SHA256數據散列,Java端仍然會以相同的異常失敗。 – DarthPaghius

回答

0

此問題的解決方案是使用混合加密。即,這涉及使用RSA來對對稱密鑰進行非對稱加密。

隨機生成對稱加密(如AES)密鑰並用它加密明文消息。然後,用RSA加密對稱密鑰。傳輸對稱加密的文本以及非對稱加密的對稱密鑰。

接收方可以解密RSA塊,這將產生對稱密鑰,允許解密對稱加密的文本。

這可以更正式地顯示如下。設MM是明文,KAESKAES是隨機選擇的AES密鑰,KPuKPu是接收者已有的公共RSA密鑰。

C1=EAES(M,KAES) 
C1=EAES(M,KAES) 
C2=ERSA(KAES,KPu) 
C2=ERSA(KAES,KPu) 
Then, send both C1C1 and C2C2. 

設KPrKPr爲接收方的私有RSA密鑰。隨後,接收機可以恢復MM作爲

KAES=DRSA(C2,KPr) 
KAES=DRSA(C2,KPr) 
M=DAES(C1,KAES) 
M=DAES(C1,KAES) 

(允許流解密或大的消息,你通常會先(大得多)C1C1發送C2C2)

+1

通常情況下,我會upvote這樣的答案,但似乎OP不希望或需要混合加密。相反,在我看來,他們想簽署和驗證的東西。 –

1

並不清楚真正的目的和這使事情變得很難,但如果你想發出JSON網絡令牌,因爲它似乎,你的實現是完全錯誤的

  • JWT的數字簽名,不加密

  • 加密與私鑰!=數字簽名

  • 你「解密」整個令牌,而不是驗證簽名,這應該是一個JSON網絡令牌的這樣hhhh.pppp.ssss的最後一部分。

@ zaph描述了錯誤,但如果使用數字簽名則不會發生。無法修復您的代碼,因此請考慮重新實現它

+0

感謝您的回答,我最初並未計劃實施JWT,而是推出更適合應用程序要求的自定義協議,並且堅持讓RSA部分能夠工作。 @ zaph提到的錯誤似乎是由圖書館的怪異行爲(或可能是壞的使用)引起的,並且已修復。 – DarthPaghius

1

簽名與使用私鑰進行加密不同。雖然兩者都將使用模式冪運算與私人指數簽名和加密使用不同的填充方法。更多信息here。您應該基本上不會看到散列和簽名作爲單獨的操作:散列是部分的簽名生成和驗證。

然而,代碼失敗的原因不同:簽名可能使用base64進行編碼。 Base64將產生一個輸出大小爲ceiling(256/3)×4。這當然等於344個字符/字節。所以你首先必須在解密結果之前解碼結果。