Skip to content

fedi-libs/apsig

Repository files navigation

apsig

PyPI CodeQL

apsig is collection of signature implemention used in ActivityPub.

This library implements the creation/verification of signatures for HTTP Signatures (draft-cavage-http-signatures-12), Linked Data Signatures 1.0, and Object Integrity Proofs (FEP-8b32).

RFC9421 implementation is progress.

Installation

# pip
pip install apsig

# uv
uv add apsig

# pdm
pdm add apsig

Example

First, prepare the keys for signing and verification. apsig uses the cryptography library.

from cryptography.hazmat.primitives.asymmetric import rsa, ed25519
from cryptography.hazmat.primitives import serialization

# For HTTP Signatures (RSA)
private_key_rsa = rsa.generate_private_key(public_exponent=65537, key_size=3092)
public_key_rsa_pem = private_key_rsa.public_key().public_bytes(
    encoding=serialization.Encoding.PEM,
    format=serialization.PublicFormat.SubjectPublicKeyInfo,
)

# For Object Integrity Proofs (Ed25519)
private_key_ed = ed25519.Ed25519PrivateKey.generate()
public_key_ed = private_key_ed.public_key()

HTTP Signature (draft)

This is used for signing HTTP requests.

import email.utils
from apsig.draft import Signer, Verifier

# === Signing ===
method = "POST"
url = "https://example.com/api/resource"
headers = {
    "Content-Type": "application/json",
    "Date": email.utils.formatdate(usegmt=True),
}
body = '{"key": "value"}'
key_id = "https://example.com/users/johndoe#main-key"

signer = Signer(
    headers=headers,
    private_key=private_key_rsa,
    method=method,
    url=url,
    key_id=key_id,
    body=body.encode("utf-8"),
)
signed_headers = signer.sign()

print(signed_headers)

# === Verifying ===
verifier = Verifier(
    public_pem=public_key_rsa_pem.decode("utf-8"),
    method=method,
    url=url,
    headers=signed_headers,
    body=body.encode("utf-8"),
)
verified_key_id = verifier.verify(raise_on_fail=True)

print(f"Verified with key: {verified_key_id}")

Object Integrity Proofs (proof)

This is used for signing JSON objects (like ActivityStreams objects).

from apsig import ProofSigner, ProofVerifier

# === Signing ===
json_object = {
    "@context": [
        "https://www.w3.org/ns/activitystreams",
        "https://w3id.org/security/data-integrity/v1",
    ],
    "id": "https://server.example/objects/1",
    "type": "Note",
    "content": "Hello world",
}
proof_options = {
    "type": "DataIntegrityProof",
    "cryptosuite": "eddsa-jcs-2022",
    "verificationMethod": "https://example.com/keys/1",
    "created": "2024-01-01T09:00:00Z",
}

signer = ProofSigner(private_key_ed)
signed_object = signer.sign(json_object, proof_options)

print(signed_object)

# === Verifying ===
verifier = ProofVerifier(public_key_ed)
verified_key_id = verifier.verify(signed_object, raise_on_fail=True)

print(f"Verified with key: {verified_key_id}")

Linked Data Signature (LD-Signature)

This is another method for signing JSON-LD objects, often used in older ActivityPub implementations.

from apsig import LDSignature

# === Signing ===
ld_signer = LDSignature()
json_ld_object = {
    "@context": [
        "https://www.w3.org/ns/activitystreams",
        "https://w3id.org/security/v1",
    ],
    "type": "Note",
    "content": "Hello, Linked Data!",
}
creator = "https://example.com/users/johndoe#main-key"

signed_ld_object = ld_signer.sign(
    doc=json_ld_object,
    creator=creator,
    private_key=private_key_rsa
)

print(signed_ld_object)

# === Verifying ===
# The public key can be passed directly.
public_key_rsa = private_key_rsa.public_key()
verified_creator = ld_signer.verify(
    doc=signed_ld_object,
    public_key=public_key_rsa,
    raise_on_fail=True
)

print(f"Verified with creator: {verified_creator}")

Documents

The document can be viewed here.

Thanks

License

MIT License

About

Signature implementation used in ActivityPub.

Topics

Resources

License

MIT, Unknown licenses found

Licenses found

MIT
LICENSE
Unknown
COPYING.md

Security policy

Stars

Watchers

Forks

Contributors 3

  •  
  •  
  •  

Languages