May 9 2023
Home | Cryptography by Hand | Prev | Next · |
Previously, we learned how to use one-time pads to encrypt and decrypt messages. One-time pads are powerful because they provide perfect secrecy: Encrypted messages are forever indecipherable to people who don't know (and can't guess) the message's secret keys.
However, one of the one-time pad's biggest weaknesses is its vulnerability to modification, also known as malleability. For example, if an attacker intercepts the one-time-pad-encrypted message "send $500 to me" and knows or can guess its structure or decrypted contents, the attacker can change the message to "send $999 to me", "burn your money", or any message of the same length or shorter, and send the modified message to the intended recipient. The recipient would decrypt the message but have no idea that its contents were changed.
Similarly, if the way you send encrypted messages is noisy or likely to accidentally alter your messages, the messages could get delivered with errors — a changed digit here or there. The recipient could still decrypt the messages, but they might contain nonsense. He couldn't determine whether the garbage was intentional or due to errors.
Message authentication codes (MACs) can prove (with high probability) that messages are authentic — that they have been neither tampered with nor corrupted during transmission. MACs are numbers (also called "tags") attached to messages. Recipients verify messages (check their authenticity) by recreating their MACs and comparing them to the attached MACs.
There are numerous MAC algorithms with different security guarantees. I'll describe one with excellent guarantees that you can do by hand. Unfortunately, authentication (checking whether messages are authentic) is not as straightforward as encryption: It requries long multiplication and division. You can use calculators and other aids if you wish.
Generally speaking, a message authentication code (MAC) is a number (a "tag") attached to a message. Generating and verifying a MAC requires a secret MAC key known only to a message's sender and receiver. Like one-time pad keys, MAC keys must be random and must remain absolutely secret.
When a sender wishes to send a message, he:
Calculating and attaching a MAC to a message is called signing.
When a person wishes to verify a received message, he:
If the MAC the recipient calculated matches the one attached to the message, the message is probably authentic; otherwise, the message has been altered or the sender or the receiver made a mistake calculating the MAC.
One-time pads guarantee perfect secrecy (when used correctly): Attackers cannot decrypt messages without knowing their secret keys.
However, MACs cannot 100% guarantee that messages are authentic. Even if attackers can't guess a message's secret MAC key (the key used to generate the message's MAC), they can always intercept the message, change it and its attached MAC, send the modified message along, and hope that they guessed the modified message's MAC correctly. If they do, the recipient will think the modified message is authentic. Thus no MAC can guarantee 100% certainty.
However, MACs can increase certainty arbitrarily. For example, we can guarantee with 99.99999% certainty that messages are authentic by increasing the MAC key and value sizes. If our certainty is high — or, equivalently, an attacker's chance of successfully forging a message (altering or faking a message) is low — attackers won't try to modify intercepted messages because they will probably fail. The procedure I describe below lets you choose how much certainty you want.
Use MACs whenever messages could be altered in transit (either maliciously or accidentally) or forged (altered or faked) by attackers. Generally, if you decide to use MACs, you should calculate and attach MACs to all of your messages. If you decide to create MACs for only some messages, an attacker could forge messages without MACs or strip MACs from intercepted messages; either way, the recipient would have no way to verify received messages. But if you and your partner agree to always use MACs, receiving a message without an attached MAC is immediately suspicious.
This section explains how to create MAC keys.
This MAC procedure assumes that encrypted messages (ciphertexts) are sequences of decimal digits. The procedure operates on blocks (groups) of these digits. You and your partner must choose:
When authenticating a one-time-pad-encrypted message, the encryption key's ID is considered part of the encrypted message, so you must count its digits when deciding m. Your choices will determine attackers' chances of successfully forging messages (creating messages with correct MACs attached).
Here are five suggested prime numbers for p for different block sizes b:
b | Suggested p | Maximum m |
---|---|---|
1 | 11 | 9 |
2 | 101 | 99 |
3 | 1,009 | 1,007 |
4 | 10,007 | 10,005 |
5 | 100,003 | 100,001 |
6 | 1,000,003 | 1,000,001 |
Remember, p must be at least two greater than m.
Given m and p, the probability that a message you receive is authentic is:
Equivalently, the probability that an attacker can successfully forge a message without being discovered is 1 minus that formula, or:
Here are some values for Pa(m, p) for different values of m and p:
p | |||||||
---|---|---|---|---|---|---|---|
m | log2 m | 11 | 101 | 1,009 | 10,007 | 100,003 | 1,000,003 |
2 | 1 | 81.8182 | 98.0198 | 99.8018 | 99.9800 | 99.9980 | 99.9998 |
4 | 2 | 72.7273 | 97.0297 | 99.7027 | 99.9700 | 99.9970 | 99.9997 |
8 | 3 | 63.6364 | 96.0396 | 99.6036 | 99.9600 | 99.9960 | 99.9996 |
16 | 4 | 95.0495 | 99.5045 | 99.9500 | 99.9950 | 99.9995 | |
32 | 5 | 94.0594 | 99.4054 | 99.9400 | 99.9940 | 99.9994 | |
64 | 6 | 93.0693 | 99.3062 | 99.9300 | 99.9930 | 99.9993 | |
128 | 7 | 99.2071 | 99.9201 | 99.9920 | 99.9992 | ||
256 | 8 | 99.1080 | 99.9101 | 99.9910 | 99.9991 |
After you choose b, m, and p for your key, you have to generate 2 + log2 m random numbers for your key. This section explains how to generate these numbers.
Generating a MAC key requires rolling dice. Dice notation specifies how many dice you should roll and how to combine their results. This section explains the dice notation that the rest of this document uses.
"dn" denotes rolling an n-sided die once. The result is a random number between 0 and n-1, inclusive. If the die is labeled 1 to n, subtract 1 from the roll's result. Here are some examples of dn:
"dn×c" denotes rolling an n-sided die once (the result of which is between 0 and n-1, inclusive) and multiplying the result by c. For example, "d10×103" means "roll a 10-sided die and multiply the result by 103 (1,000)."
"+" denotes addition. For example, "d10 + d12" means "add the results of rolling a 10-sided die and a 12-sided die".
You can combine operations. For example, "d2×102 + d10×10 + d10" means:
After choosing b, m, and p for your key, generate the following numbers randomly, all of which must be between 0 and p-1, inclusive:
If p is one of the primes I suggested earlier, use the dice notation formulas in this table to generate the numbers:
p | Formula for Generating a Random Number Less than p |
---|---|
11 | d12 |
101 | d2×102 + d10×10 + d10 |
1,009 | d2×103 + d10×102 + d10×10 + d10 |
10,007 | d2×104 + d10×103 + d10×102 + d10×10 + d10 |
100,003 | d2×105 + d10×104 + d10×103 + d10×102 + d10×10 + d10 |
1,000,003 | d2×106 + d10×105 + d10×104 + d10×103 + d10×102 + d10×10 + d10 |
The random numbers must be less than p. If you generated a number that is p or greater, try again.
Here is a complete MAC key for b = 3, m = 256 (log2 m = 8), and p = 1,009. Use whichever format is most convenient for you. The randomly-generated numbers are bold:
MAC Key block size: 3 p = 1009 q = 212 r = 132 1: 206 5: 729 2: 365 6: 736 3: 990 7: 208 4: 472 8: 207
MAC keys created using the procedure above can only be used once (like a one-time pad encryption key). To make it infinitely reusable, you must generate a random number between 0 and p-1, inclusive, for each message you send. (Use the random number generation procedure above.) Both the sender and receiver must know these numbers. If you encrypt messages using the one-time pad, the best place to write these numbers is on the bottoms or backs of encryption keys. Clearly separate these random numbers from the encryption keys' digits. For ease, label each such random number "z". For example, the bottom or back of a one-time pad encryption key might say "z = 755" if its random number is 755.
You and your partner need some way to determine which MAC key to use for each message. Always using the same MAC key is easiest. You could also make encryption keys specify which MAC keys to use. Or you could include MAC key IDs in your messages. The choice is yours. These instructions assume that you've chosen the correct MAC key.
The following instructions assume your MAC key is formatted like the example MAC key in the "Creating Keys" section. Adapt the instructions to your keys as necessary.
To sign (add a MAC to) a message:
For example, suppose you encrypt a message using the one-time pad. The resulting message is:
21956 85864 91266 53163 62122
(This message includes the encryption key's ID, 21956.)
To sign the message, pick a MAC key. Suppose the MAC key is:
MAC Key block size: 3 p = 1009 q = 212 r = 132 1: 206 5: 729 2: 365 6: 736 3: 990 7: 208 4: 472 8: 207
For step (2), copy the message to a piece of scratch paper.
For step (3), count the number of digits in the copied message. There are 25. This isn't evenly divisible by the MAC key's block size, b = 3; therefore, append "10" to the copied message so that the number of digits is 27, which is divisible by 3. Your scratch paper now looks like this:
21956 85864 91266 53163 62122 10
For step (4), group these digits into groups of 3 digits (because the MAC key's block size is b = 3 digits). Your scratch paper should have a line like this:
219 568 586 491 266 531 636 212 210
For step (5), count the number of groups. There are 9 groups, so prepend "009" to the list. Your scratch paper should look like this:
009 219 568 586 491 266 531 636 212 210
For step (6), treat the groups of 3 digits as integers. There are 10 integers. 10 is not 1, so you have to do step (6)'s sub-steps. Write "n = 1" on your scratch paper and do the following:
For step (6)(A), there are 10 integers, which is even. So don't add a 0 to the end of the list.
For step (6)(B), group the integers into pairs:
(9 219) (568 586) (491 266) (531 636) (212 210)For step (6)(C), find the random integer labeled "1:" on the MAC key (because n = 1), which is 206.
For step (6)(D), noting that the MAC key says that p = 1009, replace each pair of integers with (206a + b) mod 1009, where a and b are the pair's first and second integers, respectively:
(9 219) (568 586) (491 266) (531 636) (212 210) 55 550 512 41 495For step (6)(E), increment n by one and write "n = 2" on your scratch paper.
There are now 5 integers — half as many as before. You still have more than one integer, so repeat step (6)'s sub-steps:
For step (6)(A), there are 5 integers, which is odd. So append 0 to the end of the list of integers:
55 550 512 41 495 0For step (6)(B), group the integers into pairs:
(55 550) (512 41) (495 0)For step (6)(C), find the random integer labeled "2:" on the MAC key (because n = 2), which is 365.
For step (6)(D), noting that the MAC key says that p = 1009, replace each pair of integers with (365a + b) mod 1009, where a and b are the pair's first and second integers, respectively:
(55 550) (512 41) (495 0) 445 256 64For step (6)(E), increment n by one and write "n = 3" on your scratch paper.
There are now 3 integers. You still have more than one integer, so repeat step (6)'s sub-steps:
For step (6)(A), there are 3 integers, which is odd. So append 0 to the end of the list of integers:
445 256 64 0For step (6)(B), group the integers into pairs:
(445 256) (64 0)For step (6)(C), find the random integer labeled "3:" on the MAC key (because n = 3), which is 990.
For step (6)(D), noting that the MAC key says that p = 1009, replace each pair of integers with (990a + b) mod 1009, where a and b are the pair's first and second integers, respectively:
(445 256) (64 0) 882 802For step (6)(E), increment n by one and write "n = 4" on your scratch paper.
There are now 2 integers. You still have more than one integer, so repeat step (6)'s sub-steps:
For step (6)(A), there are 2 integers, which is even. So don't add a 0 to the end of the list.
For step (6)(B), group the integers into pairs:
(882 802)For step (6)(C), find the random integer labeled "4:" on the MAC key (because n = 4), which is 472.
For step (6)(D), noting that the MAC key says that p = 1009, replace each pair of integers with (472a + b) mod 1009, where a and b are the pair's first and second integers, respectively:
(882 802) 389For step (6)(E), increment n by one and write "n = 5" on your scratch paper.
Now you have one integer: 389. Proceed to step (7), which tells you to find the "q" and "r" integers on the MAC key. They are q = 212 and r = 132. Compute y = (389q + r) mod 1009 = (389 × 212 + 132) mod 1009 = 871.
For step (8), locate the number labeled "z" on the encryption key you used. Suppose z = 751. Calculate (y + z) mod 1009 = (871 + 751) mod 1009 = 613. This is the message's MAC.
For step (9), send this message to your partner, with the MAC clearly distinguished from the rest of the message (so the recipient knows it's the MAC):
21956 85864 91266 53163 62122 613
Finally, following step (10), burn the encryption key and the scratch paper. Keep the MAC key for future use.
You and your partner need some way to determine which MAC key to use for each message. Always using the same MAC key is easiest. You could also make encryption keys specify which MAC keys to use. Or you could include MAC key IDs in your messages. The choice is yours. These instructions assume that you've chosen the correct MAC key.
The following instructions assume your MAC key is formatted like the example in the "Creating Keys" section. Adapt the instructions to your keys as necessary.
To verify (check the MAC attached to) a message you've received:
You could ignore a message's MAC and simply decrypt the message: You don't need to verify a message to decrypt it. However, ignoring MACs means that you won't know for sure whether messages are genuine and unaltered. If message forgery or corruption is highly unlikely, this might be acceptable. The choice is yours.
The mathematical proof for this MAC procedure is far more complex than the one for encryption via one-time pads. I won't outline it here, but it's based on Theorem 6.2 from D. R. Stinson, "Universal hashing and authentication codes," 1992; read that if you want a detailed proof and background reading.
The additional random z number acts like a one-time pad for the MAC, making the otherwise limited-use MAC key infinitely reusable (assuming each encrypted message has its own random z value). The aforementioned paper by D. R. Stinson does not mention z.
The following programs calculate MACs using this document's procedure.
from typing import List # Compute the MAC of the specified message. # message MUST be a string sequence of decimal digits. # b, p, q, r, and key_random_digits are from the MAC key. # z is the random number attached to the message's encryption key. def mac(message: str, b: int, p: int, q: int, r: int, key_random_ints: List[int], z: int) -> int: # step (3) message += '1' + '0' * (b - (len(message) % b) - 1) # step (4) ints = [int(message[m:m+b]) for m in range(0, len(message), b)] # step (5) ints.insert(0, len(ints)) # step (6) n = 0 while len(ints) > 1: # step (6)(A) if len(ints) % 2 != 0: ints.append(0) # steps (6)(B) to (6)(D) ints = [(ints[m] * key_random_ints[n] + ints[m+1]) % p for m in range(0, len(ints), 2)] # step (6)(E) n += 1 # step (7) y = (q * ints[0] + r) % p # step (8) return (y + z) % p
# This GNU dc(1) program calculates MACs using signing steps (5) through (8). # It expects dc's main stack to contain integers # representing the message to sign followed by the "z" random number # from the encryption key (used by step signing (8)). # In other words, this program expects you to do # signing steps (3) and (4) yourself. # This is the MAC key. # The bold portions are the key's security parameters and random numbers. # The RandomNumberXXX values are the log2 m random numbers # but in reverse order (last first). p sp q sq r sr RandomNumberlog2(m) Sf RandomNumberlog2(m)-1 Sf RandomNumberlog2(m)-2 Sf # ... RandomNumber2 Sf RandomNumber1 Sf # The main program begins here. # treat the top of the stack as the "z" for step (8) sz # step (5), prepending the group count z1+sZ[Syz0<a]dsaxlZ1-[LyzlZ>a]dsax # steps (6)(B) through (6)(D) 0sn[rLfdSf*+lp%Stln1+snz0<i]si[Ltln1-dsn0<e]se # step (6), including sub-steps, repeated until 1 integer left in message [0]sP[z2%1=PlixLfsZlexz1<R]sRz1<R # steps (7) and (8) lq*lrlz++lp%pq