Part II: Proof · Chapter 6

Digital signatures

In one sentence

A digital signature is a value only the private-key holder can compute for a message, and anyone with the public key can check that it matches that exact, unchanged message.

Who is this for

Level: Practitioner

On this page
  1. The idea
  2. How it really works
  3. At work
  4. Common mistakes
  5. Why it matters to the business
  6. Check yourself
  7. Go deeper

The idea

  • Beginner

A hash can show that a decree has not changed, but only if you trust where the hash came from. Anyone can compute a hash, so anyone who changes the decree can compute a new one. What Rosa needs is a mark that only she can make, and that anyone can check.

That is a digital signature. It uses the key pair from chapter 3 in a new way:

  • Signing. Rosa feeds the decree and her private key into a signing algorithm. Out comes a signature: a block of bytes that belongs to this decree and this key.
  • Verifying. Anyone feeds the decree, the signature and Rosa’s public key into a verifying algorithm. The answer is simply valid or invalid.

The verifier learns two things from a valid result:

  1. The decree has not changed since it was signed. Change one comma and the check fails.
  2. The signature was made with the private key that matches this public key. Nobody without that private key could have produced it.

A digital signature is very different from a handwritten one. A handwritten signature looks the same on every page, so it can be cut out and pasted onto another page. A digital signature is computed from the content, so it is different for every message. A signature taken from one decree fails on any other decree.

There are also things a signature does not do:

  • It does not hide anything. The decree stays readable. Signing is not encryption. If you want secrecy as well, you encrypt separately.
  • It does not prove the content is true or safe. It proves who held the key that signed, not that they were honest. Criminals can sign malware with their own keys.
  • It does not tell you whose key it is. It proves the signature matches this public key. Whether this public key really belongs to Rosa is a separate question, and the subject of chapter 7.

You may have heard that signing is “encrypting with the private key”. It is not, and the next section explains why that old picture misleads.

Sign with the private key, verify with the public key Rosa signs decree Rosa's private key sign signature Anyone verifies decree signature Rosa's public key verify ✓ valid decree unchanged ✗ invalid one word changed
The private key signs; the public key verifies. Any change to the message makes verification fail.

How it really works

  • Developer
  • Expert

What happens inside sign and verify?

Every modern signature scheme has the same three operations:

  • Key generation makes the key pair.
  • Sign(private key, message) → signature.
  • Verify(public key, message, signature) → valid or invalid.

Inside, the message is first hashed (usually with SHA-256), and the signature algorithm works on that hash. That is why a broken hash function breaks signatures: if two messages share a hash, a signature on one is also valid for the other. The hashes chapter explains why MD5 and SHA-1 were retired for this reason.

The three algorithms you will meet, all approved in FIPS 186-5:

RSA-PSS ECDSA (P-256) Ed25519
Standard RFC 8017, section 8.1 FIPS 186-5 RFC 8032
Public key 384-byte modulus (RSA-3072) 65 bytes 32 bytes
Signature size 384 bytes (RSA-3072) 64 bytes as two numbers, usually 70–72 bytes in DER (never more than 72) 64 bytes
Same signature each time? No (random salt) No (random per-message secret), unless deterministic Yes, deterministic
Security strength 128 bits 128 bits about 128 bits

The older RSA scheme, PKCS #1 v1.5 signatures, is still everywhere in certificates. RFC 8017 says RSASSA-PSS “is REQUIRED in new applications” and keeps v1.5 “only for compatibility with existing applications”.

Why is a signature not “encryption with the private key”?

This picture is old and still common, so it is worth taking apart.

It only half-fits textbook RSA. In raw RSA, the maths of signing is the same exponentiation as decrypting. RFC 8017, section 5.2 says the signature primitives “are the same as RSADP and RSAEP except for the names of their input and output arguments; they are distinguished as they are intended for different purposes”. But nobody uses raw RSA. Real RSA signing first encodes the hash with a signature-specific scheme (EMSA-PSS or the v1.5 signature encoding); real RSA encryption uses OAEP. They are different schemes for different jobs, and good practice is to use separate keys for signing and for encryption.

It does not fit ECDSA or Ed25519 at all. These algorithms have no encryption operation. An ECDSA signature is two numbers, r and s, computed from the hash, the private key and a one-time secret number. Verification checks an equation using the public key. Nothing is encrypted, and nothing is decrypted.

It teaches the wrong lessons. If signing were “encrypting”, a signature would hide the message (it does not), and “decrypting with the public key” would recover the message (it does not; you need the message to verify). The better mental model: signing is a computation only the private-key holder can perform; verifying is a check anyone can perform.

Why must ECDSA’s one-time secret be perfect?

Each ECDSA signature uses a fresh secret number, often called k. FIPS 186-5 explains that generating signatures with insufficient randomness in this number “would reveal a private key”. This is not only theory: on the subject of bad randomness in signing, RFC 8032 notes that “there have been numerous security failures relating to this”.

Two designs remove the risk:

  • Deterministic ECDSA (RFC 6979), also approved in FIPS 186-5, derives k from the private key and the message.
  • EdDSA (Ed25519) is deterministic by design. RFC 8032, section 8.2 says this “protects against attacks arising from signing with bad randomness”.

For you, the rule is simple: use a well-reviewed library and never write your own signing code.

Where are signatures used in PKI?

Nearly everywhere:

  • Certificates. A certificate authority signs every certificate. RFC 5280, section 4.1.1.3: the signature is “computed upon the ASN.1 DER encoded tbsCertificate”, and by signing, “the CA certifies the binding between the public key material and the subject of the certificate”. See anatomy of an X.509 certificate.
  • The TLS handshake. In TLS 1.3 (RFC 9846), the server signs the handshake transcript with its certificate key in the CertificateVerify message (section 4.5.2). That proves it holds the private key for its certificate.
  • Revocation and transparency. CRLs, OCSP responses and Certificate Transparency log entries are all signed.
  • Software and documents. Code signing, signed releases, signed PDFs and signed Git commits. See code and document signing.

At work

  • Developer
  • IT ops

Sign and verify a file with ECDSA

Make a P-256 key pair as in chapter 3, then sign with the private key and verify with the public key:

openssl genpkey -algorithm EC -pkeyopt ec_paramgen_curve:P-256 -out rosa-key.pem
openssl pkey -in rosa-key.pem -pubout -out rosa-pub.pem
openssl dgst -sha256 -sign rosa-key.pem -out decree.sig decree.txt
openssl dgst -sha256 -verify rosa-pub.pem -signature decree.sig decree.txt
Verified OK

Now change the decree from “Three ships sail at dawn.” to “Four ships sail at dawn.” and verify the same signature again:

Verification failure

The same failure appears if you verify the original decree with someone else’s public key, for example Mallory’s. A signature only matches one message and one key pair.

Look inside an ECDSA signature

The 72-byte decree.sig file is a DER structure holding the two numbers r and s:

openssl asn1parse -inform DER -in decree.sig
    0:d=0  hl=2 l=  70 cons: SEQUENCE
    2:d=1  hl=2 l=  33 prim: INTEGER           :C3A2F62927FD863DF806E0AB2C8AA6B73614F0137752B8186DF7646136D7684C
   37:d=1  hl=2 l=  33 prim: INTEGER           :C964885610080BFC6B6BA9025DF2B9CC63E4FE9B01BA510ED955D9DD7E9FE151

No hidden message, no “encrypted hash”: just two numbers that satisfy an equation with the public key. If you sign the same file twice with ECDSA, you get two different signatures, and both verify. That is the random per-message secret at work.

Sign with Ed25519

openssl dgst -sign does not accept Ed25519 keys; the OpenSSL documentation says to use pkeyutl instead, with -rawin because Ed25519 hashes the message itself:

openssl genpkey -algorithm ED25519 -out ed-key.pem
openssl pkey -in ed-key.pem -pubout -out ed-pub.pem
openssl pkeyutl -sign -inkey ed-key.pem -rawin -in decree.txt -out decree.ed.sig
openssl pkeyutl -verify -pubin -inkey ed-pub.pem -rawin -in decree.txt -sigfile decree.ed.sig
Signature Verified Successfully

The signature is exactly 64 bytes, and signing the same file again gives the identical 64 bytes, because Ed25519 is deterministic. For comparison, an RSA-PSS signature with a 3,072-bit key (openssl dgst -sha256 -sigopt rsa_padding_mode:pss -sign rsa-key.pem …) was 384 bytes.

Sign files with an SSH key

If your team already has SSH keys, OpenSSH can sign files too (ssh-keygen manual, -Y sign and -Y verify). The verifier lists trusted signers and their public keys in an allowed_signers file:

ssh-keygen -Y sign -f id_demo -n file release.txt
ssh-keygen -Y verify -f allowed_signers -I rosa@keystone.example -n file -s release.txt.sig < release.txt
Signing file release.txt
Write signature to release.txt.sig
Good "file" signature for rosa@keystone.example with ED25519 key SHA256:wcidri7t/dcJCQN+uPbylt94bdOO9A3FVoueP7Zq1xc

With a changed file, verification fails:

Signature verification failed: incorrect signature
Could not verify signature.

Notice the allowed_signers file. It is where you decide which public key belongs to rosa@keystone.example. The signature check is only as good as that decision, which is the theme of the next chapter.

Find the signature in a real certificate

Every certificate carries its issuer’s signature. Open the sample certificate in the decoder and find the signature algorithm (for example ecdsa-with-SHA256 or sha256WithRSAEncryption) and the signature value at the end.

Try it: Certificate decoderOpen the full tool

Runs in your browser. Nothing you paste is sent anywhere.

PEM text, several PEM blocks, or a .pem, .crt, .cer or .der file (drop it on the box). Certificates are public, so they are safe to paste.

What breaks in practice

  • The signing key is the crown jewel. Anyone who copies a code-signing or CA private key can sign anything as you. Keep such keys in an HSM or a cloud key service, and require approval to use them (guarding the keys).
  • Verifying against the wrong key. Verification code that accepts a public key supplied with the message, without checking whose key it is, proves nothing. Always verify against a key you trust for a separate reason, such as a certificate chain or a pinned key.
  • Signatures that outlive their certificate. A signature checked years later needs proof of when it was made. That is what timestamps are for; see code and document signing.

Common mistakes

  • “Signing is encrypting with the private key.” It only half-fits textbook RSA and does not fit ECDSA or Ed25519, which have no encryption step. Signing is its own operation: compute a value with the private key; anyone checks it with the public key.
  • “A signed message is secret.” A signature hides nothing. If you need secrecy, encrypt as well.
  • “A valid signature means the file is safe.” It means the file is unchanged since someone signed it with that key. Malware can carry a perfectly valid signature from its author’s key.
  • “A valid signature proves Rosa wrote it.” It proves that the private key matching this public key was used. If you have the wrong public key, or Rosa’s key was stolen, the check still says valid.
  • “You need the private key to verify.” Verification only ever needs the public key. The private key never leaves the signer.
  • “A signature looks the same on every document.” Each signature is computed from its message and is useless on any other message.

Why it matters to the business

  • Leader

Check yourself

Check yourself

Mallory changes one word in a decree that Rosa signed, and keeps Rosa's original signature attached. What happens when the gate verifies it with Rosa's public key?

  1. It verifies, because the signature is genuinely Rosa's
  2. Verification fails, because the signature was computed from the original decree
  3. It verifies only if the changed word is short
Show answer

Answer B Verification fails, because the signature was computed from the original decree

Check yourself

Which description of signing is accurate for RSA-PSS, ECDSA and Ed25519 alike?

  1. The private key encrypts the message so that only the public key can decrypt it
  2. The private key computes a value from the message, and anyone checks that value with the public key; nothing is encrypted or decrypted
  3. The public key signs, and the private key verifies
Show answer

Answer B The private key computes a value from the message, and anyone checks that value with the public key; nothing is encrypted or decrypted

Check yourself

A file verifies against a public key that a forum post said belongs to Rosa. What do you actually know?

  1. Rosa wrote the file and it is safe to run
  2. The file is unchanged since it was signed with the private key matching that public key; whether the key is really Rosa's is still unproven
  3. Nothing at all, because forum posts cannot carry public keys
Show answer

Answer B The file is unchanged since it was signed with the private key matching that public key; whether the key is really Rosa's is still unproven

Go deeper

In the gameLevel 6: The signatureSignet Workshop, Keystone. In development

Short on time? The crash course covers this chapter and the previous one in Lesson 3: Fingerprints and signatures.

Early edition. Checked against the standards; an independent expert review is in progress. Found a mistake? Tell us.

Last reviewed Edition 0.9