簡體   English   中英

為什么我通過嘗試使用 java 解密 RSA 但使用 php 加密來獲得此異常?

[英]Why I get this exception by trying to decrypt RSA with java but encrypted with php?

我正在使用 PHPSecLib 使用 RSA 加密我的文本:

      $rsa = new Crypt_RSA(); 
      $rsa->setEncryptionMode(CRYPT_RSA_ENCRYPTION_PKCS1);

      extract($rsa->createKey());
      $rsa->loadKey($privatekey);

      $ciphertext = $rsa->encrypt($plaintext);

      $rsa->loadKey($publickey);
      return base64_encode($ciphertext) . ":" . base64_encode($publickey);

我得到類似 encryptedBased64:publicKeyBased64 的東西。

它似乎有效,如果我嘗試使用與 PHP 相同的方法解密它也可以。 但是嘗試用 java 解密,給了我 java.security.InvalidKeyException:無效的密鑰格式。 這是代碼:

    public static String decrypt(byte[] msg, byte[] key)
            throws Exception{

        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        X509EncodedKeySpec publicKeySpec = new X509EncodedKeySpec(key);
        PublicKey keys = keyFactory.generatePublic(publicKeySpec);

        Cipher cipher = Cipher.getInstance("RSA/None/PKCS1Padding","BC");
        cipher.init(Cipher.DECRYPT_MODE, keys);
        return new String(cipher.doFinal(msg));
    }

    public static void main(String[] args) throws Exception{
      String res = "encryptedBased64:publicKeyBased64";
      decrypt(Base64.getDecoder().decode(res.split(":")[0]),Base64.getDecoder().decode(res.split(":")[1]));
    }

無法理解為什么。

  • RSA 用於兩個上下文en-/decryptingsign-/verifying 對於加密/解密,發送者使用接收者的公鑰加密,接收者使用自己的私鑰解密。 對於簽名/驗證,發件人使用自己的私鑰進行簽名,收件人使用發件人的公鑰進行驗證。 這在此處此處進行了詳細說明。

    在這一點上,很明顯,在發布的代碼中這兩種上下文都被混淆了:對於加密/解密,發送者用他自己的私鑰加密消息,而接收者用發送者的公鑰解密它。 這是錯誤的。 如果在上述兩個代碼中都進行了修改以進行加密/解密,則 Java 中的解密也將起作用!

  • 要理解為什么解密在 PHP 的情況下有效,而在 Java 的情況下無效,必須考慮填充。 出於安全原因,實際上 RSA 必須始終與填充一起使用,例如 PKCS1-v1_5-padding 或 OAEP。 但是,填充因上下文而異。 用於加密/解密 RSAES-PKCS1-v1_5-padding 並用於簽名/驗證 RSASSA-PKCS1-v1_5-padding。 這同樣適用於 OAEP(分別為 RSAES-OAEP 和 RSASSA-PSS)。 這在RFC8017這里有詳細解釋。 重要的是,用於解密的填充與用於加密的填充相同。 否則解密將失敗。 這同樣適用於簽名/驗證。

    在下文中,假設 PKCS1-v1_5-padding 與發布的代碼一樣使用。

    在 PHP/phpseclib 中,encrypt / decrypt方法使用 RSAES-PKCS1-v1_5-padding,無論是使用公鑰還是私鑰進行加密(或解密)。 這意味着encrypt / decrypt方法始終對應於加密/解密上下文。 對於簽名/驗證,有相應的方法sign / verify 這意味着在發布的代碼中,RSAES-PKCS1-v1_5-padding 在 PHP 端用於加密和解密,這就是解密在 PHP 端起作用的原因。

    在 Java 中, Cipher類根據模式和密鑰類型的組合確定上下文或填充。 加密模式/公鑰- 和解密模式/私鑰- 組合使用 RSAES-PKCS1-v1_5-padding 定義加密/解密上下文,其他組合使用 RSASSA-PKCS1-v1_5- 定義簽名/驗證上下文填充。 這意味着在發布的代碼中,在 Java 端使用 RSASSA-PKCS1-v1_5-padding 進行解密。 因此,由於填充不同,在 PHP 中加密的消息的解密在 Java 中失敗。

    注意:通常在 Java 中, Signature類用於簽名/驗證(而Cipher類用於加密/解密)。

  • 由於發布的代碼沒有透露要加密的內容,因此還應該提及的是,只有相對較短的消息可以使用 RSA 加密,對於較長的消息,將使用對稱算法(如 AES),或兩者結合使用(混合密碼系統)。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM