Tải bản đầy đủ - 0 (trang)
11 Using OMAC (a Simple Block Cipher–Based MAC)

11 Using OMAC (a Simple Block Cipher–Based MAC)

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

OMAC has been explicitly specified for AES, and it is easy to adapt to any 128-bit

block cipher. It is possible, but a bit more work, to get it working with ciphers with

64-bit blocks. In this section, we only cover using OMAC with AES.

The basic idea behind using CBC mode as a MAC is to encrypt a message in CBC

mode and throw away everything except the very last block of output. That’s not

generally secure, though. It only works when all messages you might possibly process are a particular size.

Besides OMAC, there are several MACs that try to fix the CBC-MAC problem,

including XCBC-MAC, TMAC, and RMAC:

RMAC

RMAC (the R stands for randomized) has security issues in the general case, and

is not favored by the cryptographic community.*

XCBC-MAC

XCBC-MAC (eXtended CBC-MAC) is the foundation for TMAC and OMAC,

but it uses three different keys.

TMAC

TMAC uses two keys (thus the T in the name).

OMAC is the first good CBC-MAC derivative that uses a single key. OMAC works

the same way CBC-MAC does until the last block, where it XORs the state with an

additional value before encrypting. That additional value is derived from the result of

encrypting all zeros, and it can be performed at key setup time. That is, the additional value is key-dependent, not message-dependent.

OMAC is actually the name of a family of MAC algorithms. There are two concrete

versions, OMAC1 and OMAC2, which are slightly different but equally secure.

OMAC1 is slightly preferable because its key setup can be done a few cycles more

quickly than OMAC2’s key setup. NIST is expected to standardize on OMAC1.

First, we provide an incremental API for using OMAC. This code requires linking

against an AES implementation, and also that the macros developed in Recipe 5.5 be

defined (they bridge the API of your AES implementation with this book’s API). The

secure memory function spc_memset( ) from Recipe 13.2 is also required.

To use this API, you must instantiate an SPC_OMAC_CTX object and pass it to the various API functions. To initialize the context, call either spc_omac1_init( ) or spc_

omac2_init( ), depending on whether you want to use OMAC1 or OMAC2. The initialization functions always return success unless the key length is invalid, in which

case they return 0. Successful initialization is indicated by a return value of 1.



* Most importantly, RMAC requires the underlying block cipher to protect against related-key attacks, where

other constructs do not. Related-key attacks are not well studied, so it’s best to prefer constructs that can

avoid them when possible.



Using OMAC (a Simple Block Cipher–Based MAC) | 281

This is the Title of the Book, eMatter Edition

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



int spc_omac1_init(SPC_OMAC_CTX *ctx, unsigned char *key, int keylen);

int spc_omac2_init(SPC_OMAC_CTX *ctx, unsigned char *key, int keylen);



These functions have the following arguments:

ctx



Context object to be initialized.

key



Block cipher key.

keylen



Length of the key in bytes. The length of the key must be 16, 24, or 32 bytes; any

other key length is invalid.

Once initialized, spc_omac_update( ) can be used to process data. Note that the only

differences between OMAC1 and OMAC2 in this implementation are handled at key

setup time, so they both use the same functions for updating and finalization. Multiple calls to spc_omac_update( ) act just like making a single call where all of the data

was concatenated together. Here is its signature:

void spc_omac_update(SPC_OMAC_CTX *ctx, unsigned char *in, size_t il);



This function has the following arguments:

ctx



Context object to use for the current message.

in



Buffer that contains the data to be processed.

il



Length of the data buffer to be processed in bytes.

To obtain the output of the MAC operation, call spc_omac_final( ), which has the

following signature:

int spc_omac_final(SPC_OMAC_CTX *ctx, unsigned char *out);



This function has the following arguments:

ctx



Context object to be finalized.

out



Buffer into which the output will be placed. This buffer must be at least 16 bytes

in size. No more than 16 bytes will ever be written to it.

Here is the code implementing OMAC:

#include

typedef struct {

SPC_KEY_SCHED ks;

int

ix;

unsigned char iv[SPC_BLOCK_SZ];



282



|



Chapter 6: Hashes and Message Authentication

This is the Title of the Book, eMatter Edition

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



unsigned char c1[SPC_BLOCK_SZ]; /* L * u */

unsigned char c2[SPC_BLOCK_SZ]; /* L / u */

} SPC_OMAC_CTX;

int spc_omac1_init(SPC_OMAC_CTX *ctx, unsigned char *key, int keylen) {

int

condition, i;

unsigned char L[SPC_BLOCK_SZ] = {0,};

if (keylen != 16 && keylen != 24 && keylen != 32) return 0;

SPC_ENCRYPT_INIT(&(ctx->ks), key, keylen);

SPC_DO_ENCRYPT(&(ctx->ks), L, L);

spc_memset(ctx->iv, 0, SPC_BLOCK_SZ);

ctx->ix = 0;

/* Compute L * u */

condition = L[0] & 0x80;

ctx->c1[0] = L[0] << 1;

for (i = 1; i < SPC_BLOCK_SZ; i++) {

ctx->c1[i - 1] |= L[i] >> 7;

ctx->c1[i]

= L[i] << 1;

}

if (condition) ctx->c1[SPC_BLOCK_SZ - 1] ^= 0x87;

/* Compute L * u * u */

condition = ctx->c1[0] & 0x80;

ctx->c2[0] = ctx->c1[0] << 1;

for (i = 1; i < SPC_BLOCK_SZ; i++) {

ctx->c2[i - 1] |= ctx->c1[i] >> 7;

ctx->c2[i]

= ctx->c1[i] << 1;

}

if (condition) ctx->c2[SPC_BLOCK_SZ - 1] ^= 0x87;

spc_memset(L, 0, SPC_BLOCK_SZ);

return 1;

}

int spc_omac2_init(SPC_OMAC_CTX *ctx, unsigned char *key, int keylen) {

int

condition, i;

unsigned char L[SPC_BLOCK_SZ] = {0,};

if (keylen != 16 && keylen != 24 && keylen != 32) return 0;

SPC_ENCRYPT_INIT(&(ctx->ks), key, keylen);

SPC_DO_ENCRYPT(&(ctx->ks), L, L);

spc_memset(ctx->iv, 0, SPC_BLOCK_SZ);

ctx->ix = 0;

/* Compute L * u, storing it in c1 */

condition = L[0] >> 7;

ctx->c1[0] = L[0] << 1;

for (i = 1; i < SPC_BLOCK_SZ; i++) {

ctx->c1[i - 1] |= L[i] >> 7;

ctx->c1[i]

= L[i] << 1;

}



Using OMAC (a Simple Block Cipher–Based MAC) | 283

This is the Title of the Book, eMatter Edition

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



if (condition) ctx->c1[SPC_BLOCK_SZ - 1] ^= 0x87;

/* Compute L * u ^ -1, storing it in c2 */

condition = L[SPC_BLOCK_SZ - 1] & 0x01;

i = SPC_BLOCK_SZ;

while (--i) ctx->c2[i] = (L[i] >> 1) | (L[i - 1] << 7);

ctx->c2[0] = L[0] >> 1;

L[0] >>= 1;

if (condition) {

ctx->c2[0]

^= 0x80;

ctx->c2[SPC_BLOCK_SZ - 1] ^= 0x43;

}

spc_memset(L, 0, SPC_BLOCK_SZ);

return 1;

}

void spc_omac_update(SPC_OMAC_CTX *ctx, unsigned char *in, size_t il) {

int i;

if (il < SPC_BLOCK_SZ - ctx->ix) {

while (il--) ctx->iv[ctx->ix++] ^= *in++;

return;

}

if (ctx->ix) {

while (ctx->ix < SPC_BLOCK_SZ) --il, ctx->iv[ctx->ix++] ^= *in;

SPC_DO_ENCRYPT(&(ctx->ks), ctx->iv, ctx->iv);

}

while (il > SPC_BLOCK_SZ) {

for (i = 0; i < SPC_BLOCK_SZ / sizeof(int); i++)

((unsigned int *)(ctx->iv))[i] ^= ((unsigned int *)in)[i];

SPC_DO_ENCRYPT(&(ctx->ks), ctx->iv, ctx->iv);

in += SPC_BLOCK_SZ;

il -= SPC_BLOCK_SZ;

}

for (i = 0; i < il; i++) ctx->iv[i] ^= in[i];

ctx->ix = il;

}

int spc_omac_final(SPC_OMAC_CTX *ctx, unsigned char *out) {

int i;

if (ctx->ix != SPC_BLOCK_SZ) {

ctx->iv[ctx->ix] ^= 0x80;

for (i = 0; i < SPC_BLOCK_SZ / sizeof(int); i++)

((int *)ctx->iv)[i] ^= ((int *)ctx->c2)[i];

} else {

for (i = 0; i < SPC_BLOCK_SZ / sizeof(int); i++)

((int *)ctx->iv)[i] ^= ((int *)ctx->c1)[i];

}

SPC_DO_ENCRYPT(&(ctx->ks), ctx->iv, out);

return 1;

}



For those interested in the algorithm itself, note that we precompute two special values at key setup time, both of which are derived from the value we get from encrypt284



|



Chapter 6: Hashes and Message Authentication

This is the Title of the Book, eMatter Edition

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



ing the all-zero data block. Each precomputed value is computed by using a 128-bit

shift and a conditional XOR. The last block of data is padded, if necessary, and

XOR’d with one of these two values, depending on its length.

Here is an all-in-one wrapper to OMAC, exporting both OMAC1 and OMAC2:

int SPC_OMAC1(unsigned char key[ ], int keylen, unsigned char in[ ], size_t l,

unsigned char out[16]) {

SPC_OMAC_CTX c;

if (!spc_omac1_init(&c, key, keylen)) return 0;

spc_omac_update(&c, in, l);

spc_omac_final(&c, out);

return 1;

}

int SPC_OMAC2(unsigned char key[ ], int keylen, unsigned char in[ ], size_t l,

unsigned char out[16]) {

SPC_OMAC_CTX c;

if (!spc_omac2_init(&c, key, keylen)) return 0;

spc_omac_update(&c, in, l);

spc_omac_final(&c, out);

return 1;

}



See Also

Recipes 5.5, 6.7, 6.9, 13.2



6.12 Using HMAC or OMAC with a Nonce

Problem

You want to use HMAC or OMAC, but improve its resistance to birthday attacks

and capture replay attacks.



Solution

Use an ever-incrementing nonce that is concatenated to your message.



Discussion

Be sure to actually test the nonce when validating the nonce value, so

as to thwart capture replay attacks. (See Recipe 6.21.)



Using HMAC or OMAC with a Nonce | 285

This is the Title of the Book, eMatter Edition

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



If you’re using an off-the-shelf HMAC implementation, such as OpenSSL’s or CryptoAPI’s, you can easily concatenate your nonce to the beginning of your message.

You should use a nonce that’s at least half as large as your key size, if not larger. Ultimately, we would recommend that any nonce contain a message counter that is 64

bits (it can be smaller if you’re 100% sure you’ll never use every counter value) and a

random portion that is at least 64 bits. The random portion can generally be chosen

per session instead of per message.

Here’s a simple wrapper that provides a nonced all-in-one version of OMAC1, using

the implementation from Recipe 6.11 and a 16-byte nonce:

void spc_OMAC1_nonced(unsigned char key[ ], int keylen, unsigned char in[ ],

size_t l, unsigned char nonce[16], unsigned char out[16]) {

SPC_OMAC_CTX c;

if (!spc_omac1_init(&c, key, keylen)) abort( );

spc_omac_update(&c, nonce, 16);

spc_omac_update(&c, in, l);

spc_omac_final(&c, out);

}



See Also

Recipes 6.11, 6.21



6.13 Using a MAC That’s Reasonably Fast in

Software and Hardware

Problem

You want to use a MAC that is fast in both software and hardware.



Solution

Use CMAC. It is available from http://www.zork.org/cmac/.



Discussion

Be sure to look at our generic recommendations for using a MAC (see

Recipe 6.9).



286



|



Chapter 6: Hashes and Message Authentication

This is the Title of the Book, eMatter Edition

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



CMAC is the message-integrity component of the CWC encryption mode. It is based

on a universal hash function that is similar to hash127. It requires an 11-byte nonce

per message. The Zork implementation has the following API:

int cmac_init(cmac_t *ctx, unsigned char key[16]);

void cmac_mac(cmac_t *ctx, unsigned char *msg, u_int32 msglen,

unsigned char nonce[11], unsigned char output[16]);

void cmac_cleanup(cmac_t *ctx);

void cmac_update(cmac_t *ctx, unsigned char *msg, u_int32 msglen);

void cmac_final(cmac_t *ctx, unsigned char nonce[11], unsigned char output[16]);



The cmac_t type keeps track of state and needs to be initialized only when you key

the algorithm. You can then make messages interchangeably using the all-in-one API

or the incremental API.

The all-in-one API consists of the cmac_mac( ) function. It takes an entire message and

a nonce as arguments and produces a 16-byte output. If you want to use the incremental API, cmac_update( ) is used to pass in part of the message, and cmac_final( )

is used to set the nonce and get the resulting tag. The cmac_cleanup( ) function

securely erases the context object.

To use the CMAC API, just copy the cmac.h and cmac.c files, and compile and link

against cmac.c.



See Also

• The CMAC home page: http://www.zork.org/cmac/

• Recipe 6.9



6.14 Using a MAC That’s Optimized for Software

Speed

Problem

You want to use the MAC that is fastest in software.



Solution

Use a MAC based on Dan Bernstein’s hash127, as discussed in the next section. The

hash127 library is available from http://cr.yp.to.



Using a MAC That’s Optimized for Software Speed | 287

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ề

11 Using OMAC (a Simple Block Cipher–Based MAC)

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

×