{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Public Key Encryption \"Box\"\n", "\n", "The `box` API uses public key encryption to securely send messages between two parties who only know each others public keys. Each party has a secret key that is used to encrypt messages.\n", "\n", "[Libsodium Documentation](https://doc.libsodium.org/public-key_cryptography/authenticated_encryption)\n", "\n", "Functions:\n", "```\n", " crypto_box_new_keypair() -> crypto_box_keypair\n", "\n", " crypto_box_noncegen() -> bytea\n", "\n", " crypto_box(message bytea, nonce bytea,\n", " public bytea, secret bytea) -> bytea\n", "\n", " crypto_box_open(ciphertext bytea, nonce bytea,\n", " public bytea, secret bytea) -> bytea\n", "```\n", "\n", "`crypto_box_new_keypair()` returns a new, randomly generated, pair of\n", "keys for public key encryption. The public key can be shared with\n", "anyone. The secret key must never be shared.\n", "\n", "`crypto_box_noncegen()` generates a random nonce which will be used\n", "when encrypting messages. For security, each nonce must be used only\n", "once, though it is not a secret. The purpose of the nonce is to add\n", "randomness to the message so that the same message encrypted multiple\n", "times with the same key will produce different ciphertexts.\n", "\n", "`crypto_box()` encrypts a message using a nonce, the intended\n", "recipient's public key and the sender's secret key. The resulting\n", "ciphertext can only be decrypted by the intended recipient using their\n", "secret key. The nonce must be sent along with the ciphertext.\n", "\n", "`crypto_box_open()` descrypts a ciphertext encrypted using\n", "`crypto_box()`. It takes the ciphertext, nonce, the sender's public\n", "key and the recipient's secret key as parameters, and returns the\n", "original message. Note that the recipient should ensure that the\n", "public key belongs to the sender.\n", "\n" ] }, { "cell_type": "code", "execution_count": 1, "metadata": { "scrolled": true }, "outputs": [], "source": [ "%load_ext sql\n", "%sql postgresql://postgres@/" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Public key ncryption requires each party have a pair of keys, one public and one private, and a nonce. The nonce doesn't have to be confidential, but it should never ever be reused with the same key. The easiest way to generate a nonce is to use `crypto_secretbox_noncegen`:" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ " * postgresql://postgres@/\n", "1 rows affected.\n", " * postgresql://postgres@/\n", "1 rows affected.\n", " * postgresql://postgres@/\n", "1 rows affected.\n" ] } ], "source": [ "nonce = %sql SELECT crypto_box_noncegen::text from pgsodium.crypto_box_noncegen()\n", "nonce = nonce[0][0]\n", "\n", "bob = %sql SELECT public::text, secret::text FROM pgsodium.crypto_box_new_keypair()\n", "bob_public, bob_secret = bob[0]\n", "\n", "alice = %sql SELECT public::text, secret::text FROM pgsodium.crypto_box_new_keypair()\n", "alice_public, alice_secret = bob[0]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Encryption\n", "\n", "Alice can encrypt a message to Bob with her keypair and Bob's public key." ] }, { "cell_type": "code", "execution_count": 12, "metadata": { "scrolled": true }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ " * postgresql://postgres@/\n", "1 rows affected.\n", "Encrypted message from Alice to Bob is: \\x516414a93dc9f229a2c1d533a9c90fd82d11bf712ed12d5765\n" ] } ], "source": [ "box = %sql SELECT crypto_box::text FROM pgsodium.crypto_box('hello bob', :nonce, :bob_public, :alice_secret)\n", "box = box[0][0]\n", "print('Encrypted message from Alice to Bob is: ', box)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Decryption\n" ] }, { "cell_type": "code", "execution_count": 15, "metadata": { "scrolled": true }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ " * postgresql://postgres@/\n", "1 rows affected.\n", "Verified message is: hello bob\n" ] } ], "source": [ "message = %sql select crypto_box_open FROM pgsodium.crypto_box_open(:box, :nonce, :alice_public, :bob_secret)\n", "message = message[0][0]\n", "print('Verified message is: ', message.tobytes().decode('utf8'))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Sealed Boxes\n", "\n", "Sealed boxes are designed to anonymously send messages to a recipient given its public key.\n", "\n", "Only the recipient can decrypt these messages, using its private key. While the recipient can verify the integrity of the message, it cannot verify the identity of the sender.\n", "\n", "A message is encrypted using an ephemeral key pair, whose secret part is destroyed right after the encryption process.\n", "\n", "Without knowing the secret key used for a given message, the sender cannot decrypt its own message later. And without additional data, a message cannot be correlated with the identity of its sender." ] }, { "cell_type": "code", "execution_count": 19, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ " * postgresql://postgres@/\n", "1 rows affected.\n", " * postgresql://postgres@/\n", "1 rows affected.\n", "The sealed message is: bob is your uncle\n" ] } ], "source": [ "sealed = %sql SELECT crypto_box_seal::text FROM pgsodium.crypto_box_seal('bob is your uncle', :bob_public)\n", "sealed = sealed[0][0]\n", "\n", "message = %sql SELECT pgsodium.crypto_box_seal_open(:sealed, :bob_public, :bob_secret)\n", "message = message[0][0]\n", "print('The sealed message is: ', message.tobytes().decode('utf8'))\n", "\n" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.7.3" } }, "nbformat": 4, "nbformat_minor": 2 }