Невозможно расшифровать сообщение 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 (с использованием моих собственных ключей).