I offer $5 per error to the first person who reports an technical error in my books. Here are some reported for this book.
Changes to First Addition
Additions
- Anyone interested in the description of the private accounting mechanism in Chapter 11 may want to check out some of the privacy homomorphisms here:
Rivest, R. L., L. Adleman, and M. L. Dertouzos, ``On data banks and privacy homomorphisms,'' Foundations of Secure Computation (edited by R. DeMillo, D. Dobkin, A. Jones, and R. Lipton) (New York: Academic Press, 1978), 169-180.
There are a number of other neat randomized privacy homomorphisms in the literature. - Section 2.4.2 describes some of the mechanisms built into Postgres. One reader suggests that people take note of Postgres's ability to use stored procedures written in Perl. This is an easy way to add encryption or hashing.
- Another reader suggests that I amplify the message about the quality of some of the built-in encryption in MySQL. While I use the built-in Encrypt or Encode features, I note that they're based on either proprietary or relatively antique technologies. The best algorithms aren't represented, although this should change. Please be advised that I don't recommend using Encode or Encrypt for data that must be seriously protected. Both are relatively weak. Try a modern function like AES.
Errors and Corrections
The first person to write in with a technical error will receive a $5 reward. Please keep your eyes open. Here are the conditions:
- Only the first person to submit an error will get paid. I reserve the right to issue multiple rewards if several people submit answers around the same time. The condition only exists to prevent people from minting money by telling all of their friends to send in a submission.
- The rewards only apply to technical errors. Grammatical corrections are welcome, but I think the field is too ambiguous to judge accurately.
- This offer is subject to withdrawal at any time.
Watch this space. I'll post all notices of corrections here. Thank you.
| Page | Technical Error | Thanks Go To |
| 16 | every bit in p should be every bit in x | Mike Morton |
| 32 | adding in digits does not add a factor of 10^i; the factor is (62/52)^i | Mike Morton |
| Throughout | MD5 is generally considered to be insecure. It is better to use a newer hash function like the NIST standard SHA1. | -- |
| Throughout | When a key is used to add some extra "salt" or complexity to a hash function, f(x), it's important that the key be appended to the end of x. There are several length extension attacks on hash functions that can work on situations when the key is applied to the front. | -- |
Typographical Errors
Here are some typographical errors reported by kind readers Mike Blackwell, Tim Lord, Mike Morton, and Michael Swiercz. If you spot any new ones, please send them along. Please accept my apologies about these.
| Page | Typographical Error |
| 8 | whetehr should be whether |
| 10 | the world of cryptography researcher should be research |
| 11 | "A spokesman said the act was approved and could lead..." should be "A spokesman said the act was not approved and could lead..." |
| 13 | User scrambles should be A user... or The user... ? |
| 15 | ex nihilio should be ex nihilo |
| 17 | ,like SHA should be like SHA with no comma. |
| 30 | person's address |
| 30 | The first sentence of section 3.2 was included by mistake. It's not really a sentence but some terms for the index. They should have been invisible. |
| 30 | Pittsburg should be Pittsburgh |
| 31 | newline may be one word |
| 31 | asterix is French; asterisk is English |
| 33 | The first partial sentence in section 3.3.1 shouldn't be there. |
| 47 | The italic 'f' makes info look like in f o [two places on this page] |
| 48 | the first INSERT INTO lacks the word INSERT |
| 49 | inscrutible should be inscrutable |
| 57-- | babysitter may be one word to some |
| 61 | in tht way should be in that way |
| 71 | lookup up bids should be lookup bids |
| 71 | functiondoes should be function does |
| 78 | round off errors should be roundoff errors |
| 79 | amoung should be among |
| 79 | XORing is XOR'ing elsewhere |
| 79 | Similar solution should be A similar solution |
| 89 | predications should be predictions |
| 89 | Superbowl is two words, Super Bowl ( see, e.g., http://www.superbowl.com/) |
| 89 | I it invented should be I invented it . |
| 98 | everyone all players their predictions should be all players reveal their predictions |
| 99 | predictionsm should be predictions |
| 99 | ticks should be tics in this sense |
| 110 | card sbefore should be cards before |
| 112 | can later reveal it to claim should be can later reveal it to claim the pot. |
| 117 | pointspread should be point spread |
| 119 | Spindoctor should be SpinDoctor |
| 121 | there's a spare int at the end of setInt(5,lod); |
| 125 | Some might say study-wide, not studywide |
| 150 | discrepaencies should be discrepancies |
| 151 | itmes should be items |
| 157 | That is an more should be ...a more |
| 157 | occassionally should be occasionally |
| 158 | Some say the title is Loves Labor Lost, with no possessive. |
| 169 | I think distracter should be distraction |
| 169 | prinicples should be principles |
| 170 | repeats the basic algorithm log2n should have times after it |
| 170 | mod pm provided by the database should be mod p ... ? |
| 171 | use more decoy should be decoys |
| 177 | BIM00: servers computation should be server's computation |
| 177 | Bra95: Publike |
| 179 | personallyidentifying should be personally identifying |
Code Issues
Thanks to Ilias Aberkane for these. I have not had the time to validate some of these and I welcome any further insight.
Ch. 8.2.2 (Placing Bets)
Lottery.makeBet β the retry loop can never escape on a collision. "num" is drawn once before the do-while; when buildCoin(num) answers "Invalid serial number. Choose again.", the loop calls buildCoin(num) again with the very same num, which still fails β so one taken serial number means an infinite loop. A new draw of num inside the loop would fix it. (Minor aside: ran.nextInt() also returns negative values, so serial numbers can come out negative.)
Ch. 8.2.3 (Testing Winners)
Lottery.testBet β the SELECT is missing quotes around the string literal: "SELECT * FROM lottery WHERE name="+idHash+";" The hex idHash goes to the database unquoted, so the statement is not valid SQL and testBet can never find a stored ticket. Every other string comparison in the code (e.g. testGeeX, fetchDrugs, SitterCode) quotes the literal properly.
Ch. 8.4.3 (The License)
License.rentCar β the prepared INSERT has five placeholders (license, dateOut, dateExpected, dateBack, rate), but the code binds only parameters 1, 2, 3 and 5. Parameter 4 (dateBack) is never set, so executeUpdate() throws an SQLException every time; and the dateBack argument that is passed actually lands in dateExpected (parameter 3).
Ch. 4.2.1 (Creating a Public Key), PubKey1.insertPublicKey, and Ch. 12 (Tokens),
TokenLand.createProtocol β both run their INSERT statements through dw.executeQuery(). JDBC does not execute data-manipulation statements via executeQuery β it throws SQLException β so the rows are never inserted; insertPublicKey even returns the query string as if the insert succeeded. The sibling methods (signMessage, makeBet, addToCommissions) correctly use dw.executeUpdate().
Ch. 12, TokenLand.generateC
β the method builds the date string s = MONTH:DATE:YEAR and then never uses it; the hash is fed with now.toString() instead. So c changes on every call rather than once per day, and the constructed string is dead code.
TravelLog.java
primePump() and t2() β the sample appointments are created with `new java.util.Date(2002,2,2,12,30)` and similar calls. The deprecated Date(year,month,date,hrs,min) constructor interprets the first argument as the year minus 1900, so 2002 produces the year 3902 (and month 2 is March, since months are 0-based). Every sample appointment lands ~1900 years in the future. SitterCode.java uses Calendar correctly for the same kind of data.
TravelLog.addAppointment()
Supplementary Syllabus
Thanks to David Jamburia for these: -- The sample homework question says to extrapolate to a βcomplete 160-bit result from MD-5.β MD5 produces a 128-bit digest, not 160 bits. RFC 1321 states this explicitly: https://www.rfc-editor.org/rfc/rfc1321.html --The same question also calls `FF` a 16-bit value. `0xFF` is 8 bits; the 16-bit all-ones value would be `0xFFFF`.
`getOtherMeetings(name)` returns an empty vector for a name with no prior meetings, so `ran.nextInt() % otherPeople.size()` is a remainder-by-zero and throws ArithmeticException whenever the code reaches the fake-appointment loops. Since `before` and `howMany` are each 0 with probability 1/5, the very first call to addAppointment fails about 96% of the time.
TravelLog.pullRandomString()
int i = ran.nextInt() % v.size()` is missing the Math.abs that the sibling code uses elsewhere in the same file (e.g. the `before`, `howMany` and `with` calculations). nextInt() is negative about half the time and % keeps the sign, so elementAt(i) throws for roughly half of all calls.
SitterCode.insertWithCheck()
β the method binds all eight parameters of babysitter3Insert and then returns, but the `babysitter3Insert.executeUpdate();` call is commented out, so constructSomeDates() never inserts a single row. On top of that, parameter 2 is bound to the literal text `"ENCODE("+sitterName+",'"+messagePassword+"')"` β inside a bound parameter MySQL would store that string verbatim rather than evaluating ENCODE(), and the embedded sitterName is unquoted anyway, so it would be a syntax error even as raw SQL.
GameFace.testAll() and GameFace.revealGamePick()
β both run a SELECT and then read columns without ever calling rs.next(). A ResultSet starts before the first row, so the first getString() throws SQLException ("Before start of result set") β neither verification routine can ever print a result. Every sibling method elsewhere in the codebase does advance the cursor first (Masquerade.testName, TokenLand.testGeeX, BidManager.updateBid, ...).
NuclearLaunchCodes.recoverCode()
β splitCode() stores each share under constructMissileName(missile,"swordfish","base"+i), i.e. an MD5 hash, but recoverCode() binds the raw missile name in "SELECT code FROM base WHERE missile=?". No row ever matches, so it prints "Trouble recovering from database" four times and returns 0 β a stored code can never be recovered. (The t23() driver hits exactly this path.)
Radon1.insertIntoRadon()
β the prepared statement has six placeholders (nameID, street, zip, radon, smoke, cancer) but the code binds five, shifted one column left: setInt(3,radon) writes into `zip`, setInt(4,smoke) into `radon`, setInt(5,cancer) into `smoke`, and parameter 6 (cancer) is never bound β so executeUpdate() throws every call. And even with param 6 bound, the values would sit one column off.
CC1.bundleTransaction()
β it packs the card digits into `cc`, but then takes the "last four" from the raw input: `ccNum.substring(l-4,l)` where l = ccNum.length(). If the number arrives with a trailing space or separator, the stored last4 is e.g. "114 " instead of "2114". It should slice the packed cc (cc.substring(cc.length()-4)).