HackBlue

Tools · Cryptography and passwords in practice · 15 / 20

Digital signatures with Ed25519: sign, verify, and publish a public key

Create Ed25519 signatures in Python and with ssh-keygen, verify them, and understand what a signature proves and how to distribute the public key safely.

9 min read · practice only with authorization

What a signature proves

A valid signature shows that the holder of a specific private key signed exactly these bytes. It provides integrity and origin, and, if the private key is well protected, non-repudiation. It says nothing about whether the content is good, and it is only meaningful if you trust that the public key belongs to the claimed signer.

Ed25519 is a modern signature scheme with small keys and signatures (32 and 64 bytes), deterministic signing that avoids random-number failures, and fast verification.

In Python

Serialize the public key to share it, keep the private key in a protected file or KMS, and verify by catching InvalidSignature.

Snippet
from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey
from cryptography.hazmat.primitives import serialization
from cryptography.exceptions import InvalidSignature

priv = Ed25519PrivateKey.generate()
pub_pem = priv.public_key().public_bytes(serialization.Encoding.PEM, serialization.PublicFormat.SubjectPublicKeyInfo)
message = open('release.tar.gz', 'rb').read()
sig = priv.sign(message)

pub = serialization.load_pem_public_key(pub_pem)
try:
    pub.verify(sig, message)
    print('valid')
    pub.verify(sig, message + b'x')
except InvalidSignature:
    print('invalid after change')

Lab: sign files with SSH keys

OpenSSH can sign arbitrary files with ssh-keygen -Y. Create an allowed_signers file mapping an identity to your public key, sign a file, verify it, then modify the file and verify again. Git can use the same mechanism to sign commits with gpg.format ssh.

Snippet
ssh-keygen -t ed25519 -f lab_sign -N '' -C 'lab signer'
echo "lab@example.org $(cat lab_sign.pub)" > allowed_signers
ssh-keygen -Y sign -f lab_sign -n file release.tar.gz          # writes release.tar.gz.sig
ssh-keygen -Y verify -f allowed_signers -I lab@example.org -n file -s release.tar.gz.sig < release.tar.gz

git config gpg.format ssh && git config user.signingkey ~/lab_sign.pub && git commit -S -m 'signed lab commit'

Distributing the public key

Publish the public key or its fingerprint in several independent places: your website, repository README, and a profile on a code hosting site. Users who compare at least two sources make it much harder for an attacker to substitute a key.

Diagram

Signature valid versus signature meaningful

Math and trust are separate questions.

Valid

Shows. The matching private key signed these exact bytes

Requires. The public key and signature

Does not show. Who owns the key

Meaningful

Shows. The expected person or project signed it

Requires. A public key obtained and verified independently

Adds. Trust in the key’s identity

Check yourself

1. What does a valid Ed25519 signature prove?

2. Which command verifies a file signed with ssh-keygen -Y sign?

3. Why does Ed25519 avoid a class of failures seen in some ECDSA implementations?