IBR-DTNSuite
0.8
|
00001 /* 00002 --------------------------------------------------------------------------- 00003 Copyright (c) 1998-2006, Brian Gladman, Worcester, UK. All rights reserved. 00004 00005 LICENSE TERMS 00006 00007 The free distribution and use of this software in both source and binary 00008 form is allowed (with or without changes) provided that: 00009 00010 1. distributions of this source code include the above copyright 00011 notice, this list of conditions and the following disclaimer; 00012 00013 2. distributions in binary form include the above copyright 00014 notice, this list of conditions and the following disclaimer 00015 in the documentation and/or other associated materials; 00016 00017 3. the copyright holder's name is not used to endorse products 00018 built using this software without specific written permission. 00019 00020 ALTERNATIVELY, provided that this notice is retained in full, this product 00021 may be distributed under the terms of the GNU General Public License (GPL), 00022 in which case the provisions of the GPL apply INSTEAD OF those given above. 00023 00024 DISCLAIMER 00025 00026 This software is provided 'as is' with no explicit or implied warranties 00027 in respect of its properties, including, but not limited to, correctness 00028 and/or fitness for purpose. 00029 --------------------------------------------------------------------------- 00030 Issue Date: 13/06/2006 00031 00032 My thanks to John Viega and David McGrew for their support in developing 00033 this code and to David for testing it on a big-endain system. 00034 */ 00035 00036 //#ifdef HAVE_CONFIG_H 00037 //# include <dtn-config.h> 00038 //#endif 00039 #define BSP_ENABLED true 00040 00041 #ifdef BSP_ENABLED 00042 00043 #include "gcm.h" 00044 #include "mode_hdr.h" 00045 00046 #if defined(__cplusplus) 00047 extern "C" 00048 { 00049 #endif 00050 00051 #define BLOCK_SIZE GCM_BLOCK_SIZE /* block length */ 00052 #define BLK_ADR_MASK (BLOCK_SIZE - 1) /* mask for 'in block' address */ 00053 #define CTR_POS 12 00054 00055 #define inc_ctr(x) \ 00056 { int i = BLOCK_SIZE; while(i-- > CTR_POS && !++(ui8_ptr(x)[i])) ; } 00057 00058 ret_type gcm_init_and_key( /* initialise mode and set key */ 00059 const unsigned char key[], /* the key value */ 00060 unsigned long key_len, /* and its length in bytes */ 00061 gcm_ctx ctx[1]) /* the mode context */ 00062 { 00063 memset(ctx->ghash_h, 0, sizeof(ctx->ghash_h)); 00064 00065 /* set the AES key */ 00066 aes_encrypt_key(key, key_len, ctx->aes); 00067 00068 /* compute E(0) (for the hash function) */ 00069 aes_encrypt(ui8_ptr(ctx->ghash_h), ui8_ptr(ctx->ghash_h), ctx->aes); 00070 00071 #if defined( TABLES_64K ) 00072 init_64k_table(ui8_ptr(ctx->ghash_h), ctx->gf_t64k); 00073 #elif defined( TABLES_8K ) 00074 init_8k_table(ui8_ptr(ctx->ghash_h), ctx->gf_t8k); 00075 #elif defined( TABLES_4K ) 00076 init_4k_table(ui8_ptr(ctx->ghash_h), ctx->gf_t4k); 00077 #elif defined( TABLES_256 ) 00078 init_256_table(ui8_ptr(ctx->ghash_h), ctx->gf_t256); 00079 #endif 00080 return RETURN_OK; 00081 } 00082 00083 #if defined( TABLES_64K ) 00084 #define gf_mul_hh(a, ctx, scr) gf_mul_64k(a, ctx->gf_t64k, scr) 00085 #elif defined( TABLES_8K ) 00086 #define gf_mul_hh(a, ctx, scr) gf_mul_8k(a, ctx->gf_t8k, scr) 00087 #elif defined( TABLES_4K ) 00088 #define gf_mul_hh(a, ctx, scr) gf_mul_4k(a, ctx->gf_t4k, scr) 00089 #elif defined( TABLES_256 ) 00090 #define gf_mul_hh(a, ctx, scr) gf_mul_256(a, ctx->gf_t256, scr) 00091 #else 00092 #define gf_mul_hh(a, ctx, scr) gf_mul(a, ui8_ptr(ctx->ghash_h)) 00093 #endif 00094 00095 ret_type gcm_init_message( /* initialise a new message */ 00096 const unsigned char iv[], /* the initialisation vector */ 00097 unsigned long iv_len, /* and its length in bytes */ 00098 gcm_ctx ctx[1]) /* the mode context */ 00099 { uint_32t i, n_pos = 0, scratch[GF_BYTE_LEN >> 2]; 00100 uint_8t *p; 00101 00102 memset(ctx->ctr_val, 0, BLOCK_SIZE); 00103 if(iv_len == CTR_POS) 00104 { 00105 memcpy(ctx->ctr_val, iv, CTR_POS); ui8_ptr(ctx->ctr_val)[15] = 0x01; 00106 } 00107 else 00108 { n_pos = iv_len; 00109 while(n_pos >= BLOCK_SIZE) 00110 { 00111 xor_block_aligned(ctx->ctr_val, iv); 00112 n_pos -= BLOCK_SIZE; 00113 iv += BLOCK_SIZE; 00114 gf_mul_hh(ui8_ptr(ctx->ctr_val), ctx, scratch); 00115 } 00116 00117 if(n_pos) 00118 { 00119 p = ui8_ptr(ctx->ctr_val); 00120 while(n_pos-- > 0) 00121 *p++ ^= *iv++; 00122 gf_mul_hh(ui8_ptr(ctx->ctr_val), ctx, scratch); 00123 } 00124 n_pos = (iv_len << 3); 00125 for(i = BLOCK_SIZE - 1; n_pos; --i, n_pos >>= 8) 00126 ui8_ptr(ctx->ctr_val)[i] ^= (unsigned char)n_pos; 00127 gf_mul_hh(ui8_ptr(ctx->ctr_val), ctx, scratch); 00128 } 00129 00130 ctx->y0_val = *ui32_ptr(ui8_ptr(ctx->ctr_val) + CTR_POS); 00131 inc_ctr(ctx->ctr_val); 00132 memset(ctx->hdr_ghv, 0, BLOCK_SIZE); 00133 memset(ctx->txt_ghv, 0, BLOCK_SIZE); 00134 ctx->hdr_cnt = 0; 00135 ctx->txt_ccnt = ctx->txt_acnt = 0; 00136 return RETURN_OK; 00137 } 00138 00139 ret_type gcm_auth_header( /* authenticate the header */ 00140 const unsigned char hdr[], /* the header buffer */ 00141 unsigned long hdr_len, /* and its length in bytes */ 00142 gcm_ctx ctx[1]) /* the mode context */ 00143 { uint_32t cnt = 0, b_pos = (uint_32t)ctx->hdr_cnt & BLK_ADR_MASK; 00144 uint_32t scratch[GF_BYTE_LEN >> 2]; 00145 00146 if(!hdr_len) 00147 return RETURN_OK; 00148 00149 if(ctx->hdr_cnt && b_pos == 0) 00150 gf_mul_hh(ui8_ptr(ctx->hdr_ghv), ctx, scratch); 00151 00152 while(cnt < hdr_len && (b_pos & BUF_ADRMASK)) 00153 ui8_ptr(ctx->hdr_ghv)[b_pos++] ^= hdr[cnt++]; 00154 00155 if(!(b_pos & BUF_ADRMASK) && !((hdr + cnt - ui8_ptr(ctx->hdr_ghv)) & BUF_ADRMASK)) 00156 { 00157 while(cnt + BUF_INC <= hdr_len && b_pos <= BLOCK_SIZE - BUF_INC) 00158 { 00159 *unit_ptr(ui8_ptr(ctx->hdr_ghv) + b_pos) ^= *unit_ptr(hdr + cnt); 00160 cnt += BUF_INC; b_pos += BUF_INC; 00161 } 00162 00163 while(cnt + BLOCK_SIZE <= hdr_len) 00164 { 00165 gf_mul_hh(ui8_ptr(ctx->hdr_ghv), ctx, scratch); 00166 xor_block_aligned(ctx->hdr_ghv, hdr + cnt); 00167 cnt += BLOCK_SIZE; 00168 } 00169 } 00170 else 00171 { 00172 while(cnt < hdr_len && b_pos < BLOCK_SIZE) 00173 ui8_ptr(ctx->hdr_ghv)[b_pos++] ^= hdr[cnt++]; 00174 00175 while(cnt + BLOCK_SIZE <= hdr_len) 00176 { 00177 gf_mul_hh(ui8_ptr(ctx->hdr_ghv), ctx, scratch); 00178 xor_block(ctx->hdr_ghv, hdr + cnt); 00179 cnt += BLOCK_SIZE; 00180 } 00181 } 00182 00183 while(cnt < hdr_len) 00184 { 00185 if(b_pos == BLOCK_SIZE) 00186 { 00187 gf_mul_hh(ui8_ptr(ctx->hdr_ghv), ctx, scratch); 00188 b_pos = 0; 00189 } 00190 ui8_ptr(ctx->hdr_ghv)[b_pos++] ^= hdr[cnt++]; 00191 } 00192 00193 ctx->hdr_cnt += cnt; 00194 return RETURN_OK; 00195 } 00196 00197 ret_type gcm_auth_data( /* authenticate ciphertext data */ 00198 const unsigned char data[], /* the data buffer */ 00199 unsigned long data_len, /* and its length in bytes */ 00200 gcm_ctx ctx[1]) /* the mode context */ 00201 { uint_32t cnt = 0, b_pos = (uint_32t)(ctx->txt_acnt & BLK_ADR_MASK); 00202 uint_32t scratch[GF_BYTE_LEN >> 2]; 00203 00204 if(!data_len) 00205 return RETURN_OK; 00206 00207 if(ctx->txt_acnt && b_pos == 0) 00208 gf_mul_hh(ui8_ptr(ctx->txt_ghv), ctx, scratch); 00209 00210 while(cnt < data_len && (b_pos & BUF_ADRMASK)) 00211 ui8_ptr(ctx->txt_ghv)[b_pos++] ^= data[cnt++]; 00212 00213 if(!(b_pos & BUF_ADRMASK) && !((data + cnt - ui8_ptr(ctx->txt_ghv)) & BUF_ADRMASK)) 00214 { 00215 while(cnt + BUF_INC <= data_len && b_pos <= BLOCK_SIZE - BUF_INC) 00216 { 00217 *unit_ptr(ui8_ptr(ctx->txt_ghv) + b_pos) ^= *unit_ptr(data + cnt); 00218 cnt += BUF_INC; b_pos += BUF_INC; 00219 } 00220 00221 while(cnt + BLOCK_SIZE <= data_len) 00222 { 00223 gf_mul_hh(ui8_ptr(ctx->txt_ghv), ctx, scratch); 00224 xor_block_aligned(ctx->txt_ghv, data + cnt); 00225 cnt += BLOCK_SIZE; 00226 } 00227 } 00228 else 00229 { 00230 while(cnt < data_len && b_pos < BLOCK_SIZE) 00231 ui8_ptr(ctx->txt_ghv)[b_pos++] ^= data[cnt++]; 00232 00233 while(cnt + BLOCK_SIZE <= data_len) 00234 { 00235 gf_mul_hh(ui8_ptr(ctx->txt_ghv), ctx, scratch); 00236 xor_block(ctx->txt_ghv, data + cnt); 00237 cnt += BLOCK_SIZE; 00238 } 00239 } 00240 00241 while(cnt < data_len) 00242 { 00243 if(b_pos == BLOCK_SIZE) 00244 { 00245 gf_mul_hh(ui8_ptr(ctx->txt_ghv), ctx, scratch); 00246 b_pos = 0; 00247 } 00248 ui8_ptr(ctx->txt_ghv)[b_pos++] ^= data[cnt++]; 00249 } 00250 00251 ctx->txt_acnt += cnt; 00252 return RETURN_OK; 00253 } 00254 00255 ret_type gcm_crypt_data( /* encrypt or decrypt data */ 00256 unsigned char data[], /* the data buffer */ 00257 unsigned long data_len, /* and its length in bytes */ 00258 gcm_ctx ctx[1]) /* the mode context */ 00259 { uint_32t cnt = 0, b_pos = (uint_32t)(ctx->txt_ccnt & BLK_ADR_MASK); 00260 00261 if(!data_len) 00262 return RETURN_OK; 00263 00264 if(b_pos == 0) 00265 { 00266 aes_encrypt(ui8_ptr(ctx->ctr_val), ui8_ptr(ctx->enc_ctr), ctx->aes); 00267 inc_ctr(ctx->ctr_val); 00268 } 00269 00270 while(cnt < data_len && (b_pos & BUF_ADRMASK)) 00271 data[cnt++] ^= ui8_ptr(ctx->enc_ctr)[b_pos++]; 00272 00273 if(!(b_pos & BUF_ADRMASK) && !((data + cnt - ui8_ptr(ctx->enc_ctr)) & BUF_ADRMASK)) 00274 { 00275 while(cnt + BUF_INC <= data_len && b_pos <= BLOCK_SIZE - BUF_INC) 00276 { 00277 *unit_ptr(data + cnt) ^= *unit_ptr(ui8_ptr(ctx->enc_ctr) + b_pos); 00278 cnt += BUF_INC; b_pos += BUF_INC; 00279 } 00280 00281 while(cnt + BLOCK_SIZE <= data_len) 00282 { 00283 aes_encrypt(ui8_ptr(ctx->ctr_val), ui8_ptr(ctx->enc_ctr), ctx->aes); 00284 inc_ctr(ctx->ctr_val); 00285 xor_block_aligned(data + cnt, ctx->enc_ctr); 00286 cnt += BLOCK_SIZE; 00287 } 00288 } 00289 else 00290 { 00291 while(cnt < data_len && b_pos < BLOCK_SIZE) 00292 data[cnt++] ^= ui8_ptr(ctx->enc_ctr)[b_pos++]; 00293 00294 while(cnt + BLOCK_SIZE <= data_len) 00295 { 00296 aes_encrypt(ui8_ptr(ctx->ctr_val), ui8_ptr(ctx->enc_ctr), ctx->aes); 00297 inc_ctr(ctx->ctr_val); 00298 xor_block(data + cnt, ctx->enc_ctr); 00299 cnt += BLOCK_SIZE; 00300 } 00301 } 00302 00303 while(cnt < data_len) 00304 { 00305 if(b_pos == BLOCK_SIZE) 00306 { 00307 aes_encrypt(ui8_ptr(ctx->ctr_val), ui8_ptr(ctx->enc_ctr), ctx->aes); 00308 inc_ctr(ctx->ctr_val); 00309 b_pos = 0; 00310 } 00311 data[cnt++] ^= ui8_ptr(ctx->enc_ctr)[b_pos++]; 00312 } 00313 00314 ctx->txt_ccnt += cnt; 00315 return RETURN_OK; 00316 } 00317 00318 ret_type gcm_compute_tag( /* compute authentication tag */ 00319 unsigned char tag[], /* the buffer for the tag */ 00320 unsigned long tag_len, /* and its length in bytes */ 00321 gcm_ctx ctx[1]) /* the mode context */ 00322 { uint_32t i, ln, scratch[GF_BYTE_LEN >> 2]; 00323 uint_8t tbuf[BLOCK_SIZE]; 00324 00325 if(ctx->txt_acnt != ctx->txt_ccnt && ctx->txt_ccnt > 0) 00326 return RETURN_ERROR; 00327 00328 gf_mul_hh(ui8_ptr(ctx->hdr_ghv), ctx, scratch); 00329 gf_mul_hh(ui8_ptr(ctx->txt_ghv), ctx, scratch); 00330 00331 #if 1 /* alternative versions of the exponentiation operation */ 00332 if(ctx->hdr_cnt && (ln = (uint_32t)((ctx->txt_acnt + BLOCK_SIZE - 1) / BLOCK_SIZE))) 00333 { 00334 memcpy(tbuf, ctx->ghash_h, BLOCK_SIZE); 00335 for( ; ; ) 00336 { 00337 if(ln & 1) gf_mul(ui8_ptr(ctx->hdr_ghv), tbuf); 00338 if(!(ln >>= 1)) break; 00339 gf_mul(tbuf, tbuf); 00340 } 00341 } 00342 #else /* this one seems slower on x86 and x86_64 :-( */ 00343 if(ctx->hdr_cnt && (ln = (uint_32t)((ctx->txt_acnt + BLOCK_SIZE - 1) / BLOCK_SIZE))) 00344 { 00345 i = ln | ln >> 1; i |= i >> 2; i |= i >> 4; 00346 i |= i >> 8; i |= i >> 16; i = i & ~(i >> 1); 00347 memset(tbuf, 0, BLOCK_SIZE); 00348 tbuf[0] = 0x80; 00349 while(i) 00350 { 00351 gf_mul(tbuf, tbuf); 00352 if(i & ln) 00353 gf_mul_hh(tbuf, ctx, scratch); 00354 i >>= 1; 00355 } 00356 gf_mul(ui8_ptr(ctx->hdr_ghv), tbuf); 00357 } 00358 #endif 00359 i = BLOCK_SIZE; ln = (uint_32t)(ctx->txt_acnt << 3); 00360 while(i-- > 0) 00361 { 00362 ui8_ptr(ctx->hdr_ghv)[i] ^= ui8_ptr(ctx->txt_ghv)[i] ^ (unsigned char)ln; 00363 ln = (i == 8 ? (uint_32t)(ctx->hdr_cnt << 3) : ln >> 8); 00364 } 00365 00366 gf_mul_hh(ui8_ptr(ctx->hdr_ghv), ctx, scratch); 00367 00368 *ui32_ptr(ui8_ptr(ctx->ctr_val) + CTR_POS) = ctx->y0_val; 00369 aes_encrypt(ui8_ptr(ctx->ctr_val), ui8_ptr(ctx->enc_ctr), ctx->aes); 00370 for(i = 0; i < (unsigned int)tag_len; ++i) 00371 tag[i] = ui8_ptr(ctx->hdr_ghv)[i] ^ ui8_ptr(ctx->enc_ctr)[i]; 00372 00373 return (ctx->txt_ccnt == ctx->txt_acnt ? RETURN_OK : RETURN_WARN); 00374 } 00375 00376 ret_type gcm_end( /* clean up and end operation */ 00377 gcm_ctx ctx[1]) /* the mode context */ 00378 { 00379 memset(ctx, 0, sizeof(gcm_ctx)); 00380 return RETURN_OK; 00381 } 00382 00383 ret_type gcm_encrypt( /* encrypt & authenticate data */ 00384 unsigned char data[], /* the data buffer */ 00385 unsigned long data_len, /* and its length in bytes */ 00386 gcm_ctx ctx[1]) /* the mode context */ 00387 { 00388 00389 gcm_crypt_data(data, data_len, ctx); 00390 gcm_auth_data(data, data_len, ctx); 00391 return RETURN_OK; 00392 } 00393 00394 ret_type gcm_decrypt( /* authenticate & decrypt data */ 00395 unsigned char data[], /* the data buffer */ 00396 unsigned long data_len, /* and its length in bytes */ 00397 gcm_ctx ctx[1]) /* the mode context */ 00398 { 00399 gcm_auth_data(data, data_len, ctx); 00400 gcm_crypt_data(data, data_len, ctx); 00401 return RETURN_OK; 00402 } 00403 00404 ret_type gcm_encrypt_message( /* encrypt an entire message */ 00405 const unsigned char iv[], /* the initialisation vector */ 00406 unsigned long iv_len, /* and its length in bytes */ 00407 const unsigned char hdr[], /* the header buffer */ 00408 unsigned long hdr_len, /* and its length in bytes */ 00409 unsigned char msg[], /* the message buffer */ 00410 unsigned long msg_len, /* and its length in bytes */ 00411 unsigned char tag[], /* the buffer for the tag */ 00412 unsigned long tag_len, /* and its length in bytes */ 00413 gcm_ctx ctx[1]) /* the mode context */ 00414 { 00415 gcm_init_message(iv, iv_len, ctx); 00416 gcm_auth_header(hdr, hdr_len, ctx); 00417 gcm_encrypt(msg, msg_len, ctx); 00418 return gcm_compute_tag(tag, tag_len, ctx) ? RETURN_ERROR : RETURN_OK; 00419 } 00420 00421 ret_type gcm_decrypt_message( /* decrypt an entire message */ 00422 const unsigned char iv[], /* the initialisation vector */ 00423 unsigned long iv_len, /* and its length in bytes */ 00424 const unsigned char hdr[], /* the header buffer */ 00425 unsigned long hdr_len, /* and its length in bytes */ 00426 unsigned char msg[], /* the message buffer */ 00427 unsigned long msg_len, /* and its length in bytes */ 00428 const unsigned char tag[], /* the buffer for the tag */ 00429 unsigned long tag_len, /* and its length in bytes */ 00430 gcm_ctx ctx[1]) /* the mode context */ 00431 { uint_8t local_tag[BLOCK_SIZE]; 00432 ret_type rr; 00433 00434 gcm_init_message(iv, iv_len, ctx); 00435 gcm_auth_header(hdr, hdr_len, ctx); 00436 gcm_decrypt(msg, msg_len, ctx); 00437 rr = gcm_compute_tag(local_tag, tag_len, ctx); 00438 return (rr != RETURN_OK || memcmp(tag, local_tag, tag_len)) ? RETURN_ERROR : RETURN_OK; 00439 } 00440 00441 #if defined(__cplusplus) 00442 } 00443 #endif 00444 00445 #endif /* BSP_ENABLED */