/* =================== ELmD((5,10),127,0) Verified Decryption Function =================== */ int crypto_aead_decrypt( unsigned char *m,unsigned long long *mlen, unsigned char *nsec, const unsigned char *c, unsigned long long clen, const unsigned char *ad, unsigned long long adlen, const unsigned char *npub, const unsigned char *k ) { u8 param[]={0x5a,0,0x7f,0x80,0,0,0,0}; block L, W, Delta_0, Delta_1, Delta_2, blk, result, CS; int i,j, flag = 0; u8 zeroes[16], ozs[16], blen = 16, Is_final = 0, Is_complete =1; unsigned long long outputmlen, blk_ctr=0, blk_ctr1=0; for(i=0; i<16; i++) {zeroes[i]=0x00;} // all zero. for(i=1; i<16; i++) {ozs[i]=0x00;} ozs[0] = 0x80; //useful for padding. if(((clen % 16) != 1)||(clen < 33)) return -1; // Bugfix from Nilanjan Datta, 22 Sep 2014 if((c[clen-1]!= 0x00) && (c[clen-1]!=0x01)) return -1; key_schedule(k); /* =========== Generate the Masks ========== */ AES(10, ENCRYPT, L, zeroes, &aes_key1); mult_3(Delta_0, L); mult_inv2(Delta_0, Delta_0); mult_inv2(Delta_1, L); mult_3(Delta_2, L); mult_3(Delta_2, Delta_2); mult_inv2(Delta_2, Delta_2); /* ============= Process Associated Data ================ */ for(i=0; i<16; i++) W[i]=0x00; process_AD(W, Delta_0, npub, param, ad, adlen); load_block(CS, zeroes, zeroes, 16, 0); /* ================ Process Ciphertext Blocks ============ */ load_block(blk, c, zeroes, 16, 0); /* =================== Process 1st Block =================== */ if( (clen==33) && (c[clen-1]==0x01) ) { process_block(Delta_2, Delta_1, result, blk, W, 0, DECRYPT, Is_final, CIPHERTEXT); for(i=15; i>7; i--) { if(result[i]==0x80) { flag = 1; break; } } if(flag == 0) {return -1; } for(j=i+1; j<16; j++) { if(result[j]!=0) {return -1; }} store_bytes(m, result, 8, i-1); outputmlen = i-8; } else { process_block(Delta_2, Delta_1, result, blk, W, 1, DECRYPT, Is_final, CIPHERTEXT); store_bytes(m, result, 8, 15); m +=8; outputmlen = 8; } xor_block(CS, CS, result); store_bytes(nsec, result, 0, 7); clen -= 16; c+=16; blk_ctr ++; /* ============= Process Successive Ciphertext Blocks ============== */ while(clen > 17){ load_block(blk, c, zeroes, 16, 0); if((clen == 33) && (c[clen-1]==0x01)) { process_block(Delta_2, Delta_1, result, blk, W, 0, DECRYPT, Is_final, CIPHERTEXT); i = -1; for(i=15; i>0; i--) { if(result[i]==0x80) { flag = 1; break; } } if(flag == 0) {return -1; } for(j=i+1; j<16; j++) { if(result[j]!=0) {return -1; }} store_bytes(m, result, 0, i-1); outputmlen += i; } else{ process_block(Delta_2, Delta_1, result, blk, W, 1, DECRYPT, Is_final, CIPHERTEXT); store_bytes(m, result, 0, 15); outputmlen += 16; } xor_block(CS, CS, result); clen -= 16; c+=16; blk_ctr ++; if(clen != 17) m +=16; if(blk_ctr == IT_GAP && blk_ctr1 < IT_MAX && clen > 48){ AES(10, DECRYPT, result, W, &aes_key2); mask(Delta_2, result, result, 1); for(i=0; i<16; i++) { if(c[i] != result[i]) {return -1; } } c +=16; clen -= 16; blk_ctr =0; blk_ctr1++; } } /* ========== Process checksum block ============= */ Is_final = 1; process_block(Delta_1, Delta_2, result, CS, W, 1, ENCRYPT, Is_final, MESSAGE); for(i=0; i<16; i++) {if(result[i]!=c[i]) return -1;} *mlen = outputmlen; return 0; }
/* * Algorithm independent CBC functions. */ int cbc_encrypt_contiguous_blocks(cbc_ctx_t *ctx, char *data, size_t length, crypto_data_t *out, size_t block_size, int (*encrypt)(const void *, const uint8_t *, uint8_t *), void (*copy_block)(uint8_t *, uint8_t *), void (*xor_block)(uint8_t *, uint8_t *)) { size_t remainder = length; size_t need = 0; uint8_t *datap = (uint8_t *)data; uint8_t *blockp; uint8_t *lastp; void *iov_or_mp; offset_t offset; uint8_t *out_data_1; uint8_t *out_data_2; size_t out_data_1_len; if (length + ctx->cbc_remainder_len < block_size) { /* accumulate bytes here and return */ bcopy(datap, (uint8_t *)ctx->cbc_remainder + ctx->cbc_remainder_len, length); ctx->cbc_remainder_len += length; ctx->cbc_copy_to = datap; return (CRYPTO_SUCCESS); } lastp = (uint8_t *)ctx->cbc_iv; if (out != NULL) crypto_init_ptrs(out, &iov_or_mp, &offset); do { /* Unprocessed data from last call. */ if (ctx->cbc_remainder_len > 0) { need = block_size - ctx->cbc_remainder_len; if (need > remainder) return (CRYPTO_DATA_LEN_RANGE); bcopy(datap, &((uint8_t *)ctx->cbc_remainder) [ctx->cbc_remainder_len], need); blockp = (uint8_t *)ctx->cbc_remainder; } else { blockp = datap; } if (out == NULL) { /* * XOR the previous cipher block or IV with the * current clear block. */ xor_block(lastp, blockp); encrypt(ctx->cbc_keysched, blockp, blockp); ctx->cbc_lastp = blockp; lastp = blockp; if (ctx->cbc_remainder_len > 0) { bcopy(blockp, ctx->cbc_copy_to, ctx->cbc_remainder_len); bcopy(blockp + ctx->cbc_remainder_len, datap, need); } } else { /* * XOR the previous cipher block or IV with the * current clear block. */ xor_block(blockp, lastp); encrypt(ctx->cbc_keysched, lastp, lastp); crypto_get_ptrs(out, &iov_or_mp, &offset, &out_data_1, &out_data_1_len, &out_data_2, block_size); /* copy block to where it belongs */ if (out_data_1_len == block_size) { copy_block(lastp, out_data_1); } else { bcopy(lastp, out_data_1, out_data_1_len); if (out_data_2 != NULL) { bcopy(lastp + out_data_1_len, out_data_2, block_size - out_data_1_len); } } /* update offset */ out->cd_offset += block_size; } /* Update pointer to next block of data to be processed. */ if (ctx->cbc_remainder_len != 0) { datap += need; ctx->cbc_remainder_len = 0; } else { datap += block_size; } remainder = (size_t)&data[length] - (size_t)datap; /* Incomplete last block. */ if (remainder > 0 && remainder < block_size) { bcopy(datap, ctx->cbc_remainder, remainder); ctx->cbc_remainder_len = remainder; ctx->cbc_copy_to = datap; goto out; } ctx->cbc_copy_to = NULL; } while (remainder > 0); out: /* * Save the last encrypted block in the context. */ if (ctx->cbc_lastp != NULL) { copy_block((uint8_t *)ctx->cbc_lastp, (uint8_t *)ctx->cbc_iv); ctx->cbc_lastp = (uint8_t *)ctx->cbc_iv; } return (CRYPTO_SUCCESS); }
// If encr, encrypts, otherwise decrypts // Lua arguments: // string text (may be cleartext or encrypted text) // string password // sha256(password) is used as key for twofish // returns cleartext or encrypted text static int twofish_twoways(lua_State *L, int encr) { if (lua_gettop(L) != 2) { return 0; } if (lua_type(L, 1) != LUA_TSTRING) { return 0; } if (lua_type(L, 2) != LUA_TSTRING) { return 0; } size_t text_s; const char* text = lua_tolstring(L, 1, &text_s); size_t password_s; const char* password = lua_tolstring(L, 2, &password_s); // sha256 unsigned char sha256sum[32]; calc_sha256(sha256sum, password, password_s); // twofish - prepare key u32 *S; u32 K[40]; int k; keySched(sha256sum, 256, &S, K, &k); u32 QF[4][256]; fullKey(S, k, QF); free(S); // allocate output string // nonce is stored in the beginning int result_bytes; if (encr) { result_bytes = text_s + BLOCK_BYTES; } else { result_bytes = text_s - BLOCK_BYTES; } if (result_bytes <= 0) { return 0; } char* result = malloc(result_bytes); // twofish - make nonce (~IV) for CTR mode const char* nonce; const char* input; // points to first block of data char* output; // points to first block of data int normal_blocks; if (encr) { char* nonce_mut = result; nonce = nonce_mut; get_random_bytes(nonce_mut, BLOCK_BYTES); input = text; output = result + BLOCK_BYTES; normal_blocks = text_s / BLOCK_BYTES; } else { nonce = text; input = text + BLOCK_BYTES; output = result; normal_blocks = (text_s / BLOCK_BYTES) - 1; } int i; for (i = 0; i < normal_blocks; i++) { const char* b_in = input + i * BLOCK_BYTES; char* b_out = output + i * BLOCK_BYTES; memcpy(b_out, nonce, BLOCK_BYTES); xor_ctr(b_out, i); encrypt(K, QF, b_out); xor_block(b_out, b_in, BLOCK_BYTES); } int last_block_size = text_s % BLOCK_BYTES; if (last_block_size) { const char* b_in = input + normal_blocks * BLOCK_BYTES; char* b_out = output + normal_blocks * BLOCK_BYTES; char block[BLOCK_BYTES]; memcpy(block, nonce, BLOCK_BYTES); xor_ctr(block, normal_blocks); encrypt(K, QF, block); memcpy(b_out, block, last_block_size); xor_block(b_out, b_in, last_block_size); } lua_pushlstring(L, result, result_bytes); free(result); return 1; }
static void add_round_key( uint_8t d[N_BLOCK], const uint_8t k[N_BLOCK] ) { xor_block(d, k); }
/* * Encrypt and decrypt multiple blocks of data in counter mode. */ int ctr_mode_contiguous_blocks(ctr_ctx_t *ctx, char *data, size_t length, crypto_data_t *out, size_t block_size, int (*cipher)(const void *ks, const uint8_t *pt, uint8_t *ct), void (*xor_block)(uint8_t *, uint8_t *)) { size_t remainder = length; size_t need = 0; uint8_t *datap = (uint8_t *)data; uint8_t *blockp; uint8_t *lastp; void *iov_or_mp; offset_t offset; uint8_t *out_data_1; uint8_t *out_data_2; size_t out_data_1_len; uint64_t lower_counter, upper_counter; if (length + ctx->ctr_remainder_len < block_size) { /* accumulate bytes here and return */ bcopy(datap, (uint8_t *)ctx->ctr_remainder + ctx->ctr_remainder_len, length); ctx->ctr_remainder_len += length; ctx->ctr_copy_to = datap; return (CRYPTO_SUCCESS); } lastp = (uint8_t *)ctx->ctr_cb; if (out != NULL) crypto_init_ptrs(out, &iov_or_mp, &offset); do { /* Unprocessed data from last call. */ if (ctx->ctr_remainder_len > 0) { need = block_size - ctx->ctr_remainder_len; if (need > remainder) return (CRYPTO_DATA_LEN_RANGE); bcopy(datap, &((uint8_t *)ctx->ctr_remainder) [ctx->ctr_remainder_len], need); blockp = (uint8_t *)ctx->ctr_remainder; } else { blockp = datap; } /* ctr_cb is the counter block */ cipher(ctx->ctr_keysched, (uint8_t *)ctx->ctr_cb, (uint8_t *)ctx->ctr_tmp); lastp = (uint8_t *)ctx->ctr_tmp; /* * Increment Counter. */ lower_counter = ntohll(ctx->ctr_cb[1] & ctx->ctr_lower_mask); lower_counter = htonll(lower_counter + 1); lower_counter &= ctx->ctr_lower_mask; ctx->ctr_cb[1] = (ctx->ctr_cb[1] & ~(ctx->ctr_lower_mask)) | lower_counter; /* wrap around */ if (lower_counter == 0) { upper_counter = ntohll(ctx->ctr_cb[0] & ctx->ctr_upper_mask); upper_counter = htonll(upper_counter + 1); upper_counter &= ctx->ctr_upper_mask; ctx->ctr_cb[0] = (ctx->ctr_cb[0] & ~(ctx->ctr_upper_mask)) | upper_counter; } /* * XOR encrypted counter block with the current clear block. */ xor_block(blockp, lastp); if (out == NULL) { if (ctx->ctr_remainder_len > 0) { bcopy(lastp, ctx->ctr_copy_to, ctx->ctr_remainder_len); bcopy(lastp + ctx->ctr_remainder_len, datap, need); } } else { crypto_get_ptrs(out, &iov_or_mp, &offset, &out_data_1, &out_data_1_len, &out_data_2, block_size); /* copy block to where it belongs */ bcopy(lastp, out_data_1, out_data_1_len); if (out_data_2 != NULL) { bcopy(lastp + out_data_1_len, out_data_2, block_size - out_data_1_len); } /* update offset */ out->cd_offset += block_size; } /* Update pointer to next block of data to be processed. */ if (ctx->ctr_remainder_len != 0) { datap += need; ctx->ctr_remainder_len = 0; } else { datap += block_size; } remainder = (size_t)&data[length] - (size_t)datap; /* Incomplete last block. */ if (remainder > 0 && remainder < block_size) { bcopy(datap, ctx->ctr_remainder, remainder); ctx->ctr_remainder_len = remainder; ctx->ctr_copy_to = datap; goto out; } ctx->ctr_copy_to = NULL; } while (remainder > 0); out: return (CRYPTO_SUCCESS); }
int decrypt_final(struct poet_ctx *ctx, const uint8_t *ciphertext, uint64_t clen, const uint8_t tag[BLOCKLEN], uint8_t *plaintext) { #ifdef DEBUG int i; #endif uint64_t offset=0; block s; block tmp; block tmp2; int alpha; int beta; uint64_t len; while( clen > BLOCKLEN ) { decrypt_block(ctx, ciphertext+offset, plaintext+offset); clen -= BLOCKLEN; offset += BLOCKLEN; } /* Encrypt length of message */ ctx->mlen+=(clen*8); memset(s,0,BLOCKLEN); len = TO_LITTLE_ENDIAN_64(ctx->mlen); memcpy(s, &len, 8); AES_encrypt(s, s ,&(ctx->aes_enc)); /* Last ciphertext block must be padded if necesscary */ memcpy(tmp,ciphertext+offset,clen); memcpy(tmp+clen,tag,BLOCKLEN-clen); /* Process last block + tag generation */ BOTTOM_HASH; xor_block(tmp,s,tmp); xor_block(ctx->y, tmp,ctx->y); AES_decrypt(ctx->y, tmp, &(ctx->aes_dec)); TOP_HASH; xor_block(tmp2, tmp, ctx->x); xor_block(tmp2, s, tmp2); memcpy(ctx->x,tmp,BLOCKLEN); #ifdef DEBUG puts("S"); for(i=0;i<16;i++) printf("%02x ",s[i]); puts(""); puts("X"); for(i=0;i<16;i++) printf("%02x ",ctx->x[i]); puts(""); puts("Y"); for(i=0;i<16;i++) printf("%02x ",ctx->y[i]); puts(""); #endif /* Do tag splitting if needed */ memcpy(plaintext+offset,tmp2,clen); alpha = memcmp(tmp2+clen,ctx->tau,BLOCKLEN-clen); /* Generate tag */ TOP_HASH; xor_block(ctx->x, ctx->tau ,ctx->x); xor_block(ctx->x, ctx->tm ,ctx->x); AES_encrypt(ctx->x, tmp, &(ctx->aes_enc)); BOTTOM_HASH; xor_block(tmp, ctx->y, tmp); xor_block(tmp, ctx->tm, tmp); #ifdef DEBUG puts("tmp"); for(i=0;i<16;i++) printf("%02x ",tmp[i]); puts(""); puts("tag"); for(i=0;i<16;i++) printf("%02x ",tag[i]); puts(""); #endif beta = memcmp(tmp,tag+(BLOCKLEN-clen),clen); return alpha|beta; }
void encrypt_final(struct poet_ctx *ctx, const uint8_t *plaintext, uint64_t plen, uint8_t *ciphertext, uint8_t tag[BLOCKLEN]) { #ifdef DEBUG int i; #endif uint64_t offset=0; uint64_t len; block s; block tmp; block tmp2; while( plen > BLOCKLEN ) { encrypt_block(ctx, (plaintext+offset), (ciphertext+offset)); plen -= BLOCKLEN; offset += BLOCKLEN; } /* Encrypt length of message */ ctx->mlen+=(plen*8); memset(s,0,BLOCKLEN); len = TO_LITTLE_ENDIAN_64(ctx->mlen); memcpy(s, &len,8); AES_encrypt(s, s ,&(ctx->aes_enc)); /* Last message block must be padded if necesscary */ memcpy(tmp,plaintext+offset,plen); memcpy(tmp+plen,ctx->tau,BLOCKLEN-plen); /* Process last block + tag generation */ TOP_HASH; xor_block(tmp,s,tmp); xor_block(ctx->x,tmp,ctx->x); AES_encrypt(ctx->x, tmp, &(ctx->aes_enc)); BOTTOM_HASH; xor_block(tmp2, tmp,ctx->y); memcpy(ctx->y, tmp, BLOCKLEN); xor_block(tmp,s,tmp2); #ifdef DEBUG puts("S"); for(i=0;i<16;i++) printf("%02x ",s[i]); puts(""); puts("X"); for(i=0;i<16;i++) printf("%02x ",ctx->x[i]); puts(""); puts("Y"); for(i=0;i<16;i++) printf("%02x ",ctx->y[i]); puts(""); #endif /* Do tag splitting if needed */ memcpy(ciphertext+offset,tmp,plen); memcpy(tag,tmp+plen,BLOCKLEN-plen); /* Generate tag */ TOP_HASH; xor_block(ctx->x, ctx->tau, ctx->x); xor_block(ctx->x, ctx->tm, ctx->x); AES_encrypt(ctx->x, tmp, &(ctx->aes_enc)); BOTTOM_HASH; xor_block(tmp, ctx->y, tmp); xor_block(tmp, ctx->tm, tmp); memcpy(tag+(BLOCKLEN-plen),tmp,plen); }
int ccmp_encrypt(struct ieee80211_key *key, wbuf_t wbuf0, int hdrlen, int mfp) { struct ccmp_ctx *ctx = key->wk_private; struct ieee80211_frame *wh; wbuf_t wbuf = wbuf0; int data_len, i, space; uint8_t aad[2 * AES_BLOCK_LEN], b0[AES_BLOCK_LEN], b[AES_BLOCK_LEN], e[AES_BLOCK_LEN], s0[AES_BLOCK_LEN]; uint8_t *pos; ctx->cc_vap->iv_stats.is_crypto_ccmp++; wh = (struct ieee80211_frame *)wbuf_header(wbuf); data_len = wbuf_get_pktlen(wbuf) - (hdrlen + ccmp.ic_header); ccmp_init_blocks(&ctx->cc_aes, wh, key->wk_keytsc, data_len, b0, aad, b, s0, mfp); i = 1; pos = (u_int8_t *)wbuf_header(wbuf) + hdrlen + ccmp.ic_header; /* NB: assumes header is entirely in first mbuf */ space = wbuf_get_pktlen(wbuf) - (hdrlen + ccmp.ic_header); for (;;) { if (space > data_len) space = data_len; /* * Do full blocks. */ while (space >= AES_BLOCK_LEN) { CCMP_ENCRYPT(i, b, b0, pos, e, AES_BLOCK_LEN); pos += AES_BLOCK_LEN, space -= AES_BLOCK_LEN; data_len -= AES_BLOCK_LEN; i++; } if (data_len <= 0) /* no more data */ break; wbuf = wbuf_next(wbuf); if (wbuf == NULL) { /* last buffer */ if (space != 0) { /* * Short last block. */ CCMP_ENCRYPT(i, b, b0, pos, e, space); } break; } #if 1 /* assume only one chunk */ break; #else if (space != 0) { uint8_t *pos_next; int space_next; int len, dl, sp; wbuf_t wbufi_new; /* * Block straddles one or more mbufs, gather data * into the block buffer b, apply the cipher, then * scatter the results back into the mbuf chain. * The buffer will automatically get space bytes * of data at offset 0 copied in+out by the * CCMP_ENCRYPT request so we must take care of * the remaining data. */ wbuf_new = wbuf; dl = data_len; sp = space; for (;;) { pos_next = (u_int8_t *)wbuf_header(wbuf_new); len = min(dl, AES_BLOCK_LEN); space_next = len > sp ? len - sp : 0; if (wbuf_get_len(wbuf_new) >= space_next) { /* * This mbuf has enough data; just grab * what we need and stop. */ xor_block(b+sp, pos_next, space_next); break; } /* * This mbuf's contents are insufficient, * take 'em all and prepare to advance to * the next mbuf. */ xor_block(b+sp, pos_next, n->m_len); sp += wbuf_get_len(wbuf_new), dl -= wbuf_get_len(wbuf_new); wbuf_next = m_next; if (n == NULL) break; } CCMP_ENCRYPT(i, b, b0, pos, e, space); /* NB: just like above, but scatter data to mbufs */ dl = data_len; sp = space; for (;;) { pos_next = mtod(m, uint8_t *); len = min(dl, AES_BLOCK_LEN); space_next = len > sp ? len - sp : 0; if (m->m_len >= space_next) { xor_block(pos_next, e+sp, space_next); break; } xor_block(pos_next, e+sp, m->m_len); sp += m->m_len, dl -= m->m_len; m = m->m_next; if (m == NULL) goto done; } /* * Do bookkeeping. m now points to the last mbuf * we grabbed data from. We know we consumed a * full block of data as otherwise we'd have hit * the end of the mbuf chain, so deduct from data_len. * Otherwise advance the block number (i) and setup * pos+space to reflect contents of the new mbuf. */ data_len -= AES_BLOCK_LEN; i++; pos = pos_next + space_next; space = m->m_len - space_next; } else {
int crypto_aead_encrypt( unsigned char *c,unsigned long long *clen, const unsigned char *m,unsigned long long mlen, const unsigned char *ad,unsigned long long adlen, const unsigned char *nsec, const unsigned char *npub, const unsigned char *k ) { u8 param[]={0x0a,0,0x7f,0x80,0x80,0,0,0}; block L, W, Delta_0, Delta_1, Delta_2, blk, result, CS; int i; unsigned long long h, cnt, blk_ctr=0, blk_ctr1=0 ; u8 zeroes[16], ozs[16], blen = 16, Is_final = 0, Is_complete =1; for(i=0; i<16; i++) {zeroes[i]=0x00;} for(i=1; i<16; i++) {ozs[i]=0x00;} ozs[0] = 0x80; cnt = (8+mlen-1)/16 + 1; h = (mlen+8-1) / (IT_GAP * 16); if(h > IT_MAX) h = IT_MAX; *clen = (cnt +1)* 16 + 1 + h*16 ; if((mlen+8)%16 == 0) c[*clen-1] = 0x00; else c[*clen-1] = 0x01; key_schedule(k); /* ========== Generate the Masks =========== */ AES(10, ENCRYPT, L, zeroes, &aes_key1); //AES(6, ENCRYPT, blk, zeroes, &aes_key1); //AES(6, ENCRYPT, L, blk, &aes_key1); mult_3(Delta_0, L); mult_inv2(Delta_0, Delta_0); mult_inv2(Delta_1, L); mult_3(Delta_2, L); mult_3(Delta_2, Delta_2); mult_inv2(Delta_2, Delta_2); /* ====== Process Associated Data ======== */ for(i=0; i<16; i++) W[i]=0x00; process_AD(W, Delta_0, npub, param, ad, adlen); /* ================ Process Message Blocks ==================== */ /* ====== Process the first Message block, whose first 8 byte is the secret message number ===== */ if(mlen < 8){ Is_complete = 0; } if(mlen <= 8) { blen = 8 + mlen; } load_block(blk, nsec, m, 8, blen-8); copy_block(CS, blk); process_block(Delta_1, Delta_2, result, blk, W, Is_complete, ENCRYPT, Is_final, MESSAGE); store_bytes(c, result, 0, 15); c +=16; blk_ctr++; if(mlen >= 8) {mlen -= 8; m +=8;} else mlen = 0; /* ============= Process Successive Message blocks ================== */ while(mlen > 0){ if(mlen >= 16){ load_block(blk, m, ozs, 16, 0); if(mlen == 16) {xor_block(blk, blk, CS); } else xor_block(CS, CS, blk); blen = 16; mlen -= 16; m+=16; } else {Is_complete = 0; blen = mlen; mlen = 0; load_block(blk, m, ozs, blen, 0); xor_block(blk, CS, blk); } process_block(Delta_1, Delta_2, result, blk, W, Is_complete, ENCRYPT, Is_final, MESSAGE); store_bytes(c, result, 0, 15); c +=16; blk_ctr++; if(blk_ctr == IT_GAP && blk_ctr1 < IT_MAX && mlen>0) { AES(10, DECRYPT, result, W, &aes_key2); mask(Delta_2, result, result, 1); store_bytes(c, result, 0, 15); c +=16; blk_ctr =0; blk_ctr1++; } } /* ================ Process checksum block ====================== */ process_block(Delta_1, Delta_2, result, blk, W, 1, ENCRYPT, 1, MESSAGE); store_bytes(c, result, 0, 15); return 0; }
/* =================== ELmD(6,127,1) Verified Decryption Function =================== */ int crypto_aead_decrypt( unsigned char *m,unsigned long long *mlen, unsigned char *nsec, const unsigned char *c, unsigned long long clen, const unsigned char *ad, unsigned long long adlen, const unsigned char *npub, const unsigned char *k ) { u8 param[]={0x06,0,0x7f,0x81,0x80,0,0,0}; block L, W, Delta_0, Delta_1, Delta_2, blk, result, CS; int i; u8 zeroes[16], ozs[16], blen = 16, Is_final = 0, Is_complete =1; unsigned long long outputmlen, blk_ctr=0, blk_ctr1=0; for(i=0; i<16; i++) {zeroes[i]=0x00;} // all zero. for(i=1; i<16; i++) {ozs[i]=0x00;} ozs[0] = 0x80; //useful for padding. if(clen < 24) return -1; key_schedule(k); /* =========== Generate the Masks ========== */ AES(6, ENCRYPT, blk, zeroes, &aes_key1); AES(6, ENCRYPT, L, blk, &aes_key1); mult_3(Delta_0, L); mult_inv2(Delta_0, Delta_0); mult_inv2(Delta_1, L); mult_3(Delta_2, L); mult_3(Delta_2, Delta_2); mult_inv2(Delta_2, Delta_2); /* ============= Process Associated Data ================ */ for(i=0; i<16; i++) W[i]=0x00; process_AD(W, Delta_0, npub, param, ad, adlen); load_block(CS, zeroes, zeroes, 16, 0); /* ================ Process Ciphertext Blocks ============ */ load_block(blk, c, zeroes, 16, 0); /* =================== Process 1st Block =================== */ if(clen<32){ process_block(Delta_2, Delta_1, result, blk, W, 0, DECRYPT, Is_final, CIPHERTEXT); store_bytes(m, result, 8, 8+(clen-25)); outputmlen = clen - 24; } else { process_block(Delta_2, Delta_1, result, blk, W, 1, DECRYPT, Is_final, CIPHERTEXT); store_bytes(m, result, 8, 15); m +=8; outputmlen = 8; } xor_block(CS, CS, result); store_bytes(nsec, result, 0, 7); clen -= 16; c+=16; blk_ctr ++; if(clen < 16){ if(result[clen] != 0x80) return -1; for(i=clen+1; i<16; i++) {if(result[i]!=0) return -1;} } /* ============= Process Successive Ciphertext Blocks ============== */ while(clen > 16){ load_block(blk, c, zeroes, 16, 0); if(clen < 32){ process_block(Delta_2, Delta_1, result, blk, W, 0, DECRYPT, Is_final, CIPHERTEXT); xor_block(result, result, CS); store_bytes(m, result, 0, clen - 17); outputmlen += clen-16 ; } else{ process_block(Delta_2, Delta_1, result, blk, W, 1, DECRYPT, Is_final, CIPHERTEXT); if(clen == 32) {xor_block(result, result, CS);} store_bytes(m, result, 0, 15); outputmlen += 16; } xor_block(CS, CS, result); clen -= 16; c+=16; blk_ctr ++; if(clen < 16){ if(result[clen] != 0x80) return -1; for(i=clen+1; i<16; i++) {if(result[i]!=0) return -1;} } else m +=16; if(blk_ctr == IT_GAP && blk_ctr1 < IT_MAX && clen > 32){ AES(6, DECRYPT, result, W, &aes_key2); mask(Delta_2, result, result, 1); for(i=0; i<16; i++) { if(c[i] != result[i]) {return -1; } } c +=16; clen -= 16; blk_ctr =0; blk_ctr1++; } } /* ========== Process checksum block ============= */ Is_final = 1; process_block(Delta_1, Delta_2, result, CS, W, 1, ENCRYPT, Is_final, MESSAGE); for(i=0; i<clen; i++) {if(result[i]!=c[i]) return -1;} *mlen = outputmlen; return 0; }