{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Authentication\n", "\n", "The `auth` API uses cryptographic authenticated to verify a message has not been altered with a tag and secret key that all parties must share.\n", "\n", "[Libsodium Documentation](https://doc.libsodium.org/secret-key_cryptography/secret-key_authentication)\n", "\n", "Functions:\n", "```\n", " crypto_auth_keygen() -> bytea\n", "\n", " crypto_auth(message bytea, key bytea) -> bytea\n", "\n", " crypto_auth(message bytea, key_id bigint, context bytea = 'pgsodium') -> bytea\n", "\n", " crypto_auth_verify(mac bytea, message bytea, key bytea) -> boolean\n", "\n", " crypto_auth_verify(mac bytea, message bytea, key_id bigint, context bytea = 'pgsodium') -> boolean\n", "```\n", "\n", "`crypto_auth_keygen()` generates a message-signing key for use by\n", "`crypto_auth()`. The role `pgsodium_keymaker` is required to call this function.\n", "\n", "`crypto_auth()` generates an authentication tag (mac) for a\n", "combination of message and secret key. This does not encrypt the\n", "message; it simply provides a means to prove that the message has not\n", "been tampered with. To verify a message tagged in this way, use\n", "`crypto_auth_verify()`. This function is deterministic: for a given\n", "message and key, the generated mac will always be the same. The role `pgsodium_keyholder` is required to call the raw `key bytea` versions of these functions. The key id versions of the functions can be called with the role `pgsodium_keyiduser`.\n", "\n", "Note that this requires access to the secret\n", "key, which is not something that should normally be shared. If\n", "many users need to verify message it is usually better to use\n", "[Public Key Signatures](#user-content-public-key-signatures) rather\n", "than sharing secret keys.\n" ] }, { "cell_type": "code", "execution_count": 1, "metadata": { "scrolled": true }, "outputs": [], "source": [ "%load_ext sql\n", "%config SqlMagic.feedback=False\n", "%config SqlMagic.displaycon=False\n", "%sql postgresql://postgres@/" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Encryption requires a key 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": 2, "metadata": {}, "outputs": [], "source": [ "key = %sql select pgsodium.crypto_auth_keygen()::text\n", "key = key[0][0]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Signing\n", "\n", "A new signature is created with the message and the key:" ] }, { "cell_type": "code", "execution_count": 3, "metadata": { "scrolled": true }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "The signature is: \\x048a21486e401e4899ec6229cda326af564c41cd1b9baad57a41c3e78aaed752\n" ] } ], "source": [ "signature = %sql SELECT crypto_auth::text from pgsodium.crypto_auth('bob is your uncle', (:key)::bytea)\n", "signature = signature[0][0]\n", "print('The signature is: ', signature)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Verification\n", "\n", "Using the tag and key, verify the authenticity of the message." ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [ { "data": { "text/html": [ "\n", " \n", " \n", " \n", " \n", " \n", " \n", "
crypto_auth_verify
True
" ], "text/plain": [ "[(True,)]" ] }, "execution_count": 4, "metadata": {}, "output_type": "execute_result" } ], "source": [ "%sql SELECT crypto_auth_verify FROM pgsodium.crypto_auth_verify(:signature, 'bob is your uncle', (:key)::bytea)\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.9.2" } }, "nbformat": 4, "nbformat_minor": 2 }