I’m trying to encrypt using Wix-Velo in javascript using hybrid-crypto-js, and decrypt using python using PKCS1_v1_5 and I’m getting incorrect length error.
This is my code in Javascript:
var Crypt = require('hybrid-crypto-js').Crypt; var crypt = new Crypt(); var publicKey = "publicKey"; var privateKey = "privateKey"; var message = 'Hello world!'; // Encryption with one public RSA key var encrypted = crypt.encrypt(publicKey, message);
In python:
def decrypt_rsa(data: bytes, key: str = rsa_key) -> str: key = key.replace("-----BEGIN RSA PRIVATE KEY-----", "").replace("-----END RSA PRIVATE KEY-----", "").replace("n", "") key = b64decode(key) key = RSA.importKey(key) cipher = PKCS1_v1_5.new(key) return cipher.decrypt(data, "Error while decrypting".encode('utf-8')).decode('utf-8')
Advertisement
Answer
The easiest way to explain this is with an example. The following key pair is used for the example:
var publicKey = `-----BEGIN PUBLIC KEY----- MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCfm2uMTvb+gqXRFxWHnfCKcHfH v7aMN6oiEqTJj0BixtTYBXH89N+xuYgoIBnfMXPXPIg/UNWEOZtAETsOVvya+YBo ZZTquYJ2I0PaxtpUKkpCiEQ/bTCQIDAeUwHr0l4vUn/fmslD0rZ3+jo4Dsl8nX0O pwZQ2grQaXLb347RQwIDAQAB -----END PUBLIC KEY-----`; var privateKey = `-----BEGIN RSA PRIVATE KEY----- MIICXQIBAAKBgQCfm2uMTvb+gqXRFxWHnfCKcHfHv7aMN6oiEqTJj0BixtTYBXH8 9N+xuYgoIBnfMXPXPIg/UNWEOZtAETsOVvya+YBoZZTquYJ2I0PaxtpUKkpCiEQ/ bTCQIDAeUwHr0l4vUn/fmslD0rZ3+jo4Dsl8nX0OpwZQ2grQaXLb347RQwIDAQAB AoGBAJHi3s/10X/a7TOMFQrLy3TOzj1PN808iA7y2Zq+jIx8z0nQ2FrtfJYXTqPW i69dpVOkKakt+qwMd6J83W0DB4oyRAQriBPI2BNuTQguzeBmvC3bkrAhbfRU313G fdlUFprS+LTvb0+KCbAMM8/I0pwQMZm0K1lWSp7ILkW2/ICJAkEAz22+7TN9bx44 0VYm2HunmbuDA5APwDmBl9VmDCCcB9/mHPbHXIuMHAWxaZma+euq2uLeCdCzVdwE nk3bSNhLFwJBAMT7BeJLuob6iA4BsUyfjxQjdjTMaP4J6JWCfcFQvd2hcwcikm/W 0qcbrKv8yCgMg1C0U9iwV3g+G6RRobbYVrUCQQDLNN1FLRsl33qUAY0+qS0Q2vTH abs0emGtqB43pT6WLE8Xct7tl7vju+QI6rU7Pxd7JaOWBAGcDFXt66H2ZAZzAkA4 sHmgB+VVpVJ0nX4WLDF0PURuq4ln2xgptxVUBlWuLCG7ovJ751pWp3tJQAWmqPs9 xbf/u7hgrZcs8iVVRuulAkBAoBFO1gN1utEtr97z3lHSHjL150Tqu/w0qXI4lbuH CaAiwWj6QRUnVkYlVK56Nzl/S3MLc6OT9GN9X/B+1Ebl -----END RSA PRIVATE KEY-----`
For reasons of space, a 1024 bits key is used. Note, however, that for security reasons RSA keys with a size of at least 2048 bits must be used in practice today.
One possible output of the posted JavaScript code using this key pair is:
{ "v":"hybrid-crypto-js_0.2.4", "iv":"qAoNKj6kM0whA07xOdeiPVLF2ntPjKXWXdmy0IhJmF0=", "keys":{"e7:de:4a:da:6b:c8:ed:3a:bd:70:4d:87:23:99:9a:23:2a:ad:17:f8":"NvpGk/XyB+m+gC/d/Bzp16xXjxNKIJq4SAsz4y11OWQJa9K42jzjona18CJnsP6OZh/wmF709KgX7ZGYnqVGswQ0Q2PpLpG39t7ipj/N6taqkAy9Mydstt4Agdu5dQ8wLCSBpU3NNrgp6T06nI0Y1ISX2H45kgI47PeQnjYB4gQ="}, "cipher":"JZIHkdUd1NuKt2aj2OMdLQ==" }
The first element is the version, the second the IV, the third the AES key encrypted with RSA/OAEP and the fourth the ciphertext encrypted with AES-256/CBC, s. Hybrid Crypto JS.
To decrypt the key, the posted Python/PyCryptodome code can be used, changing the padding from PKCS#1 v1.5 to OAEP and using the above RSA key and ciphertext:
from Crypto.Cipher import PKCS1_OAEP from Crypto.PublicKey import RSA import base64 privateKey = """-----BEGIN RSA PRIVATE KEY----- MIICXQIBAAKBgQCfm2uMTvb+gqXRFxWHnfCKcHfHv7aMN6oiEqTJj0BixtTYBXH8 9N+xuYgoIBnfMXPXPIg/UNWEOZtAETsOVvya+YBoZZTquYJ2I0PaxtpUKkpCiEQ/ bTCQIDAeUwHr0l4vUn/fmslD0rZ3+jo4Dsl8nX0OpwZQ2grQaXLb347RQwIDAQAB AoGBAJHi3s/10X/a7TOMFQrLy3TOzj1PN808iA7y2Zq+jIx8z0nQ2FrtfJYXTqPW i69dpVOkKakt+qwMd6J83W0DB4oyRAQriBPI2BNuTQguzeBmvC3bkrAhbfRU313G fdlUFprS+LTvb0+KCbAMM8/I0pwQMZm0K1lWSp7ILkW2/ICJAkEAz22+7TN9bx44 0VYm2HunmbuDA5APwDmBl9VmDCCcB9/mHPbHXIuMHAWxaZma+euq2uLeCdCzVdwE nk3bSNhLFwJBAMT7BeJLuob6iA4BsUyfjxQjdjTMaP4J6JWCfcFQvd2hcwcikm/W 0qcbrKv8yCgMg1C0U9iwV3g+G6RRobbYVrUCQQDLNN1FLRsl33qUAY0+qS0Q2vTH abs0emGtqB43pT6WLE8Xct7tl7vju+QI6rU7Pxd7JaOWBAGcDFXt66H2ZAZzAkA4 sHmgB+VVpVJ0nX4WLDF0PURuq4ln2xgptxVUBlWuLCG7ovJ751pWp3tJQAWmqPs9 xbf/u7hgrZcs8iVVRuulAkBAoBFO1gN1utEtr97z3lHSHjL150Tqu/w0qXI4lbuH CaAiwWj6QRUnVkYlVK56Nzl/S3MLc6OT9GN9X/B+1Ebl -----END RSA PRIVATE KEY-----""" ciphertext = base64.b64decode("NvpGk/XyB+m+gC/d/Bzp16xXjxNKIJq4SAsz4y11OWQJa9K42jzjona18CJnsP6OZh/wmF709KgX7ZGYnqVGswQ0Q2PpLpG39t7ipj/N6taqkAy9Mydstt4Agdu5dQ8wLCSBpU3NNrgp6T06nI0Y1ISX2H45kgI47PeQnjYB4gQ=") key = RSA.importKey(privateKey) cipher = PKCS1_OAEP.new(key) message = cipher.decrypt(ciphertext) print(message.hex()) # 8ec759594b7cc96c44d624f5a58bf736a9f761f3191de2fd0ff1e5c2bb3a8868
Now the actual ciphertext can be decrypted:
from Crypto.Cipher import AES from Crypto.Util.Padding import unpad from base64 import b64decode iv = b64decode("qAoNKj6kM0whA07xOdeiPVLF2ntPjKXWXdmy0IhJmF0=")[:AES.block_size] key = bytes.fromhex("8ec759594b7cc96c44d624f5a58bf736a9f761f3191de2fd0ff1e5c2bb3a8868") ciphertext = b64decode("JZIHkdUd1NuKt2aj2OMdLQ==") cipher = AES.new(key, AES.MODE_CBC, iv) decrypted = unpad(cipher.decrypt(ciphertext), AES.block_size) print(str(len(decrypted)) + " - " + decrypted.decode('utf-8')) # 12 - Hello world!
Note that the IV has a length of 32 bytes, of which only the first 16 bytes (corresponding to the AES block size) are used for AES.
For completeness: The fingerprint e7:de...17:f8
used in the ciphertext of the JavaScript code is the SHA1 hash of the public key in PKCS#1 format, DER encoded.