Skip to content

Instantly share code, notes, and snippets.

@lukehinds
Created June 16, 2025 15:45
Show Gist options
  • Save lukehinds/56a80397ba4f908541dabf7ceedd3582 to your computer and use it in GitHub Desktop.
Save lukehinds/56a80397ba4f908541dabf7ceedd3582 to your computer and use it in GitHub Desktop.
Display the source blob
Display the rendered blob
Raw
{
"cells": [
{
"cell_type": "code",
"execution_count": 1,
"id": "fd416903",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Requirement already satisfied: cbor2 in ./.venv/lib/python3.11/site-packages (5.6.5)\n",
"Requirement already satisfied: cose in ./.venv/lib/python3.11/site-packages (0.9.dev8)\n",
"Requirement already satisfied: cryptography in ./.venv/lib/python3.11/site-packages (45.0.4)\n",
"Requirement already satisfied: ecdsa in ./.venv/lib/python3.11/site-packages (from cose) (0.19.1)\n",
"Requirement already satisfied: attrs in ./.venv/lib/python3.11/site-packages (from cose) (25.3.0)\n",
"Requirement already satisfied: certvalidator in ./.venv/lib/python3.11/site-packages (from cose) (0.11.1)\n",
"Requirement already satisfied: cffi>=1.14 in ./.venv/lib/python3.11/site-packages (from cryptography) (1.17.1)\n",
"Requirement already satisfied: pycparser in ./.venv/lib/python3.11/site-packages (from cffi>=1.14->cryptography) (2.22)\n",
"Requirement already satisfied: asn1crypto>=0.18.1 in ./.venv/lib/python3.11/site-packages (from certvalidator->cose) (1.5.1)\n",
"Requirement already satisfied: oscrypto>=0.16.1 in ./.venv/lib/python3.11/site-packages (from certvalidator->cose) (1.3.0)\n",
"Requirement already satisfied: six>=1.9.0 in ./.venv/lib/python3.11/site-packages (from ecdsa->cose) (1.17.0)\n",
"\n",
"\u001b[1m[\u001b[0m\u001b[34;49mnotice\u001b[0m\u001b[1;39;49m]\u001b[0m\u001b[39;49m A new release of pip is available: \u001b[0m\u001b[31;49m24.3.1\u001b[0m\u001b[39;49m -> \u001b[0m\u001b[32;49m25.1.1\u001b[0m\n",
"\u001b[1m[\u001b[0m\u001b[34;49mnotice\u001b[0m\u001b[1;39;49m]\u001b[0m\u001b[39;49m To update, run: \u001b[0m\u001b[32;49mpip install --upgrade pip\u001b[0m\n",
"Note: you may need to restart the kernel to use updated packages.\n"
]
}
],
"source": [
"\n",
"%pip install cbor2 cose cryptography\n"
]
},
{
"cell_type": "code",
"execution_count": 2,
"id": "8e2ef28a",
"metadata": {},
"outputs": [],
"source": [
"\n",
"import json\n",
"import base64\n",
"import time\n",
"import cbor2\n",
"\n",
"from cryptography.hazmat.primitives.asymmetric import ec\n",
"from cryptography.hazmat.primitives import hashes\n",
"from cryptography.hazmat.primitives.asymmetric.utils import decode_dss_signature\n",
"\n",
"from cose.messages import Sign1Message\n",
"from cose.keys.ec2 import EC2Key\n",
"from cose.algorithms import Es256\n",
"from cose.keys.curves import P256\n"
]
},
{
"cell_type": "code",
"execution_count": 3,
"id": "186ec0d5",
"metadata": {},
"outputs": [],
"source": [
"\n",
"def b64url(data: bytes) -> str:\n",
" return base64.urlsafe_b64encode(data).rstrip(b\"=\").decode()\n",
"\n",
"# Generate EC key\n",
"private_key = ec.generate_private_key(ec.SECP256R1())\n",
"public_key = private_key.public_key()\n",
"numbers = private_key.private_numbers()\n",
"pub_numbers = numbers.public_numbers\n",
"x = pub_numbers.x.to_bytes(32, byteorder='big')\n",
"y = pub_numbers.y.to_bytes(32, byteorder='big')\n",
"d = numbers.private_value.to_bytes(32, byteorder='big')\n",
"\n",
"# Create EC2 COSE key\n",
"cose_key = EC2Key(\n",
" crv=P256,\n",
" x=x,\n",
" y=y,\n",
" d=d,\n",
" optional_params={\"alg\": Es256}\n",
")\n"
]
},
{
"cell_type": "code",
"execution_count": 4,
"id": "78f5e745",
"metadata": {},
"outputs": [],
"source": [
"\n",
"payload = {\n",
" \"iss\": \"supply-chain-stuff\",\n",
" \"sub\": \"component-123\",\n",
" \"event\": \"build\",\n",
" \"ts\": \"2025-06-16T00:00:00Z\",\n",
" \"metadata\": {\n",
" \"version\": \"4.18.7\",\n",
" \"build_hash\": \"f3d4a1c2e6b90123aaef0987ddeeccbbf0e4d2e1f54ac9ba7c65db7fa2d3984b\",\n",
" \"compiler\": \"gcc 13.2.0\",\n",
" \"build_host\": \"ci-builder-12.internal.net\",\n",
" \"env\": {\n",
" \"GOOS\": \"linux\",\n",
" \"GOARCH\": \"amd64\",\n",
" \"CGO_ENABLED\": \"1\",\n",
" \"LD_LIBRARY_PATH\": \"/usr/local/lib\",\n",
" \"PATH\": \"/usr/local/bin:/usr/bin:/bin\"\n",
" }\n",
" },\n",
" \"build_logs\": \"\\n\".join([f\"[INFO] Step {i}: Completed\" for i in range(1, 51)]),\n",
" \"dependencies\": [\n",
" {\"name\": f\"lib-{i}\", \"version\": f\"{i}.{i+1}.{i+2}\", \"checksum\": f\"sha256:{i*12345:x}...\"}\n",
" for i in range(50)\n",
" ],\n",
" \"attestation\": {\n",
" \"provenance\": {\n",
" \"builder\": \"GitHub Actions\",\n",
" \"repo\": \"github.com/example/project\",\n",
" \"commit\": \"c0ffee1234badcafe123\",\n",
" \"workflow\": \"build-and-test.yml\",\n",
" \"trigger\": \"push\"\n",
" },\n",
" \"signing_policy\": \"strict\",\n",
" \"expires\": \"2026-06-16T00:00:00Z\"\n",
" }\n",
"}\n"
]
},
{
"cell_type": "code",
"execution_count": 5,
"id": "145d458c",
"metadata": {},
"outputs": [],
"source": [
"\n",
"# COSE Signing\n",
"start_cose = time.time()\n",
"msg = Sign1Message(phdr={\"alg\": Es256}, payload=cbor2.dumps(payload))\n",
"msg.key = cose_key\n",
"signed_cose = msg.encode()\n",
"end_cose = time.time()\n"
]
},
{
"cell_type": "code",
"execution_count": 6,
"id": "052b4014",
"metadata": {},
"outputs": [],
"source": [
"\n",
"# JWT Signing (Sigstore-style)\n",
"header = {\"alg\": \"ES256\", \"typ\": \"JWT\"}\n",
"b64_header = b64url(json.dumps(header, separators=(\",\", \":\")).encode())\n",
"b64_payload = b64url(json.dumps(payload, separators=(\",\", \":\")).encode())\n",
"signing_input = f\"{b64_header}.{b64_payload}\".encode()\n",
"\n",
"start_jwt = time.time()\n",
"signature = private_key.sign(signing_input, ec.ECDSA(hashes.SHA256()))\n",
"r, s = decode_dss_signature(signature)\n",
"raw_signature = r.to_bytes(32, \"big\") + s.to_bytes(32, \"big\")\n",
"b64_signature = b64url(raw_signature)\n",
"jwt_token = f\"{b64_header}.{b64_payload}.{b64_signature}\"\n",
"end_jwt = time.time()\n"
]
},
{
"cell_type": "code",
"execution_count": 7,
"id": "bdeba35d",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Comparison Results\n",
"---------------------\n",
"Original Payload Size (JSON): 5709\n",
"Signed COSE Size (bytes): 4648\n",
"Signed JWT Size (bytes): 7275\n",
"Size Difference (%): 56.52\n",
"COSE Signing Time (s): 0.011529\n",
"JWT Signing Time (s): 0.001421\n"
]
}
],
"source": [
"\n",
"print(\"Comparison Results\")\n",
"print(\"---------------------\")\n",
"print(\"Original Payload Size (JSON):\", len(json.dumps(payload)))\n",
"print(\"Signed COSE Size (bytes):\", len(signed_cose))\n",
"print(\"Signed JWT Size (bytes):\", len(jwt_token.encode()))\n",
"print(\"Size Difference (%):\", round((len(jwt_token.encode()) - len(signed_cose)) / len(signed_cose) * 100, 2))\n",
"print(\"COSE Signing Time (s):\", round(end_cose - start_cose, 6))\n",
"print(\"JWT Signing Time (s):\", round(end_jwt - start_jwt, 6))\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "edecc384",
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": ".venv",
"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.11.11"
}
},
"nbformat": 4,
"nbformat_minor": 5
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment