Skip to content

Commit

Permalink
feat: add test vector playground
Browse files Browse the repository at this point in the history
  • Loading branch information
geonnave committed Oct 10, 2023
1 parent c3fcfa6 commit e677de2
Showing 1 changed file with 268 additions and 0 deletions.
268 changes: 268 additions & 0 deletions examples/test-vectors-playground.ipynb
Original file line number Diff line number Diff line change
@@ -0,0 +1,268 @@
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Test Vectors for draft-lake-authz\n",
"\n",
"Requirements:\n",
"\n",
"```python\n",
"pip install cryptography==3.4.7 cbor2==5.3.0 rich==10.6.0 hkdf==0.0.3\n",
"```"
]
},
{
"cell_type": "code",
"execution_count": 18,
"metadata": {},
"outputs": [],
"source": [
"import rich, cbor2, hkdf, hashlib\n",
"from cryptography.hazmat.primitives import asymmetric, serialization\n",
"from cryptography.hazmat.primitives.ciphers import aead\n",
"from cryptography.hazmat.primitives.asymmetric import ec\n",
"from cryptography.hazmat.primitives import hashes\n",
"from cryptography.hazmat.primitives.kdf.hkdf import HKDF\n",
"from cryptography.hazmat.backends import default_backend\n",
"from binascii import hexlify, unhexlify"
]
},
{
"cell_type": "code",
"execution_count": 17,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"\n",
"# input\n",
"LOC_W = \"7818636f61703a2f2f656e726f6c6c6d656e742e736572766572\"\n",
"ID_U = \"a104412b\"\n",
"SS = 2\n",
"\n",
"# static_keys\n",
"U = \"555C89F41EA42D458F0B4D74499E1C177BA9AD910F525BACF3D64D35E8568DEC\"\n",
"G_U = \"AC69E4299F79FAED612E37C37F99D2B3939B142A8E8E65B90FAB5001F7F2CF56\"\n",
"V = \"1DAF151B30F0F247AEB5598C1EEE8664384166BBC37F262DC6581A67486BCF3C\"\n",
"G_V = \"188B3E5A62352FFCDE66894FCDBBCB33D243A045BAA99357A72012A6AF3A33AD\"\n",
"W = \"4E5E15AB35008C15B89E91F9F329164D4AACD53D9923672CE0019F9ACD98573F\"\n",
"G_W = \"FFA4F102134029B3B156890B88C9D9619501196574174DCB68A07DB0588E4D41\"\n",
"\n",
"# ephemeral_keys\n",
"X = \"A0C71BDBA570FFD270D90BDF416C142921F214406271FCF55B8567F079B50DA0\"\n",
"G_X = \"FF14FB42677CE9D016907F571E5E1CD4E815F098AA37084063A0C34570F6F7F5\"\n",
"Y = \"A1D1A1C084AB0D912CC7A15B7F252FABCA252FAD4CAA8E5D569C94578B52A047\"\n",
"G_Y = \"9F69C52FAE8F7EA9194022C70B238FCBF4AFFFDFFC8341EEC85BA68E2F9BB744\"\n",
"Z = \"644658D815CBCA8EA863090A2D498990B5C75357A729231EC3DE7DF5A7AFE49E\"\n",
"G_Z = \"6B67C90638924C4AE8472CA6FB9A90BE5F43132753346379C672972D323F7A41\"\n",
"\n",
"# enc_id\n",
"enc_id = \"36b4ce1137cdc1e9b2c21d8bd5a0c5a311adbd3259\"\n",
"salt_fixme = \"0000000000000000000000000000000000000000000000000000000000000000\"\n",
"g_xw = \"e19be60432dfa2e033af21329d393a5d0d3150a6c998b4f4b951af67694dbe1a\"\n",
"prk = \"04da32d221db25db701667f9d3903374a45a9b04f25d1cb481b099a480cece04\"\n",
"k_1 = \"9540f7fa26ee9430f7caaa37a6ea438a\"\n",
"iv_1 = \"3d9489764d109bc4bda5bd0d13\"\n",
"plaintext = \"44a104412b\"\n",
"enc_structure = \"8368456e63727970743040424102\"\n",
"\n",
"# voucher_info\n",
"voucher_info = \"5832581a7818636f61703a2f2f656e726f6c6c6d656e742e7365727665725536b4ce1137cdc1e9b2c21d8bd5a0c5a311adbd3259\"\n",
"voucher_info_seq = \"581a7818636f61703a2f2f656e726f6c6c6d656e742e7365727665725536b4ce1137cdc1e9b2c21d8bd5a0c5a311adbd3259\"\n"
]
}
],
"source": [
"def format_tv(tv, nokeys=False):\n",
" for k, v in tv.items():\n",
" if k[0] == \"_\" or (nokeys and k in [\"static_keys\", \"ephemeral_keys\"]):\n",
" continue\n",
" elif type(v) == dict:\n",
" print(f\"\\n# {k}\")\n",
" format_tv(v)\n",
" elif type(v) == int:\n",
" print(f'{k:<8} = {v}')\n",
" else:\n",
" print(f'{k:<8} = \"{v}\"')\n",
"\n",
"def add_keys(tv):\n",
" def as_hex(k):\n",
" return hex(k)[2:]\n",
" def new_keypair_dx_testvector(agent):\n",
" private_key = ec.generate_private_key(ec.SECP256R1(), backend=default_backend())\n",
" x = private_key.public_key().public_numbers().x\n",
" y = private_key.public_key().public_numbers().y\n",
" d = private_key.private_numbers().private_value\n",
" return {f\"{agent}\": as_hex(d), f\"G_{agent}\": as_hex(x), f\"_G_{agent}_y\": as_hex(y)}\n",
"\n",
" tv[\"static_keys\"] = {}\n",
" tv[\"ephemeral_keys\"] = {}\n",
" for a in [\"U\", \"V\", \"W\"]:\n",
" tv[\"static_keys\"].update(new_keypair_dx_testvector(a))\n",
" for a in [\"X\", \"Y\", \"Z\"]:\n",
" tv[\"ephemeral_keys\"].update(new_keypair_dx_testvector(a))\n",
"\n",
" return tv\n",
"\n",
"def p256_ecdh(d_hex, x_hex, y_hex):\n",
" private_key = ec.derive_private_key(int(d_hex, 16), ec.SECP256R1(), default_backend())\n",
" # NOTE: rust uses the compressed form of the public key (without the y coordinate), but the result should be the same\n",
" public_key = ec.EllipticCurvePublicNumbers(\n",
" int(x_hex, 16),\n",
" int(y_hex, 16),\n",
" ec.SECP256R1()\n",
" ).public_key(default_backend())\n",
" return private_key.exchange(ec.ECDH(), public_key).hex()\n",
"\n",
"def hkdf_extract(salt, ikm):\n",
" return hkdf.hkdf_extract(unhexlify(salt), unhexlify(ikm), hash=hashlib.sha256).hex()\n",
"\n",
"def hkdf_expand(prk, info, length):\n",
" return hkdf.hkdf_expand(unhexlify(prk), info, length, hash=hashlib.sha256).hex()\n",
"\n",
"def aes_ccm_encrypt_tag_8(key, iv, enc_structure, plaintext):\n",
" return aead.AESCCM(unhexlify(key)).encrypt(unhexlify(iv), unhexlify(plaintext), unhexlify(enc_structure)).hex()\n",
"\n",
"def add_enc_id(tv):\n",
" salt_fixme = \"00\" * 32 # FIXME rust\n",
" g_xw = p256_ecdh(tv[\"ephemeral_keys\"][\"X\"], tv[\"static_keys\"][\"G_W\"], tv[\"static_keys\"][\"_G_W_y\"])\n",
" prk = hkdf_extract(salt_fixme, g_xw)\n",
" k_1 = hkdf_expand(prk, cbor2.dumps(0)+cbor2.dumps(b'')+cbor2.dumps(32), 16) # info is (0, b'', 16) # FIXME[draft] make 'length' explicit\n",
" iv_1 = hkdf_expand(prk, cbor2.dumps(1)+cbor2.dumps(b'')+cbor2.dumps(32), 13) # info is (1, b'', 13) # FIXME[draft] make 'length' explicit\n",
" plaintext = cbor2.dumps(unhexlify(tv[\"input\"][\"ID_U\"])).hex()\n",
" _ss = tv[\"input\"][\"SS\"].to_bytes(1, byteorder='big')\n",
" enc_structure = cbor2.dumps([\"Encrypt0\", b'', cbor2.dumps(_ss)]).hex()\n",
" enc_id = aes_ccm_encrypt_tag_8(k_1, iv_1, enc_structure, plaintext)\n",
" tv.update({\n",
" \"enc_id\": {\n",
" \"enc_id\": enc_id,\n",
" \"salt_fixme\": salt_fixme,\n",
" \"g_xw\": g_xw,\n",
" \"prk\": prk,\n",
" \"k_1\": k_1,\n",
" \"iv_1\": iv_1,\n",
" \"plaintext\": plaintext,\n",
" \"enc_structure\": enc_structure,\n",
" }\n",
" })\n",
"\n",
" return tv\n",
"\n",
"def add_voucher_info(tv):\n",
" voucher_info_seq = (cbor2.dumps(unhexlify(tv[\"input\"][\"LOC_W\"])) + cbor2.dumps(unhexlify(tv[\"enc_id\"][\"enc_id\"]))).hex()\n",
" voucher_info = cbor2.dumps(unhexlify(voucher_info_seq)).hex()\n",
" tv.update({\n",
" \"voucher_info\": {\n",
" \"voucher_info\": voucher_info,\n",
" \"voucher_info_seq\": voucher_info_seq,\n",
" }\n",
" })\n",
" return tv\n",
"\n",
"tv = {\n",
" \"input\": {\n",
" \"LOC_W\": cbor2.dumps(\"coap://enrollment.server\").hex(), # already a tstr\n",
" \"ID_U\": cbor2.dumps({4: b'\\x2B'}).hex(),\n",
" \"SS\": 2,\n",
" },\n",
" 'static_keys': {\n",
" 'U': '555C89F41EA42D458F0B4D74499E1C177BA9AD910F525BACF3D64D35E8568DEC',\n",
" 'G_U': 'AC69E4299F79FAED612E37C37F99D2B3939B142A8E8E65B90FAB5001F7F2CF56',\n",
" '_G_U_y': '9572CF756D05E8B80DF519AEF4BF43E546BCB871A8BC4B676ED548F24F4EC362',\n",
" 'V': '1DAF151B30F0F247AEB5598C1EEE8664384166BBC37F262DC6581A67486BCF3C',\n",
" 'G_V': '188B3E5A62352FFCDE66894FCDBBCB33D243A045BAA99357A72012A6AF3A33AD',\n",
" '_G_V_y': 'C19B9BCB27EF514228016F94DE85C068AFE416B80752EDF256F2593FE367766A',\n",
" 'W': '4E5E15AB35008C15B89E91F9F329164D4AACD53D9923672CE0019F9ACD98573F',\n",
" 'G_W': 'FFA4F102134029B3B156890B88C9D9619501196574174DCB68A07DB0588E4D41',\n",
" '_G_W_y': 'BD08125C1A5E9C4F4AA60198A9F897EB656784DE50C0FE840FE3683FC20C295C'\n",
" },\n",
" 'ephemeral_keys': {\n",
" 'X': 'A0C71BDBA570FFD270D90BDF416C142921F214406271FCF55B8567F079B50DA0',\n",
" 'G_X': 'FF14FB42677CE9D016907F571E5E1CD4E815F098AA37084063A0C34570F6F7F5',\n",
" '_G_X_y': '353AFA30B59B6FA90843F8BECD981CEDC0A2BD3E61421EAFE171544D9994C769',\n",
" 'Y': 'A1D1A1C084AB0D912CC7A15B7F252FABCA252FAD4CAA8E5D569C94578B52A047',\n",
" 'G_Y': '9F69C52FAE8F7EA9194022C70B238FCBF4AFFFDFFC8341EEC85BA68E2F9BB744',\n",
" '_G_Y_y': '52CB7AAF4E56C610C91A6185B92AFF5B03E9F73E6010AEBBA72B9C4BDA269C9A',\n",
" 'Z': '644658D815CBCA8EA863090A2D498990B5C75357A729231EC3DE7DF5A7AFE49E',\n",
" 'G_Z': '6B67C90638924C4AE8472CA6FB9A90BE5F43132753346379C672972D323F7A41',\n",
" '_G_Z_y': 'FA1EFAD24A287B1FEF04683B5B24963A107067541B2E4766088552EE11337D87'\n",
" },\n",
"}\n",
"# tv = add_keys(tv) # uncomment to generate a new set of keys\n",
"\n",
"tv = add_enc_id(tv)\n",
"tv = add_voucher_info(tv)\n",
"\n",
"# rich.print(tv)\n",
"format_tv(tv)\n",
"# format_tv(tv, nokeys=True)"
]
},
{
"cell_type": "code",
"execution_count": 125,
"metadata": {},
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"..\n",
"----------------------------------------------------------------------\n",
"Ran 2 tests in 0.016s\n",
"\n",
"OK\n"
]
},
{
"data": {
"text/plain": [
"<unittest.main.TestProgram at 0x7f16d0973f40>"
]
},
"execution_count": 125,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"import unittest\n",
"\n",
"class Test(unittest.TestCase):\n",
" def test_ead_1(self):\n",
" self.assertEqual(\n",
" p256_ecdh(tv[\"ephemeral-keys\"][\"X\"], tv[\"static-keys\"][\"G_W\"], tv[\"static-keys\"][\"_G_W_y\"]), \n",
" p256_ecdh(tv[\"static-keys\"][\"W\"], tv[\"ephemeral-keys\"][\"G_X\"], tv[\"ephemeral-keys\"][\"_G_X_y\"]), \n",
" )\n",
"\n",
"unittest.main(argv=[''], exit=False)"
]
}
],
"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.10.12"
},
"orig_nbformat": 4
},
"nbformat": 4,
"nbformat_minor": 2
}

0 comments on commit e677de2

Please sign in to comment.