> For the complete documentation index, see [llms.txt](https://blackdreams-organization.gitbook.io/etamp/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://blackdreams-organization.gitbook.io/etamp/examples/python.md).

# Python

#### Description:

In Python, the `jwt` and `ecdsa` libraries are used to generate JWT tokens and to sign messages respectively. The `uuid` library is used to generate a unique identifier for the `Id` field.

#### Required Libraries:

1. `PyJWT`: A Python library to encode and decode JWT tokens.
2. `ecdsa`: A Python library for signing and verifying messages using ECDSA.
3. `uuid`: A Python library to generate unique identifiers.
4. `cryptography` : A Python library provides cryptographic recipes and primitives.

{% code overflow="wrap" lineNumbers="true" %}

```bash
pip install PyJWT ecdsa cryptography
```

{% endcode %}

{% code overflow="wrap" lineNumbers="true" %}

```python
import jwt
import ecdsa
from cryptography.hazmat.primitives.asymmetric import ec
from cryptography.hazmat.primitives import serialization
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.backends import default_backend
import uuid
import datetime
import base64

# Key generation for JWT
private_key_jwt = ecdsa.SigningKey.generate(curve=ecdsa.NIST521p)
public_key_jwt = private_key_jwt.verifying_key

# Key generation for ECDH
private_key_ecdh = ec.generate_private_key(ec.SECP256R1(), default_backend())
peer_public_key = ec.generate_private_key(ec.SECP256R1(), default_backend()).public_key()

def private_key_to_pem(sk):
    # Convert the SigningKey to a PEM formatted string
    return sk.to_pem().decode()

def sign_message(message, private_key):
    signature = private_key.sign(message.encode())
    return base64.b64encode(signature).decode()

def encrypt_message_ecdh(message):
    shared_key = private_key_ecdh.exchange(ec.ECDH(), peer_public_key)
    return shared_key[:len(message)].hex()  # Return as hex for simplicity

def generate_etamp():
    header = {
        "alg": "ES512",
        "typ": "ETAMP"
    }
    
    current_time = datetime.datetime.now(datetime.timezone.utc)
    expiration_time = current_time + datetime.timedelta(seconds=3600)  # 1 hour later
    not_before_time = current_time

    senderServerId = str(uuid.uuid4())
    senderId = str(uuid.uuid4())
    recipientId = str(uuid.uuid4())
    message_id = str(uuid.uuid4())

    payload = {
        "jti": str(uuid.uuid4()),
        "exp": int(expiration_time.timestamp()),
        "nbf": int(not_before_time.timestamp()),
        "messageId": message_id,
        "senderUserName": "user1",
        "senderId": senderId,
        "recipient": "user2",
        "recipientId": recipientId,
        "senderServerName": "WebServer1",
        "senderServerId": senderServerId,
        "recipientServerName": "WebServer1",
        "recipientServerId": senderServerId,
        "iss": f"{senderServerId}.WebServer1.user1.{senderId}",
        "sub": "Message",
        "audience": f"{senderServerId}.WebServer1.user2.{recipientId}",
        "message": encrypt_message_ecdh("This is a secret message"),
        "timestamp": current_time.strftime('%Y-%m-%dT%H:%M:%SZ')
    }
    
    pem_private_key = private_key_to_pem(private_key_jwt)
    token = jwt.encode(payload, pem_private_key, algorithm="ES512", headers=header)

    # ETAMP structure for a message
    message_etamp = {
        "Id": message_id,
        "Token": token,
        "SignatureToken": sign_message(token, private_key_jwt),
        "SignatureMessage": sign_message(message_id + token + sign_message(token, private_key_jwt), private_key_jwt)
    }

    return message_etamp

if __name__ == "__main__":
    print(generate_etamp())
```

{% endcode %}


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://blackdreams-organization.gitbook.io/etamp/examples/python.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
