Search code examples
pythonnode.jsencryptioncryptojs

How to Decrypt Cryptojs RC4Drop encrypted data in python


Below is the code in my nodejs project to encrypt and decrypt the data which is working perfectly.. I need to decrypt this nodejs encrypted data using python.

    encryptData(data) {
        try {
        var encryptionKey = CryptoJS.enc.Utf8.parse("SecretKey");
        return CryptoJS.RC4Drop.encrypt(JSON.stringify(data), encryptionKey, {
            drop: 3072 / 4
        }).toString();
        } catch (error) {
            console.error(error);
        }
    },
    decryptData(encrypted) {
        try {
            var encryptionKey = CryptoJS.enc.Utf8.parse("SecretKey");
            const plainPass = CryptoJS.RC4Drop.decrypt(encrypted, encryptionKey, {
                drop: 3072 / 4
            }).toString(CryptoJS.enc.Utf8);
            return plainPass;

        } catch (error) {
            console.error(error);
        }

    },

How do I implement this similar decryption functionality in python?

I tried below code but its not working.

def rc4_drop(key, data, drop_bytes):
    # RC4 Encryption/Decryption
    cipher = ARC4.new(key)
    decrypted = cipher.decrypt(data)
    
    # Apply drop functionality
    if drop_bytes < len(decrypted):
        return decrypted[drop_bytes:]
    else:
        return b''

def decrypt_data(encrypted_base64, key, drop_bytes):
    try:
        # Convert Base64-encoded encrypted data to bytes
        encrypted_bytes = base64.b64decode(encrypted_base64)
        print("Encrypted bytes:", encrypted_bytes)

        # Convert the key to bytes
        key_bytes = key.encode('utf-8')
        print("Key bytes:", key_bytes)

        # Decrypt data with RC4 and apply drop bytes
        plaintext_bytes = rc4_drop(key_bytes, encrypted_bytes, drop_bytes)
        print("Plaintext bytes after dropping:", plaintext_bytes)
        
        # Convert bytes to string
        return plaintext_bytes.decode('utf-8') if plaintext_bytes else ''
    
    except Exception as e:
        print(f"An error occurred: {e}")
        return None

Sample input and output from the Javascript code: Encryption of "Hello" results in base64 output RlxFVdR/FA==.


Solution

  • The way you are applying the drop functionality in Python doesn't make sense as you must drop the first drop_bytes bytes from the stream cipher's output before decrypting the data, whereas you are doing it afterwards. Although I haven't tested this, one simple way is to prepend the cipher with drop_bytes number of dummy bytes and throw away that many initial bytes of the decrypted result, i.e.

    dummy = b' ' * drop_bytes
    decrypted = cipher.decrypt(dummy + data)[drop_bytes:]
    return decrypted
    

    but as pointed out in a comment by Oliver in the Staging Ground, the cryptodome implementation of RC4 directly supports dropping bytes with the keyword argument drop, i.e.

    cipher = ARC4.new(key, drop=drop_bytes)
    return cipher.decrypt(data)