Contiki-NG
ccm-star.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2013, Hasso-Plattner-Institut.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  * notice, this list of conditions and the following disclaimer in the
12  * documentation and/or other materials provided with the distribution.
13  * 3. Neither the name of the Institute nor the names of its contributors
14  * may be used to endorse or promote products derived from this software
15  * without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  *
29  * This file is part of the Contiki operating system.
30  *
31  */
32 
33 /**
34  * \file
35  * AES_128-based CCM* implementation.
36  * \author
37  * Original: Konrad Krentz <konrad.krentz@gmail.com>
38  * Generified version: Justin King-Lacroix <justin.kinglacroix@gmail.com>
39  */
40 
41 #include "ccm-star.h"
42 #include "lib/aes-128.h"
43 #include <string.h>
44 
45 /* As per RFC 3610. L == 2 (m_len is two bytes long). */
46 #define CCM_STAR_AUTH_FLAGS(AUTH, MICLEN) (((AUTH) ? (1u << 6) : 0) | ((((MICLEN) - 2u) >> 1) << 3) | 1u)
47 #define CCM_STAR_ENCRYPTION_FLAGS 1
48 /* The auth data can have a variable length, but this implementation supports
49  * only the case of 0 < l(a) < (2^16 - 2^8) */
50 #define MAX_A_LEN 0xfeff
51 /* Valid values are 4, 6, 8, 10, 12, 14, and 16 octets */
52 #define MIC_LEN_VALID(x) ((x) >= 4 && (x) <= 16 && (x) % 2 == 0)
53 
54 /*---------------------------------------------------------------------------*/
55 static void
56 set_iv(uint8_t *iv,
57  uint8_t flags,
58  const uint8_t *nonce,
59  uint16_t counter)
60 {
61  iv[0] = flags;
62  memcpy(iv + 1, nonce, CCM_STAR_NONCE_LENGTH);
63  iv[14] = counter >> 8;
64  iv[15] = counter;
65 }
66 /*---------------------------------------------------------------------------*/
67 /* XORs the block m[pos] ... m[pos + 15] with K_{counter} */
68 static void
69 ctr_step(const uint8_t *nonce,
70  uint16_t pos,
71  uint8_t *m_and_result,
72  uint16_t m_len,
73  uint16_t counter)
74 {
75  uint8_t a[AES_128_BLOCK_SIZE];
76  uint8_t i;
77 
78  set_iv(a, CCM_STAR_ENCRYPTION_FLAGS, nonce, counter);
79  AES_128.encrypt(a);
80 
81  for(i = 0; (pos + i < m_len) && (i < AES_128_BLOCK_SIZE); i++) {
82  m_and_result[pos + i] ^= a[i];
83  }
84 }
85 /*---------------------------------------------------------------------------*/
86 static void
87 mic(const uint8_t *nonce,
88  const uint8_t *m, uint16_t m_len,
89  const uint8_t *a, uint16_t a_len,
90  uint8_t *result,
91  uint8_t mic_len)
92 {
93  uint8_t x[AES_128_BLOCK_SIZE];
94  uint32_t pos; /* 32-bits as can need to exceed m_len to reach end of loop */
95  uint8_t i;
96 
97  set_iv(x, CCM_STAR_AUTH_FLAGS(a_len > 0, mic_len), nonce, m_len);
98  AES_128.encrypt(x);
99 
100  if(a_len) {
101  x[0] = x[0] ^ (a_len >> 8);
102  x[1] = x[1] ^ a_len;
103  for(i = 2; (i - 2 < a_len) && (i < AES_128_BLOCK_SIZE); i++) {
104  x[i] ^= a[i - 2];
105  }
106 
107  AES_128.encrypt(x);
108 
109  pos = 14;
110  while(pos < a_len) {
111  for(i = 0; (pos + i < a_len) && (i < AES_128_BLOCK_SIZE); i++) {
112  x[i] ^= a[pos + i];
113  }
114  pos += AES_128_BLOCK_SIZE;
115  AES_128.encrypt(x);
116  }
117  }
118 
119  if(m_len) {
120  pos = 0;
121  while(pos < m_len) {
122  for(i = 0; (pos + i < m_len) && (i < AES_128_BLOCK_SIZE); i++) {
123  x[i] ^= m[pos + i];
124  }
125  pos += AES_128_BLOCK_SIZE;
126  AES_128.encrypt(x);
127  }
128  }
129 
130  ctr_step(nonce, 0, x, AES_128_BLOCK_SIZE, 0);
131 
132  memcpy(result, x, mic_len);
133 }
134 /*---------------------------------------------------------------------------*/
135 static void
136 ctr(const uint8_t *nonce, uint8_t *m, uint16_t m_len)
137 {
138  uint32_t pos; /* 32-bits as can need to exceed m_len to reach end of loop */
139  uint16_t counter;
140 
141  pos = 0;
142  counter = 1;
143  while(pos < m_len) {
144  ctr_step(nonce, pos, m, m_len, counter++);
145  pos += AES_128_BLOCK_SIZE;
146  }
147 }
148 /*---------------------------------------------------------------------------*/
149 static void
150 set_key(const uint8_t *key)
151 {
152  AES_128.set_key(key);
153 }
154 /*---------------------------------------------------------------------------*/
155 static void
156 aead(const uint8_t* nonce,
157  uint8_t* m, uint16_t m_len,
158  const uint8_t* a, uint16_t a_len,
159  uint8_t *result, uint8_t mic_len,
160  int forward)
161 {
162  if(a_len > MAX_A_LEN || !MIC_LEN_VALID(mic_len)) {
163  return;
164  }
165 
166  if(!forward) {
167  /* decrypt */
168  ctr(nonce, m, m_len);
169  }
170 
171  mic(nonce,
172  m, m_len,
173  a, a_len,
174  result,
175  mic_len);
176 
177  if(forward) {
178  /* encrypt */
179  ctr(nonce, m, m_len);
180  }
181 }
182 /*---------------------------------------------------------------------------*/
183 const struct ccm_star_driver ccm_star_driver = {
184  set_key,
185  aead
186 };
187 /*---------------------------------------------------------------------------*/
Structure of CCM* drivers.
Definition: ccm-star.h:56
CCM* header file.
void(* aead)(const uint8_t *nonce, uint8_t *m, uint16_t m_len, const uint8_t *a, uint16_t a_len, uint8_t *result, uint8_t mic_len, int forward)
Combines authentication and encryption.
Definition: ccm-star.h:73
AES-128.
void(* set_key)(const uint8_t *key)
Sets the key in use.
Definition: ccm-star.h:62
void(* set_key)(const uint8_t *key)
Sets the current key.
Definition: aes-128.h:62