1

I use this PHP code to encrypt a string:

use ParagonIE\Halite\KeyFactory;
use ParagonIE\Halite\Symmetric\Crypto as Symmetric;
use ParagonIE\HiddenString\HiddenString;
define("SECURE_PLACE", '/home/htdocs/secure_place/encryption.key');

/*
//already generated
$enc_key = KeyFactory::generateEncryptionKey();
KeyFactory::save($enc_key, $secure_place);
*/

$enc_key = KeyFactory::loadEncryptionKey(SECURE_PLACE);

$string = "String to be encrypted";

$cipherstring = \ParagonIE\Halite\Symmetric\Crypto::encrypt(
  new HiddenString(
   $string
  ),
    $enc_key 
);

I could decrypt it in PHP with:

$string = \ParagonIE\Halite\Symmetric\Crypto::decrypt(
    $cipherstring,
    $enc_key
);

but I need this to be done in Python3, as I am going to POST send the encrypted string to an AWS lambda handler.py function.

I know Halite is a PHP library, but I also understand that it is a wrapper for Libsodium, which is "a portable, cross-compilable, installable, packageable fork of NaCl, with a compatible API, and an extended API to improve usability even further."

Does anyone know which dependency should I use in Python3 (providing the code, if possible) to get the string decrypted? I guess I will need to set enc_key as a Lambda environment variable.

1 Answer 1

2

Easier Cross Language Secrets

While it is possible to try to figure out how to recreate Halite's encryption in Python, I would suggest moving one layer of abstraction below and using libsodium's high level encryption API directly.

The PHP code to encrypt the data then becomes:

$nonce = \Sodium\randombytes_buf(\Sodium\CRYPTO_SECRETBOX_NONCEBYTES);
$string = "String to be encrypted";

$cipherstring = sodium_crypto_secretbox(
    $string, $nonce, $enc_key->getRawKeyMaterial());

$encoder = Halite::chooseEncoder(Halite::ENCODE_BASE64URLSAFE);
$cipherstring = $encoder($cipherstring);
$nonce = $encoder($nonce);

Now you just need to get the nonce and cipherstring to Python, if you want to keep using base64 and use the pynacl package, the code looks like this:

import nacl.secret
import nacl.encoding

decoder = nacl.encoding.URLSafeBase64Encoder

box = nacl.secret.SecretBox(
    # Key goes here, doesn't necessarily have to be base64-encoded
    "EtUEpKO2q2clEO5HRL0mk-DtQyHIt7Wf_6t1dSacrFI=", decoder
)

nonce = decoder.decode("Maxm2hN-0C4zqE3viwFVJO03I8eWJcm2")
ciphertext = decoder.decode("TpXjfPonHzBQnObD9JPtPhQc-wKIIq8Y-4o_Um3UtVut-ixCDp4=")

print(box.decrypt(ciphertext, nonce))

Rationale

The reason I say this is because if you dig into Halite's encryption code, they've essentially manually re-implemented a lot of what secretbox does. It seems like Halite is really only designed to be used with PHP. By using libsodium directly, you avoid the possibility of Halite changing their protocol and breaking your code.

Sign up to request clarification or add additional context in comments.

5 Comments

Nice. I will try that and let you know. But it seems that $nonce and $enc_key are generated on the fly by PHP code, right? How can I have them as envars on my lambda py part?
The $enc_key like you said can be stored as part of an environment variable on lambda. No need to regenerate that. The $nonce however needs to be sent as part of the POST, just like the cipher text.
Trying now. PHP generated a huge key, like 31400400f253bdb365f187d53bd8175e4013acf2809f5c5d0b7c86c2a3385a89dfecfeb0cd941a8cb459af59f1acd5372fb16a503c8495cd6e811185cdd3784a2de52bf48c773f9377582e74a83c5e5b9ff8f8e8afea23fc90816ec2752f36e9dc9b1563. I placed the key on your python code and it is throwing nacl.exceptions.ValueError: The key must be exactly 32 bytes long
That key is hex-encoded, change the line to box = nacl.secret.SecretBox(..., nacl.encoding.HexEncoder)
Aah actually, Halite puts some extra stuff when saving the key to a file. Try getting it out with just $encoder = Halite::chooseEncoder(Halite::ENCODE_BASE64URLSAFE); $encoder($enc_key->getRawKeyMaterial());

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.