Created
February 3, 2024 01:45
-
-
Save heathhenley/7ecf13aec81eb09399d204e240306e00 to your computer and use it in GitHub Desktop.
S63.ipynb
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"nbformat": 4, | |
"nbformat_minor": 0, | |
"metadata": { | |
"colab": { | |
"provenance": [], | |
"authorship_tag": "ABX9TyP+ZAEr/o7RunkYh6KNKxzx", | |
"include_colab_link": true | |
}, | |
"kernelspec": { | |
"name": "python3", | |
"display_name": "Python 3" | |
}, | |
"language_info": { | |
"name": "python" | |
} | |
}, | |
"cells": [ | |
{ | |
"cell_type": "markdown", | |
"metadata": { | |
"id": "view-in-github", | |
"colab_type": "text" | |
}, | |
"source": [ | |
"<a href=\"https://colab.research.google.com/gist/heathhenley/7ecf13aec81eb09399d204e240306e00/s63.ipynb\" target=\"_parent\"><img src=\"https://colab.research.google.com/assets/colab-badge.svg\" alt=\"Open In Colab\"/></a>" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 7, | |
"metadata": { | |
"colab": { | |
"base_uri": "https://localhost:8080/" | |
}, | |
"id": "D_hb2MDSd4aG", | |
"outputId": "f1fd02d5-e303-4a21-d28b-b0712533a5df" | |
}, | |
"outputs": [ | |
{ | |
"output_type": "stream", | |
"name": "stdout", | |
"text": [ | |
"Collecting pycryptodome\n", | |
" Downloading pycryptodome-3.20.0-cp35-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (2.1 MB)\n", | |
"\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m2.1/2.1 MB\u001b[0m \u001b[31m10.5 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", | |
"\u001b[?25hInstalling collected packages: pycryptodome\n", | |
"Successfully installed pycryptodome-3.20.0\n" | |
] | |
} | |
], | |
"source": [ | |
"%pip install pycryptodome" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"source": [ | |
"# This example is the one in 5.2.1 in the linked doc:\n", | |
"# https://iho.int/uploads/user/Services%20and%20Standards/ENC_ECDIS/data_protection/S-63_Test_Data_Implementation_Guide_v1.1.pdf\n", | |
"from Crypto.Cipher import Blowfish\n", | |
"import binascii\n", | |
"\n", | |
"# Hardware ID / encrypted HW_ID\n", | |
"\n", | |
"# Assigned to manufacturer (OEM) by IHO:\n", | |
"m_id = \"10\"\n", | |
"m_key = \"10121\".encode()\n", | |
"\n", | |
"# Generated by manufacturer (OEM) for each installation:\n", | |
"# - padded to 8 bytes\n", | |
"hw_id = \"12345\".encode() + b\"\\x03\" * 3\n", | |
"\n", | |
"# Encrypt hardware id with blowfish and m_key:\n", | |
"cipher = Blowfish.new(m_key, Blowfish.MODE_ECB)\n", | |
"encrypted_hw_id = cipher.encrypt(hw_id).hex().upper()\n", | |
"print(f\"Encrypted HW_ID: {encrypted_hw_id}\")\n", | |
"\n", | |
"# When it's time to decrypt:\n", | |
"print(f\"Decrypted: {cipher.decrypt(bytes.fromhex(encrypted_hw_id))[:5].decode()}\")" | |
], | |
"metadata": { | |
"colab": { | |
"base_uri": "https://localhost:8080/" | |
}, | |
"id": "1GEJPczsd9Hq", | |
"outputId": "7fb6f47d-5e86-4eca-dc85-ccd844613033" | |
}, | |
"execution_count": 52, | |
"outputs": [ | |
{ | |
"output_type": "stream", | |
"name": "stdout", | |
"text": [ | |
"Encrypted HW_ID: 66B5CBFDF7E4139D\n", | |
"Decrypted: 12345\n" | |
] | |
} | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"source": [ | |
"import binascii\n", | |
"\n", | |
"# Compute the CRC32 checksum of the encrypted hw_id:\n", | |
"crc = binascii.crc32(encrypted_hw_id.encode())\n", | |
"crc = f\"{crc:x}\".upper().zfill(8)\n", | |
"print(f\"CRC32: {crc}\")" | |
], | |
"metadata": { | |
"colab": { | |
"base_uri": "https://localhost:8080/" | |
}, | |
"id": "vepO6fu3tWCA", | |
"outputId": "bc60eef1-4c8c-4eb4-e2ff-90f457892e15" | |
}, | |
"execution_count": 111, | |
"outputs": [ | |
{ | |
"output_type": "stream", | |
"name": "stdout", | |
"text": [ | |
"CRC32: 5B6086C2\n" | |
] | |
} | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"source": [ | |
"# Now we have everything to compute the UPN:\n", | |
"upn = encrypted_hw_id + crc + m_id.encode().hex().upper()\n", | |
"\n", | |
"print(f\"UPN: {upn}\")" | |
], | |
"metadata": { | |
"colab": { | |
"base_uri": "https://localhost:8080/" | |
}, | |
"id": "abSWi31WvXcB", | |
"outputId": "415ec9ba-ddae-4e4f-9821-58e40f608a2b" | |
}, | |
"execution_count": 112, | |
"outputs": [ | |
{ | |
"output_type": "stream", | |
"name": "stdout", | |
"text": [ | |
"UPN: 66B5CBFDF7E4139D5B6086C23130\n" | |
] | |
} | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"source": [ | |
"import os\n", | |
"\n", | |
"# An example of how you might make a 5 byte key:\n", | |
"\n", | |
"# random 5 byte key - using cryptographically secure option\n", | |
"os.urandom(5).hex()" | |
], | |
"metadata": { | |
"colab": { | |
"base_uri": "https://localhost:8080/", | |
"height": 35 | |
}, | |
"id": "JIavBR1SY5Sd", | |
"outputId": "2a02cd7a-8604-4c8e-80d4-df067cfcfa21" | |
}, | |
"execution_count": 3, | |
"outputs": [ | |
{ | |
"output_type": "execute_result", | |
"data": { | |
"text/plain": [ | |
"'20b459214d'" | |
], | |
"application/vnd.google.colaboratory.intrinsic+json": { | |
"type": "string" | |
} | |
}, | |
"metadata": {}, | |
"execution_count": 3 | |
} | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"source": [ | |
"import binascii\n", | |
"from Crypto.Cipher import Blowfish\n", | |
"\n", | |
"# Check the checksum, and then decrypt hardware_id:\n", | |
"\n", | |
"upn = \"66B5CBFDF7E4139D5B6086C23130\"\n", | |
"# We looked up the MKEY using the MID at the end of the UPN (3130)\n", | |
"MKEY = \"10121\"\n", | |
"\n", | |
"# the encrypted hw id is the first 16 chars\n", | |
"encrypted_hw_id = upn[:16]\n", | |
"\n", | |
"# the crc check is the next 8:\n", | |
"crc = upn[16:24]\n", | |
"\n", | |
"# we can make sure it matches to ensure there was no error / data\n", | |
"# integrity issues:\n", | |
"assert crc == f\"{binascii.crc32(encrypted_hw_id.encode()):x}\".upper()\n", | |
"\n", | |
"# The crc checks out, so lets decrypt the hw_id using the m_key:\n", | |
"cipher = Blowfish.new(MKEY.encode(), Blowfish.MODE_ECB)\n", | |
"\n", | |
"decrypted_hw_id = cipher.decrypt(bytes.fromhex(encrypted_hw_id))\n", | |
"# only the first 5, the rest is padding\n", | |
"print(f\"HW_ID: {decrypted_hw_id[:5].decode()}\")" | |
], | |
"metadata": { | |
"colab": { | |
"base_uri": "https://localhost:8080/" | |
}, | |
"id": "Z8yAnDArY64M", | |
"outputId": "2aed110c-4c27-415b-c6c7-2a91195d3c28" | |
}, | |
"execution_count": 64, | |
"outputs": [ | |
{ | |
"output_type": "stream", | |
"name": "stdout", | |
"text": [ | |
"HW_ID: 12345\n" | |
] | |
} | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"source": [ | |
"# Encypt the cell keys:\n", | |
"\n", | |
"hw_id = \"12345\" # --> got this from the UPN as above\n", | |
"# append first byte of hw_id to end of hw_id (in 9.6.2 of standard)\n", | |
"hw_id = hw_id + hw_id[0]\n", | |
"\n", | |
"# padding to 8 bytes\n", | |
"padding = b\"\\x03\" * 3\n", | |
"\n", | |
"# the cell keys that were randomly generated, and used to encrypt the cell\n", | |
"cell_key1, cell_key2 = \"9C467D359D\", \"27737811B4\"\n", | |
"\n", | |
"cipher = Blowfish.new(hw_id.encode(), Blowfish.MODE_ECB)\n", | |
"eck1 = cipher.encrypt(bytes.fromhex(cell_key1) + padding).hex().upper()\n", | |
"eck2 = cipher.encrypt(bytes.fromhex(cell_key2) + padding).hex().upper()\n", | |
"\n", | |
"print(f\"Encrypted key 1: {eck1}\\nEncrypted key 2: {eck2}\")" | |
], | |
"metadata": { | |
"colab": { | |
"base_uri": "https://localhost:8080/" | |
}, | |
"id": "dm7wkIjpjVqU", | |
"outputId": "bc0a4fbb-e82c-4143-d4c9-8abb72c21813" | |
}, | |
"execution_count": 191, | |
"outputs": [ | |
{ | |
"output_type": "stream", | |
"name": "stdout", | |
"text": [ | |
"Encrypted key 1: F7B3814E59C84805\n", | |
"Encrypted key 2: D150D571B9BE53A6\n" | |
] | |
} | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"source": [ | |
"# Make a permit:\n", | |
"cell_name = \"NO4D0512\"\n", | |
"expiration_date = \"20040826\"\n", | |
"permit = f\"{cell_name}{expiration_date}{eck1}{eck2}\".upper()\n", | |
"hex_crc = f\"{binascii.crc32(permit.encode()):x}\".upper()\n", | |
"bytes_crc = bytes.fromhex(hex_crc)\n", | |
"encrypted_crc = cipher.encrypt(bytes_crc + b\"\\x04\" * 4).hex().upper()\n", | |
"permit += encrypted_crc\n", | |
"print(f\"Full cell permit: {permit}\")" | |
], | |
"metadata": { | |
"colab": { | |
"base_uri": "https://localhost:8080/" | |
}, | |
"id": "QLRIDH50kaz_", | |
"outputId": "12a9d74b-f49e-400b-ffad-1497627e0761" | |
}, | |
"execution_count": 177, | |
"outputs": [ | |
{ | |
"output_type": "stream", | |
"name": "stdout", | |
"text": [ | |
"Full cell permit: NO4D051220040826F7B3814E59C84805D150D571B9BE53A642E5B05951975E9C\n" | |
] | |
} | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"source": [ | |
"# Decrypt the cell keys, use them to decrypt the charts, and then extract!\n", | |
"import zipfile\n", | |
"\n", | |
"full_permit = \"NO4D051220040826F7B3814E59C84805D150D571B9BE53A642E5B05951975E9C\"\n", | |
"\n", | |
"# extract encrypted cell key\n", | |
"eck1 = full_permit[16:32]\n", | |
"\n", | |
"# go backwards to get the cell key from the permit\n", | |
"hw_id = \"12345\"\n", | |
"hw_id6 = hw_id + hw_id[0]\n", | |
"\n", | |
"# decrypt the cell key\n", | |
"cipher = Blowfish.new(hw_id6.encode(), Blowfish.MODE_ECB)\n", | |
"ck1 = cipher.decrypt(bytes.fromhex(eck1))[:5]\n", | |
"\n", | |
"# encrypted s57\n", | |
"with open(\"NO4D0512.000\", \"rb\") as f:\n", | |
" encrypted_s57 = f.read()\n", | |
"\n", | |
"# decrypt the s57 data with the cell key\n", | |
"cipher = Blowfish.new(ck1, Blowfish.MODE_ECB)\n", | |
"decrypted_s57_zip = cipher.decrypt(encrypted_s57)\n", | |
"\n", | |
"# check the header (the zip file header starts with PK)\n", | |
"assert decrypted_s57_zip[0:2] == b\"PK\", \"invalid zip\"\n", | |
"\n", | |
"# save a copy of the decrypted chart\n", | |
"with open(\"NO4D0512_decrypted.000\", \"wb\") as f:\n", | |
" f.write(decrypted_s57_zip)\n", | |
"\n", | |
"# extract\n", | |
"with zipfile.ZipFile(\"NO4D0512_decrypted.000\") as z:\n", | |
" z.extractall(\"NO4D0512_decrypted_unzipped.000\")\n" | |
], | |
"metadata": { | |
"id": "YN1-uaM1yk5z" | |
}, | |
"execution_count": 205, | |
"outputs": [] | |
}, | |
{ | |
"cell_type": "code", | |
"source": [], | |
"metadata": { | |
"id": "p2vMnUHSJDvT" | |
}, | |
"execution_count": 162, | |
"outputs": [] | |
} | |
] | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment