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
00037
00038
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
00052 #define BLK_ADR_MASK (BLOCK_SIZE - 1)
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(
00059 const unsigned char key[],
00060 unsigned long key_len,
00061 gcm_ctx ctx[1])
00062 {
00063 memset(ctx->ghash_h, 0, sizeof(ctx->ghash_h));
00064
00065
00066 aes_encrypt_key(key, key_len, ctx->aes);
00067
00068
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(
00096 const unsigned char iv[],
00097 unsigned long iv_len,
00098 gcm_ctx ctx[1])
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(
00140 const unsigned char hdr[],
00141 unsigned long hdr_len,
00142 gcm_ctx ctx[1])
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(
00198 const unsigned char data[],
00199 unsigned long data_len,
00200 gcm_ctx ctx[1])
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(
00256 unsigned char data[],
00257 unsigned long data_len,
00258 gcm_ctx ctx[1])
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(
00319 unsigned char tag[],
00320 unsigned long tag_len,
00321 gcm_ctx ctx[1])
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
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
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(
00377 gcm_ctx ctx[1])
00378 {
00379 memset(ctx, 0, sizeof(gcm_ctx));
00380 return RETURN_OK;
00381 }
00382
00383 ret_type gcm_encrypt(
00384 unsigned char data[],
00385 unsigned long data_len,
00386 gcm_ctx ctx[1])
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(
00395 unsigned char data[],
00396 unsigned long data_len,
00397 gcm_ctx ctx[1])
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(
00405 const unsigned char iv[],
00406 unsigned long iv_len,
00407 const unsigned char hdr[],
00408 unsigned long hdr_len,
00409 unsigned char msg[],
00410 unsigned long msg_len,
00411 unsigned char tag[],
00412 unsigned long tag_len,
00413 gcm_ctx ctx[1])
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(
00422 const unsigned char iv[],
00423 unsigned long iv_len,
00424 const unsigned char hdr[],
00425 unsigned long hdr_len,
00426 unsigned char msg[],
00427 unsigned long msg_len,
00428 const unsigned char tag[],
00429 unsigned long tag_len,
00430 gcm_ctx ctx[1])
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