Decrypting the user of an open-sheet request

Hi Team!

I know everyone must be super busy with the rollout of the new Messenger Apps. I hope somebody still gets a chance to reply to my question :slight_smile: It’s going to be huge and I am super excited to see this coming!

I am currently implementing the open-sheet flow and have a couple of questions around that:

  1. I have problems decrypting the user. If you had any examples on how to do this in PHP ( > 7.1) it would be appreciated). Specifically how to get the IV and auth_tag.

  2. The documentation doesn’t specify which you use for encryption. I have tried the “Identity verification Secret” as well as the “OAuth Client Secret”, but no luck.

  3. It would actually be super helpful to have the user already available during the initialize flow.

Any help/insights would be appreciated.

Cheers,
MacSebi

Hi MacSebi!

Thanks for the questions!

  1. I’m not familiar with PHP so I’m afraid I’m not much help. Perhaps @sean or another member here might be able to help?
  2. Right now we’re using a temporary value for the secret value you’ll use to decrypt the user data in that request. In the future you will use the Oauth secret but for now it’s a hard-coded value. Would you mind sending me a message via the Intercom Messenger on the docs page? I’ll give you the value you need there. :slight_smile:
  3. This is definitely something we’re going to be adding in an iteration here soon.

Cheers,
Jeff

Hi @macsebi

For decrypting the user object in the open sheet flow we have an example in Ruby here: https://intercom.tech-docs.io/app-lifecycle/request-flows/sheets-flow/open-sheet-request

The secret you should be using is the OAuth Client Secret. I haven’t tried this in PHP myself but maybe https://gist.github.com/odan/138dbd41a0c5ef43cbf529b03d814d7c is useful

The IV should be the first 12 characters (GCM_IV_LENGTH in the Ruby example) of the decoded user and the auth_tag is the last 16 characters (GCM_AUTH_TAG_LENGTH in the Ruby example).

If you have some example code that you have tried that might also be useful to share

Thanks,
Sean

Hi @jeff, Hi @sean, Thanks for your responses. I did see the Ruby example, but couldn’t get decrypting to work in PHP. I’ll update you if I have something working. Maybe then you can add some other languages in your examples. :slight_smile:
PS: Sorry for the delay in my reply. I wasn’t notified about your responses :frowning:

Hi @sean,

I’ve tried again and while I manage to decode (properly extract $iv and $tag) for an example that I have encoded myself, I don’t get anywhere with the object I get from you guys. I must be missing something (very simple probably).

Here is an example:

<?php 

    $encodedUser = 'BASE64_ENCODED+USER+OBJECT/FROM+POST+REQUEST';
    $decodedUser = base64_decode($encodedUser);

    $secret = '<supersecret_token>'; // Use OAuth Client Secret
    $key = openssl_digest($secret, 'sha256');

    $ivlen = 12; // openssl_cipher_iv_length('aes-256-gcm')
    $taglen = 16; // default

    $iv = substr($decodedUser, 0, $ivlen);
    $tag = substr($decodedUser, strlen($decodedUser) - $taglen);

    $cipherLen = strlen($decodedUser) - $ivlen - $taglen;
    $cipherText = substr($decodedUser, $ivlen, $cipherLen);

    $decruptedUser = openssl_decrypt($cipherText, 'aes-256-gcm', $key, OPENSSL_RAW_DATA, $iv, $tag);

?>

Same problem in Nodejs! :raised_hands:

Sorry for the delay in getting back to you @macsebi, I have a working PHP example now (tested on PHP7.1)

<?php 
$encodedUser = "<USER-FROM-REQUEST>";

$decodedUser = base64_decode($encodedUser);

$secret = "<THIS-IS-A-SECRET>";
$key = openssl_digest($secret, 'sha256', TRUE);

$ivlen = 12;
$taglen = 16;

$iv = substr($decodedUser, 0, $ivlen);
$tag = substr($decodedUser, strlen($decodedUser) - $taglen, $taglen);

$cipherLen = strlen($decodedUser) - $taglen - $ivlen;
$cipherText = substr($decodedUser, $ivlen, $cipherLen);

$decryptedUser = openssl_decrypt($cipherText, 'aes-256-gcm', $key, OPENSSL_RAW_DATA, $iv, $tag);
?>

The important part here is passing TRUE to openssl_digest (http://php.net/manual/en/function.openssl-digest.php) as without it there is the following error:

error:0607A082:digital envelope routines:EVP_CIPHER_CTX_set_key_length:invalid key length

(Found by calling openssl_error_string() )

I hope this helps!

1 Like

@hugovillain Do you have some example code to share?

Thanks @sean! As I said - something stupid tiny… Thanks so much. I should have tested that RAW parameter…

Hi, I came to this issue also in nodejs. My inspiration was PHP source code, but Im not sure what Im doing wrong. I always get: ERROR: Unsupported state or unable to authenticate data.

I implemented it this way

        const masterkey = 'MY-INTERCOM-CLIENT-SECRET';
        const decodedUser = user; // encoded user

        // base64 decoding
        const bData = Buffer.from(decodedUser, 'base64');

        // convert data to buffers
        const ivlen = 12;
        const iv = bData.slice(0, ivlen);

        const taglen = 16;
        const tag = bData.slice(decodedUser.length - taglen, taglen);

        const cipherLen = decodedUser.length - taglen - ivlen;
        const cipherText = bData.slice(ivlen, cipherLen);

        let hash = crypto.createHash('sha256').update(masterkey);
        let key = Buffer.from(hash.digest("binary"), "binary");//buffer from binary string.

        // AES 256 GCM Mode
        const decipher = crypto.createDecipheriv('aes-256-gcm', key, iv);
        decipher.setAuthTag(tag);

        // encrypt the given text
        const decrypted = decipher.update(cipherText, 'binary', 'utf8') + decipher.final('utf8');

        // ERROR: Unsupported state or unable to authenticate data
        console.log(decrypted);

Thanks. :slight_smile:

Hi all,

I finally found solution for decrypting user in nodejs. Here is my gist, feel free to use it.

Hey @michal.ustanik - just stumbled upon this, awesome! We’ll be sure to add this to the docs too for anybody that needs a Node.js example :+1:

If anyone is implementing the decryption code in Python 3, here’s what I did. Hopefully it’ll save you some time:

It should also work with Python 2, but I haven’t tested it!

@zach would it be a good idea to add this to the Intercom docs too?

Nice one @sanjeevan - I’ll put this in too :+1: