// PMAC1'(N) // Param: pointers to V, n (nonce) and k (key) // Modifies v. void pmac1(unsigned char *v, const unsigned char *n, const unsigned char *k) { unsigned char delta0[NUM_BYTES]; getl(delta0, k); // delta0 <- 3^3 * L for (int j = 0; j < 3; j++) { multiplyby3(delta0); } // 3*delta0 multiplyby3(delta0); // N xor 3*delta0 for (int i = 0; i < NUM_BYTES; i++) { delta0[i] = delta0[i] ^ n[i]; } // V = E_k(N xor 3*delta0) aes128e(v, delta0, k); }
/* Under the 16-byte (128-bit) key at k and the 12-byte (96-bit) nonce at n, encrypt the plaintext at p and store it at c. The length of the plaintext is a multiple of 16 bytes given at len (e.g., len = 2 for a 32-byte p). The length of the ciphertext c is (len+1)*16 bytes. */ void aes128ocb(unsigned char *c, const unsigned char *k, const unsigned char *n, const unsigned char *p, const unsigned int len) { /* Array of zeros for use with aes128e */ unsigned char zeros[16]; int i; for (i = 0; i < 16; ++i) { zeros[i] = 0x00; } unsigned char l[16]; unsigned char l_dollar[16]; aes128e(l, zeros, k); /* Now l is l_star */ doubleB(l, 16); /* Now l is l_dollar */ /* We keep l_dollar for using it for calculate the tag */ for (i = 0; i < 16; ++i) { l_dollar[i] = l[i]; } doubleB(l, 16); /* Now l is l_0 */ /* m = bitlen(P)/128 */ unsigned int m = ((16*len)*8)/128; /* numL is the maximum value of trailing zeros for the given size m */ unsigned int numL = msb(m) + 1; /* ls is the array of all the l_i arrays */ unsigned char ls[numL][16]; int a; for (a = 0; a < numL; ++a) { for (i = 0; i < 16; ++i) { ls[a][i] = l[i]; } doubleB(l, 16); } /* Addition of 0x00000001 to the nonce */ unsigned char nonce[20]; nonce[0] = nonce[1] = nonce[2] = 0x00; nonce[3] = 0x01; a = 0; for (i = 4; i < 20; ++i) { nonce[i] = n[a]; ++a; } /* Bottom is the integer value of the last 6 bits of nonce */ unsigned int bottom = nonce[15]&0x3F; /* Temporal array for aes128e with last 6 bits of nonce to zero */ unsigned char top[16]; for (i = 0; i < 16; ++i) { top[i] = nonce[i]; } top[15] = nonce[15]&0xC0; /* Calculation of ktop using the block cipher */ unsigned char ktop[16]; aes128e(ktop, top, k); /* Stretch is ktop concatenated with the xor of the bits 1...64 and 9...72 of ktop */ unsigned char stretch[24]; for (i = 0; i < 16; ++i) { stretch[i] = ktop[i]; } a = 0; for (i = 16; i < 24; ++i) { stretch[i] = (ktop[a] ^ ktop[a + 1]); ++a; } /* Array of the m offset arrays */ unsigned char offset[m][16]; /* Array of the m checksum arrays */ unsigned char checksum[m][16]; /* Temporal array for get stretch[1 + bottom...128 + bottom] */ unsigned char tempS[24]; for (i = 0; i < 24; ++i) { tempS[i] = stretch[i]; } /* Shifting of stretch bottom times to the left */ for (i = 0; i < bottom; ++i) { shiftB(tempS, 24); } /* Copy of temp array to offset and inicialization of checksum */ for (i = 0; i < 16; ++i) { offset[0][i] = tempS[i]; checksum[0][i] = 0x00; } /* Temporal arrays for use them with aes128 as plaintext and ciphertext */ unsigned char temp1[16]; unsigned char temp2[16]; int ntzV; /* Counters */ int countP1 = 0; int countP2 = 0; int countC = 0; /* Loop over the m blocks */ for (i = 1; i <= m; ++i) { /* Number of trailing zeros in i */ ntzV = ntz(i); /* Calculation of the offset_i with xor betwen offset_{i-1} and l_{ntz(i)} */ for (a = 0; a < 16; ++a) { offset[i][a] = offset[i - 1][a] ^ ls[ntzV][a]; } /* Calculation of xor betwen p_i and offset_i for use it in aes128 */ for (a = 0; a < 16; ++a) { temp1[a] = (p[countP1] ^ offset[i][a]); ++countP1; } aes128e(temp2, temp1, k); /* Calculation of c_i with xor betwen offset_i and result of aes128 */ for (a = 0; a < 16; ++a) { c[countC] = offset[i][a] ^ temp2[a]; ++countC; } /* Calculation of checksum_i with the xor betwen checksum_{i-1} and p_i */ for (a = 0; a < 16; ++a) { checksum[i][a] = checksum[i - 1][a] ^ p[countP2]; ++countP2; } } unsigned char tag[16]; unsigned char tempTag[16]; /* Calculation of the xor betwen checksum_m, offset_m and l_dollar for use it in aes128 to calculate the tag */ int w; for (w = 0; w < 16; ++w) { tempTag[w] = ((l_dollar[w] ^ offset[m][w]) ^ checksum[m][w]); } aes128e(tag, tempTag, k); /* Concatenation of the tag at the end of the ciphertext. 16*m is the current lenght of the cipher lenght and 16*m +16 is the total lenght */ int countTag = 0; for (a = 16*m; a < (16*m + 16); ++a) { c[a] = tag[countTag]; ++countTag; } }
/* Under the 16-byte key at k and the 16-byte nonce at n, encrypt the plaintext at m and store it at c. Store the 16-byte tag in the end of c. The length of the plaintext is a multiple of 16 bytes given at d (e.g., d = 2 for a 32-byte m). */ void aescopa(unsigned char *c, const unsigned char *k, const unsigned char *n, const unsigned char *m, const unsigned int d) { unsigned char v[NUM_BYTES]; unsigned char s[NUM_BYTES]; unsigned char sigma[NUM_BYTES]; unsigned char l[NUM_BYTES]; unsigned char aes1[NUM_BYTES]; unsigned char aes2[NUM_BYTES]; unsigned char t[NUM_BYTES]; // V <- PMAC1'(N) pmac1(v, n, k); // (C,S) <- ENCRYPT(V,M) encrypt(v, m, c, s, k, d); // Sigma <- M[1] xor M[2] xor ... M[d] // Initial sigma == M[1] memcpy(sigma, m, NUM_BYTES); for (int i = 1; i < d; i++) { for (int j = 0; j < NUM_BYTES; j++) { sigma[j] = sigma[j] ^ m[i*NUM_BYTES+j]; } } // Sigma xor (2^(d-1)*3^2*L) // 3^2 L getl(l, k); multiplyby3(l); multiplyby3(l); // 2^(d-1) (3^2 L) for (int i = 0; i < d-1; i++) { multiplyby2(l); } // Sigma xor ... for (int i = 0; i < NUM_BYTES; i++) { sigma[i] = sigma[i] ^ l[i]; } // E_k(sigma xor ...) = aes1 aes128e(aes1, sigma, k); // aes1 xor S for (int i = 0; i < NUM_BYTES; i++) { aes1[i] = aes1[i] ^ s[i]; } // E_k(aes1 xor S) = aes2 aes128e(aes2, aes1, k); // 7L getl(l, k); multiplyby7(l); // 2^d*7L for (int i = 0; i < d; i++) { multiplyby2(l); } // T = aes2 xor 2^d*7L for (int i = 0; i < NUM_BYTES; i++) { t[i] = aes2[i] ^ l[i]; } // Copy T to the end of C. memcpy((c+d*NUM_BYTES), t, NUM_BYTES); }
// (C,S) <- ENCRYPT(V,M) // Params: pointers to v, m, c, s, key k, length d void encrypt(unsigned char *v, const unsigned char *m, unsigned char *c, unsigned char *s, const unsigned char *k, const unsigned int d) { unsigned char delta0[NUM_BYTES]; unsigned char delta1[NUM_BYTES]; unsigned char l[NUM_BYTES]; // Holder for the current block. unsigned char tempm[NUM_BYTES]; unsigned char tempm2[NUM_BYTES]; unsigned char tempv[NUM_BYTES]; unsigned char v1[NUM_BYTES]; // delta0 <- 3L getl(delta0, k); multiplyby3(delta0); // delta1 <- 2L getl(delta1, k); multiplyby2(delta1); // V[0] <- V xor L getl(l, k); for (int i = 0; i < NUM_BYTES; i++) { v[i] = v[i] ^ l[i]; } // One 128-bit block at a time. for (int i = 0; i < d; i++) { // Copy the block to the temp holder. memcpy(tempm, m+i*NUM_BYTES, NUM_BYTES); // M[i] xor delta0 for (int j = 0; j < NUM_BYTES; j++) { tempm[j] = tempm[j] ^ delta0[j]; } // E_k(M[i] xor delta0) aes128e(tempm2, tempm, k); // V[i] <- E_k(M[i] xor delta0) xor V[i-1] for (int j = 0; j < NUM_BYTES; j++) { v1[j] = tempm2[j] ^ v[j]; } // E_k(V[i]) aes128e(tempv, v1, k); // C[i] = E_k(V[i]) xor delta1 for (int j = 0; j < NUM_BYTES; j++) { c[i*NUM_BYTES+j] = tempv[j] ^ delta1[j]; } // Set up next round: // 2*delta0, 2*delta1, V[i-1] = V[i] multiplyby2(delta0); multiplyby2(delta1); memcpy(v, v1, NUM_BYTES); } // Copy the final value of v[i] to s memcpy(s, v1, NUM_BYTES); }
// Helper function to generate L=E_k(0) when needed. void getl(unsigned char *l, const unsigned char *k) { unsigned char temp[NUM_BYTES] = {0x00}; aes128e(l, temp, k); }