├── AES.cpp ├── AES.h ├── AES_config.h ├── Base64.cpp ├── Base64.h ├── README.md ├── aes_encryption.ino └── iv-5-snap.png /AES.cpp: -------------------------------------------------------------------------------- 1 | #include "AES.h" 2 | 3 | /* 4 | --------------------------------------------------------------------------- 5 | Copyright (c) 1998-2008, Brian Gladman, Worcester, UK. All rights reserved. 6 | 7 | LICENSE TERMS 8 | 9 | The redistribution and use of this software (with or without changes) 10 | is allowed without the payment of fees or royalties provided that: 11 | 12 | 1. source code distributions include the above copyright notice, this 13 | list of conditions and the following disclaimer; 14 | 15 | 2. binary distributions include the above copyright notice, this list 16 | of conditions and the following disclaimer in their documentation; 17 | 18 | 3. the name of the copyright holder is not used to endorse products 19 | built using this software without specific written permission. 20 | 21 | DISCLAIMER 22 | 23 | This software is provided 'as is' with no explicit or implied warranties 24 | in respect of its properties, including, but not limited to, correctness 25 | and/or fitness for purpose. 26 | --------------------------------------------------------------------------- 27 | Issue 09/09/2006 28 | 29 | This is an AES implementation that uses only 8-bit byte operations on the 30 | cipher state (there are options to use 32-bit types if available). 31 | 32 | The combination of mix columns and byte substitution used here is based on 33 | that developed by Karl Malbrain. His contribution is acknowledged. 34 | */ 35 | 36 | /* This version derived by Mark Tillotson 2012-01-23, tidied up, slimmed down 37 | and tailored to 8-bit microcontroller abilities and Arduino datatypes. 38 | 39 | The s-box and inverse s-box were retained as tables (0.5kB PROGMEM) but all 40 | the other transformations are coded to save table space. Many efficiency 41 | improvments to the routines mix_sub_columns() and inv_mix_sub_columns() 42 | (mainly common sub-expression elimination). 43 | 44 | Only the routines with precalculated subkey schedule are retained (together 45 | with set_key() - this does however mean each AES object takes 240 bytes of 46 | RAM, alas) 47 | 48 | The CBC routines side-effect the iv argument (so that successive calls work 49 | together correctly). 50 | 51 | All the encryption and decryption routines work with plain == cipher for 52 | in-place encryption, note. 53 | 54 | */ 55 | 56 | 57 | /* functions for finite field multiplication in the AES Galois field */ 58 | 59 | /* code was modified by george spanos 60 | * 16/12/14 61 | */ 62 | 63 | // GF(2^8) stuff 64 | 65 | #define WPOLY 0x011B 66 | #define DPOLY 0x008D 67 | 68 | static const byte s_fwd [0x100] PROGMEM = 69 | { 70 | 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76, 71 | 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, 72 | 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15, 73 | 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75, 74 | 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84, 75 | 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf, 76 | 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8, 77 | 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, 78 | 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73, 79 | 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb, 80 | 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, 81 | 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08, 82 | 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a, 83 | 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e, 84 | 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf, 85 | 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16, 86 | } ; 87 | 88 | static const byte s_inv [0x100] PROGMEM = 89 | { 90 | 0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb, 91 | 0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb, 92 | 0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e, 93 | 0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25, 94 | 0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92, 95 | 0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84, 96 | 0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06, 97 | 0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b, 98 | 0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73, 99 | 0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e, 100 | 0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b, 101 | 0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4, 102 | 0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f, 103 | 0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef, 104 | 0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61, 105 | 0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d, 106 | } ; 107 | 108 | // times 2 in the GF(2^8) 109 | #define f2(x) ((x) & 0x80 ? (x << 1) ^ WPOLY : x << 1) 110 | #define d2(x) (((x) >> 1) ^ ((x) & 1 ? DPOLY : 0)) 111 | 112 | static byte s_box (byte x) 113 | { 114 | // return fwd_affine (pgm_read_byte (&inv [x])) ; 115 | return pgm_read_byte (& s_fwd [x]) ; 116 | } 117 | 118 | // Inverse Sbox 119 | static byte is_box (byte x) 120 | { 121 | // return pgm_read_byte (&inv [inv_affine (x)]) ; 122 | return pgm_read_byte (& s_inv [x]) ; 123 | } 124 | 125 | 126 | static void xor_block (byte * d, byte * s) 127 | { 128 | for (byte i = 0 ; i < N_BLOCK ; i += 4) 129 | { 130 | *d++ ^= *s++ ; // some unrolling 131 | *d++ ^= *s++ ; 132 | *d++ ^= *s++ ; 133 | *d++ ^= *s++ ; 134 | } 135 | } 136 | 137 | static void copy_and_key (byte * d, byte * s, byte * k) 138 | { 139 | for (byte i = 0 ; i < N_BLOCK ; i += 4) 140 | { 141 | *d++ = *s++ ^ *k++ ; // some unrolling 142 | *d++ = *s++ ^ *k++ ; 143 | *d++ = *s++ ^ *k++ ; 144 | *d++ = *s++ ^ *k++ ; 145 | } 146 | } 147 | 148 | // #define add_round_key(d, k) xor_block (d, k) 149 | 150 | /* SUB ROW PHASE */ 151 | 152 | static void shift_sub_rows (byte st [N_BLOCK]) 153 | { 154 | st [0] = s_box (st [0]) ; st [4] = s_box (st [4]) ; 155 | st [8] = s_box (st [8]) ; st [12] = s_box (st [12]) ; 156 | 157 | byte tt = st [1] ; 158 | st [1] = s_box (st [5]) ; st [5] = s_box (st [9]) ; 159 | st [9] = s_box (st [13]) ; st [13] = s_box (tt) ; 160 | 161 | tt = st[2] ; st [2] = s_box (st [10]) ; st [10] = s_box (tt) ; 162 | tt = st[6] ; st [6] = s_box (st [14]) ; st [14] = s_box (tt) ; 163 | 164 | tt = st[15] ; 165 | st [15] = s_box (st [11]) ; st [11] = s_box (st [7]) ; 166 | st [7] = s_box (st [3]) ; st [3] = s_box (tt) ; 167 | } 168 | 169 | static void inv_shift_sub_rows (byte st[N_BLOCK]) 170 | { 171 | st [0] = is_box (st[0]) ; st [4] = is_box (st [4]); 172 | st [8] = is_box (st[8]) ; st [12] = is_box (st [12]); 173 | 174 | byte tt = st[13] ; 175 | st [13] = is_box (st [9]) ; st [9] = is_box (st [5]) ; 176 | st [5] = is_box (st [1]) ; st [1] = is_box (tt) ; 177 | 178 | tt = st [2] ; st [2] = is_box (st [10]) ; st [10] = is_box (tt) ; 179 | tt = st [6] ; st [6] = is_box (st [14]) ; st [14] = is_box (tt) ; 180 | 181 | tt = st [3] ; 182 | st [3] = is_box (st [7]) ; st [7] = is_box (st [11]) ; 183 | st [11] = is_box (st [15]) ; st [15] = is_box (tt) ; 184 | } 185 | 186 | /* SUB COLUMNS PHASE */ 187 | 188 | static void mix_sub_columns (byte dt[N_BLOCK], byte st[N_BLOCK]) 189 | { 190 | byte j = 5 ; 191 | byte k = 10 ; 192 | byte l = 15 ; 193 | for (byte i = 0 ; i < N_BLOCK ; i += N_COL) 194 | { 195 | byte a = st [i] ; 196 | byte b = st [j] ; j = (j+N_COL) & 15 ; 197 | byte c = st [k] ; k = (k+N_COL) & 15 ; 198 | byte d = st [l] ; l = (l+N_COL) & 15 ; 199 | byte a1 = s_box (a), b1 = s_box (b), c1 = s_box (c), d1 = s_box (d) ; 200 | byte a2 = f2(a1), b2 = f2(b1), c2 = f2(c1), d2 = f2(d1) ; 201 | dt[i] = a2 ^ b2^b1 ^ c1 ^ d1 ; 202 | dt[i+1] = a1 ^ b2 ^ c2^c1 ^ d1 ; 203 | dt[i+2] = a1 ^ b1 ^ c2 ^ d2^d1 ; 204 | dt[i+3] = a2^a1 ^ b1 ^ c1 ^ d2 ; 205 | } 206 | } 207 | 208 | static void inv_mix_sub_columns (byte dt[N_BLOCK], byte st[N_BLOCK]) 209 | { 210 | for (byte i = 0 ; i < N_BLOCK ; i += N_COL) 211 | { 212 | byte a1 = st [i] ; 213 | byte b1 = st [i+1] ; 214 | byte c1 = st [i+2] ; 215 | byte d1 = st [i+3] ; 216 | byte a2 = f2(a1), b2 = f2(b1), c2 = f2(c1), d2 = f2(d1) ; 217 | byte a4 = f2(a2), b4 = f2(b2), c4 = f2(c2), d4 = f2(d2) ; 218 | byte a8 = f2(a4), b8 = f2(b4), c8 = f2(c4), d8 = f2(d4) ; 219 | byte a9 = a8 ^ a1,b9 = b8 ^ b1,c9 = c8 ^ c1,d9 = d8 ^ d1 ; 220 | byte ac = a8 ^ a4,bc = b8 ^ b4,cc = c8 ^ c4,dc = d8 ^ d4 ; 221 | 222 | dt[i] = is_box (ac^a2 ^ b9^b2 ^ cc^c1 ^ d9) ; 223 | dt[(i+5)&15] = is_box (a9 ^ bc^b2 ^ c9^c2 ^ dc^d1) ; 224 | dt[(i+10)&15] = is_box (ac^a1 ^ b9 ^ cc^c2 ^ d9^d2) ; 225 | dt[(i+15)&15] = is_box (a9^a2 ^ bc^b1 ^ c9 ^ dc^d2) ; 226 | } 227 | } 228 | 229 | /******************************************************************************/ 230 | 231 | AES::AES(){ 232 | byte ar_iv[8] = { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01 }; 233 | memcpy(iv,ar_iv,8); 234 | memcpy(iv+8,ar_iv,8); 235 | arr_pad[0] = 0x01; 236 | arr_pad[1] = 0x02; 237 | arr_pad[2] = 0x03; 238 | arr_pad[3] = 0x04; 239 | arr_pad[4] = 0x05; 240 | arr_pad[5] = 0x06; 241 | arr_pad[6] = 0x07; 242 | arr_pad[7] = 0x08; 243 | arr_pad[8] = 0x09; 244 | arr_pad[9] = 0x0a; 245 | arr_pad[10] = 0x0b; 246 | arr_pad[11] = 0x0c; 247 | arr_pad[12] = 0x0d; 248 | arr_pad[13] = 0x0e; 249 | arr_pad[14] = 0x0f; 250 | } 251 | 252 | /******************************************************************************/ 253 | 254 | byte AES::set_key (byte key [], int keylen) 255 | { 256 | byte hi ; 257 | switch (keylen) 258 | { 259 | case 16: 260 | case 128: 261 | keylen = 16; // 10 rounds 262 | round = 10 ; 263 | break; 264 | case 24: 265 | case 192: 266 | keylen = 24; // 12 rounds 267 | round = 12 ; 268 | break; 269 | case 32: 270 | case 256: 271 | keylen = 32; // 14 rounds 272 | round = 14 ; 273 | break; 274 | default: 275 | round = 0; 276 | return FAILURE; 277 | } 278 | hi = (round + 1) << 4 ; 279 | copy_n_bytes (key_sched, key, keylen) ; 280 | byte t[4] ; 281 | byte next = keylen ; 282 | for (byte cc = keylen, rc = 1 ; cc < hi ; cc += N_COL) 283 | { 284 | for (byte i = 0 ; i < N_COL ; i++) 285 | t[i] = key_sched [cc-4+i] ; 286 | if (cc == next) 287 | { 288 | next += keylen ; 289 | byte ttt = t[0] ; 290 | t[0] = s_box (t[1]) ^ rc ; 291 | t[1] = s_box (t[2]) ; 292 | t[2] = s_box (t[3]) ; 293 | t[3] = s_box (ttt) ; 294 | rc = f2 (rc) ; 295 | } 296 | else if (keylen == 32 && (cc & 31) == 16) 297 | { 298 | for (byte i = 0 ; i < 4 ; i++) 299 | t[i] = s_box (t[i]) ; 300 | } 301 | byte tt = cc - keylen ; 302 | for (byte i = 0 ; i < N_COL ; i++) 303 | key_sched [cc + i] = key_sched [tt + i] ^ t[i] ; 304 | } 305 | return SUCCESS ; 306 | } 307 | 308 | /******************************************************************************/ 309 | 310 | void AES::clean () 311 | { 312 | for (byte i = 0 ; i < KEY_SCHEDULE_BYTES ; i++) 313 | key_sched [i] = 0 ; 314 | round = 0 ; 315 | } 316 | 317 | /******************************************************************************/ 318 | 319 | void AES::copy_n_bytes (byte * d, byte * s, byte nn) 320 | { 321 | while (nn >= 4) 322 | { 323 | *d++ = *s++ ; // some unrolling 324 | *d++ = *s++ ; 325 | *d++ = *s++ ; 326 | *d++ = *s++ ; 327 | nn -= 4 ; 328 | } 329 | while (nn--) 330 | *d++ = *s++ ; 331 | } 332 | 333 | /******************************************************************************/ 334 | 335 | byte AES::encrypt (byte plain [N_BLOCK], byte cipher [N_BLOCK]) 336 | { 337 | if (round) 338 | { 339 | byte s1 [N_BLOCK], r ; 340 | copy_and_key (s1, plain, (byte*) (key_sched)) ; 341 | 342 | for (r = 1 ; r < round ; r++) 343 | { 344 | byte s2 [N_BLOCK] ; 345 | mix_sub_columns (s2, s1) ; 346 | copy_and_key (s1, s2, (byte*) (key_sched + r * N_BLOCK)) ; 347 | } 348 | shift_sub_rows (s1) ; 349 | copy_and_key (cipher, s1, (byte*) (key_sched + r * N_BLOCK)) ; 350 | } 351 | else 352 | return FAILURE ; 353 | return SUCCESS ; 354 | } 355 | 356 | /******************************************************************************/ 357 | 358 | byte AES::cbc_encrypt (byte * plain, byte * cipher, int n_block, byte iv [N_BLOCK]) 359 | { 360 | while (n_block--) 361 | { 362 | xor_block (iv, plain) ; 363 | if (encrypt (iv, iv) != SUCCESS) 364 | return FAILURE ; 365 | copy_n_bytes (cipher, iv, N_BLOCK) ; 366 | plain += N_BLOCK ; 367 | cipher += N_BLOCK ; 368 | } 369 | return SUCCESS ; 370 | } 371 | 372 | /******************************************************************************/ 373 | 374 | byte AES::cbc_encrypt (byte * plain, byte * cipher, int n_block) 375 | { 376 | while (n_block--) 377 | { 378 | xor_block (iv, plain) ; 379 | if (encrypt (iv, iv) != SUCCESS) 380 | return FAILURE ; 381 | copy_n_bytes (cipher, iv, N_BLOCK) ; 382 | plain += N_BLOCK ; 383 | cipher += N_BLOCK ; 384 | } 385 | return SUCCESS ; 386 | } 387 | 388 | /******************************************************************************/ 389 | 390 | byte AES::decrypt (byte plain [N_BLOCK], byte cipher [N_BLOCK]) 391 | { 392 | if (round) 393 | { 394 | byte s1 [N_BLOCK] ; 395 | copy_and_key (s1, plain, (byte*) (key_sched + round * N_BLOCK)) ; 396 | inv_shift_sub_rows (s1) ; 397 | 398 | for (byte r = round ; --r ; ) 399 | { 400 | byte s2 [N_BLOCK] ; 401 | copy_and_key (s2, s1, (byte*) (key_sched + r * N_BLOCK)) ; 402 | inv_mix_sub_columns (s1, s2) ; 403 | } 404 | copy_and_key (cipher, s1, (byte*) (key_sched)) ; 405 | } 406 | else 407 | return FAILURE ; 408 | return SUCCESS ; 409 | } 410 | 411 | /******************************************************************************/ 412 | 413 | byte AES::cbc_decrypt (byte * cipher, byte * plain, int n_block, byte iv [N_BLOCK]) 414 | { 415 | while (n_block--) 416 | { 417 | byte tmp [N_BLOCK] ; 418 | copy_n_bytes (tmp, cipher, N_BLOCK) ; 419 | if (decrypt (cipher, plain) != SUCCESS) 420 | return FAILURE ; 421 | xor_block (plain, iv) ; 422 | copy_n_bytes (iv, tmp, N_BLOCK) ; 423 | plain += N_BLOCK ; 424 | cipher += N_BLOCK; 425 | } 426 | return SUCCESS ; 427 | } 428 | 429 | /******************************************************************************/ 430 | 431 | byte AES::cbc_decrypt (byte * cipher, byte * plain, int n_block) 432 | { 433 | while (n_block--) 434 | { 435 | byte tmp [N_BLOCK] ; 436 | copy_n_bytes (tmp, cipher, N_BLOCK) ; 437 | if (decrypt (cipher, plain) != SUCCESS) 438 | return FAILURE ; 439 | xor_block (plain, iv) ; 440 | copy_n_bytes (iv, tmp, N_BLOCK) ; 441 | plain += N_BLOCK ; 442 | cipher += N_BLOCK; 443 | } 444 | return SUCCESS ; 445 | } 446 | 447 | /*****************************************************************************/ 448 | 449 | void AES::set_IV(unsigned long long int IVCl){ 450 | memcpy(iv,&IVCl,8); 451 | memcpy(iv+8,&IVCl,8); 452 | IVC = IVCl; 453 | } 454 | 455 | /******************************************************************************/ 456 | 457 | void AES::iv_inc(){ 458 | IVC += 1; 459 | memcpy(iv,&IVC,8); 460 | memcpy(iv+8,&IVC,8); 461 | } 462 | 463 | /******************************************************************************/ 464 | 465 | int AES::get_size(){ 466 | return size; 467 | } 468 | 469 | /******************************************************************************/ 470 | 471 | void AES::set_size(int sizel){ 472 | size = sizel; 473 | } 474 | 475 | 476 | /******************************************************************************/ 477 | 478 | void AES::get_IV(byte *out){ 479 | memcpy(out,&IVC,8); 480 | memcpy(out+8,&IVC,8); 481 | } 482 | 483 | /******************************************************************************/ 484 | 485 | void AES::calc_size_n_pad(int p_size){ 486 | int s_of_p = p_size - 1; 487 | if ( s_of_p % N_BLOCK == 0){ 488 | size = s_of_p; 489 | }else{ 490 | size = s_of_p + (N_BLOCK-(s_of_p % N_BLOCK)); 491 | } 492 | pad = size - s_of_p; 493 | } 494 | 495 | /******************************************************************************/ 496 | 497 | void AES::padPlaintext(void* in,byte* out) 498 | { 499 | memcpy(out,in,size); 500 | for (int i = size-pad; i < size; i++){; 501 | out[i] = arr_pad[pad - 1]; 502 | } 503 | } 504 | 505 | /******************************************************************************/ 506 | 507 | bool AES::CheckPad(byte* in,int lsize){ 508 | if (in[lsize-1] <= 0x0f){ 509 | int lpad = (int)in[lsize-1]; 510 | for (int i = lsize - 1; i >= lsize-lpad; i--){ 511 | if (arr_pad[lpad - 1] != in[i]){ 512 | return false; 513 | } 514 | } 515 | }else{ 516 | return true; 517 | } 518 | return true; 519 | } 520 | 521 | /******************************************************************************/ 522 | 523 | void AES::printArray(byte output[],bool p_pad) 524 | { 525 | uint8_t i,j; 526 | uint8_t loops = size/N_BLOCK; 527 | uint8_t outp = N_BLOCK; 528 | for (j = 0; j < loops; j += 1){ 529 | if (p_pad && (j == (loops - 1)) ) { outp = N_BLOCK - pad; } 530 | for (i = 0; i < outp; i++) 531 | { 532 | printf_P(PSTR("%c"),output[j*N_BLOCK + i]); 533 | } 534 | } 535 | printf_P(PSTR("\n")); 536 | } 537 | 538 | /******************************************************************************/ 539 | 540 | void AES::printArray(byte output[],int sizel) 541 | { 542 | for (int i = 0; i < sizel; i++) 543 | { 544 | printf_P(PSTR("%x"),output[i]); 545 | } 546 | printf_P(PSTR("\n")); 547 | } 548 | 549 | 550 | /******************************************************************************/ 551 | 552 | void AES::do_aes_encrypt(byte *plain,int size_p,byte *cipher,byte *key, int bits, byte ivl [N_BLOCK]){ 553 | calc_size_n_pad(size_p); 554 | byte plain_p[get_size()]; 555 | padPlaintext(plain,plain_p); 556 | int blocks = get_size() / N_BLOCK; 557 | set_key (key, bits) ; 558 | cbc_encrypt (plain_p, cipher, blocks, ivl); 559 | } 560 | 561 | /******************************************************************************/ 562 | 563 | void AES::do_aes_encrypt(byte *plain,int size_p,byte *cipher,byte *key, int bits){ 564 | calc_size_n_pad(size_p); 565 | byte plain_p[get_size()]; 566 | padPlaintext(plain,plain_p); 567 | int blocks = get_size() / N_BLOCK; 568 | set_key (key, bits) ; 569 | cbc_encrypt (plain_p, cipher, blocks); 570 | } 571 | 572 | /******************************************************************************/ 573 | 574 | void AES::do_aes_decrypt(byte *cipher,int size_c,byte *plain,byte *key, int bits, byte ivl [N_BLOCK]){ 575 | set_size(size_c); 576 | int blocks = size_c / N_BLOCK; 577 | set_key (key, bits); 578 | cbc_decrypt (cipher,plain, blocks, ivl); 579 | } 580 | 581 | /******************************************************************************/ 582 | 583 | void AES::do_aes_decrypt(byte *cipher,int size_c,byte *plain,byte *key, int bits){ 584 | set_size(size_c); 585 | int blocks = size_c / N_BLOCK; 586 | set_key (key, bits); 587 | cbc_decrypt (cipher,plain, blocks); 588 | } 589 | 590 | 591 | /******************************************************************************/ 592 | 593 | #if defined(AES_LINUX) 594 | double AES::millis(){ 595 | gettimeofday(&tv, NULL); 596 | return (tv.tv_sec + 0.000001 * tv.tv_usec); 597 | } 598 | #endif 599 | -------------------------------------------------------------------------------- /AES.h: -------------------------------------------------------------------------------- 1 | #ifndef __AES_H__ 2 | #define __AES_H__ 3 | 4 | #include "AES_config.h" 5 | /* 6 | --------------------------------------------------------------------------- 7 | Copyright (c) 1998-2008, Brian Gladman, Worcester, UK. All rights reserved. 8 | 9 | LICENSE TERMS 10 | 11 | The redistribution and use of this software (with or without changes) 12 | is allowed without the payment of fees or royalties provided that: 13 | 14 | 1. source code distributions include the above copyright notice, this 15 | list of conditions and the following disclaimer; 16 | 17 | 2. binary distributions include the above copyright notice, this list 18 | of conditions and the following disclaimer in their documentation; 19 | 20 | 3. the name of the copyright holder is not used to endorse products 21 | built using this software without specific written permission. 22 | 23 | DISCLAIMER 24 | 25 | This software is provided 'as is' with no explicit or implied warranties 26 | in respect of its properties, including, but not limited to, correctness 27 | and/or fitness for purpose. 28 | --------------------------------------------------------------------------- 29 | Issue 09/09/2006 30 | 31 | This is an AES implementation that uses only 8-bit byte operations on the 32 | cipher state. 33 | */ 34 | 35 | /* code was modified by george spanos 36 | * 16/12/14 37 | */ 38 | 39 | class AES 40 | { 41 | public: 42 | 43 | /* The following calls are for a precomputed key schedule 44 | 45 | NOTE: If the length_type used for the key length is an 46 | unsigned 8-bit character, a key length of 256 bits must 47 | be entered as a length in bytes (valid inputs are hence 48 | 128, 192, 16, 24 and 32). 49 | */ 50 | /** \fn AES() 51 | * \brief AES constructor 52 | * 53 | * This function initialized an instance of AES. 54 | */ 55 | AES(); 56 | 57 | /** Set the cipher key for the pre-keyed version. 58 | * @param key[] pointer to the key string. 59 | * @param keylen Integer that indicates the length of the key. 60 | * @note NOTE: If the length_type used for the key length is an unsigned 8-bit character, 61 | * a key length of 256 bits must be entered as a length in bytes 62 | * (valid inputs are hence 128, 192, 16, 24 and 32). 63 | * 64 | */ 65 | byte set_key (byte key[], int keylen) ; 66 | 67 | /** clean up subkeys after use. 68 | * 69 | */ 70 | void clean () ; // delete key schedule after use 71 | 72 | /** copying and xoring utilities. 73 | * @param *AESt byte pointer of the AEStination array. 74 | * @param *src byte pointer of the source array. 75 | * @param n byte, indicating the sizeof the bytes to be copied. 76 | * @note this is an alternative for memcpy(void *s1,const void *s2, site_t n), 77 | * i have not updated the function in the implementation yet, but it is considered a future plan. 78 | * 79 | */ 80 | void copy_n_bytes (byte * AESt, byte * src, byte n) ; 81 | 82 | /** Encrypt a single block of 16 bytes . 83 | * @param plain[N_BLOCK] Array of the plaintext. 84 | * @param cipher[N_BLOCK] Array of the ciphertext. 85 | * @note The N_BLOCK is defined in AES_config.h as, 86 | * @code #define N_ROW 4 87 | * #define N_COL 4 88 | * #define N_BLOCK (N_ROW * N_COL) 89 | * @endcode 90 | * Changed to that will change the Block_size. 91 | * @Return 0 if SUCCESS or -1 if FAILURE 92 | * 93 | */ 94 | byte encrypt (byte plain [N_BLOCK], byte cipher [N_BLOCK]) ; 95 | 96 | /** CBC encrypt a number of blocks (input and return an IV). 97 | * 98 | * @param *plain Pointer, points to the plaintex. 99 | * @param *cipher Pointer, points to the ciphertext that will be created. 100 | * @param n_block integer, indicated the number of blocks to be ciphered. 101 | * @param iv[N_BLOCK] byte Array that holds the IV (initialization vector). 102 | * @Return 0 if SUCCESS or -1 if FAILURE 103 | * 104 | */ 105 | byte cbc_encrypt (byte * plain, byte * cipher, int n_block, byte iv [N_BLOCK]) ; 106 | 107 | /** CBC encrypt a number of blocks (input and return an IV). 108 | * 109 | * @param *plain Pointer, points to the plaintex. 110 | * @param *cipher Pointer, points to the ciphertext that will be created. 111 | * @param n_block integer, indicated the number of blocks to be ciphered. 112 | * @Return 0 if SUCCESS or -1 if FAILURE 113 | * 114 | */ 115 | byte cbc_encrypt (byte * plain, byte * cipher, int n_block) ; 116 | 117 | 118 | /** Decrypt a single block of 16 bytes 119 | * @param cipher[N_BLOCK] Array of the ciphertext. 120 | * @param plain[N_BLOCK] Array of the plaintext. 121 | * @note The N_BLOCK is defined in AES_config.h as, 122 | * @code #define N_ROW 4 123 | * #define N_COL 4 124 | * #define N_BLOCK (N_ROW * N_COL) 125 | * @endcode 126 | * Changed to that will change the Block_size. 127 | * @Return 0 if SUCCESS or -1 if FAILURE 128 | * 129 | */ 130 | byte decrypt (byte cipher [N_BLOCK], byte plain [N_BLOCK]) ; 131 | 132 | /** CBC decrypt a number of blocks (input and return an IV) 133 | * 134 | * @param *cipher Pointer, points to the ciphertext that will be created. 135 | * @param *plain Pointer, points to the plaintex. 136 | * @param n_block integer, indicated the number of blocks to be ciphered. 137 | * @param iv[N_BLOCK] byte Array that holds the IV (initialization vector). 138 | * @Return 0 if SUCCESS or -1 if FAILURE 139 | * 140 | */ 141 | byte cbc_decrypt (byte * cipher, byte * plain, int n_block, byte iv [N_BLOCK]) ; 142 | 143 | /** CBC decrypt a number of blocks (input and return an IV) 144 | * 145 | * @param *cipher Pointer, points to the ciphertext that will be created. 146 | * @param *plain Pointer, points to the plaintex. 147 | * @param n_block integer, indicated the number of blocks to be ciphered. 148 | * @Return 0 if SUCCESS or -1 if FAILURE 149 | * 150 | */ 151 | byte cbc_decrypt (byte * cipher, byte * plain, int n_block) ; 152 | 153 | /** Sets IV (initialization vector) and IVC (IV counter). 154 | * This function changes the ivc and iv variables needed for AES. 155 | * 156 | * @param IVCl int or hex value of iv , ex. 0x0000000000000001 157 | * @note example: 158 | * @code unsigned long long int my_iv = 01234567; @endcode 159 | */ 160 | void set_IV(unsigned long long int IVCl); 161 | 162 | /** increase the iv (initialization vector) and IVC (IV counter) by 1 163 | * 164 | * This function increased the VI by one step in order to have a different IV each time 165 | * 166 | */ 167 | void iv_inc(); 168 | 169 | /** Getter method for size 170 | * 171 | * This function return the size 172 | * @return an integer, that is the size of the of the padded plaintext, 173 | * thus, the size of the ciphertext. 174 | */ 175 | int get_size(); 176 | 177 | /** Setter method for size 178 | * 179 | * This function sets the size of the plaintext+pad 180 | * 181 | */ 182 | void set_size(int sizel); 183 | 184 | /** Getter method for IV 185 | * 186 | * This function return the IV 187 | * @param out byte pointer that gets the IV. 188 | * @return none, the IV is writed to the out pointer. 189 | */ 190 | void get_IV(byte *out); 191 | 192 | /** Calculates the size of the plaintext and the padding. 193 | * 194 | * Calculates the size of theplaintext with the padding 195 | * and the size of the padding needed. Moreover it stores them in their class variables. 196 | * 197 | * @param p_size the size of the byte array ex sizeof(plaintext) 198 | */ 199 | void calc_size_n_pad(int p_size); 200 | 201 | /** Pads the plaintext 202 | * 203 | * This function pads the plaintext and returns an char array with the 204 | * plaintext and the padding in order for the plaintext to be compatible with 205 | * 16bit size blocks required by AES 206 | * 207 | * @param in the string of the plaintext in a byte array 208 | * @param out The string of the out array. 209 | * @return no return, The padded plaintext is stored in the out pointer. 210 | */ 211 | void padPlaintext(void* in,byte* out); 212 | 213 | /** Check the if the padding is correct. 214 | * 215 | * This functions checks the padding of the plaintext. 216 | * 217 | * @param in the string of the plaintext in a byte array 218 | * @param size the size of the string 219 | * @return true if correct / false if not 220 | */ 221 | bool CheckPad(byte* in,int size); 222 | 223 | /** Prints the array given. 224 | * 225 | * This function prints the given array and pad, 226 | * It is mainlly used for debugging purpuses or to output the string. 227 | * 228 | * @param output[] the string of the text in a byte array 229 | * @param p_pad optional, used to print with out the padding characters 230 | */ 231 | void printArray(byte output[],bool p_pad = true); 232 | 233 | /** Prints the array given. 234 | * 235 | * This function prints the given array in Hexadecimal. 236 | * 237 | * @param output[] the string of the text in a byte array 238 | * @param sizel the size of the array. 239 | */ 240 | void printArray(byte output[],int sizel); 241 | 242 | /** User friendly implementation of AES-CBC encryption. 243 | * 244 | * @param *plain pointer to the plaintext 245 | * @param size_p size of the plaintext 246 | * @param *cipher pointer to the ciphertext 247 | * @param *key pointer to the key that will be used. 248 | * @param bits bits of the encryption/decrpytion 249 | * @param ivl[N_BLOCK] the initialization vector IV that will be used for encryption. 250 | * @note The key will be stored in class variable. 251 | */ 252 | void do_aes_encrypt(byte *plain,int size_p,byte *cipher,byte *key, int bits, byte ivl [N_BLOCK]); 253 | 254 | /** User friendly implementation of AES-CBC encryption. 255 | * 256 | * @param *plain pointer to the plaintext 257 | * @param size_p size of the plaintext 258 | * @param *cipher pointer to the ciphertext 259 | * @param *key pointer to the key that will be used. 260 | * @param bits bits of the encryption/decrpytion 261 | * @note The key will be stored in class variable. 262 | */ 263 | void do_aes_encrypt(byte *plain,int size_p,byte *cipher,byte *key, int bits); 264 | 265 | /** User friendly implementation of AES-CBC decryption. 266 | * 267 | * @param *cipher pointer to the ciphertext 268 | * @param size_c size of the ciphertext 269 | * @param *plain pointer to the plaintext 270 | * @param *key pointer to the key that will be used. 271 | * @param bits bits of the encryption/decrpytion 272 | * @param ivl[N_BLOCK] the initialization vector IV that will be used for decryption. 273 | * @note The key will be stored in class variable. 274 | */ 275 | void do_aes_decrypt(byte *cipher,int size_c,byte *plain,byte *key, int bits, byte ivl [N_BLOCK]); 276 | 277 | /** User friendly implementation of AES-CBC decryption. 278 | * 279 | * @param *cipher pointer to the ciphertext 280 | * @param size_c size of the ciphertext 281 | * @param *plain pointer to the plaintext 282 | * @param *key pointer to the key that will be used. 283 | * @param bits bits of the encryption/decrpytion 284 | * @note The key will be stored in class variable. 285 | */ 286 | void do_aes_decrypt(byte *cipher,int size_c,byte *plain,byte *key, int bits); 287 | 288 | #if defined(AES_LINUX) 289 | /** 290 | * used in linux in order to retrieve the time in milliseconds. 291 | * 292 | * @return returns the milliseconds in a double format. 293 | */ 294 | double millis(); 295 | #endif 296 | private: 297 | int round ;/**< holds the number of rounds to be used. */ 298 | byte key_sched [KEY_SCHEDULE_BYTES] ;/**< holds the pre-computed key for the encryption/decrpytion. */ 299 | unsigned long long int IVC;/**< holds the initialization vector counter in numerical format. */ 300 | byte iv[16];/**< holds the initialization vector that will be used in the cipher. */ 301 | int pad;/**< holds the size of the padding. */ 302 | int size;/**< hold the size of the plaintext to be ciphered */ 303 | #if defined(AES_LINUX) 304 | timeval tv;/**< holds the time value on linux */ 305 | byte arr_pad[15];/**< holds the hexadecimal padding values on linux */ 306 | #else 307 | byte arr_pad[15] = { 0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f };/**< holds the hexadecimal padding values */ 308 | #endif 309 | } ; 310 | 311 | 312 | #endif 313 | 314 | /** 315 | * @example aes.ino 316 | * For Arduino
317 | * Updated: spaniakos 2015
318 | * 319 | * This is an example of how to use AES in CBC mode easily. 320 | * The text and keys can be either in HEX or String format.
321 | */ 322 | 323 | /** 324 | * @example aes.cpp 325 | * For Rasberry pi
326 | * Updated: spaniakos 2015
327 | * 328 | * This is an example of how to use AES in CBC mode easily. 329 | * The text and keys can be either in HEX or String format.
330 | */ 331 | 332 | /** 333 | * @example test_vectors.ino 334 | * For Arduino
335 | * Updated: spaniakos 2015
336 | * 337 | * This is an example of monte carlo test vectors, in order to justify the effectiveness of the algorithm.
338 | * plus is a classical approach to the AES encryption library with out the easy to use add-on modifications. 339 | */ 340 | 341 | /** 342 | * @example test_vectors.cpp 343 | * For Rasberry pi
344 | * Updated: spaniakos 2015
345 | * 346 | * This is an example of monte carlo test vectors, in order to justify the effectiveness of the algorithm.
347 | * plus is a classical approach to the AES encryption library with out the easy to use add-on modifications. 348 | */ 349 | 350 | /** 351 | * @mainpage AES library for Arduino and Raspberry pi. 352 | * 353 | * @section Goals design Goals 354 | * 355 | * This library is AESigned to be... 356 | * @li Fast and efficient. 357 | * @li Able to effectively encrypt and decrypt any size of string. 358 | * @li Able to encrypt and decrypt using AES 359 | * @li Able to encrypt and decrypt using AES-CBC 360 | * @li Easy for the user to use in his programs. 361 | * 362 | * @section Acknowledgements Acknowledgements 363 | * This is an AES library for the Arduino, based on tzikis's AES library, which you can find here:.
364 | * Tzikis library was based on scottmac`s library, which you can find here:
365 | * 366 | * @section Installation Installation 367 | *

Arduino

368 | * Create a folder named _AES_ in the _libraries_ folder inside your Arduino sketch folder. If the 369 | * libraries folder doesn't exist, create it. Then copy everything inside. (re)launch the Arduino IDE.
370 | * You're done. Time for a mojito 371 | * 372 | *

Raspberry pi

373 | * install

374 | * 375 | * sudo make install
376 | * cd examples_Rpi
377 | * make

378 | * 379 | * What to do after changes to the library

380 | * sudo make clean
381 | * sudo make install
382 | * cd examples_Rpi
383 | * make clean
384 | * make

385 | * What to do after changes to a sketch

386 | * cd examples_Rpi
387 | * make

388 | * or
389 | * make clean
390 | * make


391 | * How to start a sketch

392 | * cd examples_Rpi
393 | * sudo ./

394 | * 395 | * @section News News 396 | * 397 | * If issues are discovered with the documentation, please report them here 398 | * @section Useful Useful References 399 | * 400 | * Please refer to: 401 | * 402 | * @li AES Class Documentation 403 | * @li Download 404 | * @li Source Code 405 | * @li All spaniakos Documentation Main Page 406 | * 407 | * @section Board_Support Board Support 408 | * 409 | * Most standard Arduino based boards are supported: 410 | * - Arduino 411 | * - Intel Galileo support 412 | * - Raspberry Pi Support 413 | * 414 | * - The library has not been tested to other boards, but it should suppport ATMega 328 based boards,Mega Boards,Arduino Due,ATTiny board 415 | */ 416 | -------------------------------------------------------------------------------- /AES_config.h: -------------------------------------------------------------------------------- 1 | /* code was modified by george spanos 2 | * 16/12/14 3 | */ 4 | 5 | #ifndef __AES_CONFIG_H__ 6 | #define __AES_CONFIG_H__ 7 | 8 | #if (defined(__linux) || defined(linux)) && !defined(__ARDUINO_X86__) 9 | 10 | #define AES_LINUX 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #else 19 | #include 20 | #endif 21 | 22 | #include 23 | #include 24 | 25 | #if defined(__ARDUINO_X86__) || (defined (__linux) || defined (linux)) 26 | #undef PROGMEM 27 | #define PROGMEM __attribute__(( section(".progmem.data") )) 28 | #define pgm_read_byte(p) (*(p)) 29 | typedef unsigned char byte; 30 | #define printf_P printf 31 | #define PSTR(x) (x) 32 | #else 33 | #if (defined(__AVR__)) 34 | #include 35 | #else 36 | #include 37 | #endif 38 | #endif 39 | 40 | #define N_ROW 4 41 | #define N_COL 4 42 | #define N_BLOCK (N_ROW * N_COL) 43 | #define N_MAX_ROUNDS 14 44 | #define KEY_SCHEDULE_BYTES ((N_MAX_ROUNDS + 1) * N_BLOCK) 45 | #define SUCCESS (0) 46 | #define FAILURE (-1) 47 | 48 | #endif 49 | -------------------------------------------------------------------------------- /Base64.cpp: -------------------------------------------------------------------------------- 1 | #include "Base64.h" 2 | 3 | #if (defined(__AVR__)) 4 | #include 5 | #else 6 | #include 7 | #endif 8 | 9 | const char PROGMEM b64_alphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" 10 | "abcdefghijklmnopqrstuvwxyz" 11 | "0123456789+/"; 12 | 13 | /* 'Private' declarations */ 14 | inline void a3_to_a4(unsigned char * a4, unsigned char * a3); 15 | inline void a4_to_a3(unsigned char * a3, unsigned char * a4); 16 | inline unsigned char b64_lookup(char c); 17 | 18 | int base64_encode(char *output, char *input, int inputLen) { 19 | int i = 0, j = 0; 20 | int encLen = 0; 21 | unsigned char a3[3]; 22 | unsigned char a4[4]; 23 | 24 | while(inputLen--) { 25 | a3[i++] = *(input++); 26 | if(i == 3) { 27 | a3_to_a4(a4, a3); 28 | 29 | for(i = 0; i < 4; i++) { 30 | output[encLen++] = pgm_read_byte(&b64_alphabet[a4[i]]); 31 | } 32 | 33 | i = 0; 34 | } 35 | } 36 | 37 | if(i) { 38 | for(j = i; j < 3; j++) { 39 | a3[j] = '\0'; 40 | } 41 | 42 | a3_to_a4(a4, a3); 43 | 44 | for(j = 0; j < i + 1; j++) { 45 | output[encLen++] = pgm_read_byte(&b64_alphabet[a4[j]]); 46 | } 47 | 48 | while((i++ < 3)) { 49 | output[encLen++] = '='; 50 | } 51 | } 52 | output[encLen] = '\0'; 53 | return encLen; 54 | } 55 | 56 | int base64_decode(char * output, char * input, int inputLen) { 57 | int i = 0, j = 0; 58 | int decLen = 0; 59 | unsigned char a3[3]; 60 | unsigned char a4[4]; 61 | 62 | 63 | while (inputLen--) { 64 | if(*input == '=') { 65 | break; 66 | } 67 | 68 | a4[i++] = *(input++); 69 | if (i == 4) { 70 | for (i = 0; i <4; i++) { 71 | a4[i] = b64_lookup(a4[i]); 72 | } 73 | 74 | a4_to_a3(a3,a4); 75 | 76 | for (i = 0; i < 3; i++) { 77 | output[decLen++] = a3[i]; 78 | } 79 | i = 0; 80 | } 81 | } 82 | 83 | if (i) { 84 | for (j = i; j < 4; j++) { 85 | a4[j] = '\0'; 86 | } 87 | 88 | for (j = 0; j <4; j++) { 89 | a4[j] = b64_lookup(a4[j]); 90 | } 91 | 92 | a4_to_a3(a3,a4); 93 | 94 | for (j = 0; j < i - 1; j++) { 95 | output[decLen++] = a3[j]; 96 | } 97 | } 98 | output[decLen] = '\0'; 99 | return decLen; 100 | } 101 | 102 | int base64_enc_len(int plainLen) { 103 | int n = plainLen; 104 | return (n + 2 - ((n + 2) % 3)) / 3 * 4; 105 | } 106 | 107 | int base64_dec_len(char * input, int inputLen) { 108 | int i = 0; 109 | int numEq = 0; 110 | for(i = inputLen - 1; input[i] == '='; i--) { 111 | numEq++; 112 | } 113 | 114 | return ((6 * inputLen) / 8) - numEq; 115 | } 116 | 117 | inline void a3_to_a4(unsigned char * a4, unsigned char * a3) { 118 | a4[0] = (a3[0] & 0xfc) >> 2; 119 | a4[1] = ((a3[0] & 0x03) << 4) + ((a3[1] & 0xf0) >> 4); 120 | a4[2] = ((a3[1] & 0x0f) << 2) + ((a3[2] & 0xc0) >> 6); 121 | a4[3] = (a3[2] & 0x3f); 122 | } 123 | 124 | inline void a4_to_a3(unsigned char * a3, unsigned char * a4) { 125 | a3[0] = (a4[0] << 2) + ((a4[1] & 0x30) >> 4); 126 | a3[1] = ((a4[1] & 0xf) << 4) + ((a4[2] & 0x3c) >> 2); 127 | a3[2] = ((a4[2] & 0x3) << 6) + a4[3]; 128 | } 129 | 130 | inline unsigned char b64_lookup(char c) { 131 | if(c >='A' && c <='Z') return c - 'A'; 132 | if(c >='a' && c <='z') return c - 71; 133 | if(c >='0' && c <='9') return c + 4; 134 | if(c == '+') return 62; 135 | if(c == '/') return 63; 136 | return -1; 137 | } 138 | -------------------------------------------------------------------------------- /Base64.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013 Adam Rudd. 3 | * See LICENSE for more information 4 | */ 5 | #ifndef _BASE64_H 6 | #define _BASE64_H 7 | 8 | /* b64_alphabet: 9 | * Description: Base64 alphabet table, a mapping between integers 10 | * and base64 digits 11 | * Notes: This is an extern here but is defined in Base64.c 12 | */ 13 | extern const char b64_alphabet[]; 14 | 15 | /* base64_encode: 16 | * Description: 17 | * Encode a string of characters as base64 18 | * Parameters: 19 | * output: the output buffer for the encoding, stores the encoded string 20 | * input: the input buffer for the encoding, stores the binary to be encoded 21 | * inputLen: the length of the input buffer, in bytes 22 | * Return value: 23 | * Returns the length of the encoded string 24 | * Requirements: 25 | * 1. output must not be null or empty 26 | * 2. input must not be null 27 | * 3. inputLen must be greater than or equal to 0 28 | */ 29 | int base64_encode(char *output, char *input, int inputLen); 30 | 31 | /* base64_decode: 32 | * Description: 33 | * Decode a base64 encoded string into bytes 34 | * Parameters: 35 | * output: the output buffer for the decoding, 36 | * stores the decoded binary 37 | * input: the input buffer for the decoding, 38 | * stores the base64 string to be decoded 39 | * inputLen: the length of the input buffer, in bytes 40 | * Return value: 41 | * Returns the length of the decoded string 42 | * Requirements: 43 | * 1. output must not be null or empty 44 | * 2. input must not be null 45 | * 3. inputLen must be greater than or equal to 0 46 | */ 47 | int base64_decode(char *output, char *input, int inputLen); 48 | 49 | /* base64_enc_len: 50 | * Description: 51 | * Returns the length of a base64 encoded string whose decoded 52 | * form is inputLen bytes long 53 | * Parameters: 54 | * inputLen: the length of the decoded string 55 | * Return value: 56 | * The length of a base64 encoded string whose decoded form 57 | * is inputLen bytes long 58 | * Requirements: 59 | * None 60 | */ 61 | int base64_enc_len(int inputLen); 62 | 63 | /* base64_dec_len: 64 | * Description: 65 | * Returns the length of the decoded form of a 66 | * base64 encoded string 67 | * Parameters: 68 | * input: the base64 encoded string to be measured 69 | * inputLen: the length of the base64 encoded string 70 | * Return value: 71 | * Returns the length of the decoded form of a 72 | * base64 encoded string 73 | * Requirements: 74 | * 1. input must not be null 75 | * 2. input must be greater than or equal to zero 76 | */ 77 | int base64_dec_len(char *input, int inputLen); 78 | 79 | #endif // _BASE64_H 80 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # arduino-esp8266-aes-encryption-with-nodejs 2 | 3 | This repo demostrates how to encypt your data using [AES](https://github.com/spaniakos/AES) and decrypt it using NodeJS crypto-js library. If you are looking for PHP port see https://zeitwesentech.com/blog/?p=521 (I am not the author) 4 | 5 | 6 | You can find the library version here 7 | https://github.com/kakopappa/arduino-esp8266-aes-lib 8 | 9 | Complete article is here: (I am not the author) 10 | https://primalcortex.wordpress.com/2016/06/17/esp8266-logging-data-in-a-backend-aes-and-crypto-js/. 11 | 12 | I have fixed few bugs related ESP8266 and combined it with AES and Base64 13 | 14 | How to use this: 15 | 16 | 1. Clone the github repo. 17 | 2. open aes_encryption.ino in Arduino 18 | 3. Flash 19 | 20 | ![conole output](https://github.com/kakopappa/arduino-esp8266-aes-encryption-with-nodejs/blob/master/iv-5-snap.png "Console") 21 | 22 | 23 | 4. Copy the iv, encrypted data and replace the esp8266_msg, esp8266_iv in the javascript code below. 24 | 25 | 26 | 27 | Here is the NodeJS Code. 28 | 29 | ```javascript 30 | //npm install --save-dev crypto-js 31 | var CryptoJS = require("crypto-js"); 32 | var esp8266_msg = 'IqszviDrXw5juapvVrQ2Eh/H3TqBsPkSOYY25hOQzJck+ZWIg2QsgBqYQv6lWHcdOclvVLOSOouk3PmGfIXv//cURM8UBJkKF83fPawwuxg='; 33 | var esp8266_iv = 'Cqkbb7OxPGoXhk70DjGYjw=='; 34 | 35 | // The AES encryption/decryption key to be used. 36 | var AESKey = '2B7E151628AED2A6ABF7158809CF4F3C'; 37 | 38 | var plain_iv = new Buffer( esp8266_iv , 'base64').toString('hex'); 39 | var iv = CryptoJS.enc.Hex.parse( plain_iv ); 40 | var key= CryptoJS.enc.Hex.parse( AESKey ); 41 | 42 | console.log("Let's "); 43 | 44 | // Decrypt 45 | var bytes = CryptoJS.AES.decrypt( esp8266_msg, key , { iv: iv} ); 46 | var plaintext = bytes.toString(CryptoJS.enc.Base64); 47 | var decoded_b64msg = new Buffer(plaintext , 'base64').toString('ascii'); 48 | var decoded_msg = new Buffer( decoded_b64msg , 'base64').toString('ascii'); 49 | 50 | console.log("Decryptedage: ", decoded_msg); 51 | ``` 52 | 53 | 54 | -------------------------------------------------------------------------------- /aes_encryption.ino: -------------------------------------------------------------------------------- 1 | #include "AES.h" 2 | #include "base64.h" 3 | 4 | AES aes; 5 | 6 | uint8_t getrnd() { 7 | uint8_t really_random = *(volatile uint8_t *)0x3FF20E44; 8 | return really_random; 9 | } 10 | 11 | // Generate a random initialization vector 12 | void gen_iv(byte *iv) { 13 | for (int i = 0 ; i < N_BLOCK ; i++ ) { 14 | iv[i]= (byte) getrnd(); 15 | } 16 | } 17 | 18 | void setup() { 19 | Serial.begin(115200); 20 | Serial.println("\nBooting..."); 21 | 22 | char b64data[200]; 23 | byte cipher[1000]; 24 | byte iv [N_BLOCK] ; 25 | 26 | Serial.println("Let's encrypt:"); 27 | // Our AES key. Note that is the same that is used on the Node-Js side but as hex bytes. 28 | byte key[] = { 0x2B, 0x7E, 0x15, 0x16, 0x28, 0xAE, 0xD2, 0xA6, 0xAB, 0xF7, 0x15, 0x88, 0x09, 0xCF, 0x4F, 0x3C }; 29 | 30 | // The unitialized Initialization vector 31 | byte my_iv[N_BLOCK] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; 32 | 33 | // Our message to encrypt. Static for this example. 34 | String msg = "{\"data\":{\"value\":300}, \"SEQN\":700 , \"msg\":\"IT WORKS!!\" }"; 35 | 36 | aes.set_key( key , sizeof(key)); // Get the globally defined key 37 | gen_iv( my_iv ); // Generate a random IV 38 | 39 | // Print the IV 40 | base64_encode( b64data, (char *)my_iv, N_BLOCK); 41 | Serial.println(" IV b64: " + String(b64data)); 42 | 43 | Serial.println(" Message: " + msg ); 44 | 45 | int b64len = base64_encode(b64data, (char *)msg.c_str(),msg.length()); 46 | Serial.println (" Message in B64: " + String(b64data) ); 47 | Serial.println (" The lenght is: " + String(b64len) ); 48 | 49 | // For sanity check purpose 50 | //base64_decode( decoded , b64data , b64len ); 51 | //Serial.println("Decoded: " + String(decoded)); 52 | 53 | // Encrypt! With AES128, our key and IV, CBC and pkcs7 padding 54 | aes.do_aes_encrypt((byte *)b64data, b64len , cipher, key, 128, my_iv); 55 | 56 | Serial.println("Encryption done!"); 57 | 58 | Serial.println("Cipher size: " + String(aes.get_size())); 59 | 60 | base64_encode(b64data, (char *)cipher, aes.get_size() ); 61 | Serial.println ("Encrypted data in base64: " + String(b64data) ); 62 | 63 | Serial.println("Done..."); 64 | } 65 | 66 | void loop() { 67 | // put your main code here, to run repeatedly: 68 | 69 | } 70 | -------------------------------------------------------------------------------- /iv-5-snap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kakopappa/arduino-esp8266-aes-encryption-with-nodejs/5f2f0a2bff5ede82cc8c945e7bd6d8a1eb107fa7/iv-5-snap.png --------------------------------------------------------------------------------