<!-- https://pkizerotohero.com/handbook/digital-signatures/ | Markdown mirror of the HTML page | PKI Zero to Hero, by Duyutech BV -->

> How digital signatures work: sign with a private key, verify with the public key. RSA-PSS, ECDSA, Ed25519, and why signing is not encrypting.

Source: https://pkizerotohero.com/handbook/digital-signatures/ · Last reviewed: 2026-10-20

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

- [Beginner](https://pkizerotohero.com/start/#beginner)
- [Developer](https://pkizerotohero.com/start/#developer)
- [IT ops](https://pkizerotohero.com/start/#itops)
- [Expert](https://pkizerotohero.com/start/#expert)
- [Leader](https://pkizerotohero.com/start/#leader)

Level: **Practitioner**

- [New to this? Start with The idea](https://pkizerotohero.com/handbook/digital-signatures/#the-idea)
- [Developer? Jump to How it really works](https://pkizerotohero.com/handbook/digital-signatures/#how-it-really-works)
- [IT ops? At work](https://pkizerotohero.com/handbook/digital-signatures/#at-work)
- [Leader? Why it matters](https://pkizerotohero.com/handbook/digital-signatures/#why-it-matters-to-the-business)

## The idea

- Beginner

A [hash](https://pkizerotohero.com/handbook/hashes/) 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](https://pkizerotohero.com/handbook/glossary/#digital-signature). It uses the [key pair](https://pkizerotohero.com/handbook/key-pairs/) 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](https://pkizerotohero.com/handbook/binding-identity/).

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.

*Diagram: Signing: the decree and Rosa's private key go into the sign step, which outputs a signature. Verifying: the decree, the signature and Rosa's public key go into the verify step. With the unchanged decree the result is valid, marked with a tick. With a changed decree the result is invalid, marked with a cross.*

The private key signs; the public key verifies. Any change to the message makes verification fail.

In the game

In the game: the signet ring

In Level 6, Rosa signs decrees at the Signet Workshop, and the town gate checks each one with her public key. A decree that a forger has altered fails at the gate, however perfect it looks. The picture is a signet ring pressed into wax: only Rosa has the ring.

**Where the picture stops being true:** a ring leaves the same imprint on every letter, so an imprint could be copied onto a forged letter. A real signature is computed from the message itself, so it is different every time and useless on any other message. And a real signature is checked with mathematics and a public key, not by eye.

## 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](https://pkizerotohero.com/handbook/hashes/) explains why MD5 and SHA-1 were retired for this reason.

The three algorithms you will meet, all approved in [FIPS 186-5](https://csrc.nist.gov/pubs/fips/186-5/final):

|  | RSA-PSS | ECDSA (P-256) | Ed25519 |
| --- | --- | --- | --- |
| Standard | [RFC 8017, section 8.1](https://www.rfc-editor.org/rfc/rfc8017#section-8.1) | FIPS 186-5 | [RFC 8032](https://www.rfc-editor.org/rfc/rfc8032) |
| 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](https://www.rfc-editor.org/rfc/rfc8017#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](https://www.rfc-editor.org/rfc/rfc6979)), 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](https://www.rfc-editor.org/rfc/rfc8032#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](https://www.rfc-editor.org/rfc/rfc5280#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](https://pkizerotohero.com/handbook/x509-certificates/).
- **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](https://www.rfc-editor.org/rfc/rfc9846#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](https://pkizerotohero.com/handbook/code-signing/).

## At work

- Developer
- IT ops

### Sign and verify a file with ECDSA

Make a P-256 key pair as in [chapter 3](https://pkizerotohero.com/handbook/key-pairs/), then sign with the private key and verify with the public key:

```bash
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
```

```text
Verified OK
```

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

```text
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*:

```bash
openssl asn1parse -inform DER -in decree.sig
```

```text
    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](https://docs.openssl.org/3.2/man1/openssl-dgst/) says to use `pkeyutl` instead, with `-rawin` because Ed25519 hashes the message itself:

```bash
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
```

```text
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](https://man.openbsd.org/ssh-keygen.1), `-Y sign` and `-Y verify`). The verifier lists trusted signers and their public keys in an `allowed_signers` file:

```bash
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
```

```text
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:

```text
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.

*Interactive tool: Certificate decoder (runs in the browser at [/tools/decoder/](https://pkizerotohero.com/tools/decoder/))*

### 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](https://pkizerotohero.com/handbook/hsm-and-key-ceremonies/)).
- **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](https://pkizerotohero.com/handbook/code-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

Why it matters to the business

Your signing keys are your signature

Digital signatures decide what your customers’ computers trust: software updates, certificates, e-invoices and contracts. If a signing key is stolen, an attacker can sign malware or documents that verify perfectly as yours, and recovering means revoking the key and re-signing everything. Signatures also do not judge content: a signed file is not a safe file. Ask your teams: which keys sign on our behalf, where are they stored, who can use them, and how would we revoke and replace one in a day? Fund hardware protection and approval steps for those keys.

## 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

What happened

The signature matches the original decree, not the changed one.

Why

A signature is computed from the hash of the exact message. Any change gives a different hash, so the old signature no longer fits.

The rule

A valid signature means the message is exactly what was signed. Any change breaks it.

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

What happened

Signing and verifying are their own operations, not encryption and decryption.

Why

ECDSA and Ed25519 have no encryption operation at all, and real RSA signatures use a different encoding from RSA encryption. A signature also does not hide the message.

The rule

Sign with the private key, verify with the public key. Signing is not 'encrypting with the private key'.

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

What happened

The signature check succeeded against a key from an untrusted source.

Why

Verification proves the link between message, signature and public key. It cannot prove who owns the public key. An impostor can post her own key under Rosa's name.

The rule

A signature proves possession of a private key. Binding that key to a name needs a trusted channel or a certificate.

## Go deeper

- [FIPS 186-5: Digital Signature Standard](https://csrc.nist.gov/pubs/fips/186-5/final): RSA, ECDSA (including deterministic ECDSA) and EdDSA as approved by NIST.
- [RFC 8017, sections 5.2 and 8](https://www.rfc-editor.org/rfc/rfc8017#section-8): RSA signature schemes, and how they differ from RSA encryption.
- [RFC 8032](https://www.rfc-editor.org/rfc/rfc8032): Ed25519 and Ed448, including why deterministic signing helps (section 8.2).
- [RFC 6979](https://www.rfc-editor.org/rfc/rfc6979): deterministic ECDSA.
- [RFC 5280, section 4.1.1.3](https://www.rfc-editor.org/rfc/rfc5280#section-4.1.1.3): what a CA’s signature on a certificate covers.
- [RFC 9846, section 4.5.2](https://www.rfc-editor.org/rfc/rfc9846#section-4.5.2): the TLS 1.3 CertificateVerify signature.
- [OpenSSL `pkeyutl` documentation](https://docs.openssl.org/3.2/man1/openssl-pkeyutl/): signing and verifying, including Ed25519 with `-rawin`.

Short on time? The crash course covers this chapter and the previous one in [Lesson 3: Fingerprints and signatures](https://pkizerotohero.com/course/fingerprints-and-signatures/).

**Early edition.** Checked against the standards; an independent expert review is in progress. Found a mistake? [Tell us](https://pkizerotohero.com/contact/?topic=content-error&page=/handbook/digital-signatures/).

Last reviewed 20 October 2026Edition 0.9

## Keep going

Crash course: [Lesson 3: Fingerprints and signatures](https://pkizerotohero.com/course/fingerprints-and-signatures/)

### How-to guides

- [How to sign code with signtool and cosign](https://pkizerotohero.com/guides/code-signing-signtool-cosign/)

### Tools

- [Certificate decoder](https://pkizerotohero.com/tools/decoder/): Paste a PEM certificate and read every field in plain words.

### Topics

- [Hashes and signatures](https://pkizerotohero.com/topics/signing/)
- [Post-quantum cryptography](https://pkizerotohero.com/topics/post-quantum/)
