{"id":348,"date":"2023-08-06T13:03:41","date_gmt":"2023-08-06T13:03:41","guid":{"rendered":"https:\/\/python.garden\/?p=348"},"modified":"2023-08-07T14:13:13","modified_gmt":"2023-08-07T14:13:13","slug":"implement-the-elliptic-curve-diffie-hellman-ecdh-key-exchange-protocol-in-python","status":"publish","type":"post","link":"https:\/\/python.garden\/index.php\/2023\/08\/06\/implement-the-elliptic-curve-diffie-hellman-ecdh-key-exchange-protocol-in-python\/","title":{"rendered":"Implement the Elliptic Curve Diffie-Hellman (ECDH) key exchange protocol in Python."},"content":{"rendered":"\n<p><strong>WARNING!<\/strong><\/p>\n\n\n\n<p><strong>Please note that this is just a demonstration and should not be used for any serious cryptographic work.<\/strong><\/p>\n\n\n\n<p>Elliptic Curve Cryptography (ECC) is a form of public key cryptography that relies on the math of elliptic curves. ECDH is a variant of the Diffie-Hellman protocol that uses ECC.<\/p>\n\n\n\n<p>Here&#8217;s a simplified outline:<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Step 1: Install Required Libraries<\/h3>\n\n\n\n<p>First, we need to install the necessary Python libraries. In this case, we&#8217;ll use <code>cryptography<\/code> and <code>ecdsa<\/code>.<\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;python&quot;,&quot;mime&quot;:&quot;text\/x-python&quot;,&quot;theme&quot;:&quot;material&quot;,&quot;lineNumbers&quot;:true,&quot;styleActiveLine&quot;:true,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;&quot;,&quot;language&quot;:&quot;Python&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;python&quot;}\">pip install cryptography ecdsa<\/pre><\/div>\n\n\n\n<h3 class=\"wp-block-heading\">Step 2: Define the Elliptic Curve<\/h3>\n\n\n\n<p>We&#8217;ll use the NIST standard P-256 curve (also known as secp256r1).<\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;python&quot;,&quot;mime&quot;:&quot;text\/x-python&quot;,&quot;theme&quot;:&quot;material&quot;,&quot;lineNumbers&quot;:true,&quot;styleActiveLine&quot;:true,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;&quot;,&quot;language&quot;:&quot;Python&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;python&quot;}\">from cryptography.hazmat.primitives import serialization\nfrom cryptography.hazmat.primitives.asymmetric import ec\nfrom cryptography.hazmat.primitives import hashes\n\ncurve = ec.SECP256R1()<\/pre><\/div>\n\n\n\n<h3 class=\"wp-block-heading\">Step 3: Generate Public-Private Key Pairs<\/h3>\n\n\n\n<p>Both parties (let&#8217;s call them Alice and Bob) should generate their private-public key pairs.<\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;python&quot;,&quot;mime&quot;:&quot;text\/x-python&quot;,&quot;theme&quot;:&quot;material&quot;,&quot;lineNumbers&quot;:true,&quot;styleActiveLine&quot;:true,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;&quot;,&quot;language&quot;:&quot;Python&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;python&quot;}\"># Alice\nprivate_key_Alice = ec.generate_private_key(curve)\npublic_key_Alice = private_key_Alice.public_key()\n\n# Bob\nprivate_key_Bob = ec.generate_private_key(curve)\npublic_key_Bob = private_key_Bob.public_key()<\/pre><\/div>\n\n\n\n<h3 class=\"wp-block-heading\">Step 4: Exchange Public Keys<\/h3>\n\n\n\n<p>Alice and Bob now exchange public keys. In a real-world application, this would be done over a secure but not necessarily private channel, for instance, over HTTPS.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Step 5: Generate Shared Secret<\/h3>\n\n\n\n<p>Both Alice and Bob can now generate a shared secret using their own private keys and the other party&#8217;s public key.<\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;python&quot;,&quot;mime&quot;:&quot;text\/x-python&quot;,&quot;theme&quot;:&quot;material&quot;,&quot;lineNumbers&quot;:true,&quot;styleActiveLine&quot;:true,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;&quot;,&quot;language&quot;:&quot;Python&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;python&quot;}\"># Alice\nshared_secret_Alice = private_key_Alice.exchange(ec.ECDH(), public_key_Bob)\n\n# Bob\nshared_secret_Bob = private_key_Bob.exchange(ec.ECDH(), public_key_Alice)<\/pre><\/div>\n\n\n\n<p>This will generate the same shared secret on both ends.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Step 6: Derive a Symmetric Key<\/h3>\n\n\n\n<p>To use this shared secret for symmetric cryptography, it needs to be derived into a key. Here we can use the HKDF (HMAC-based Extract-and-Expand Key Derivation Function) to derive a symmetric key.<\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;python&quot;,&quot;mime&quot;:&quot;text\/x-python&quot;,&quot;theme&quot;:&quot;material&quot;,&quot;lineNumbers&quot;:true,&quot;styleActiveLine&quot;:true,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;&quot;,&quot;language&quot;:&quot;Python&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;python&quot;}\">from cryptography.hazmat.primitives.kdf.hkdf import HKDF\n\ndef derive_key(shared_secret):\n    return HKDF(\n        algorithm=hashes.SHA256(),\n        length=32,\n        salt=None,\n        info=None,\n    ).derive(shared_secret)\n\n# Alice\nkey_Alice = derive_key(shared_secret_Alice)\n\n# Bob\nkey_Bob = derive_key(shared_secret_Bob)<\/pre><\/div>\n\n\n\n<p>The resulting keys <code>key_Alice<\/code> and <code>key_Bob<\/code> will be identical and can be used for symmetric encryption\/decryption.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Step 7: Encrypt and Decrypt Messages<\/h3>\n\n\n\n<p>Now Alice and Bob can use these keys to encrypt and decrypt messages between them. AES is a commonly used symmetric encryption algorithm, but any symmetric algorithm can be used.<\/p>\n\n\n\n<p>Please remember, the example provided is simplified and is not sufficient for real-world cryptographic needs. For real-world applications, you should use well-tested libraries like OpenSSL or libraries that provide a high-level interface to tested cryptographic primitives.<\/p>\n\n\n\n<p>And always remember, cryptography is a complex and nuanced field. When implementing it, even small mistakes can have large implications. Therefore, it&#8217;s usually recommended to use tested implementations and libraries where possible and consult with security experts when necessary.<\/p>\n\n\n\n<p>Absolutely, let&#8217;s now consider a simple example where we have a server and a client that want to communicate securely.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Server-Client Key Exchange<\/h3>\n\n\n\n<p>In a server-client scenario, the server and client will each have their own private key and will exchange public keys. Then, they will use each other&#8217;s public key and their own private key to create a shared secret.<\/p>\n\n\n\n<p>First, let&#8217;s set up a simple server and client using the socket library.<\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;python&quot;,&quot;mime&quot;:&quot;text\/x-python&quot;,&quot;theme&quot;:&quot;material&quot;,&quot;lineNumbers&quot;:true,&quot;styleActiveLine&quot;:true,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;&quot;,&quot;language&quot;:&quot;Python&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;python&quot;}\">import socket\n\n# The server's host and port\nHOST = '127.0.0.1' \nPORT = 65432<\/pre><\/div>\n\n\n\n<h3 class=\"wp-block-heading\">Server Code<\/h3>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;python&quot;,&quot;mime&quot;:&quot;text\/x-python&quot;,&quot;theme&quot;:&quot;material&quot;,&quot;lineNumbers&quot;:true,&quot;styleActiveLine&quot;:true,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;&quot;,&quot;language&quot;:&quot;Python&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;python&quot;}\">def server_program():\n    # Create a socket object\n    server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)\n\n    # Bind the socket to the host and port\n    server_socket.bind((HOST, PORT))\n\n    # Listen for incoming connections\n    server_socket.listen(1)\n\n    # Accept a connection\n    conn, addr = server_socket.accept()\n\n    print('Connection from:', addr)\n\n    # Server's private and public keys\n    private_key_server = ec.generate_private_key(curve)\n    public_key_server = private_key_server.public_key().public_bytes(\n        encoding=serialization.Encoding.PEM,\n        format=serialization.PublicFormat.SubjectPublicKeyInfo\n    )\n\n    # Send the server's public key to the client\n    conn.sendall(public_key_server)\n\n    # Receive the client's public key\n    public_key_client = serialization.load_pem_public_key(\n        conn.recv(1024),\n        backend=default_backend()\n    )\n\n    # Generate the shared secret\n    shared_secret_server = private_key_server.exchange(ec.ECDH(), public_key_client)\n    key_server = derive_key(shared_secret_server)\n\n    # Use the derived symmetric key for further communication...\n    # ...<\/pre><\/div>\n\n\n\n<h3 class=\"wp-block-heading\">Client Code<\/h3>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;python&quot;,&quot;mime&quot;:&quot;text\/x-python&quot;,&quot;theme&quot;:&quot;material&quot;,&quot;lineNumbers&quot;:true,&quot;styleActiveLine&quot;:true,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;&quot;,&quot;language&quot;:&quot;Python&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;python&quot;}\">def client_program():\n    # Create a socket object\n    client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)\n\n    # Connect to the server\n    client_socket.connect((HOST, PORT))\n\n    # Client's private and public keys\n    private_key_client = ec.generate_private_key(curve)\n    public_key_client = private_key_client.public_key().public_bytes(\n        encoding=serialization.Encoding.PEM,\n        format=serialization.PublicFormat.SubjectPublicKeyInfo\n    )\n\n    # Send the client's public key to the server\n    client_socket.sendall(public_key_client)\n\n    # Receive the server's public key\n    public_key_server = serialization.load_pem_public_key(\n        client_socket.recv(1024),\n        backend=default_backend()\n    )\n\n    # Generate the shared secret\n    shared_secret_client = private_key_client.exchange(ec.ECDH(), public_key_server)\n    key_client = derive_key(shared_secret_client)\n\n    # Use the derived symmetric key for further communication...\n    # ...<\/pre><\/div>\n\n\n\n<p>This simple server-client setup allows for the exchange of public keys and the creation of a shared secret key for further symmetric encryption.<\/p>\n\n\n\n<p>Do keep in mind that in a real-world application, you would need to consider many additional factors such as validation of public keys, handling multiple clients, concurrent connections, timeouts, handling of exceptions and errors, secure storage of private keys, etc.<\/p>\n\n\n\n<p>Additionally, using raw sockets to implement secure communication can be complex and error-prone, especially when considering real-world networking complexities such as NAT, firewall traversal, etc. Libraries and tools such as OpenSSL, or higher-level protocols such as HTTPS, provide tested and robust implementations of these concepts.<br><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Step-By-Step Implementation of Server-Client ECDH<\/h2>\n\n\n\n<p>Let&#8217;s break down the server-client interaction process into more detailed steps.<\/p>\n\n\n\n<p>The purpose of these steps is to establish a secure communication channel between a server and a client using the ECDH protocol to exchange keys. This secure channel can then be used for transmitting messages securely.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Step 1: Server Setup<\/h3>\n\n\n\n<p>The server sets up a listening socket and waits for incoming connections from clients. Here&#8217;s the basic setup for a Python server using the <code>socket<\/code> library.<\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;python&quot;,&quot;mime&quot;:&quot;text\/x-python&quot;,&quot;theme&quot;:&quot;material&quot;,&quot;lineNumbers&quot;:true,&quot;styleActiveLine&quot;:true,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;&quot;,&quot;language&quot;:&quot;Python&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;python&quot;}\">def server_setup():\n    server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)\n    server_socket.bind((HOST, PORT))\n    server_socket.listen(1)\n    return server_socket<\/pre><\/div>\n\n\n\n<h3 class=\"wp-block-heading\">Step 2: Client Setup<\/h3>\n\n\n\n<p>On the client side, the client initiates a connection to the server.<\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;python&quot;,&quot;mime&quot;:&quot;text\/x-python&quot;,&quot;theme&quot;:&quot;material&quot;,&quot;lineNumbers&quot;:true,&quot;styleActiveLine&quot;:true,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;&quot;,&quot;language&quot;:&quot;Python&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;python&quot;}\">def client_setup():\n    client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)\n    client_socket.connect((HOST, PORT))\n    return client_socket<\/pre><\/div>\n\n\n\n<h3 class=\"wp-block-heading\">Step 3: Key Generation<\/h3>\n\n\n\n<p>Both the server and the client generate their respective public and private keys.<\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;python&quot;,&quot;mime&quot;:&quot;text\/x-python&quot;,&quot;theme&quot;:&quot;material&quot;,&quot;lineNumbers&quot;:true,&quot;styleActiveLine&quot;:true,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;&quot;,&quot;language&quot;:&quot;Python&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;python&quot;}\"># Server\nprivate_key_server = ec.generate_private_key(curve)\npublic_key_server = private_key_server.public_key()\n\n# Client\nprivate_key_client = ec.generate_private_key(curve)\npublic_key_client = private_key_client.public_key()<\/pre><\/div>\n\n\n\n<h3 class=\"wp-block-heading\">Step 4: Key Exchange<\/h3>\n\n\n\n<p>Once a connection has been established, the client and the server exchange public keys. In our case, let&#8217;s say the client initiates the exchange by sending its public key first.<\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;python&quot;,&quot;mime&quot;:&quot;text\/x-python&quot;,&quot;theme&quot;:&quot;material&quot;,&quot;lineNumbers&quot;:true,&quot;styleActiveLine&quot;:true,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;&quot;,&quot;language&quot;:&quot;Python&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;python&quot;}\"># Client sends its public key\nclient_socket.sendall(public_key_client.public_bytes(serialization.Encoding.PEM, serialization.PublicFormat.SubjectPublicKeyInfo))\n\n# Server receives client's public key\npublic_key_client_received = serialization.load_pem_public_key(server_socket.recv(1024), backend=default_backend())<\/pre><\/div>\n\n\n\n<p>After the server receives the client&#8217;s public key, it sends back its own public key.<\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;python&quot;,&quot;mime&quot;:&quot;text\/x-python&quot;,&quot;theme&quot;:&quot;material&quot;,&quot;lineNumbers&quot;:true,&quot;styleActiveLine&quot;:true,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;&quot;,&quot;language&quot;:&quot;Python&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;python&quot;}\"># Server sends its public key\nserver_socket.sendall(public_key_server.public_bytes(serialization.Encoding.PEM, serialization.PublicFormat.SubjectPublicKeyInfo))\n\n# Client receives server's public key\npublic_key_server_received = serialization.load_pem_public_key(client_socket.recv(1024), backend=default_backend())<\/pre><\/div>\n\n\n\n<h3 class=\"wp-block-heading\">Step 5: Shared Secret Generation<\/h3>\n\n\n\n<p>Both the server and the client use their own private key and the received public key to create a shared secret.<\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;python&quot;,&quot;mime&quot;:&quot;text\/x-python&quot;,&quot;theme&quot;:&quot;material&quot;,&quot;lineNumbers&quot;:true,&quot;styleActiveLine&quot;:true,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;&quot;,&quot;language&quot;:&quot;Python&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;python&quot;}\"># Server\nshared_secret_server = private_key_server.exchange(ec.ECDH(), public_key_client_received)\nkey_server = derive_key(shared_secret_server)\n\n# Client\nshared_secret_client = private_key_client.exchange(ec.ECDH(), public_key_server_received)\nkey_client = derive_key(shared_secret_client)<\/pre><\/div>\n\n\n\n<h3 class=\"wp-block-heading\">Step 6: Symmetric Encryption<\/h3>\n\n\n\n<p>With the derived shared keys, the client and server can now communicate securely using a symmetric encryption algorithm like AES. Messages encrypted with the shared secret can only be decrypted by someone possessing the same secret.<\/p>\n\n\n\n<p>Please remember that the above code is simplified for the purposes of this demonstration. Real-world applications will need to handle networking errors, buffer overflows, and other such concerns. Moreover, please always refer to best practices and use tested libraries when working with cryptography to avoid introducing security vulnerabilities.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>WARNING! Please note that this is just a demonstration and should not be used for any serious cryptographic work. Elliptic Curve Cryptography (ECC) is a form of public key cryptography&hellip;<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[1],"tags":[],"class_list":["post-348","post","type-post","status-publish","format-standard","hentry","category-uncategorized"],"featured_image_src":null,"author_info":{"display_name":"shababdoo","author_link":"https:\/\/python.garden\/index.php\/author\/shababdoo\/"},"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/python.garden\/index.php\/wp-json\/wp\/v2\/posts\/348","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/python.garden\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/python.garden\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/python.garden\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/python.garden\/index.php\/wp-json\/wp\/v2\/comments?post=348"}],"version-history":[{"count":0,"href":"https:\/\/python.garden\/index.php\/wp-json\/wp\/v2\/posts\/348\/revisions"}],"wp:attachment":[{"href":"https:\/\/python.garden\/index.php\/wp-json\/wp\/v2\/media?parent=348"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/python.garden\/index.php\/wp-json\/wp\/v2\/categories?post=348"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/python.garden\/index.php\/wp-json\/wp\/v2\/tags?post=348"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}