Tải bản đầy đủ - 0 (trang)
7 Representing Keys (or Other Binary Data) as English Text

7 Representing Keys (or Other Binary Data) as English Text

Tải bản đầy đủ - 0trang



/* len parameter is measured in bytes. Remaining bits padded with 0. */

unsigned char *spc_bin2words(const unsigned char *str, size_t len) {


add_space = 0;


i, leftbits, leftovers, scratch = 0, scratch_bits = 0;

unsigned char *p, *res;

res = (unsigned char *)malloc((len * 8 / BITS_IN_LIST + 1) * (MAX_WORDLEN + 1));

if (!res) abort( );

res[0] = 0;

for (i = 0; i < len; i++) {

leftovers = str[i];

leftbits = 8;

while (leftbits) {

if (scratch_bits + leftbits <= BITS_IN_LIST) {

scratch |= (leftovers << (BITS_IN_LIST - leftbits - scratch_bits));

scratch_bits += leftbits;

leftbits = 0;

} else {

scratch |= (leftovers >> (leftbits - (BITS_IN_LIST - scratch_bits)));

leftbits -= (BITS_IN_LIST - scratch_bits);

leftovers &= ((1 << leftbits) - 1);

scratch_bits = BITS_IN_LIST;


if (scratch_bits = = BITS_IN_LIST) {

p = words[scratch];

/* The strcats are a bit inefficient because they start from the front of

* the string each time. But, they're less confusing, and these strings

* should never get more than a few words long, so efficiency will

* probably never be a real concern.


if (add_space) strcat(res, " ");

strcat(res, p);

scratch = scratch_bits = 0;

add_space = 1;




if (scratch_bits) { /* Emit the final word */

p = words[scratch];

if (add_space) strcat(res, " ");

strcat(res, p);


res = (unsigned char *)realloc(res, strlen(res) + 1);

if (!res) abort( ); /* realloc failed; should never happen, as size shrinks */

return res;


To save space, the dictionary file (wordlist.h) is not provided here. Instead, you can

find it on the book’s web site.

Representing Keys (or Other Binary Data) as English Text | 129

This is the Title of the Book, eMatter Edition

Copyright © 2007 O’Reilly & Associates, Inc. All rights reserved.

The previous code is subtly incompatible with the S/KEY dictionary

because their dictionary is not in alphabetical order. (S/KEY is an

authentication system using one-time passwords.) Be sure to use the

right dictionary!

The code is written in such a way that you can use dictionaries of different sizes if

you wish to encode a different number of bits per word. Currently, the dictionary

encodes 11 bits of data (by having exactly 211 words), where no word is more than 4

characters long. The web site also provides a dictionary that encodes 13 bits of data,

where no word is more than 6 letters long. The previous code can be modified to use

the larger dictionary simply by changing the two appropriate preprocessor definitions at the top.

The algorithm takes 11 bits of the binary string, then finds the word that maps to the

unique 11-bit value. Note that it is rare for the number of bits represented by a single word to align exactly to a byte. For example, if you were to encode a 2-byte

binary string, those 16 bits would be encoded by 2 words, which could represent up

to 22 bits. Therefore, there will usually be leftover bits. In the case of 2 bytes, there

are 6 leftover bits. The algorithm sets all leftover bits to 0.

Because of this padding scheme, the output doesn’t always encode how many bytes

were in the input. For example, if the output is 6 words long, the input could have

been either 7 or 8 bytes long. Therefore, you need to manually truncate the output to

the desired length.

See Also

Recipe 4.8


Converting Text Keys to Binary Keys


A user enters a textual representation of a key or other binary data (see Recipe 4.7).

You need to convert it to binary.


Parse out the words, then look them up in the dictionary to reconstruct the actual

bits, as shown in the code included in the next section.



Chapter 4: Symmetric Cryptography Fundamentals

This is the Title of the Book, eMatter Edition

Copyright © 2007 O’Reilly & Associates, Inc. All rights reserved.


This function spc_words2bin() uses the wordlist.h file provided on the book’s web

site, and it can be changed as described in Recipe 4.7.






#define BITS_IN_LIST 11

#define MAX_WORDLEN 4

unsigned char *spc_words2bin(unsigned char *str, size_t *outlen) {


cmp, i;


bitsinword, curbits, needed, reslen;

unsigned int ix, min, max;

unsigned char *p = str, *r, *res, word[MAX_WORDLEN + 1];

curbits = reslen = *outlen = 0;

if(!(r = res = (unsigned char *)malloc((strlen(str) + 1) / 2))

return 0;

memset(res, 0, (strlen(str) + 1) / 2);

for (;;) {

while (isspace(*p)) p++;

if (!*p) break;

/* The +1 is because we expect to see a space or a NULL after each and every

* word; otherwise, there's a syntax error.


for (i = 0; i < MAX_WORDLEN + 1; i++) {

if (!*p || isspace(*p)) break;

if (islower(*p)) word[i] = *p++ - ' ';

else if (isupper(*p)) word[i] = *p++;

else {


return 0;



if (i = = MAX_WORDLEN + 1) {


return 0;


word[i] = 0;

min = 0;

max = (1 << BITS_IN_LIST) - 1;

do {

if (max < min) {


return 0; /* Word not in list! */


ix = (max + min) / 2;

cmp = strcmp(word, words[ix]);

Converting Text Keys to Binary Keys | 131

This is the Title of the Book, eMatter Edition

Copyright © 2007 O’Reilly & Associates, Inc. All rights reserved.

if (cmp > 0) min = ix + 1;

else if (cmp < 0) max = ix - 1;

} while (cmp);

bitsinword = BITS_IN_LIST;

while (bitsinword) {

needed = 8 - curbits;

if (bitsinword <= needed) {

*r |= (ix << (needed - bitsinword));

curbits += bitsinword;

bitsinword = 0;

} else {

*r |= (ix >> (bitsinword - needed));

bitsinword -= needed;

ix &= ((1 << bitsinword) - 1);

curbits = 8;


if (curbits = = 8) {

curbits = 0;

*++r = 0;





if (curbits && *r) {


return 0; /* Error, bad format, extra bits! */


*outlen = reslen;

return (unsigned char *)realloc(res, reslen);


The inputs to the spc_words2bin( ) function are str, which is the English representation of the binary string, and outlen, which is a pointer to how many bytes are in the

output. The return value is a binary string of length len. Note that any bits encoded

by the English words that don’t compose a full byte must be zero, but are otherwise


You must know a priori how many bytes you expect to get out of this function. For

example, 6 words might map to a 56-bit binary string or to a 64-bit binary string (5

words can encode at most 55 bits, and 6 words encodes up to 66 bits).

See Also

Recipe 4.7



Chapter 4: Symmetric Cryptography Fundamentals

This is the Title of the Book, eMatter Edition

Copyright © 2007 O’Reilly & Associates, Inc. All rights reserved.


Using Salts, Nonces, and Initialization



You want to use an algorithm that requires a salt, a nonce or an initialization vector

(IV). You need to understand the differences among these three things and figure out

how to select good specimens of each.


There’s a lot of terminology confusion, and the following “Discussion” section contains our take on it. Basically, salts and IVs should be random, and nonces are usually sequential, potentially with a random salt as a component, if there is room. With

sequential nonces, you need to ensure that you never repeat a single {key, nonce}


To get good random values, use a well-seeded, cryptographically strong pseudo-random number generator (see the appropriate recipes in Chapter 11). Using that, get

the necessary number of bits. For salt, 64 bits is sufficient. For an IV, get one of the

requisite size.


Salts, nonces, and IVs are all one-time values used in cryptography that don’t need to

be secret, but still lead to additional security. It is generally assumed that these values are visible to attackers, even if it is sometimes possible to hide them. At the very

least, the security of cryptographic algorithms and protocols should not depend on

the secrecy of such values.

We try to be consistent with respect to this terminology in the book.

However, in the real world, even among cryptographers there’s a lot of

inconsistency. Therefore, be sure to follow the directions in the documentation for whatever primitive you’re using.


Salt is random data that helps protect against dictionary and other precomputation

attacks. Generally, salt is used in password-based systems and is concatenated to the

front of a password before processing. Password systems often use a one-way hash

function to turn a password into an “authenticator.” In the simplest such system, if

there were no salt, an attacker could build a dictionary of common passwords and

just look up the original password by authenticator.

Using Salts, Nonces, and Initialization Vectors | 133

This is the Title of the Book, eMatter Edition

Copyright © 2007 O’Reilly & Associates, Inc. All rights reserved.

The use of salt means that the attacker would have to produce a totally separate dictionary for every possible salt value. If the salt is big enough, it essentially makes dictionary attacks infeasible. However, the attacker can generally still try to guess every

password without using a stronger protocol. For a discussion of various passwordbased authentication technologies, see Recipe 8.1.

If the salt isn’t chosen at random, certain dictionaries will be more likely than others. For this reason, salt is generally expected to be random.

Salt can be generated using the techniques discussed in Chapter 11.


Nonces* are bits of data often input to cryptographic protocols and algorithms,

including many message authentication codes and some encryption modes. Such values should only be used a single time with any particular cryptographic key. In fact,

reuse generally isn’t prohibited, but the odds of reuse need to be exceptionally low.

That is, if you have a nonce that is very large compared to the number of times you

expect to use it (e.g., the nonce is 128 bits, and you don’t expect to use it more than

232 times), it is sufficient to choose nonces using a cryptographically strong pseudorandom number generator.

Sequential nonces have a few advantages over random nonces:

• You can easily guarantee that nonces are not repeated. Note, though, that if the

possible nonce space is large, this is not a big concern.

• Many protocols already send a unique sequence number for each packet, so one

can save space in transmitted messages.

• The sequential ordering of nonces can be used to prevent replay attacks, but

only if you actually check to ensure that the nonce is always incrementing. That

is, if each message has a nonce attached to it, you can tell whether the message

came in the right order, by looking at the nonce and making sure its value is

always incrementing.

However, randomness in a nonce helps prevent against classes of attacks that amortize work across multiple keys in the same system.

We recommend that nonces have both a random portion and a sequential portion.

Generally, the most significant bytes should be random, and the final 6 to 8 bytes

should be sequential. An 8-byte counter can accommodate 264 messages without the

counter’s repeating, which should be more than big enough for any system.

If you use both a nonce and a salt, you can select a single random part for each key

you use. The nonce on the whole has to be unique, but the salt can remain fixed for

* In the UK, “nonce” is slang for a child sex offender. However, this term is widespread in the cryptographic

world, so we use it.



Chapter 4: Symmetric Cryptography Fundamentals

This is the Title of the Book, eMatter Edition

Copyright © 2007 O’Reilly & Associates, Inc. All rights reserved.

Tài liệu bạn tìm kiếm đã sẵn sàng tải về

7 Representing Keys (or Other Binary Data) as English Text

Tải bản đầy đủ ngay(0 tr)