Skip to content

Conversation & visitor data encryption

Overview

Chat conversation, visitor data and visitor file upload encryption is an extra feature in our service. If it is enabled you can toggle encryption for any room in your company.

When encryption is on, whenever a new chat session is created, an AES key is also generated and stored to two places. A plaintext version of the key is stored in cache with a 90-minute expiration time. Another copy of this key is encrypted with customer provided RSA public key and stored to our database.

During chat session this AES key is used to encrypt all message content. Every time a new chat log is saved to database, the cached AES key is given a new expiration time of 90 minutes. While the cached key exist, all chat logs are automatically decrypted.

Visitor API data values are also encrypted. The AES key used in encryption is different from the one used with chat sessions. This key is also cached but only for 30 minutes. The timer resets on every visitor pageload. An RSA encrypted version of this AES key is stored as an API data entry with name _encrypted_aes_key.

Symmetric AES encryption

Our implementation of AES encryption uses https://github.com/pyca/cryptography library maintained by Python Cryptographic Authority (PyCA). We use 256-bit AES keys and encryption is done in CBC mode.

Keys are stored in json format.

Example of an encryption key

1
2
3
4
5
6
7
8
9
{
    "hmacKey": {
        "hmacKeyString": "4PTHmiELMFxA_O8yYTtl6mhdkNBi01TYSUe8vsD6NV4",
        "size": 256
    },
    "aesKeyString": "gIhuVsdgLYnsko6h-3GTIe2PIkB3W0hyUtQYG0A2WUw",
    "mode": "CBC",
    "size": 256
}

Encrypted data is also signed with a HMAC key. The ciphertext resulting from encryption has following format:

  • First 5 bytes are metadata
  • Next 16 bytes are the initialization vector
  • Next bytes are the encrypted content
  • Last 20 bytes are the signature, which is generated over all the preceding bytes

Please note that the signature is generated over already encrypted data. Before storing the ciphertext it is base64 encoded.

Asymmetric RSA encryption

After generating the AES key it is encrypted with customer's RSA public key and stored. Our implementation uses PyCryptodome's RSA module. RSA key has to be at least 2048-bits long. RSA encryption follows PKCS #1 OAEP standard

How to generate keys?

To generate RSA key pair you can use following openssl commands.

How to generate keys with OpenSSL

1
2
openssl genrsa -des3 -out private.pem 2048
openssl rsa -in private.pem -outform PEM -pubout -out public.pem

These will generate you a RSA key pair and save them to files private.pem and public.pem. Public key from public.pem can be pasted to our public key settings interface as is.

How to decrypt?

While the AES key exists in our cache chat logs are decrypted automatically. After that decryption has to be done by customer.

Giosg provides multiple ways to decrypt your data. Easiest way is to use Giosg Vault Decrypt app. This app is a web interface where you can paste your private key and get the decrypted chat data back. However this app is not meant for bulk decryption and is useful only if you need to occasionally decrypt chat logs.

For more advanced use cases where you want to automate decryption you can use our Giosg Crypter Python package. This package provides a command line tool and a Python library to decrypt your data.

Giosg also provides similar tool written in Java as an example if you need to implement decryption in Java or some other language to integrate to your stack.

Decryption using Giosg Crypter

Install Giosg Crypter Python package and follow the guide it provides. Familiarity with Python and our HTTP API and Public HTTP API documentations are recommended.

First install the required dependencies and either use the installed command line tool or create your own script with the Python library.

Installing dependencies

1
pip install git+https://github.com/giosg/giosg_crypter.git#egg=giosg.crypter==0.0.1

Command line tool

1
decrypt path/to/your/private/key/file https://url/to/the/chat/<chat_session_id> -t <your_user_api_token>

Create your own script

1
2
3
4
5
6
7
8
9
import subprocess
from giosg.crypter import AESKey, asymmetric_decrypt, symmetric_decrypt

private_key = subprocess.check_output(['openssl', 'rsa', '-in', 'path/to/your/private/key/file'])
# encrypted_key_from_chat_session should be read from "encrypted_symmetric_key" field in chat session
aes_key = asymmetric_decrypt(private_key, encrypted_key_from_chat_session)
key = AESKey.from_json(aes_key)
# message_field_to_be_decrypted should be read from "encrypted_message" field in chat session
decrypted_message = symmetric_decrypt(key, message_field_to_be_decrypted])

Implementing your own decryption

In case you want or need to implement your own decryption app, here are the steps you should performn. Input data and expected outputs to test that functionality is correct can be found from below.

Steps

  1. Load RSA Private key from PEM file
  2. Load chat session and its messages from Giosg Chat's API and Chat Messages API's.
  3. Read encrypted_symmetric_key field from the chat session. This is the AES key encrypted with customer's RSA public key.
  4. base64 decode the bytes of encrypted_symmetric_key.
  5. Use RSA private key to decrypt the encrypted_symmetric_key. It uses PKCS#1 OAEP protocol with SHA-1.
  6. Parse the the decrypted value of encrypted_symmteric_key as JSON and get the value aesKeyString from the parsed JSON.
  7. URL Safe base64 decode the aesKeyString value.
  8. Loop over the chat messages in the session and use AES key aesKeyString to decrypt the message content from field encrypted_message. Use AES/CBC/PKCS5Padding mode.

You may also take a look on our open source Github repositories https://github.com/giosg/giosg_crypter/ and https://github.com/giosg/java-decrypt-app to see how it is implemented in Python and Java.

Example input

If you implement your own decryption you can use these keys and inputs to verify that the your decryption code works

Decryption process:

  • Use RSA Private Key (example data 1) to decrypt RSA encrypted AES key (example data 2)
  • If the encryption was successful then the result should be Decrypted AES Key (example data 3)
  • Use Decrypted AES Key (example data 3) to decrypt the AES encrypted message content (example data 4)
  • If the encryption was successful then the result should be AES decrypted message content (example data 5)

Example data 1: Example RSA private key (do not use in production)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
-----BEGIN RSA PRIVATE KEY-----
MIIEpQIBAAKCAQEAw3XH/gCi6AvM19+lMxl1/AqRWq5PxJyWSBT/UMpjrIUlE/ET
e/aZ2skB8YqT+CPVpNY/2+xUnKhnqwZzoDlkw/vsGeEJLaMCsN3eWzO4IdK9cV6s
gf/XfiJIYgd6QCVAtww7hzn83aoKUyL7fWFvN8s0Bi9OsVLXEyEk3ZqeBeoSPv3b
PZsPjmi3cTxdsSRRsYXItrjxNIu8CD6SxHwrswTwknFzldCQ/GgsTMRblJYb80UM
dZLIJeQuXt948jVwU+OttSmld9jExXDIESjeyH0mUidTjg/w4rKi6DXqdfxevSxq
G/pD1101Zmun8WdtlTPD93V5ZGKRM3H3OiqQUwIDAQABAoIBAQCpJiVzuANCwut7
qcxiA1eqTU7q5cycPlKDgMBOn0dQxkyHDGqrLYaJ4sfuytkwtXou00aiQMwcYlSM
meG4N9LvE/WHk8qIlvg+LVM/I+vmQWS2VpL9UXWgb3SqeQQfvN1bS5e8d79P6NZU
igKPx6Ei7JRSAeCc7i64HEe2CxdTz26cSYjyfPDaS952af1VwVBVBCcb8TIyx5mc
iQBt8PWpw+wTlBxdNeU29ofx49beEQpkmNUKDLCRrP24uGtBo/pRnco6rFCX70lU
CYM1hWqdq85C+s50fRZm5e3bc8UP7RotXjj1s653tCGYCCkfIdb7Q7kMvKgX0EVE
ObmuTQfRAoGBAPkxBwU3drXwBTkrg+VMPSFb3yR27XrWV7pQ/v7VIJQ5W5Od0u/a
xE54dWra+SoFIx+X38pVo6qSOeLM/uyRW90FZKynMBZY5EMWZcVOTjFeOd9LAEI1
6ksYyAYJGW1Vy/g9ocAZVdcI16tkbqrV7vWcOsG2qwlN/c07bYkRo4FZAoGBAMjM
7cMiNru0+0CxoBjPpsWizZcwuxlm5KOLOh7wCHjPS3DT2SKxDHTeEmb8ceu6UlXc
2/fh4SyUOz62GYfXeK/btIr/p5UyA002w7t4V5ZLhsXGvYv4JSpF9EA3EHYxpKcb
SK4QZb7klRZ4zS/Yd8uqujPRKCiYiKUzVnEg1l2LAoGAGHunq+yKHlAJw1cyK0o1
S1zCbMu+g24hym2A0DrSa53DEJrWCbjdxrPxHWGMT4OXstfyJegKH40kYNMxTL7v
XqTUAl6ey+NJ8gl2UE9kQVd3qietS9QOQ/iYVnd4ZxSh6K7tgHk8xNbakb1ZXjGM
u9bwsu2mmlBuWka3eVshTGkCgYEAt+7/3D764/ZkMF6EyDVuDpuSt2tr91jJFwXx
t2UoXYGFGVT1EVIclvDU6oFT2RpTUVN+KxI9sRgXLNqhiE1Xv78BIlIMsB2f6JrB
sHgLwyBr07644f3sDU0G78uAyMOwj2HusYNTsAiyiGMfkTQ4h9dbuRteLdGLWcgs
5nOt6QECgYEAjFEXz78FC9di3jBCbdVHehyzF9aIzEa9+5eqBza2FqFpeAX29wuE
yG245fwb5DmMPl8V33+SdZWpa38W8ruG265Q+cOXkHVhO+h03tQnmiJAzUDE8OpS
hqk8XHdtcOmpX3Zn5i6ewuDewTmfJu6jPcdTsboGPFD0YGf2NpvL7j0=
-----END RSA PRIVATE KEY-----

Example data 2: RSA encrypted AES key

1
2
3
4
5
MyBY7CGGixwKYM88/CBvGT2cN7v3yzldk+YkYjwB92Nyk41cQyFf0eGFZ9DmVXQ0NbACan4v71+z
ulothiDQVQ8I94xTgJmRK16Vu0FhFYfW15grYmVMnnPG9pp0PUFIMd3VWZHKMkkBVmX9l02Irzne
MunalUjKQTCO5HZaJTDIbAIsRiFKAw0bQZyvv5X5WDY1s888WRYXQikJRwqjKYxKqncd6F9dy+6a
0pzNe+ZUNOKST6dc4phWCoxxGXgWcZNG1eTagzM9WScLvJPwkYawQi385oENPzjLU3P477pVjFDm
Hd3KZvEHjJ6IFUgm6FNxee6XsxiYXITSPVxJ0g==

Example data 3: Output RSA decrypted AES key

1
2
3
4
5
6
7
8
9
{
    "hmacKey": {
        "hmacKeyString": "Wf7oZEWQTpspt0g1ZISN0SNFS21w5DdVOp579RqBg20",
        "size": 256
    },
    "aesKeyString": "dIz4N3wn4V3RfRjyteWRS5_fkXzuo8fFP1ZLMgck_wg",
    "mode": "CBC",
    "size": 256
}

Example data 4: AES encrypted message content

1
2
AJxNkp3ZS9McVTYPDyckR7ub7ri5oIObzl0a45t13owvG8ouGfAdfZiosw4hxCgc1iYg88v1xZRL
Ff0/UJr/CcqfCzJjSA4ZWg==

Example data 5: AES decrypted message content

1
The Line is Open!