/*! \brief This function performs ECB encryption on input plain text blocks. * \param plainText pointer to the array containing the plain text bytes * \param cipherText pointer to the array where the encrypted cipher output has to be stored * \param size size of the input plain text */ void ecb_encrypt(uint8_t *plainText, uint8_t *cipherText, uint32_t size) { uint32_t input_block_size = 0; uint8_t block_count = 0; //Calculate the number of input blocks input_block_size = size/AES_BLOCK_SIZE; for(block_count = 0;block_count < input_block_size; block_count++){ //Perform forward cipher for the input blocks aes_cipher(plainText+(block_count * AES_BLOCK_SIZE), cipherText+(block_count * AES_BLOCK_SIZE)); } }
/** * This function reads the plaintext file in blocks of 16-bytes, and loads the * bytes into the state block. This state block is a 4x4 matrix, however, while * the array is row-major order, the bytes are arranged vertically. So for bytes * b0, b1, b2,..., b15, the state matrix will look like this: * * [b0, b4, b8 , b12] * [b1, b5, b9 , b13] * [b2, b6, b10, b14] * [b3, b7, b11, b15] * * As such, we read/write the bytes from/to the files sequentially into a * separate buffer, and fill in the state block from there. The cipher then * assumes that the state is arranged as above. * * @param fdin - File descriptor for the plaintext file. Should be a binary file * that has already been opened for reading. * @param fdout - File descriptor for the cipher file, which should be a new * binary file opened for writing. * @param key - Pointer to the encryption key. */ bool encrypt_file(FILE *fdin, FILE *fdout, aes_key_t *key) { int i, b, num_blocks; size_t bytes_read; long int file_size; uint8_t buffer[18]; /* A little bit of extra, just in case */ uint8_t **state; /* Initialize state block on the heap */ state = (uint8_t**)malloc(4 * sizeof(uint8_t*)); for (i = 0; i < 4; i++) state[i] = (uint8_t*)malloc(4); /* Allocate each row */ /* Determine the size of the file. */ fseek(fdin, 0L, SEEK_END); file_size = ftell(fdin); rewind(fdin); /* Determine the number of blocks to encrypt */ num_blocks = file_size / AES_BLOCK_SIZE; if (file_size % AES_BLOCK_SIZE) num_blocks++; VERBOSE("Size of file: %ld bytes (%d blocks)\n", file_size, num_blocks); /* Encrypt each block */ for (b = 0; b < num_blocks; b++) { if (flags.verbose) { printf("Encrypting block %d of %d.\r", b+1, num_blocks); fflush(stdin); } /* Read in next 16 bytes. */ bytes_read = fread(buffer, sizeof(uint8_t), 16, fdin); if (ferror(fdin) != 0) { fprintf(stderr, PROGRAM_NAME ": Error: File read error.\n"); return false; } /* If we did not read a full block, pad with 0's */ while (bytes_read < 16) buffer[bytes_read++] = 0; /* Fill state block */ for (i = 0; i < AES_BLOCK_SIZE; i++) state[i%4][i/4] = buffer[i]; aes_cipher(state, key); /* Run cipher on the current state matrix*/ /* Get the newly encrypted byte sequence */ for (i = 0; i < AES_BLOCK_SIZE; i++) buffer[i] = state[i%4][i/4]; /* Write result to the output file */ if (fwrite(buffer, sizeof(uint8_t), 16, fdout) != 16) { fprintf(stderr, PROGRAM_NAME ": Error: File write error.\n"); return false; } } VERBOSE("\n"); for (i = 0; i < 4; i++) free(state[i]); free(state); return true; }
/*! \brief This function performs CFB decryption on input cipher text blocks. * \param cipherText pointer to the array containing the cipher text bytes * \param plainText pointer to the array where the decrypted plain text has to be stored * \param init_vector pointer to the array containing the unique initialization vector * \param mode CFB mode in bits - can be 8, 64, 128. * \param size size of the input plain text */ void cfb_decrypt(uint8_t *cipherText, uint8_t *plainText, uint8_t *init_vector, uint8_t mode, uint32_t size) { uint32_t input_block_size = 0; uint8_t block_count = 0, byte_count = 0, cfb_byte = 0; uint8_t init_vector_temp[AES_BLOCK_SIZE] = {0}; uint8_t index1 = 0, index2 = 0; bool index2_flag = false; /* calculate cfb bytes * cfb_byte = 16 for 128 bit CFB, * cfb_byte = 8 for 64-bit CFB, * cfb_byte = 4 for 32-bit CFB, * cfb_byte = 2 for 16-bit CFB, * cfb_byte = 1 for 8-bit CFB */ cfb_byte = mode/8; //Calculate the number of input blocks input_block_size = (size / AES_BLOCK_SIZE ); for(byte_count = 0; byte_count<AES_BLOCK_SIZE; byte_count++){ //Moving initial vector to a temp array init_vector_temp[byte_count] = init_vector[byte_count]; } //Forward cipher of initial vector 1 aes_cipher(init_vector_temp, plainText); //XOR-ing cipher text 's' bits with output block s bits for(byte_count = 0; byte_count < cfb_byte; byte_count++){ plainText[byte_count] = cipherText[byte_count] ^ plainText[byte_count]; } //Decryption of remaining blocks for(block_count = 1;block_count < ((AES_BLOCK_SIZE * input_block_size) / cfb_byte); block_count++){ index1 = 0; //Preparation of Initialization vector for the next round for (byte_count = 0; byte_count < AES_BLOCK_SIZE; byte_count++){ if(block_count < ((AES_BLOCK_SIZE/cfb_byte))+1){ /* For the first few blocks where initialization vector and cipher output * is used to generate the init_vector_temp */ if(byte_count < (16 - (block_count + cfb_byte -1))){ init_vector_temp[byte_count] = init_vector[byte_count + (cfb_byte + block_count - 1)]; }else{ init_vector_temp [byte_count] = cipherText[index1++]; } if (block_count == (AES_BLOCK_SIZE / cfb_byte)){ index2_flag = true; } }else{ /* For the remaining blocks where init_vector_temp is generated from the cipher * output from the previous block. AES Standard FIPS SP800-38A explains more on * generation of init_vector for each block in different CFB modes */ init_vector_temp[byte_count] = cipherText[(cfb_byte * index2) + byte_count]; } } if (index2_flag == true){ index2 = index2+1; } //Sending initialization vector to the cipher function to get 16 byte output block aes_cipher(init_vector_temp, (plainText+(block_count * cfb_byte))); //XOR-ing cipher text 's' bits with output block s bits for(byte_count = 0; byte_count < cfb_byte; byte_count++){ plainText[(byte_count + (block_count * cfb_byte))] = cipherText[(byte_count + (block_count * cfb_byte))]^ plainText[(byte_count + (block_count * cfb_byte))]; } } }
int main(int argc, char *argv[]) { uint8_t i; /* * Appendix A - Key Expansion Examples */ /* 128 bits */ /* uint8_t key[] = { 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c}; */ /* 192 bits */ /* uint8_t key[] = { 0x8e, 0x73, 0xb0, 0xf7, 0xda, 0x0e, 0x64, 0x52, 0xc8, 0x10, 0xf3, 0x2b, 0x80, 0x90, 0x79, 0xe5, 0x62, 0xf8, 0xea, 0xd2, 0x52, 0x2c, 0x6b, 0x7b}; */ /* 256 bits */ /* uint8_t key[] = { 0x60, 0x3d, 0xeb, 0x10, 0x15, 0xca, 0x71, 0xbe, 0x2b, 0x73, 0xae, 0xf0, 0x85, 0x7d, 0x77, 0x81, 0x1f, 0x35, 0x2c, 0x07, 0x3b, 0x61, 0x08, 0xd7, 0x2d, 0x98, 0x10, 0xa3, 0x09, 0x14, 0xdf, 0xf4}; */ /* uint8_t in[] = { 0x32, 0x43, 0xf6, 0xa8, 0x88, 0x5a, 0x30, 0x8d, 0x31, 0x31, 0x98, 0xa2, 0xe0, 0x37, 0x07, 0x34}; // 128 */ /* * Appendix C - Example Vectors */ /* 128 bit key */ /* uint8_t key[] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f}; */ /* 192 bit key */ /* uint8_t key[] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17}; */ /* 256 bit key */ uint8_t key[] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f}; uint8_t in[] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff}; uint8_t out[16]; // 128 uint8_t *w; // expanded key w = aes_init(sizeof(key)); aes_key_expansion(key, w); printf("Plaintext message:\n"); for (i = 0; i < 4; i++) { printf("%x %x %x %x ", in[4*i+0], in[4*i+1], in[4*i+2], in[4*i+3]); } printf("\n"); aes_cipher(in /* in */, out /* out */, w /* expanded key */); printf("Ciphered message:\n"); for (i = 0; i < 4; i++) { printf("%x %x %x %x ", out[4*i+0], out[4*i+1], out[4*i+2], out[4*i+3]); } printf("\n"); aes_inv_cipher(out, in, w); printf("Original message (after inv cipher):\n"); for (i = 0; i < 4; i++) { printf("%x %x %x %x ", in[4*i+0], in[4*i+1], in[4*i+2], in[4*i+3]); } printf("\n"); free(w); exit(0); }