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)