00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036 #ifdef HAVE_CONFIG_H
00037 # include <dtn-config.h>
00038 #endif
00039
00040 #ifdef BSP_ENABLED
00041
00042 #include "gcm.h"
00043 #include "mode_hdr.h"
00044
00045 #if defined(__cplusplus)
00046 extern "C"
00047 {
00048 #endif
00049
00050 #define BLOCK_SIZE GCM_BLOCK_SIZE
00051 #define BLK_ADR_MASK (BLOCK_SIZE - 1)
00052 #define CTR_POS 12
00053
00054 #define inc_ctr(x) \
00055 { int i = BLOCK_SIZE; while(i-- > CTR_POS && !++(ui8_ptr(x)[i])) ; }
00056
00057 ret_type gcm_init_and_key(
00058 const unsigned char key[],
00059 unsigned long key_len,
00060 gcm_ctx ctx[1])
00061 {
00062 memset(ctx->ghash_h, 0, sizeof(ctx->ghash_h));
00063
00064
00065 aes_encrypt_key(key, key_len, ctx->aes);
00066
00067
00068 aes_encrypt(ui8_ptr(ctx->ghash_h), ui8_ptr(ctx->ghash_h), ctx->aes);
00069
00070 #if defined( TABLES_64K )
00071 init_64k_table(ui8_ptr(ctx->ghash_h), ctx->gf_t64k);
00072 #elif defined( TABLES_8K )
00073 init_8k_table(ui8_ptr(ctx->ghash_h), ctx->gf_t8k);
00074 #elif defined( TABLES_4K )
00075 init_4k_table(ui8_ptr(ctx->ghash_h), ctx->gf_t4k);
00076 #elif defined( TABLES_256 )
00077 init_256_table(ui8_ptr(ctx->ghash_h), ctx->gf_t256);
00078 #endif
00079 return RETURN_OK;
00080 }
00081
00082 #if defined( TABLES_64K )
00083 #define gf_mul_hh(a, ctx, scr) gf_mul_64k(a, ctx->gf_t64k, scr)
00084 #elif defined( TABLES_8K )
00085 #define gf_mul_hh(a, ctx, scr) gf_mul_8k(a, ctx->gf_t8k, scr)
00086 #elif defined( TABLES_4K )
00087 #define gf_mul_hh(a, ctx, scr) gf_mul_4k(a, ctx->gf_t4k, scr)
00088 #elif defined( TABLES_256 )
00089 #define gf_mul_hh(a, ctx, scr) gf_mul_256(a, ctx->gf_t256, scr)
00090 #else
00091 #define gf_mul_hh(a, ctx, scr) gf_mul(a, ui8_ptr(ctx->ghash_h))
00092 #endif
00093
00094 ret_type gcm_init_message(
00095 const unsigned char iv[],
00096 unsigned long iv_len,
00097 gcm_ctx ctx[1])
00098 { uint_32t i, n_pos = 0, scratch[GF_BYTE_LEN >> 2];
00099 uint_8t *p;
00100
00101 memset(ctx->ctr_val, 0, BLOCK_SIZE);
00102 if(iv_len == CTR_POS)
00103 {
00104 memcpy(ctx->ctr_val, iv, CTR_POS); ui8_ptr(ctx->ctr_val)[15] = 0x01;
00105 }
00106 else
00107 { n_pos = iv_len;
00108 while(n_pos >= BLOCK_SIZE)
00109 {
00110 xor_block_aligned(ctx->ctr_val, iv);
00111 n_pos -= BLOCK_SIZE;
00112 iv += BLOCK_SIZE;
00113 gf_mul_hh(ui8_ptr(ctx->ctr_val), ctx, scratch);
00114 }
00115
00116 if(n_pos)
00117 {
00118 p = ui8_ptr(ctx->ctr_val);
00119 while(n_pos-- > 0)
00120 *p++ ^= *iv++;
00121 gf_mul_hh(ui8_ptr(ctx->ctr_val), ctx, scratch);
00122 }
00123 n_pos = (iv_len << 3);
00124 for(i = BLOCK_SIZE - 1; n_pos; --i, n_pos >>= 8)
00125 ui8_ptr(ctx->ctr_val)[i] ^= (unsigned char)n_pos;
00126 gf_mul_hh(ui8_ptr(ctx->ctr_val), ctx, scratch);
00127 }
00128
00129 ctx->y0_val = *ui32_ptr(ui8_ptr(ctx->ctr_val) + CTR_POS);
00130 inc_ctr(ctx->ctr_val);
00131 memset(ctx->hdr_ghv, 0, BLOCK_SIZE);
00132 memset(ctx->txt_ghv, 0, BLOCK_SIZE);
00133 ctx->hdr_cnt = 0;
00134 ctx->txt_ccnt = ctx->txt_acnt = 0;
00135 return RETURN_OK;
00136 }
00137
00138 ret_type gcm_auth_header(
00139 const unsigned char hdr[],
00140 unsigned long hdr_len,
00141 gcm_ctx ctx[1])
00142 { uint_32t cnt = 0, b_pos = (uint_32t)ctx->hdr_cnt & BLK_ADR_MASK;
00143 uint_32t scratch[GF_BYTE_LEN >> 2];
00144
00145 if(!hdr_len)
00146 return RETURN_OK;
00147
00148 if(ctx->hdr_cnt && b_pos == 0)
00149 gf_mul_hh(ui8_ptr(ctx->hdr_ghv), ctx, scratch);
00150
00151 while(cnt < hdr_len && (b_pos & BUF_ADRMASK))
00152 ui8_ptr(ctx->hdr_ghv)[b_pos++] ^= hdr[cnt++];
00153
00154 if(!(b_pos & BUF_ADRMASK) && !((hdr + cnt - ui8_ptr(ctx->hdr_ghv)) & BUF_ADRMASK))
00155 {
00156 while(cnt + BUF_INC <= hdr_len && b_pos <= BLOCK_SIZE - BUF_INC)
00157 {
00158 *unit_ptr(ui8_ptr(ctx->hdr_ghv) + b_pos) ^= *unit_ptr(hdr + cnt);
00159 cnt += BUF_INC; b_pos += BUF_INC;
00160 }
00161
00162 while(cnt + BLOCK_SIZE <= hdr_len)
00163 {
00164 gf_mul_hh(ui8_ptr(ctx->hdr_ghv), ctx, scratch);
00165 xor_block_aligned(ctx->hdr_ghv, hdr + cnt);
00166 cnt += BLOCK_SIZE;
00167 }
00168 }
00169 else
00170 {
00171 while(cnt < hdr_len && b_pos < BLOCK_SIZE)
00172 ui8_ptr(ctx->hdr_ghv)[b_pos++] ^= hdr[cnt++];
00173
00174 while(cnt + BLOCK_SIZE <= hdr_len)
00175 {
00176 gf_mul_hh(ui8_ptr(ctx->hdr_ghv), ctx, scratch);
00177 xor_block(ctx->hdr_ghv, hdr + cnt);
00178 cnt += BLOCK_SIZE;
00179 }
00180 }
00181
00182 while(cnt < hdr_len)
00183 {
00184 if(b_pos == BLOCK_SIZE)
00185 {
00186 gf_mul_hh(ui8_ptr(ctx->hdr_ghv), ctx, scratch);
00187 b_pos = 0;
00188 }
00189 ui8_ptr(ctx->hdr_ghv)[b_pos++] ^= hdr[cnt++];
00190 }
00191
00192 ctx->hdr_cnt += cnt;
00193 return RETURN_OK;
00194 }
00195
00196 ret_type gcm_auth_data(
00197 const unsigned char data[],
00198 unsigned long data_len,
00199 gcm_ctx ctx[1])
00200 { uint_32t cnt = 0, b_pos = (uint_32t)(ctx->txt_acnt & BLK_ADR_MASK);
00201 uint_32t scratch[GF_BYTE_LEN >> 2];
00202
00203 if(!data_len)
00204 return RETURN_OK;
00205
00206 if(ctx->txt_acnt && b_pos == 0)
00207 gf_mul_hh(ui8_ptr(ctx->txt_ghv), ctx, scratch);
00208
00209 while(cnt < data_len && (b_pos & BUF_ADRMASK))
00210 ui8_ptr(ctx->txt_ghv)[b_pos++] ^= data[cnt++];
00211
00212 if(!(b_pos & BUF_ADRMASK) && !((data + cnt - ui8_ptr(ctx->txt_ghv)) & BUF_ADRMASK))
00213 {
00214 while(cnt + BUF_INC <= data_len && b_pos <= BLOCK_SIZE - BUF_INC)
00215 {
00216 *unit_ptr(ui8_ptr(ctx->txt_ghv) + b_pos) ^= *unit_ptr(data + cnt);
00217 cnt += BUF_INC; b_pos += BUF_INC;
00218 }
00219
00220 while(cnt + BLOCK_SIZE <= data_len)
00221 {
00222 gf_mul_hh(ui8_ptr(ctx->txt_ghv), ctx, scratch);
00223 xor_block_aligned(ctx->txt_ghv, data + cnt);
00224 cnt += BLOCK_SIZE;
00225 }
00226 }
00227 else
00228 {
00229 while(cnt < data_len && b_pos < BLOCK_SIZE)
00230 ui8_ptr(ctx->txt_ghv)[b_pos++] ^= data[cnt++];
00231
00232 while(cnt + BLOCK_SIZE <= data_len)
00233 {
00234 gf_mul_hh(ui8_ptr(ctx->txt_ghv), ctx, scratch);
00235 xor_block(ctx->txt_ghv, data + cnt);
00236 cnt += BLOCK_SIZE;
00237 }
00238 }
00239
00240 while(cnt < data_len)
00241 {
00242 if(b_pos == BLOCK_SIZE)
00243 {
00244 gf_mul_hh(ui8_ptr(ctx->txt_ghv), ctx, scratch);
00245 b_pos = 0;
00246 }
00247 ui8_ptr(ctx->txt_ghv)[b_pos++] ^= data[cnt++];
00248 }
00249
00250 ctx->txt_acnt += cnt;
00251 return RETURN_OK;
00252 }
00253
00254 ret_type gcm_crypt_data(
00255 unsigned char data[],
00256 unsigned long data_len,
00257 gcm_ctx ctx[1])
00258 { uint_32t cnt = 0, b_pos = (uint_32t)(ctx->txt_ccnt & BLK_ADR_MASK);
00259
00260 if(!data_len)
00261 return RETURN_OK;
00262
00263 if(b_pos == 0)
00264 {
00265 aes_encrypt(ui8_ptr(ctx->ctr_val), ui8_ptr(ctx->enc_ctr), ctx->aes);
00266 inc_ctr(ctx->ctr_val);
00267 }
00268
00269 while(cnt < data_len && (b_pos & BUF_ADRMASK))
00270 data[cnt++] ^= ui8_ptr(ctx->enc_ctr)[b_pos++];
00271
00272 if(!(b_pos & BUF_ADRMASK) && !((data + cnt - ui8_ptr(ctx->enc_ctr)) & BUF_ADRMASK))
00273 {
00274 while(cnt + BUF_INC <= data_len && b_pos <= BLOCK_SIZE - BUF_INC)
00275 {
00276 *unit_ptr(data + cnt) ^= *unit_ptr(ui8_ptr(ctx->enc_ctr) + b_pos);
00277 cnt += BUF_INC; b_pos += BUF_INC;
00278 }
00279
00280 while(cnt + BLOCK_SIZE <= data_len)
00281 {
00282 aes_encrypt(ui8_ptr(ctx->ctr_val), ui8_ptr(ctx->enc_ctr), ctx->aes);
00283 inc_ctr(ctx->ctr_val);
00284 xor_block_aligned(data + cnt, ctx->enc_ctr);
00285 cnt += BLOCK_SIZE;
00286 }
00287 }
00288 else
00289 {
00290 while(cnt < data_len && b_pos < BLOCK_SIZE)
00291 data[cnt++] ^= ui8_ptr(ctx->enc_ctr)[b_pos++];
00292
00293 while(cnt + BLOCK_SIZE <= data_len)
00294 {
00295 aes_encrypt(ui8_ptr(ctx->ctr_val), ui8_ptr(ctx->enc_ctr), ctx->aes);
00296 inc_ctr(ctx->ctr_val);
00297 xor_block(data + cnt, ctx->enc_ctr);
00298 cnt += BLOCK_SIZE;
00299 }
00300 }
00301
00302 while(cnt < data_len)
00303 {
00304 if(b_pos == BLOCK_SIZE)
00305 {
00306 aes_encrypt(ui8_ptr(ctx->ctr_val), ui8_ptr(ctx->enc_ctr), ctx->aes);
00307 inc_ctr(ctx->ctr_val);
00308 b_pos = 0;
00309 }
00310 data[cnt++] ^= ui8_ptr(ctx->enc_ctr)[b_pos++];
00311 }
00312
00313 ctx->txt_ccnt += cnt;
00314 return RETURN_OK;
00315 }
00316
00317 ret_type gcm_compute_tag(
00318 unsigned char tag[],
00319 unsigned long tag_len,
00320 gcm_ctx ctx[1])
00321 { uint_32t i, ln, scratch[GF_BYTE_LEN >> 2];
00322 uint_8t tbuf[BLOCK_SIZE];
00323
00324 if(ctx->txt_acnt != ctx->txt_ccnt && ctx->txt_ccnt > 0)
00325 return RETURN_ERROR;
00326
00327 gf_mul_hh(ui8_ptr(ctx->hdr_ghv), ctx, scratch);
00328 gf_mul_hh(ui8_ptr(ctx->txt_ghv), ctx, scratch);
00329
00330 #if 1
00331 if(ctx->hdr_cnt && (ln = (uint_32t)((ctx->txt_acnt + BLOCK_SIZE - 1) / BLOCK_SIZE)))
00332 {
00333 memcpy(tbuf, ctx->ghash_h, BLOCK_SIZE);
00334 for( ; ; )
00335 {
00336 if(ln & 1) gf_mul(ui8_ptr(ctx->hdr_ghv), tbuf);
00337 if(!(ln >>= 1)) break;
00338 gf_mul(tbuf, tbuf);
00339 }
00340 }
00341 #else
00342 if(ctx->hdr_cnt && (ln = (uint_32t)((ctx->txt_acnt + BLOCK_SIZE - 1) / BLOCK_SIZE)))
00343 {
00344 i = ln | ln >> 1; i |= i >> 2; i |= i >> 4;
00345 i |= i >> 8; i |= i >> 16; i = i & ~(i >> 1);
00346 memset(tbuf, 0, BLOCK_SIZE);
00347 tbuf[0] = 0x80;
00348 while(i)
00349 {
00350 gf_mul(tbuf, tbuf);
00351 if(i & ln)
00352 gf_mul_hh(tbuf, ctx, scratch);
00353 i >>= 1;
00354 }
00355 gf_mul(ui8_ptr(ctx->hdr_ghv), tbuf);
00356 }
00357 #endif
00358 i = BLOCK_SIZE; ln = (uint_32t)(ctx->txt_acnt << 3);
00359 while(i-- > 0)
00360 {
00361 ui8_ptr(ctx->hdr_ghv)[i] ^= ui8_ptr(ctx->txt_ghv)[i] ^ (unsigned char)ln;
00362 ln = (i == 8 ? (uint_32t)(ctx->hdr_cnt << 3) : ln >> 8);
00363 }
00364
00365 gf_mul_hh(ui8_ptr(ctx->hdr_ghv), ctx, scratch);
00366
00367 *ui32_ptr(ui8_ptr(ctx->ctr_val) + CTR_POS) = ctx->y0_val;
00368 aes_encrypt(ui8_ptr(ctx->ctr_val), ui8_ptr(ctx->enc_ctr), ctx->aes);
00369 for(i = 0; i < (unsigned int)tag_len; ++i)
00370 tag[i] = ui8_ptr(ctx->hdr_ghv)[i] ^ ui8_ptr(ctx->enc_ctr)[i];
00371
00372 return (ctx->txt_ccnt == ctx->txt_acnt ? RETURN_OK : RETURN_WARN);
00373 }
00374
00375 ret_type gcm_end(
00376 gcm_ctx ctx[1])
00377 {
00378 memset(ctx, 0, sizeof(gcm_ctx));
00379 return RETURN_OK;
00380 }
00381
00382 ret_type gcm_encrypt(
00383 unsigned char data[],
00384 unsigned long data_len,
00385 gcm_ctx ctx[1])
00386 {
00387
00388 gcm_crypt_data(data, data_len, ctx);
00389 gcm_auth_data(data, data_len, ctx);
00390 return RETURN_OK;
00391 }
00392
00393 ret_type gcm_decrypt(
00394 unsigned char data[],
00395 unsigned long data_len,
00396 gcm_ctx ctx[1])
00397 {
00398 gcm_auth_data(data, data_len, ctx);
00399 gcm_crypt_data(data, data_len, ctx);
00400 return RETURN_OK;
00401 }
00402
00403 ret_type gcm_encrypt_message(
00404 const unsigned char iv[],
00405 unsigned long iv_len,
00406 const unsigned char hdr[],
00407 unsigned long hdr_len,
00408 unsigned char msg[],
00409 unsigned long msg_len,
00410 unsigned char tag[],
00411 unsigned long tag_len,
00412 gcm_ctx ctx[1])
00413 {
00414 gcm_init_message(iv, iv_len, ctx);
00415 gcm_auth_header(hdr, hdr_len, ctx);
00416 gcm_encrypt(msg, msg_len, ctx);
00417 return gcm_compute_tag(tag, tag_len, ctx) ? RETURN_ERROR : RETURN_OK;
00418 }
00419
00420 ret_type gcm_decrypt_message(
00421 const unsigned char iv[],
00422 unsigned long iv_len,
00423 const unsigned char hdr[],
00424 unsigned long hdr_len,
00425 unsigned char msg[],
00426 unsigned long msg_len,
00427 const unsigned char tag[],
00428 unsigned long tag_len,
00429 gcm_ctx ctx[1])
00430 { uint_8t local_tag[BLOCK_SIZE];
00431 ret_type rr;
00432
00433 gcm_init_message(iv, iv_len, ctx);
00434 gcm_auth_header(hdr, hdr_len, ctx);
00435 gcm_decrypt(msg, msg_len, ctx);
00436 rr = gcm_compute_tag(local_tag, tag_len, ctx);
00437 return (rr != RETURN_OK || memcmp(tag, local_tag, tag_len)) ? RETURN_ERROR : RETURN_OK;
00438 }
00439
00440 #if defined(__cplusplus)
00441 }
00442 #endif
00443
00444 #endif