Невозможно расшифровать сообщение RSA-OAEP, зашифрованное с помощью PyCryptodome, с использованием SubtleCrypto Web Crypto API

На стороне сервера я использую PyCryptodome для шифрования сообщения с помощью RSA-OAEP (с SHA-256).
Я пытаюсь расшифровать сообщение с помощью SubtleCrypto Web Crypto API на стороне клиента, но это дает мне ошибку DOMException без каких-либо дополнительных подробностей.
В SubtleCrypto я могу без проблем импортировать закрытый ключ, сгенерированный в PyCryptodome, но он выдает ошибку, когда я пытаюсь расшифровать сообщение.

Я также попытался импортировать открытый ключ, сгенерированный на PyCryptodome на стороне клиента, чтобы зашифровать то же сообщение с помощью SubtleCrypto. В этом случае я могу без проблем расшифровать его, используя тот же алгоритм, что и раньше.

Несовместимы ли алгоритмы RSA-OAEP между этими двумя библиотеками? Я заметил, что PyCryptodome ссылается на RFC 8017(v2.2) и SubtleCrypto RFC 3447(v2.1) в соответствующей документации.

Редактировать:

  • Код на стороне сервера (pycryptodome==3.9.8):

      from Crypto.PublicKey import RSA
      from Crypto.Cipher import PKCS1_OAEP
    
      class Cipher:
    
      def rsa_encrypt(self, data, key_string):
          key = RSA.importKey(key_string)
          rsa_encryption_cipher = PKCS1_OAEP.new(key)
          ciphertext = rsa_encryption_cipher.encrypt(data)
          return base64.b64encode(ciphertext)
    
      def rsa_decrypt(self, data, key_string):
          data = base64.b64decode(data)
          key = RSA.importKey(key_string)
          rsa_decryption_cipher = PKCS1_OAEP.new(key)
          plaintext = rsa_decryption_cipher.decrypt(data)
          return plaintext
    
    ( ... ) 
    
  • Код на стороне клиента

    private decryptRSAString (encryptedText: string, privateKey: string) : Observable<ArrayBuffer> {
    
      return Observable.create ((observer: any) => {
    
        let keyBuffer: ArrayBuffer = this.str2ab(window.atob(privateKey));
        let encryptedTextBuffer: ArrayBuffer = this.str2ab(window.atob(encryptedText));
        let algorithmParams: RsaHashedImportParams = {
          name: "RSA-OAEP",
          hash: "SHA-256"
        };
        window.crypto.subtle.importKey(
          'pkcs8',
          keyBuffer,
          algorithmParams,
          true,
          ["decrypt"]
        ).then (
          (cryptoKey: CryptoKey) => {
            window.crypto.subtle.decrypt(
              {
                name: "RSA-OAEP"
              },
              cryptoKey,
              encryptedTextBuffer
            ).then (
              (decryptedMessage: ArrayBuffer) => {
                observer.next (decryptedMessage);
                observer.complete();
              },
              (error: any) => {
                observer.error (error)
              }
            )
          },
          (error: any) => {
            observer.error (error)
          }
        );
      });
    }
    

1 ответ

Решение

PyCryptodome вовсе не применяется алгоритм SHA-256, как по умолчанию для переваривания OAEP, но SHA-1, здесь. Соответственно, на стороне WebCrypto необходимо использовать SHA-1:

let algorithmParams: RsaHashedImportParams = {
    name: "RSA-OAEP",
    hash: "SHA-1"
};

Конечно, вы также можете применить SHA-256 на стороне PyCryptodome, тогда никаких изменений на стороне WebCrypto не требуется.

from Crypto.Hash import SHA256
...
rsa_encryption_cipher = PKCS1_OAEP.new(key, SHA256) # default: Crypto.Hash.SHA1

Имея согласованные дайджесты с обеих сторон, я могу успешно расшифровать зашифрованный текст с помощью вашего кода WebCrypto, который я ранее сгенерировал с помощью вашего кода PyCryptodome (с использованием моих собственных ключей).

Другие вопросы по тегам