Lesson 05 / 21
Asymmetric Encryption
The separation of the public and private key's roles: two of four possible key-operation combinations working, one giving secrecy and the other a source claim, a 190-byte upper bound in a 2048-bit modulus, the secret item count dropping from 7.69×10^7 to 12,401 at 12,401 participants and the transported secret item falling to zero, and hybrid use cutting overhead from 38 percent to 7 percent.
Published Updated
In this lesson
- Distinguishes what each of the public and private key's four possible operation combinations provides by actually running them
- Compares the asymmetric scheme's secret item count and transported secret item count with the symmetric scheme
- Measures direct asymmetric transport's size limit and calculates hybrid use's operation count
Contents
The previous lesson’s unresolved item stood in a single sentence: to start an encrypted conversation, a pre-shared secret is needed, and sharing that secret itself needs an encrypted channel. The loop cannot be broken from inside symmetric encryption, because a single key carries both the lock and the key that opens it.
This lesson splits the lock in two. Of the two keys generated together, one locks and the other unlocks; the two are not interchangeable, and one of them can be given to everyone. The split itself turns into a countable question: of the four possible key-operation combinations, which ones work, and what do the ones that work provide?
Two Keys, One Pair
CF14: in asymmetric encryption, two keys are generated together and are mathematically linked. An operation done with one is only reversed with the other; it is not reversed with the same key.
CF15: encrypting with the public key gives secrecy — only the private key’s owner can read the output. Encrypting with the private key does not give secrecy, because the public key is with everyone; what it carries is a source claim.
// asymmetric/role.mjs — which operation the public and private key perform in which // direction is actually run. A key pair is generated for the center in the fictional // regional measurement network; key material is not printed, only length and outcome are. import { generateKeyPairSync, publicEncrypt, privateDecrypt, privateEncrypt, publicDecrypt, constants } from "node:crypto"; // CF14: in asymmetric encryption, two keys are generated together; an operation done // with one is only reversed with the other, not with the same key. // CF15: encrypting with the public key gives secrecy (only the private key's owner reads // it); encrypting with the private key does not give secrecy, it carries a source claim. const BITS = 2048; const { publicKey: PUBLIC, privateKey: PRIVATE } = generateKeyPairSync("rsa", { modulusLength: BITS }); const READING = "SAY-4417|2026-03-01T06:00Z|41982"; const OAEP = { oaepHash: "sha256", padding: constants.RSA_PKCS1_OAEP_PADDING }; const attempt = (f) => { try { return f().toString() === READING ? "yes" : "no"; } catch { return "no"; } }; const printRow = (g, ...s) => console.log(s.map((v, i) => (g[i] < 0 ? String(v).padEnd(-g[i]) : String(v).padStart(g[i]))).join("")); const oaepEncrypted = publicEncrypt({ key: PUBLIC, ...OAEP }, Buffer.from(READING)); const privateEncrypted = privateEncrypt(PRIVATE, Buffer.from(READING)); const R = [-12, -12, 9, -24]; printRow(R, "encryptor", "decryptor", "worked", " provides"); for (const [a, b, f, provides] of [ ["public", "private", () => privateDecrypt({ key: PRIVATE, ...OAEP }, oaepEncrypted), "secrecy"], ["public", "public", () => publicDecrypt(PUBLIC, oaepEncrypted), "-"], ["private", "public", () => publicDecrypt(PUBLIC, privateEncrypted), "source claim"], ["private", "private", () => privateDecrypt(PRIVATE, privateEncrypted), "-"], ]) printRow(R, a, b, attempt(f), " " + provides); const CAP = BITS / 8 - 2 * 32 - 2; // upper bound for OAEP-SHA256 const fits = (n) => { try { publicEncrypt({ key: PUBLIC, ...OAEP }, Buffer.alloc(n)); return "yes"; } catch { return "no"; } }; console.log(`\nmodulus ${BITS} bits = ${BITS / 8} bytes; OAEP-SHA256 cap ${CAP} bytes`); const S = [10, 9, 14]; printRow(S, "plaintext", "fits", "cipher bytes"); for (const n of [32, CAP, CAP + 1]) printRow(S, n + " bytes", fits(n), fits(n) === "yes" ? publicEncrypt({ key: PUBLIC, ...OAEP }, Buffer.alloc(n)).length + " bytes" : "-"); console.log(`reading ${Buffer.byteLength(READING)} bytes; ciphertext form ${oaepEncrypted.length} bytes`);
encryptor decryptor worked provides public private yes secrecy public public no - private public yes source claim private private no - modulus 2048 bits = 256 bytes; OAEP-SHA256 cap 190 bytes plaintext fits cipher bytes 32 bytes yes 256 bytes 190 bytes yes 256 bytes 191 bytes no - reading 32 bytes; ciphertext form 256 bytes
Two of the four combinations work and two do not. The two rows that do not work say the same thing: an operation done with one key is not reversed with that same key. This is the one structural difference from the symmetric scheme, and the rest of the lesson counts this difference’s consequences.
The two rows that work are each other’s opposite. The encrypt with the public key, decrypt with the private key direction gives secrecy: since the public key is with everyone, anyone can send an encrypted reading to the center, but the only side that can read it is the private key’s owner. In the fictional measurement network, this means none of the 12,400 meter endpoints can read what another one sends.
The encrypt with the private key, decrypt with the public key direction, on the other hand, does not give secrecy — since the public key is with everyone, anyone can decrypt the output. What it gives is a source claim: if the decryption succeeds, the side that performed the operation is the side holding the private key. This direction is the foundation of the digital signature and is taken up in its own form in the seventh lesson.
The lower table gives asymmetric encryption’s second constraint. The modulus is 256 bytes, and the padding scheme consumes 66 bytes of it; the largest plaintext that can be transported is 190 bytes. 190 bytes works, 191 bytes does not. The output, though, is 256 bytes no matter what the input is — even a 32-byte reading grows to 256 bytes, an eightfold overhead.
The Secret Item Count and Hybrid Use
The size limit looks like an obstacle, but the real measurement is elsewhere: how many secret items does this scheme require, and how many of them are transported?
// asymmetric/item.mjs — the asymmetric scheme's effect on the secret item count and hybrid // use for large data (model + running measurement). Participant counts are fictional. import { generateKeyPairSync, publicEncrypt, privateDecrypt, randomBytes, createCipheriv, createDecipheriv, constants } from "node:crypto"; // CF16: the asymmetric scheme reduces the secret item count from n(n-1)/2 to n, and none // of the secret items are transported; the only thing transported is the public key, and it is not secret. const printRow = (g, ...s) => console.log(s.map((v, i) => (g[i] < 0 ? String(v).padEnd(-g[i]) : String(v).padStart(g[i]))).join("")); const format = (x) => x >= 1e7 ? x.toExponential(2) : Math.round(x).toLocaleString("en-US"); const A = [12, 12, 11, 11, 20, 20]; printRow(A, "participant", "symmetric", "asymmetric", "asymmetric", "transported secret", "transported secret"); printRow(A, "", "secret item", "secret", "public", "item (sym)", "item (asym)"); for (const n of [2, 7, 40, 12_401]) { const c = (n * (n - 1)) / 2; printRow(A, format(n), format(c), format(n), format(n), format(c), 0); } const { publicKey: PUBLIC, privateKey: PRIVATE } = generateKeyPairSync("rsa", { modulusLength: 2048 }); const OAEP = { oaepHash: "sha256", padding: constants.RSA_PKCS1_OAEP_PADDING }; const BATCH = Buffer.alloc(4096, 65); // fictional daily reading batch const CAP = 190; // OAEP-SHA256 upper bound const key = randomBytes(32), nonce = randomBytes(12); const cipher = createCipheriv("aes-256-gcm", key, nonce); const body = Buffer.concat([cipher.update(BATCH), cipher.final()]), tag = cipher.getAuthTag(); const envelope = publicEncrypt({ key: PUBLIC, ...OAEP }, key); const decipher = createDecipheriv("aes-256-gcm", privateDecrypt({ key: PRIVATE, ...OAEP }, envelope), nonce); decipher.setAuthTag(tag); const recovered = Buffer.concat([decipher.update(body), decipher.final()]); console.log(`\nif a ${BATCH.length}-byte batch were transported two ways:`); const B = [-16, 12, 12, 14, 10]; printRow(B, "path", "asymmetric", "symmetric", "output bytes", "overhead"); const direct = Math.ceil(BATCH.length / CAP); printRow(B, "direct RSA", direct, 0, format(direct * 256), Math.round((direct * 256 / BATCH.length - 1) * 100) + "%"); const hybrid = envelope.length + nonce.length + body.length + tag.length; printRow(B, "hybrid", 1, 1, format(hybrid), Math.round((hybrid / BATCH.length - 1) * 100) + "%"); console.log("did the hybrid path return the batch unchanged:", recovered.equals(BATCH) ? "yes" : "no");
participant symmetric asymmetric asymmetric transported secret transported secret
secret item secret public item (sym) item (asym)
2 1 2 2 1 0
7 21 7 7 21 0
40 780 40 40 780 0
12,401 7.69e+7 12,401 12,401 7.69e+7 0
if a 4096-byte batch were transported two ways:
path asymmetric symmetric output bytes overhead
direct RSA 22 0 5,632 38%
hybrid 1 1 4,380 7%
did the hybrid path return the batch unchanged: yes
The first table’s second and third columns close the previous lesson’s question. For 12,401 participants, the symmetric scheme needs 7.69×10^7 secret items while the asymmetric scheme needs 12,401 — dropping from quadratic to linear. The public key count is also 12,401, but those items are not secret, and the management cost of a non-secret item is an entirely different matter.
The real number is in the last column, and it is zero. In the symmetric scheme, every secret item has to be transported to both sides; in a 12,401-endpoint network, that means 7.69×10^7 transports, and that was the source of the manual items counted in the previous lesson. In the asymmetric scheme, no secret item is transported: each side generates its own private key itself and sends it nowhere. The only thing transported is the public key, and it can travel over an open channel.
The second table shows how the size limit is worked around. If a 4096-byte batch is transported directly with asymmetric encryption, 22 separate operations are needed and the output rises to 5,632 bytes, a 38 percent overhead. On the hybrid path, asymmetric encryption transports only a 32-byte symmetric key; the batch itself is encrypted with a symmetric mode. The operation count drops to one, the output becomes 4,380 bytes, and the overhead falls to 7 percent. The last line confirms that this path actually works.
The difference in operation count is not just a byte calculation. Asymmetric operations are many times more expensive than symmetric operations, and the direct path repeats this expensive operation 22 times for a 4-kilobyte batch. On the hybrid path, the expensive operation is done once and the whole batch is carried by the cheap operation. If the fictional network processes 12,400 batches a day, the difference between the two paths is 260,400 extra asymmetric operations a day.
The hybrid scheme’s split is clear: asymmetric encryption carries the key, symmetric encryption carries the data. Each one’s chain stays as it was in its own lesson; on the hybrid path, the chain gets longer, because now both the private key’s secrecy and the symmetric chain’s four items have to be correct at the same time.
Why Key Lengths Cannot Be Compared
The symmetric key here was 256 bits, the asymmetric key 2048 bits. The numbers cannot be read on the same scale, because the two schemes’ security comes from different places. With a symmetric key, the only path is trying the key one by one, and the cost is 2^256. With an asymmetric key, the public key is mathematically linked to the private key, and there are cheaper ways to break that link than trying one by one; the key length is made larger to counter those cheaper paths.
| Scheme | Key bits | Equivalent symmetric security | Key/output size |
|---|---|---|---|
| symmetric | 128 | 128 bit | 16 bytes |
| symmetric | 256 | 256 bit | 32 bytes |
| factoring-based | 2048 | approximately 112 bit | 256 bytes |
| factoring-based | 3072 | approximately 128 bit | 384 bytes |
| elliptic-curve-based | 256 | approximately 128 bit | 32 bytes |
The table reads as follows: a 2048-bit asymmetric key does not come close to the security a 256-bit symmetric key provides; it is equivalent to roughly a 112-bit symmetric key. To raise the equivalence, the asymmetric key has to be pushed up to 3072 bits, and that carries every operation’s output to 384 bytes.
The last line is a separate option. In the elliptic-curve-based scheme, the same equivalence is reached with a 256-bit key, that is, 32 bytes. In the fictional measurement network, this difference translates directly into an item: if 12,400 endpoints each carry a 256-byte envelope per message, the daily load is eight times what it would be with a 32-byte envelope. On constrained endpoints, what decides the choice is not the algorithm’s name, it is this size arithmetic.
The Root’s Name and the Unproven Item
The trust root here is a single item: the private key existing only with its owner. This item is born the moment the key is generated, and where that generation happens is the root’s first item. If the key pair is generated at the center and distributed to the endpoints, the private key has been transported at least once, and the previous lesson’s transport problem comes back; if each endpoint generates its own pair itself, the transported secret item count stays at zero. Generating it yourself has its own condition: the endpoint’s random number generator has to be unpredictable. In a pair generated with a predictable generator, the private key can be regenerated even if it never leaks at all. The item count that falls when the root breaks is different from the symmetric scheme. If a private key leaks, every past and future message sent to that key’s owner drops; in a network with 12,401 participants, that is all the traffic reaching the center. Renewal, though, is cheap — a new pair is generated and the public key is distributed; no secret item is transported.
Where the root sits is a separate item count. If the private key sits in a file at the center, the items that can reach it can be counted one by one: the file’s permission record, the memory of the process reading the file, its backup copy, the medium the backup travels on, and the copy the distribution automation accesses — five items. All five of the five have to be kept correct at the same time, and a flaw in any one of them opens the root.
Generating and keeping the key inside a hardware security module it never leaves changes this count. Since the key never leaves the module, there is no file to read, no backup to take, and no copy to transport; a single item remains — authorization to use the module. The item count drops from five to one. The cost is countable too: since the key cannot be exported, it cannot be backed up either, and if the module is lost, the key is lost permanently — renewal means public key distribution at 12,401 endpoints.
But there is one more item in the chain that has not been named, and this lesson does not close it. A meter endpoint uses the center’s public key to send an encrypted reading to the center. Nothing proves that public key really belongs to the center. Since the public key is not secret, it comes over an open channel, and anything that comes over an open channel can be altered. A reading encrypted with the wrong public key is read by whoever holds that key’s private counterpart.
This item is the entire subject of the course’s second topic. In this lesson it can only be counted: two of four combinations work, the secret item count drops to linear, the transported secret item is zero — and the public key’s owner is still unverified.
Summary
- The public and private key are generated together; two of four key-operation combinations work, and an operation done with one key is not reversed with the same key.
- Encrypting with the public key gives secrecy; encrypting with the private key does not give secrecy, it carries a source claim.
- In a 2048-bit modulus, the largest plaintext that can be transported is 190 bytes, and the output is 256 bytes no matter what the input is.
- The asymmetric scheme drops the secret item count from 7.69×10^7 to 12,401 at 12,401 participants; the transported secret item count is zero.
- In hybrid use, asymmetric encryption carries the key, symmetric encryption carries the data: for a 4096-byte batch, the operation count drops from 22 to 1, and the overhead drops from 38 percent to 7 percent.
- The trust root is the private key’s secrecy; who the public key belongs to is not proven in this scheme.
Next Step
The hybrid path transported the key, but the side that sent the transported key chose it. This has two consequences. First, the session key’s quality depends entirely on that side’s generator. Second, and heavier: recorded encrypted traffic is stored, and if the center’s private key leaks years later, every session key up to that point is extracted back out of its envelope, and all past traffic is opened. The next lesson actually runs, with small parameters, a method that removes both of these consequences at once: a shared secret that both sides contribute to, that never crosses the channel, and that neither side determines on its own. The items left in the eavesdropper’s hands will be counted one by one.
To keep your progress and take notes, Log in
My notes
Log in to take notes.