December 30 2024
Home | Cryptography by Hand | Prev | Next · |
We explored a simple yet effective message authentication code (MAC) in the previous chapter. Now we'll learn an alternative way to calculate MACs that provides slightly stronger theoretical guarantees but is more difficult to calculate. I personally prefer the simpler method because you can do it by hand without complex pen-and-paper math, but if you don't mind more work, consider this chapter's method.
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