// encryption: data must be NUL-padded to BLOCKSIZE // decryption: data must be padded to BLOCKSIZE // len must be < 2^31 void SymmCipher::ctr_crypt(byte* data, unsigned len, m_off_t pos, ctr_iv ctriv, byte* mac, bool encrypt, bool initmac) { assert(!(pos & (KEYLENGTH - 1))); byte ctr[BLOCKSIZE], tmp[BLOCKSIZE]; MemAccess::set<int64_t>(ctr,ctriv); setint64(pos / BLOCKSIZE, ctr + sizeof ctriv); if (mac && initmac) { memcpy(mac, ctr, sizeof ctriv); memcpy(mac + sizeof ctriv, ctr, sizeof ctriv); } while ((int)len > 0) { if (encrypt) { if(mac) { xorblock(data, mac); ecb_encrypt(mac); } ecb_encrypt(ctr, tmp); xorblock(tmp, data); } else { ecb_encrypt(ctr, tmp); xorblock(tmp, data); if (mac) { if (len >= (unsigned)BLOCKSIZE) { xorblock(data, mac); } else { xorblock(data, mac, len); } ecb_encrypt(mac); } } len -= BLOCKSIZE; data += BLOCKSIZE; incblock(ctr); } }
static void convert_passwd(char *buf, char *newpwd, const int keyfd) { uint8_t key[HEXPASSWDLEN]; Key_schedule schedule; unsigned int i, j; if (!newpwd) { /* convert to binary */ for (i = j = 0; i < sizeof(key); i += 2, j++) buf[j] = (unhex(buf[i]) << 4) | unhex(buf[i + 1]); if (j <= DES_KEY_SZ) memset(buf + j, 0, sizeof(key) - j); } if (keyfd > -1) { lseek(keyfd, 0, SEEK_SET); read(keyfd, key, sizeof(key)); /* convert to binary */ for (i = j = 0; i < sizeof(key); i += 2, j++) key[j] = (unhex(key[i]) << 4) | unhex(key[i + 1]); if (j <= DES_KEY_SZ) memset(key + j, 0, sizeof(key) - j); key_sched((C_Block *) key, schedule); memset(key, 0, sizeof(key)); if (newpwd) { ecb_encrypt((C_Block *) newpwd, (C_Block *) newpwd, schedule, DES_ENCRYPT); } else { /* decrypt the password */ ecb_encrypt((C_Block *) buf, (C_Block *) buf, schedule, DES_DECRYPT); } memset(&schedule, 0, sizeof(schedule)); } if (newpwd) { const unsigned char hextable[] = "0123456789ABCDEF"; /* convert to hex */ for (i = j = 0; i < DES_KEY_SZ; i++, j += 2) { buf[j] = hextable[(newpwd[i] & 0xF0) >> 4]; buf[j + 1] = hextable[newpwd[i] & 0x0F]; } } }
C4Err ECB_Encrypt(Cipher_Algorithm algorithm, const void * key, const void * in, size_t bytesIn, void * out ) { int err = kC4Err_NoErr; int status = CRYPT_OK; symmetric_ECB ECB; int keylen = 0; int cipher = -1; switch(algorithm) { case kCipher_Algorithm_AES128: keylen = 128 >> 3; cipher = find_cipher("aes"); break; case kCipher_Algorithm_AES192: keylen = 192 >> 3; cipher = find_cipher("aes"); break; case kCipher_Algorithm_AES256: keylen = 256 >> 3; cipher = find_cipher("aes"); break; case kCipher_Algorithm_2FISH256: keylen = 256 >> 3; cipher = find_cipher("twofish"); break; default: RETERR(kC4Err_BadCipherNumber); } status = ecb_start(cipher, key, keylen, 0, &ECB ); CKSTAT; status = ecb_encrypt(in, out, bytesIn, &ECB); CKSTAT; done: ecb_done(&ECB); if(status != CRYPT_OK) err = sCrypt2C4Err(status); return err; }
// encryption: data must be NUL-padded to BLOCKSIZE // decryption: data must be padded to BLOCKSIZE // len must be < 2^31 void SymmCipher::ctr_crypt(byte* data, unsigned len, m_off_t pos, ctr_iv ctriv, byte* mac, int encrypt) { assert(!(pos&(KEYLENGTH-1))); byte ctr[BLOCKSIZE], tmp[BLOCKSIZE]; *(uint64_t*)ctr = ctriv; setint64(pos/BLOCKSIZE,ctr+sizeof ctriv); memcpy(mac,ctr,sizeof ctriv); memcpy(mac+sizeof ctriv,ctr,sizeof ctriv); while ((int)len > 0) { if (encrypt) { xorblock(data,mac); ecb_encrypt(mac); ecb_encrypt(ctr,tmp); xorblock(tmp,data); } else { ecb_encrypt(ctr,tmp); xorblock(tmp,data); if (len >= (unsigned)BLOCKSIZE) xorblock(data,mac); else xorblock(data,mac,len); ecb_encrypt(mac); } len -= BLOCKSIZE; data += BLOCKSIZE; incblock(ctr); } }
uint32_t ecb_ut(void) { uint8_t key[16] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55 }; uint8_t clear_text[16] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55 }; uint8_t cipher_text[16]; uint32_t status = 0; struct ecb ecb; struct ecb_ut_context context; ecb_encrypt(key, clear_text, cipher_text, 0); context.done = 0; ecb.in_key_le = key; ecb.in_clear_text_le = clear_text; ecb.fp_ecb = ecb_cb; ecb.context = &context; status = ecb_encrypt_nonblocking(&ecb); do { __WFE(); __SEV(); __WFE(); } while (!context.done); if (context.status != 0) { return context.status; } status = memcmp(cipher_text, context.cipher_text, sizeof(cipher_text)); if (status) { return status; } return status; }
static int EncryptECB( int cipher, int rounds, int counterMode, unsigned char *iv, unsigned char *key, unsigned long keyLength, unsigned char *data, unsigned long dataLength, unsigned char *dest ) { int status; symmetric_ECB state; status = ecb_start(cipher, key, keyLength, rounds, &state); if (status == CRYPT_OK) { status = ecb_encrypt(data, dest, dataLength, &state); ecb_done(&state); } return status; }
static int RunCipherKAT( katvector *kat) { int err = CRYPT_OK; char* name = NULL; uint8_t *out = NULL; size_t alloc_len = MAX(kat->EBClen, kat->CBClen); symmetric_ECB ECB; symmetric_CBC CBC; out = malloc(alloc_len); ZERO(out, alloc_len); // err = cipher_is_valid(kat->algor); CKERR; name = cipher_name(kat->algor); printf("\t%-7s %d ", name, kat->keysize); printf("%6s", "ECB"); DO( ecb_start(kat->algor, kat->key, kat->keysize>>3, 0, &ECB)); DO( ecb_encrypt(kat->PT, out, kat->PTlen, &ECB)) /* check against know-answer */ DO( compareResults( kat->EBC, out, kat->EBClen , kResultFormat_Byte, "Symmetric Encrypt")); DO(ecb_decrypt(out, out, kat->PTlen, &ECB)); /* check against orginal plain-text */ DO(compareResults( kat->PT, out, kat->PTlen , kResultFormat_Byte, "Symmetric Decrypt")); printf("%6s", "CBC"); DO(cbc_start(kat->algor, kat->IV, kat->key, kat->keysize>>3, 0, &CBC)); DO(cbc_encrypt(kat->PT, out, kat->PTlen, &CBC)); /* check against know-answer */ DO(compareResults( kat->CBC, out, kat->CBClen , kResultFormat_Byte, "Symmetric Encrypt")); // reset CBC befire decrypt*/ cbc_done(&CBC); DO(cbc_start(kat->algor, kat->IV, kat->key, kat->keysize>>3, 0, &CBC)); DO(cbc_decrypt(out, out, kat->PTlen, &CBC)); /* check against orginal plain-text */ DO( compareResults( kat->PT, out, kat->PTlen , kResultFormat_Byte, "Symmetric Decrypt")); done: ecb_done(&ECB); cbc_done(&CBC); free(out); printf("\n"); return err; }
/*! * \brief Main application function. \n * -> Initialize clock \n * -> Initialize USART for print functions \n * -> Initialize AES to generate Key schedule for AES-128 \n * -> Based on the AES mode enabled in conf_example.h file, \n * execute encryption and decryption of a message and \n * compare them against input data to check its functionality. \n * -> The decrypted message can be viewed on the COM port terminal \n */ int main(void) { /* * Initialize the System clock * Note: Clock should be configured in conf_clock.h */ system_init(); /* Configure EDBG SERCOM UART to print messages */ configure_usart(); /* Generate key schedule for AES-128 from the Cipher Key */ aes_init(key_vectors); /* Print status messages */ printf("AES key generated successfully!..\r\n"); /* Print Input message for user */ printf("\n The message to be encrypted is:\r\n"); printf("\n %s \r\n",pText); /* * Perform ECB, CFB, OFB, CTR and CBC Encryption and Decryption * based on the mode enabled in conf_example.h. User can choose * the mode that he wants to evaluate. By default, all modes are * enabled. * The decrypted message is printed to EDBG virtual COM port. * If the decrypted message is same as the input plain text, * it ensures the working of each mode. */ #if (AES_ECB == true) //Perform ECB Encryption ecb_encrypt( pText, cText, sizeof(pText) ); for (volatile int i = 0; i < 1000; i++); //Perform ECB Decryption ecb_decrypt( cText, pText1, sizeof(cText)); //Print decrypted message printf("\n Decrypted message using AES-ECB mode : \r\n"); printf("\n %s \r\n",pText1); #endif #if (AES_CFB == true) //Perform CFB Encryption cfb_encrypt(pText, cText, init_vector, CFB_MODE_128, sizeof(pText)); for (volatile int i = 0; i < 1000; i++); //Perform CFB Decryption cfb_decrypt(cText, pText1, init_vector, CFB_MODE_128, sizeof(cText)); //Print decrypted message printf("\n Decrypted message using AES-CFB mode : \r\n"); printf("\n %s \r\n",pText1); #endif #if (AES_OFB == true) //Perform OFB Encryption ofb_encrypt(pText, cText, init_vector, sizeof(pText)); for (volatile int i = 0; i < 1000; i++); //Perform OFB Decryption ofb_encrypt(cText, pText1, init_vector, sizeof(cText)); //Print decrytped message printf("\n Decrypted message using AES-OFB mode : \r\n"); printf("\n %s \r\n",pText1); #endif #if (AES_CTR == true) /* Initialize Counter block with initialization vector, * nonce and counter value */ ctr_blk_t counter_vector = { .i_vector = AES_CTR_IVECTOR, .nonce = AES_CTR_NONCE, .counter = AES_CTR_COUNTER }; //Perform CTR Encryption ctr_encrypt_decrypt(pText, cText, &counter_vector, sizeof(pText)); //Send Counter block value to decryptor for (volatile int i = 0; i < 1000; i++); counter_vector.i_vector = AES_CTR_IVECTOR; counter_vector.nonce = AES_CTR_NONCE; counter_vector.counter = AES_CTR_COUNTER; //Perform CTR Decryption ctr_encrypt_decrypt(cText, pText1, &counter_vector, sizeof(pText1)); //Print decrypted message printf("\n Decrypted message using AES-CTR mode : \r\n"); printf("\n %s \r\n",pText1); #endif /*! \warning CBC mode is done at the last as it process input plain text * during encryption and so the plain text value is not retained. * For testing purpose, to preserve the input plan text for testing with * other modes, this mode is added at the last. */ #if (AES_CBC == true) //Perform CBC Encryption cbc_encrypt(pText, cText, init_vector, sizeof(pText)); for (volatile int i = 0; i < 1000; i++); //Perform CBC Decryption cbc_decrypt(cText, pText1, init_vector, sizeof(cText)); //Print decrypted message printf("\n Decrypted message using AES-CBC mode : \r\n"); printf("\n %s \r\n",pText1); #endif /* Forever loop */ while(1); }
TEE_Result tee_cipher_update(void *ctx, uint32_t algo, TEE_OperationMode mode, bool last_block, const uint8_t *data, size_t len, uint8_t *dst) { TEE_Result res; int ltc_res = CRYPT_OK; size_t block_size; uint8_t tmp_block[64], tmp2_block[64]; int nb_blocks, len_last_block; struct symmetric_CTS *cts; /* * Check that the block contains the correct number of data, apart * for the last block in some XTS / CTR / XTS mode */ res = tee_cipher_get_block_size(algo, &block_size); if (res != TEE_SUCCESS) return res; if ((len % block_size) != 0) { if (!last_block) return TEE_ERROR_BAD_PARAMETERS; switch (algo) { case TEE_ALG_AES_ECB_NOPAD: case TEE_ALG_DES_ECB_NOPAD: case TEE_ALG_DES3_ECB_NOPAD: case TEE_ALG_AES_CBC_NOPAD: case TEE_ALG_DES_CBC_NOPAD: case TEE_ALG_DES3_CBC_NOPAD: return TEE_ERROR_BAD_PARAMETERS; case TEE_ALG_AES_CTR: case TEE_ALG_AES_XTS: case TEE_ALG_AES_CTS: /* * These modes doesn't require padding for the last * block. * * This isn't entirely true, both XTS and CTS can only * encrypt minimum one block and also they need at least * one complete block in the last update to finish the * encryption. The algorithms are supposed to detect * that, we're only making sure that all data fed up to * that point consists of complete blocks. */ break; default: return TEE_ERROR_NOT_SUPPORTED; } } switch (algo) { case TEE_ALG_AES_ECB_NOPAD: case TEE_ALG_DES_ECB_NOPAD: case TEE_ALG_DES3_ECB_NOPAD: if (mode == TEE_MODE_ENCRYPT) ltc_res = ecb_encrypt(data, dst, len, (symmetric_ECB *)ctx); else ltc_res = ecb_decrypt(data, dst, len, (symmetric_ECB *)ctx); break; case TEE_ALG_AES_CBC_NOPAD: case TEE_ALG_DES_CBC_NOPAD: case TEE_ALG_DES3_CBC_NOPAD: if (mode == TEE_MODE_ENCRYPT) ltc_res = cbc_encrypt(data, dst, len, (symmetric_CBC *)ctx); else ltc_res = cbc_decrypt(data, dst, len, (symmetric_CBC *)ctx); break; case TEE_ALG_AES_CTR: if (mode == TEE_MODE_ENCRYPT) ltc_res = ctr_encrypt(data, dst, len, (symmetric_CTR *)ctx); else ltc_res = ctr_decrypt(data, dst, len, (symmetric_CTR *)ctx); break; case TEE_ALG_AES_XTS: return TEE_ERROR_NOT_SUPPORTED; /* if (mode == TEE_MODE_ENCRYPT) { ltc_res = xts_encrypt(data, dst, len, (symmetric_xts *)ctx); } else { ltc_res = xts_decrypt(data, dst, len, (symmetric_xts *)ctx); } */ break; case TEE_ALG_AES_CTS: /* * From http://en.wikipedia.org/wiki/Ciphertext_stealing * CBC ciphertext stealing encryption using a standard * CBC interface: * 1. Pad the last partial plaintext block with 0. * 2. Encrypt the whole padded plaintext using the * standard CBC mode. * 3. Swap the last two ciphertext blocks. * 4. Truncate the ciphertext to the length of the * original plaintext. * * CBC ciphertext stealing decryption using a standard * CBC interface * 1. Dn = Decrypt (K, Cn-1). Decrypt the second to last * ciphertext block. * 2. Cn = Cn || Tail (Dn, B-M). Pad the ciphertext to the * nearest multiple of the block size using the last * B-M bits of block cipher decryption of the * second-to-last ciphertext block. * 3. Swap the last two ciphertext blocks. * 4. Decrypt the (modified) ciphertext using the standard * CBC mode. * 5. Truncate the plaintext to the length of the original * ciphertext. */ cts = (struct symmetric_CTS *)ctx; if (!last_block) return tee_cipher_update( &cts->cbc, TEE_ALG_AES_CBC_NOPAD, mode, last_block, data, len, dst); /* Compute the last block length and check constraints */ if (block_size > 64) return TEE_ERROR_BAD_STATE; nb_blocks = ((len + block_size - 1) / block_size); if (nb_blocks < 2) return TEE_ERROR_BAD_STATE; len_last_block = len % block_size; if (len_last_block == 0) len_last_block = block_size; if (mode == TEE_MODE_ENCRYPT) { memcpy(tmp_block, data + ((nb_blocks - 1) * block_size), len_last_block); memset(tmp_block + len_last_block, 0, block_size - len_last_block); res = tee_cipher_update( &cts->cbc, TEE_ALG_AES_CBC_NOPAD, mode, 0, data, (nb_blocks - 1) * block_size, dst); if (res != TEE_SUCCESS) return res; memcpy(dst + (nb_blocks - 1) * block_size, dst + (nb_blocks - 2) * block_size, len_last_block); res = tee_cipher_update( &cts->cbc, TEE_ALG_AES_CBC_NOPAD, mode, 0, tmp_block, block_size, dst + (nb_blocks - 2) * block_size); if (res != TEE_SUCCESS) return res; } else { /* 1. Decrypt the second to last ciphertext block */ res = tee_cipher_update( &cts->ecb, TEE_ALG_AES_ECB_NOPAD, mode, 0, data + (nb_blocks - 2) * block_size, block_size, tmp2_block); if (res != TEE_SUCCESS) return res; /* 2. Cn = Cn || Tail (Dn, B-M) */ memcpy(tmp_block, data + ((nb_blocks - 1) * block_size), len_last_block); memcpy(tmp_block + len_last_block, tmp2_block + len_last_block, block_size - len_last_block); /* 3. Swap the last two ciphertext blocks */ /* done by passing the correct buffers in step 4. */ /* 4. Decrypt the (modified) ciphertext */ if (nb_blocks > 2) { res = tee_cipher_update( &cts->cbc, TEE_ALG_AES_CBC_NOPAD, mode, 0, data, (nb_blocks - 2) * block_size, dst); if (res != TEE_SUCCESS) return res; } res = tee_cipher_update( &cts->cbc, TEE_ALG_AES_CBC_NOPAD, mode, 0, tmp_block, block_size, dst + ((nb_blocks - 2) * block_size)); if (res != TEE_SUCCESS) return res; res = tee_cipher_update( &cts->cbc, TEE_ALG_AES_CBC_NOPAD, mode, 0, data + ((nb_blocks - 2) * block_size), block_size, tmp_block); if (res != TEE_SUCCESS) return res; /* 5. Truncate the plaintext */ memcpy(dst + (nb_blocks - 1) * block_size, tmp_block, len_last_block); break; } break; default: return TEE_ERROR_NOT_SUPPORTED; } if (ltc_res == CRYPT_OK) return TEE_SUCCESS; else return TEE_ERROR_BAD_STATE; }