1214501Srpaulo/* 2214501Srpaulo * One-key CBC MAC (OMAC1) hash with AES-128 3214501Srpaulo * 4214501Srpaulo * Copyright (c) 2003-2007, Jouni Malinen <j@w1.fi> 5214501Srpaulo * 6252726Srpaulo * This software may be distributed under the terms of the BSD license. 7252726Srpaulo * See README for more details. 8214501Srpaulo */ 9214501Srpaulo 10214501Srpaulo#include "includes.h" 11214501Srpaulo 12214501Srpaulo#include "common.h" 13214501Srpaulo#include "aes.h" 14214501Srpaulo#include "aes_wrap.h" 15214501Srpaulo 16214501Srpaulostatic void gf_mulx(u8 *pad) 17214501Srpaulo{ 18214501Srpaulo int i, carry; 19214501Srpaulo 20214501Srpaulo carry = pad[0] & 0x80; 21214501Srpaulo for (i = 0; i < AES_BLOCK_SIZE - 1; i++) 22214501Srpaulo pad[i] = (pad[i] << 1) | (pad[i + 1] >> 7); 23214501Srpaulo pad[AES_BLOCK_SIZE - 1] <<= 1; 24214501Srpaulo if (carry) 25214501Srpaulo pad[AES_BLOCK_SIZE - 1] ^= 0x87; 26214501Srpaulo} 27214501Srpaulo 28214501Srpaulo 29214501Srpaulo/** 30214501Srpaulo * omac1_aes_128_vector - One-Key CBC MAC (OMAC1) hash with AES-128 31214501Srpaulo * @key: 128-bit key for the hash operation 32214501Srpaulo * @num_elem: Number of elements in the data vector 33214501Srpaulo * @addr: Pointers to the data areas 34214501Srpaulo * @len: Lengths of the data blocks 35214501Srpaulo * @mac: Buffer for MAC (128 bits, i.e., 16 bytes) 36214501Srpaulo * Returns: 0 on success, -1 on failure 37214501Srpaulo * 38214501Srpaulo * This is a mode for using block cipher (AES in this case) for authentication. 39214501Srpaulo * OMAC1 was standardized with the name CMAC by NIST in a Special Publication 40214501Srpaulo * (SP) 800-38B. 41214501Srpaulo */ 42214501Srpauloint omac1_aes_128_vector(const u8 *key, size_t num_elem, 43214501Srpaulo const u8 *addr[], const size_t *len, u8 *mac) 44214501Srpaulo{ 45214501Srpaulo void *ctx; 46214501Srpaulo u8 cbc[AES_BLOCK_SIZE], pad[AES_BLOCK_SIZE]; 47214501Srpaulo const u8 *pos, *end; 48214501Srpaulo size_t i, e, left, total_len; 49214501Srpaulo 50214501Srpaulo ctx = aes_encrypt_init(key, 16); 51214501Srpaulo if (ctx == NULL) 52214501Srpaulo return -1; 53214501Srpaulo os_memset(cbc, 0, AES_BLOCK_SIZE); 54214501Srpaulo 55214501Srpaulo total_len = 0; 56214501Srpaulo for (e = 0; e < num_elem; e++) 57214501Srpaulo total_len += len[e]; 58214501Srpaulo left = total_len; 59214501Srpaulo 60214501Srpaulo e = 0; 61214501Srpaulo pos = addr[0]; 62214501Srpaulo end = pos + len[0]; 63214501Srpaulo 64214501Srpaulo while (left >= AES_BLOCK_SIZE) { 65214501Srpaulo for (i = 0; i < AES_BLOCK_SIZE; i++) { 66214501Srpaulo cbc[i] ^= *pos++; 67214501Srpaulo if (pos >= end) { 68214501Srpaulo e++; 69214501Srpaulo pos = addr[e]; 70214501Srpaulo end = pos + len[e]; 71214501Srpaulo } 72214501Srpaulo } 73214501Srpaulo if (left > AES_BLOCK_SIZE) 74214501Srpaulo aes_encrypt(ctx, cbc, cbc); 75214501Srpaulo left -= AES_BLOCK_SIZE; 76214501Srpaulo } 77214501Srpaulo 78214501Srpaulo os_memset(pad, 0, AES_BLOCK_SIZE); 79214501Srpaulo aes_encrypt(ctx, pad, pad); 80214501Srpaulo gf_mulx(pad); 81214501Srpaulo 82214501Srpaulo if (left || total_len == 0) { 83214501Srpaulo for (i = 0; i < left; i++) { 84214501Srpaulo cbc[i] ^= *pos++; 85214501Srpaulo if (pos >= end) { 86214501Srpaulo e++; 87214501Srpaulo pos = addr[e]; 88214501Srpaulo end = pos + len[e]; 89214501Srpaulo } 90214501Srpaulo } 91214501Srpaulo cbc[left] ^= 0x80; 92214501Srpaulo gf_mulx(pad); 93214501Srpaulo } 94214501Srpaulo 95214501Srpaulo for (i = 0; i < AES_BLOCK_SIZE; i++) 96214501Srpaulo pad[i] ^= cbc[i]; 97214501Srpaulo aes_encrypt(ctx, pad, mac); 98214501Srpaulo aes_encrypt_deinit(ctx); 99214501Srpaulo return 0; 100214501Srpaulo} 101214501Srpaulo 102214501Srpaulo 103214501Srpaulo/** 104214501Srpaulo * omac1_aes_128 - One-Key CBC MAC (OMAC1) hash with AES-128 (aka AES-CMAC) 105214501Srpaulo * @key: 128-bit key for the hash operation 106214501Srpaulo * @data: Data buffer for which a MAC is determined 107214501Srpaulo * @data_len: Length of data buffer in bytes 108214501Srpaulo * @mac: Buffer for MAC (128 bits, i.e., 16 bytes) 109214501Srpaulo * Returns: 0 on success, -1 on failure 110214501Srpaulo * 111214501Srpaulo * This is a mode for using block cipher (AES in this case) for authentication. 112214501Srpaulo * OMAC1 was standardized with the name CMAC by NIST in a Special Publication 113214501Srpaulo * (SP) 800-38B. 114214501Srpaulo */ 115214501Srpauloint omac1_aes_128(const u8 *key, const u8 *data, size_t data_len, u8 *mac) 116214501Srpaulo{ 117214501Srpaulo return omac1_aes_128_vector(key, 1, &data, &data_len, mac); 118214501Srpaulo} 119