Encode in Laravel, decode in Python

后端 未结 3 1032
爱一瞬间的悲伤
爱一瞬间的悲伤 2021-01-23 16:56

I\'m using Laravel\'s encryptString method to encrypt some data on my website. This uses OpenSSL\'s 256-bit AES-CBC encryption without any serialization. I\'m now trying to decr

3条回答
  •  长发绾君心
    2021-01-23 17:07

    Full Working Code with MAC Validation

    Adding to Gonzalo's submission, Laravel's encrypted message is a base64 json-encoded array consisting of the following key pairs:

    [
          'iv' => 'generated initialization vector (iv)',
          'value' => 'encrypted, base64ed, signed value',
          'mac'  => 'message authentication code (mac)'
    ]
    

    The 'value' is signed using a message authentication code (MAC) to verify that the value has not changed during transit.

    The MAC extracted from the payload (encrypted message) should be checked against the mac extracted from the 'value' (this can be done using the key, iv, and value). Laravel's encryption scheme can be found on GitHub: src/Illuminate/Encryption/Encrypter.php

    Referencing a discussion thread on Laravel, I traced a partial solution on Github: orian/crypt.py (which is a fork of fideloper/crypt.py).

    I have forked off of Orian's code and fixed an input parameter issue. The code works as expected as long as the encryption key (passed in as an input to decrypt()) is base64 decoded and does not include the 'base64:' that is typically prepended to the APP_KEY environmental variable string assignment found in the .env file.

    Solution: pilatuspc12ng/crypt.py

    The code snippet of the crypt.py is shown below:

    import base64
    import json
    from Crypto.Cipher import AES
    from phpserialize import loads
    import hashlib
    import hmac
    
    
    def decrypt(payload, key):
        """
        Decrypt strings that have been encrypted using Laravel's encrypter (AES-256 encryption).
        Plain text is encrypted in Laravel using the following code:
        >>> ciphertext = Crypt::encrypt('hello world');
        The ciphertext is a base64's json-encoded array consisting of the following keys:
           [
              'iv' => 'generated initialization vector (iv)',
              'value' => 'encrypted, base64ed, signed value',
              'mac'  => 'message authentication code (mac)'
           ]
        The 'value' is signed using a message authentication code (MAC) so verify that the value has not changed during
        transit.
        Parameters:
        payload (str): Laravel encrypted text.
        key (str): Encryption key (base64 decoded). Make sure 'base64:' has been removed from string.
        Returns:
        str: plaintext
        """
    
        data = json.loads(base64.b64decode(payload))
        if not valid_mac(key, data):
            return None
    
        value = base64.b64decode(data['value'])
        iv = base64.b64decode(data['iv'])
    
        return unserialize(mcrypt_decrypt(value, iv, key)).decode("utf-8")
    
    def mcrypt_decrypt(value, iv, key):
        AES.key_size=128
        crypt_object=AES.new(key=key,mode=AES.MODE_CBC,IV=iv)
        return crypt_object.decrypt(value)
    
    def unserialize(serialized):
        return loads(serialized)
    
    def valid_mac(key, data):
        dig = hmac.new(key, digestmod=hashlib.sha256)
        dig.update(data['iv'].encode('utf8'))
        dig.update(data['value'].encode('utf8'))
        dig = dig.hexdigest()
        return dig==data['mac']
    

提交回复
热议问题