static void generate_subkey(struct crypto_cipher *tfm, u8 *k1, u8 *k2) { u8 l[AES_BLOCK_SIZE], tmp[AES_BLOCK_SIZE]; u8 const_rb[AES_BLOCK_SIZE] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x87}; u8 const_zero[AES_BLOCK_SIZE] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; crypto_cipher_encrypt_one(tfm, l, const_zero); if ((l[0] & 0x80) == 0) { /* If MSB(l) = 0, then k1 = l << 1 */ leftshift_onebit(l, k1); } else { /* Else k1 = ( l << 1 ) (+) Rb */ leftshift_onebit(l, tmp); xor_128(tmp, const_rb, k1); } if ((k1[0] & 0x80) == 0) { leftshift_onebit(k1, k2); } else { leftshift_onebit(k1, tmp); xor_128(tmp, const_rb, k2); } }
void generate_subkey(unsigned char *key, unsigned char *K1, unsigned char *K2) { unsigned char L[16]; unsigned char Z[16]; unsigned char tmp[16]; int i; for (i = 0; i<16; i++) Z[i] = 0; AES_128(key, Z, L); if ((L[0] & 0x80) == 0) { /* If MSB(L) = 0, then K1 = L << 1 */ leftshift_onebit(L, K1); } else { /* Else K1 = ( L << 1 ) (+) Rb */ leftshift_onebit(L, tmp); xor_128(tmp, const_Rb, K1); } if ((K1[0] & 0x80) == 0) { leftshift_onebit(K1, K2); } else { leftshift_onebit(K1, tmp); xor_128(tmp, const_Rb, K2); } return; }
static void ccGenAESSubKey(const struct ccmode_ecb *aesmode, ccecb_ctx *ctx, void *key1, void *key2) { uint8_t L[16]; uint8_t Z[16]; uint8_t tmp[16]; memset(Z, 0, 16); aesmode->ecb(ctx, 1, Z, L); if ( (L[0] & 0x80) == 0 ) { /* If MSB(L) = 0, then K1 = L << 1 */ leftshift_onebit(L, key1); } else { /* Else K1 = ( L << 1 ) (+) Rb */ leftshift_onebit(L, tmp); xor_128(tmp,const_Rb, key1); } if ( (((uint8_t *)key1)[0] & 0x80) == 0 ) { leftshift_onebit(key1, key2); } else { leftshift_onebit(key1, tmp); xor_128(tmp,const_Rb, key2); } return; }
void CCAESCmac(const void *key, const uint8_t *data, size_t dataLength, /* length of data in bytes */ void *macOut) /* MAC written here */ { uint8_t X[16],Y[16], M_last[16], padded[16]; uint8_t K1[16], K2[16]; int flag; size_t n; const struct ccmode_ecb *aesmode = getCipherMode(kCCAlgorithmAES128, kCCModeECB, kCCEncrypt).ecb; ccecb_ctx_decl(aesmode->size, ctx); CC_DEBUG_LOG(ASL_LEVEL_ERR, "Entering\n"); // CMacInit aesmode->init(aesmode, ctx, 16, key); aesmode->ecb(ctx, 1, Y, X); ccGenAESSubKey(aesmode, ctx, K1, K2); // CMacUpdates (all in this case) n = (dataLength+15) / 16; /* n is number of rounds */ if ( 0 == n ) { n = 1; flag = 0; } else { if ( (dataLength%16) == 0 ) flag = 1; else flag = 0; } if ( flag ) { /* last block is complete block */ xor_128(&data[16*(n-1)],K1,M_last); } else { ccAESCMacPadding(&data[16*(n-1)],padded,dataLength%16); xor_128(padded,K2,M_last); } memset(X, 0, 16); for (size_t i=0; i<n-1; i++ ) { xor_128(X,&data[16*i],Y); /* Y := Mi (+) X */ aesmode->ecb(ctx, 1, Y, X); } // CMacFinal xor_128(X,M_last,Y); aesmode->ecb(ctx, 1, Y, X); memcpy(macOut, X, 16); }
void Generate_Subkey(Aes *aes, unsigned char *k1, unsigned char *k2) { unsigned char l[BLOCKSIZE]; aes_encrypt(aes, l, const_Zero); leftshift_onebit(l, k1); if (MSB(l[0]) != 0) { xor_128(k1, const_Rb, k1); } leftshift_onebit(k1, k2); if (MSB(k1[0]) != 0) { xor_128(k2, const_Rb, k2); } }
void AES_CMAC(unsigned char *key, unsigned char *input, int length, unsigned char *mac) { unsigned char X[16], Y[16], M_last[16], padded[16]; unsigned char K1[16], K2[16]; int n, i, flag; generate_subkey(key, K1, K2); n = (length + 15) / 16; /* n is number of rounds */ if (n == 0) { n = 1; flag = 0; } else { if ((length % 16) == 0) { /* last block is a complete block */ flag = 1; } else { /* last block is not complete block */ flag = 0; } } if (flag) { /* last block is complete block */ xor_128(&input[16 * (n - 1)], K1, M_last); } else { padding(&input[16 * (n - 1)], padded, length % 16); xor_128(padded, K2, M_last); } for (i = 0; i<16; i++) X[i] = 0; for (i = 0; i<n - 1; i++) { xor_128(X, &input[16 * i], Y); /* Y := Mi (+) X */ AES_128(key, Y, X); /* X := AES-128(KEY, Y); */ } xor_128(X, M_last, Y); AES_128(key, Y, X); for (i = 0; i<16; i++) { mac[i] = X[i]; } }
void cmac_calc_mic(struct crypto_cipher *tfm, u8 *m, u16 length, u8 *mac) { u8 x[AES_BLOCK_SIZE], y[AES_BLOCK_SIZE]; u8 m_last[AES_BLOCK_SIZE], padded[AES_BLOCK_SIZE]; u8 k1[AES_KEYSIZE_128], k2[AES_KEYSIZE_128]; int cmpBlk; int i, nBlocks = (length + 15)/AES_BLOCK_SIZE; generate_subkey(tfm, k1, k2); if (nBlocks == 0) { nBlocks = 1; cmpBlk = 0; } else { cmpBlk = ((length % AES_BLOCK_SIZE) == 0) ? 1 : 0; } if (cmpBlk) { /* Last block is complete block */ xor_128(&m[AES_BLOCK_SIZE * (nBlocks - 1)], k1, m_last); } else { /* Last block is not complete block */ padding(&m[AES_BLOCK_SIZE * (nBlocks - 1)], padded, length % AES_BLOCK_SIZE); xor_128(padded, k2, m_last); } for (i = 0; i < AES_BLOCK_SIZE; i++) x[i] = 0; for (i = 0; i < (nBlocks - 1); i++) { xor_128(x, &m[AES_BLOCK_SIZE * i], y); /* y = Mi (+) x */ crypto_cipher_encrypt_one(tfm, x, y); /* x = AES-128(KEY, y) */ } xor_128(x, m_last, y); crypto_cipher_encrypt_one(tfm, x, y); vos_mem_copy(mac, x, CMAC_TLEN); }
void aes_cmac(const unsigned char *key, const unsigned char *message, int len, unsigned char *mac) { Aes aes; wc_AesSetKey(&aes, key, BLOCKSIZE, 0, AES_ENCRYPTION); unsigned char k1[BLOCKSIZE], k2[BLOCKSIZE], xorResult[BLOCKSIZE], lastBlock[BLOCKSIZE]; Generate_Subkey(&aes, k1, k2); int nBlocks = (len + BLOCKSIZE - 1) / BLOCKSIZE; bool needs_padding; if (nBlocks == 0) { nBlocks = 1; needs_padding = true; } else { needs_padding = (len % BLOCKSIZE) != 0; } if (needs_padding) { padding(&message[BLOCKSIZE * (nBlocks - 1)], lastBlock, len % BLOCKSIZE); xor_128(lastBlock, k2, lastBlock); } else { xor_128(&message[BLOCKSIZE * (nBlocks - 1)], k1, lastBlock); } for (int i = 0; i < BLOCKSIZE; i++) mac[i] = 0x00; for (int i = 0; i < nBlocks - 1; i++) { xor_128(&message[i * BLOCKSIZE], mac, xorResult); aes_encrypt(&aes, mac, xorResult); } xor_128(lastBlock, mac, xorResult); aes_encrypt(&aes, mac, xorResult); }
void aes128k128d(unsigned char *key, unsigned char *data, unsigned char *ciphertext) { int round; int i; unsigned char intermediatea[16]; unsigned char intermediateb[16]; unsigned char round_key[16]; for(i=0; i<16; i++) round_key[i] = key[i]; for (round = 0; round < 11; round++) { if (round == 0) { xor_128(round_key, data, ciphertext); next_key(round_key, round); } else if (round == 10) { byte_sub(ciphertext, intermediatea); shift_row(intermediatea, intermediateb); xor_128(intermediateb, round_key, ciphertext); } else /* 1 - 9 */ { byte_sub(ciphertext, intermediatea); shift_row(intermediatea, intermediateb); mix_column(&intermediateb[0], &intermediatea[0]); mix_column(&intermediateb[4], &intermediatea[4]); mix_column(&intermediateb[8], &intermediatea[8]); mix_column(&intermediateb[12], &intermediatea[12]); xor_128(intermediatea, round_key, ciphertext); next_key(round_key, round); } } }
int crypto_aead_decrypt( unsigned char *m,unsigned long long *outputmlen, 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 ) { u64 mlen, n, origmlen, start ; const byte *ptr, *origc; byte temp[AES_BYTES], *p ; int i ; assert( m != NULL ) ; assert( outputmlen != NULL ) ; assert( c != NULL ) ; assert( ad != NULL ) ; assert( npub != NULL ) ; assert( k != NULL ) ; if( clen < AUTH_BYTES) return -1; /* where auth data should be */ mlen = clen - AUTH_BYTES ; ptr = c + mlen ; *outputmlen = mlen; setup(mlen, adlen, npub, k) ; do_additional( ad, adlen ) ; origc = c; origmlen = mlen; #ifdef TESTING printf("decrypt: total %llu text %llu ad %llu\n", clen, mlen, adlen ) ; printf("decrypt: ciphertext starts with %08xu\n", ((u32 *) origc)[0] ) ; printf("decrypt: starting authentication check %08x\n", ((u32 *) ptr)[0] ) ; #endif /* authenticate */ start = mlen ; while( (mlen > 0) && (mlen <= start) ) { n = (u64) ((mlen >= AES_BYTES) ? AES_BYTES : mlen) ; addmul( (byte *) accum, c, n, (byte *) H) ; c += n; mlen -= n; } if( mlen > start ) { #ifdef TESTING printf("decrypt: mlen out of bounds\n" ) ; #endif return -2 ; } #ifdef TESTING printf("decrypt: auth before finalisation %08x %08x\n", accum[0], accum[1] ) ; #endif mix_in(finalblock) ; xor_128( accum, I ) ; /* see if we have a match */ if( memcmp((void *) accum, (void *) ptr, AUTH_BYTES) != 0) { #ifdef TESTING printf("decrypt: auth failed, result here %08x\n", accum[0] ) ; #endif return -3; } #ifdef TESTING printf("decrypt: auth matched, going to decrypt\n" ) ; printf("decrypt: 1st ciphertext word %08x\n", *((u32 *) c) ) ; #endif /* reset things start encryption with correct ChaCha state */ c = origc; mlen = origmlen; setup(mlen, adlen, npub, k) ; /* decrypt, simpler than encryption no authentication to do */ start = mlen ; while( (mlen > 0) && (mlen <= start) ) { n = (u64) ((mlen >= AES_BYTES)? AES_BYTES : mlen) ; white_aes( temp ) ; for( i = 0, p = temp ; i < n ; i++, c++, m++, p++ ) *m = *c ^ *p ; mlen -= n; } if( mlen > start ) { #ifdef TESTING printf("decrypt: mlen out of bounds\n" ) ; #endif return -2 ; } #ifdef TESTING printf("decrypt: reached end, showing first words\n" ) ; printf("plaintext %08x ciphertext %08x auth %08x\n",*((u32 *) m), *((u32 *) c), accum[0] ) ; #endif memset( temp, 0, AES_BYTES ) ; cleanup() ; return 0; }
/* declarations for this and decrypt copied from Bernstein's example AES-GCM code to be sure they match test framework */ 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 ) { u64 n, start ; byte temp[AES_BYTES] ; byte *p, *q, *ptr ; int i ; #ifdef TESTING byte *origm, *origc ; assert( c != NULL ) ; /* are framework declarations compatible with mine? */ assert( sizeof(long long) == sizeof( u64) ) ; printf("encrypt: plaintext %llu ad %llu\n", mlen, adlen ) ; origm = m ; origc = c ; #endif /* Bernstein's example aes-gcm code sets *clen I copy that, assuming the interface needs it */ *clen = mlen+AUTH_BYTES ; /* address for authentication data */ ptr = c + mlen ; /* key schedule */ setup( mlen, (u64) adlen, npub, k) ; /* data authenticated but not encrypted */ do_additional( ad, (u64) adlen ) ; /* encryption mlen is unsigned so always > = 0 use start for an error check */ start = mlen ; while( (mlen != 0) && (mlen <= start) ) { n = (u64) ((mlen >= AES_BYTES)? AES_BYTES : mlen) ; white_aes( temp ) ; for( i = 0, p = temp, q = c ; i < n ; i++, q++, m++, p++ ) *q = *m ^ *p ; addmul( (byte *) accum, c, n, (byte *) H) ; mlen -= n; c += n ; } if( mlen > start ) { #ifdef TESTING printf("encrypt: mlen out of bounds\n" ) ; #endif return -2 ; } #ifdef TESTING printf("encrypt: auth before finalisation %08x %08x\n", accum[0], accum[1] ) ; #endif /* finish authentication */ mix_in(finalblock) ; xor_128( accum, I ) ; memcpy( ptr, (void *) accum, AES_BYTES ) ; #ifdef TESTING printf("encrypt: reached end, showing first words\n" ) ; printf("plaintext %08x ciphertext %08x auth %08x\n", *((u32 *) origm), *((u32 *) origc), accum[0] ) ; #endif memset( temp, 0, AES_BYTES ) ; cleanup() ; return 0 ; }
int crypto_aead_decrypt(unsigned char *m, unsigned long long *outputmlen, 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) { AES_KEY key[1]; AES_KEY kappa_0[1]; AES_KEY kappa_m[1]; unsigned char nonce[BLOCK_LENGTH]; CPFB_BLOCK X[1]; CPFB_BLOCK P[1]; CPFB_BLOCK stream[1]; unsigned long long counter; unsigned long long mlen; (void)nsec; /* avoid warning */ if (clen < TAG_LENGTH) return -1; *outputmlen = mlen = clen - TAG_LENGTH; init(npub,k,kappa_0,key,nonce); /* Block encoding alen and mlen * In an online implementation, it would be done at the end, and X would be 0 */ store64(X->u8, mlen); X->u32[2] = htobe32((crypto_uint32)adlen); X->counter = 0; AES_encrypt(X, X, kappa_0); /* AD processing */ counter = 0; while (adlen > PAYLOAD_LENGTH) { load_96_ctr(P,ad,++counter); AES_encrypt(P, stream, kappa_0); xor_128(X, stream, X); ad += PAYLOAD_LENGTH; adlen -= PAYLOAD_LENGTH; } if (adlen > 0) { load_partial_ctr(P,ad,adlen,++counter); AES_encrypt(P, stream, kappa_0); xor_128(X, stream, X); } /* Plaintext processing */ if (mlen > 0) { /* New kappa */ gen_next_kappa(nonce,kappa_0,kappa_m,key); counter = 0; /* P_0 processing */ P->u64[0] = P->u64[1] = 0; AES_encrypt(P, stream, kappa_m); while (mlen > PAYLOAD_LENGTH) { store_xor_96(m,(CPFB_BLOCK*)c,stream); load_96_ctr(P,m,++counter); AES_encrypt(P, stream, kappa_m); xor_128(X, stream, X); c += PAYLOAD_LENGTH; m += PAYLOAD_LENGTH; mlen -= PAYLOAD_LENGTH; } if (mlen > 0) { store_xor_partial(m,(CPFB_BLOCK*)c,stream,mlen); load_partial_ctr(P,m,mlen,++counter); AES_encrypt(P, stream, kappa_m); xor_128(X, stream, X); c += mlen; } } AES_encrypt(X, X, kappa_0); return verify_tag(c,X->u8); }
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) { AES_KEY key[1]; AES_KEY kappa_0[1]; AES_KEY kappa_m[1]; unsigned char nonce[BLOCK_LENGTH]; CPFB_BLOCK X[1]; CPFB_BLOCK P[1]; CPFB_BLOCK stream[1]; unsigned long long i; unsigned long long counter; (void)nsec; /* avoid warning */ *clen = mlen + TAG_LENGTH; /* Key schedule, nonce initialization and generation of first kappa */ init(npub,k,kappa_0,key,nonce); /* Block encoding alen and mlen * In an online implementation, it would be done at the end, and X would be 0 */ store64(X->u8, mlen); X->u32[2] = htobe32((crypto_uint32)adlen); X->counter = 0; AES_encrypt(X, X, kappa_0); /* AD processing */ counter = 0; while (adlen > PAYLOAD_LENGTH) { load_96_ctr(P,ad,++counter); AES_encrypt(P, stream, kappa_0); xor_128(X, stream, X); ad += PAYLOAD_LENGTH; adlen -= PAYLOAD_LENGTH; } if (adlen > 0) { load_partial_ctr(P,ad,adlen,++counter); AES_encrypt(P, stream, kappa_0); xor_128(X, stream, X); } /* Plaintext processing */ if (mlen > 0) { /* Increment nonce and generate new kappa * First subkey of kappa_m is modified * (xored with first subkey of kappa_0) */ gen_next_kappa(nonce,kappa_0, kappa_m,key); counter = 0; /* P_0 processing */ P->u64[0] = P->u64[1] = 0; AES_encrypt(P, stream, kappa_m); while (mlen > PAYLOAD_LENGTH) { load_96_ctr(P,m,++counter); store_xor_96(c,P,stream); AES_encrypt(P, stream, kappa_m); xor_128(X, stream, X); c += PAYLOAD_LENGTH; m += PAYLOAD_LENGTH; mlen -= PAYLOAD_LENGTH; } if (mlen > 0) { load_partial_ctr(P,m,mlen,++counter); store_xor_partial(c,P,stream,mlen); AES_encrypt(P, stream, kappa_m); xor_128(X, stream, X); c += mlen; } } AES_encrypt(X, X, kappa_0); for (i = 0; i < TAG_LENGTH; i++) c[i] = X->u8[i]; return 0; }