BOOL gcm_add_cipher(gcm *g,int mode,char *plain,int len,char *cipher) { /* Add plaintext to extract ciphertext, or visa versa, depending on mode. len is length of plaintext/ciphertext. Note this file combines GHASH() functionality with encryption/decryption */ int i,j=0; MR_WORD counter; MR_BYTE B[16]; if (g->status==GCM_ACCEPTING_HEADER) g->status=GCM_ACCEPTING_CIPHER; if (g->status!=GCM_ACCEPTING_CIPHER) return FALSE; while (j<len) { if (cipher!=NULL) { counter=pack((MR_BYTE *)&(g->a.f[12])); counter++; unpack(counter,(MR_BYTE *)&(g->a.f[12])); /* increment counter */ for (i=0;i<16;i++) B[i]=g->a.f[i]; aes_ecb_encrypt(&(g->a),B); /* encrypt it */ } for (i=0;i<16 && j<len;i++) { if (cipher==NULL) g->stateX[i]^=plain[j++]; else { if (mode==GCM_ENCRYPTING) cipher[j]=plain[j]^B[i]; if (mode==GCM_DECRYPTING) plain[j]=cipher[j]^B[i]; g->stateX[i]^=cipher[j++]; } g->lenC[1]++; if (g->lenC[1]==0) g->lenC[0]++; } gf2mul(g); } if (len%16!=0) g->status=GCM_NOT_ACCEPTING_MORE; return TRUE; }
/* Add Ciphertext - decrypts to plaintext */ int MCL_GCM_add_cipher(mcl_gcm *g,char *plain,char *cipher,int len) { /* Add ciphertext to extract plaintext, len is length of ciphertext. */ int i,j=0; unsign32 counter; uchar B[16]; if (g->status==MCL_GCM_ACCEPTING_HEADER) g->status=MCL_GCM_ACCEPTING_CIPHER; if (g->status!=MCL_GCM_ACCEPTING_CIPHER) return 0; while (j<len) { counter=pack((uchar *)&(g->a.f[12])); counter++; unpack(counter,(uchar *)&(g->a.f[12])); /* increment counter */ for (i=0;i<16;i++) B[i]=g->a.f[i]; MCL_AES_ecb_encrypt(&(g->a),B); /* encrypt it */ for (i=0;i<16 && j<len;i++) { plain[j]=cipher[j]^B[i]; g->stateX[i]^=cipher[j++]; g->lenC[1]++; if (g->lenC[1]==0) g->lenC[0]++; } gf2mul(g); } if (len%16!=0) g->status=MCL_GCM_NOT_ACCEPTING_MORE; return 1; }
void gcm_finish(gcm *g,char *tag) { /* Finish off and extract tag (MAC) */ int i,j; MR_WORD F[4]; MR_BYTE L[16]; /* convert lengths from bytes to bits */ F[0]=(g->lenA[0]<<3)|(g->lenA[1]&0xE0000000)>>29; F[1]=g->lenA[1]<<3; F[2]=(g->lenC[0]<<3)|(g->lenC[1]&0xE0000000)>>29; F[3]=g->lenC[1]<<3; for (i=j=0;i<NB;i++,j+=4) unpack(F[i],(MR_BYTE *)&L[j]); for (i=0;i<16;i++) g->stateX[i]^=L[i]; gf2mul(g); g->counter=1; unpack(g->counter,(MR_BYTE *)&(g->a.f[12])); /* reset counter */ for (i=0;i<16;i++) L[i]=g->a.f[i]; aes_ecb_encrypt(&(g->a),L); /* E(K,Y0) */ for (i=0;i<16;i++) L[i]^=g->stateX[i]; g->status=GCM_FINISHED; for (i=0;i<16;i++) tag[i]=L[i]; aes_end(&(g->a)); }
BOOL gcm_add_cipher(gcm *g,int mode,char *plain,int len,char *cipher) { /* Add plaintext to extract ciphertext, or visa versa, depending on mode. len is length of plaintext/ciphertext */ int i,j=0; MR_BYTE B[16]; if (g->status==GCM_ACCEPTING_HEADER) g->status=GCM_ACCEPTING_CIPHER; if (g->status!=GCM_ACCEPTING_CIPHER) return FALSE; while (j<len) { g->counter++; unpack(g->counter,(MR_BYTE *)&(g->a.f[12])); /* get counter */ for (i=0;i<16;i++) B[i]=g->a.f[i]; aes_ecb_encrypt(&(g->a),B); /* encrypt it */ for (i=0;i<16 && j<len;i++) { if (mode==GCM_ENCRYPTING) cipher[j]=plain[j]^B[i]; if (mode==GCM_DECRYPTING) plain[j]=cipher[j]^B[i]; g->stateX[i]^=cipher[j++]; g->lenC[1]++; if (g->lenC[1]==0) g->lenC[0]++; } gf2mul(g); } if (len%16!=0) g->status=GCM_NOT_ACCEPTING_MORE; return TRUE; }
/* SU= 32 */ static void MCL_GCM_wrap(mcl_gcm *g) { /* Finish off GMCL_HASH */ int i,j; unsign32 F[4]; uchar L[16]; /* convert lengths from bytes to bits */ F[0]=(g->lenA[0]<<3)|(g->lenA[1]&0xE0000000)>>29; F[1]=g->lenA[1]<<3; F[2]=(g->lenC[0]<<3)|(g->lenC[1]&0xE0000000)>>29; F[3]=g->lenC[1]<<3; for (i=j=0;i<NB;i++,j+=4) unpack(F[i],(uchar *)&L[j]); for (i=0;i<16;i++) g->stateX[i]^=L[i]; gf2mul(g); }
static void gcm_wrap(gcm *g) { /* Finish off GHASH */ int i,j; MR_WORD F[4]; MR_BYTE L[16]; /* convert lengths from bytes to bits */ F[0]=(g->lenA[0]<<3)|(g->lenA[1]&0xE0000000)>>29; F[1]=g->lenA[1]<<3; F[2]=(g->lenC[0]<<3)|(g->lenC[1]&0xE0000000)>>29; F[3]=g->lenC[1]<<3; for (i=j=0;i<NB;i++,j+=4) unpack(F[i],(MR_BYTE *)&L[j]); for (i=0;i<16;i++) g->stateX[i]^=L[i]; gf2mul(g); }
/* Add Header data - included but not encrypted */ int MCL_GCM_add_header(mcl_gcm* g,char *header,int len) { /* Add some header. Won't be encrypted, but will be authenticated. len is length of header */ int i,j=0; if (g->status!=MCL_GCM_ACCEPTING_HEADER) return 0; while (j<len) { for (i=0;i<16 && j<len;i++) { g->stateX[i]^=header[j++]; g->lenA[1]++; if (g->lenA[1]==0) g->lenA[0]++; } gf2mul(g); } if (len%16!=0) g->status=MCL_GCM_ACCEPTING_CIPHER; return 1; }
static int MCL_GCM_ghash(mcl_gcm *g,char *plain,int len) { int i,j=0; if (g->status==MCL_GCM_ACCEPTING_HEADER) g->status=MCL_GCM_ACCEPTING_CIPHER; if (g->status!=MCL_GCM_ACCEPTING_CIPHER) return 0; while (j<len) { for (i=0;i<16 && j<len;i++) { g->stateX[i]^=plain[j++]; g->lenC[1]++; if (g->lenC[1]==0) g->lenC[0]++; } gf2mul(g); } if (len%16!=0) g->status=MCL_GCM_NOT_ACCEPTING_MORE; return 1; }
static int GCM_ghash(gcm *g,char *plain,int len) { int i,j=0; unsign32 counter; uchar B[16]; if (g->status==GCM_ACCEPTING_HEADER) g->status=GCM_ACCEPTING_CIPHER; if (g->status!=GCM_ACCEPTING_CIPHER) return 0; while (j<len) { for (i=0;i<16 && j<len;i++) { g->stateX[i]^=plain[j++]; g->lenC[1]++; if (g->lenC[1]==0) g->lenC[0]++; } gf2mul(g); } if (len%16!=0) g->status=GCM_NOT_ACCEPTING_MORE; return 1; }