halite icon indicating copy to clipboard operation
halite copied to clipboard

How (is it possible) to decrypte in Pytyhon?

Open luisrock opened this issue 5 years ago • 2 comments

I placed a question at StackOverflow on how to Decrypt in Python a string encrypted in PHP with Halite/Libsodium, but I was wondering if it is ever possible...

If so, can you put me in the right direction?

luisrock avatar Sep 02 '19 18:09 luisrock

Struggling with the same thing using PyNaCL. Below is how far (or "not far") I got.

  • On the PHP side:

    // Load encryption Key
    $encryptionKeyPath = '/path/to/encryption.key';
    $encryptionKey = \ParagonIE\Halite\KeyFactory::loadEncryptionKey($encryptionKeyPath);
    
    // Encrypt Value (using the default ENCODE_BASE64URLSAFE encoder)
    // ~> Yields a string like 'MUIEAI…'
    $encryptedValue = \ParagonIE\Halite\Symmetric\Crypto::encrypt(
      new \ParagonIE\HiddenString\HiddenString($value_to_encrypt),
      $encryptionKey
    );
    
    // Get Encryption Key to use within PyNaCl
    // ~> Yields a base64-encoded string representing the encryption key
    $encoder = \ParagonIE\Halite\Halite::chooseEncoder(\ParagonIE\Halite\Halite::ENCODE_BASE64URLSAFE);
    echo 'base64_encoded_key to use with PyNaCl: ' . $encoder($encryptionKey->getRawKeyMaterial());
    
  • On the Python side:

    import nacl.secret
    
    encrypted_value = 'MUIEA…'
    base64_encoded_key = '…' # See output above to complete this
    
    box = nacl.secret.SecretBox(
      base64_encoded_key,
      nacl.encoding.URLSafeBase64Encoder
    )
    
    plaintext = box.decrypt(
        encrypted_value,
        None,
        nacl.encoding.URLSafeBase64Encoder
    )
    
    print(plaintext.decode('utf-8'))
    

All I'm getting from this is a nacl.exceptions.CryptoError: Decryption failed. Ciphertext failed verification Exception.

I think I'm stumbling over the 2nd parameter of box.decrypt in the Python code which I'm setting to None. It is the value for so called "nonce" but I have no clue on how to extract that out of Halite.

Update: Looking into the code of the Symmetric Crypto class I an unpacking of the 'MUIEA…' string happens to extract the actually encrypted value, nonce, etc. — Will look into that …

bramus avatar Feb 06 '20 15:02 bramus

When manually calling the unpackMessageForDecryption method I can extract the nonce (at index 3) and the encrypted string (at index 4).

$decoder = \ParagonIE\Halite\Halite::chooseEncoder(\ParagonIE\Halite\Halite::ENCODE_BASE64URLSAFE, true);
$parts = \ParagonIE\Halite\Symmetric\Crypto::unpackMessageForDecryption($decoder('MUIEA…'));

$nonce = $parts[3];
$encrypted = $parts[4];

I've recreated this functionality in the Python code based upon its logic:

nonce = nacl.encoding.URLSafeBase64Encoder.decode(encrypted_value)[36:60] # start at 36, length of 24
encrypted = nacl.encoding.URLSafeBase64Encoder.decode(encrypted_value)[60:len(string)-112] # start at 60, length of 112 (not 124 as mentioned in the Halite source?!)

When comparing the base64 encoded values of both the PHP and the Python nonce and encrypted params they do match. Decrypting (in Python) however still is no go. Still getting the nacl.exceptions.CryptoError: Decryption failed. Ciphertext failed verification Exception.

Think I am close, but am still missing a part …

bramus avatar Feb 06 '20 15:02 bramus