/* The user-supplied UMAC key is stretched using AES in a counter * mode to supply all random bits needed by UMAC. The kdf function takes * an AES internal key representation 'key' and writes a stream of * 'nbytes' bytes to the memory pointed at by 'bufp'. Each distinct * 'ndx' causes a distinct byte stream. */ static void kdf(void *bufp, aes_int_key key, UINT8 ndx, int nbytes) { UINT8 in_buf[AES_BLOCK_LEN] = {0}; UINT8 out_buf[AES_BLOCK_LEN]; UINT8 *dst_buf = (UINT8 *)bufp; int i; /* Setup the initial value */ in_buf[AES_BLOCK_LEN-9] = ndx; in_buf[AES_BLOCK_LEN-1] = i = 1; while (nbytes >= AES_BLOCK_LEN) { aes_encryption(in_buf, out_buf, key); memcpy(dst_buf,out_buf,AES_BLOCK_LEN); in_buf[AES_BLOCK_LEN-1] = ++i; nbytes -= AES_BLOCK_LEN; dst_buf += AES_BLOCK_LEN; } if (nbytes) { aes_encryption(in_buf, out_buf, key); memcpy(dst_buf,out_buf,nbytes); } explicit_bzero(in_buf, sizeof(in_buf)); explicit_bzero(out_buf, sizeof(out_buf)); }
static void pdf_init(pdf_ctx *pc, aes_int_key prf_key) { UINT8 buf[UMAC_KEY_LEN]; kdf(buf, prf_key, 0, UMAC_KEY_LEN); aes_key_setup(buf, pc->prf_key); /* Initialize pdf and cache */ memset(pc->nonce, 0, sizeof(pc->nonce)); aes_encryption(pc->nonce, pc->cache, pc->prf_key); }
int main() { std::string plaintext = "Hello world."; std::string ciphertext; std::string decrypted_text; // Key and IV setup. byte key[CryptoPP::AES::DEFAULT_KEYLENGTH]; byte iv[CryptoPP::AES::BLOCKSIZE]; memset(key, 0x00, CryptoPP::AES::DEFAULT_KEYLENGTH); memset(iv, 0x00, CryptoPP::AES::BLOCKSIZE); // Dump plaintext test. std::cout << "The plaintext size = " << plaintext.size() << std::endl; std::cout << "The plaintext = " << plaintext << std::endl; // Encrypt. CryptoPP::AES::Encryption aes_encryption (key, CryptoPP::AES::DEFAULT_KEYLENGTH); CryptoPP::CBC_Mode_ExternalCipher::Encryption cbc_cipher_encryption(aes_encryption, iv); CryptoPP::StreamTransformationFilter stf_encryptor(cbc_cipher_encryption, new CryptoPP::StringSink(ciphertext)); stf_encryptor.Put(reinterpret_cast<const unsigned char*>(plaintext.c_str()), plaintext.length()); stf_encryptor.MessageEnd(); // Dump ciphertext. std::cout << "The ciphertext size = " << ciphertext.size() << std::endl; std::cout << "The ciphertext is:" << std::endl; for (int i = 0; i < ciphertext.size(); i ++) { std::cout << "0x" << std::hex << (0xFF & static_cast<byte>(ciphertext[i])) << " "; } std::cout << std::endl; // Decrypt. CryptoPP::AES::Decryption aes_decryption(key, CryptoPP::AES::DEFAULT_KEYLENGTH); CryptoPP::CBC_Mode_ExternalCipher::Decryption cbc_cipher_decryption(aes_decryption, iv); CryptoPP::StreamTransformationFilter stf_decryptor(cbc_cipher_decryption, new CryptoPP::StringSink(decrypted_text)); stf_decryptor.Put(reinterpret_cast<const unsigned char*>(ciphertext.c_str()), ciphertext.length()); stf_decryptor.MessageEnd(); // Dump decrypted_text. std::cout << "The decrypted_text size = " << std::to_string(decrypted_text.size()) << std::endl; std::cout << "The decrypted_text = " << decrypted_text << std::endl; return 0; }
static void pdf_gen_xor(pdf_ctx *pc, const UINT8 nonce[8], UINT8 buf[8]) { /* 'ndx' indicates that we'll be using the 0th or 1st eight bytes * of the AES output. If last time around we returned the ndx-1st * element, then we may have the result in the cache already. */ #if (UMAC_OUTPUT_LEN == 4) #define LOW_BIT_MASK 3 #elif (UMAC_OUTPUT_LEN == 8) #define LOW_BIT_MASK 1 #elif (UMAC_OUTPUT_LEN > 8) #define LOW_BIT_MASK 0 #endif union { UINT8 tmp_nonce_lo[4]; UINT32 align; } t; #if LOW_BIT_MASK != 0 int ndx = nonce[7] & LOW_BIT_MASK; #endif memcpy(t.tmp_nonce_lo, nonce + 4, sizeof(t.tmp_nonce_lo)); t.tmp_nonce_lo[3] &= ~LOW_BIT_MASK; /* zero last bit */ if (memcmp(t.tmp_nonce_lo, pc->nonce + 1, sizeof(t.tmp_nonce_lo)) != 0 || memcmp(nonce, pc->nonce, sizeof(t.tmp_nonce_lo)) != 0) { memcpy(pc->nonce, nonce, sizeof(t.tmp_nonce_lo)); memcpy(pc->nonce + 4, t.tmp_nonce_lo, sizeof(t.tmp_nonce_lo)); aes_encryption(pc->nonce, pc->cache, pc->prf_key); } #if (UMAC_OUTPUT_LEN == 4) xor32(buf, 0, pc->cache, ndx); #elif (UMAC_OUTPUT_LEN == 8) xor64(buf, 0, pc->cache, ndx); #elif (UMAC_OUTPUT_LEN == 12) xor64(buf, 0, pc->cache, 0); xor32(buf, 2, pc->cache, 2); #elif (UMAC_OUTPUT_LEN == 16) xor64(buf, 0, pc->cache, 0); xor64(buf, 1, pc->cache, 1); #endif }
static void pdf_gen_xor(pdf_ctx *pc, const UINT8 nonce[8], UINT8 buf[8]) { /* 'ndx' indicates that we'll be using the 0th or 1st eight bytes * of the AES output. If last time around we returned the ndx-1st * element, then we may have the result in the cache already. */ #if (UMAC_OUTPUT_LEN == 4) #define LOW_BIT_MASK 3 #elif (UMAC_OUTPUT_LEN == 8) #define LOW_BIT_MASK 1 #elif (UMAC_OUTPUT_LEN > 8) #define LOW_BIT_MASK 0 #endif union { UINT8 tmp_nonce_lo[4]; UINT32 align; } t; #if LOW_BIT_MASK != 0 int ndx = nonce[7] & LOW_BIT_MASK; #endif *(UINT32 *)t.tmp_nonce_lo = ((const UINT32 *)nonce)[1]; t.tmp_nonce_lo[3] &= ~LOW_BIT_MASK; /* zero last bit */ if ( (((UINT32 *)t.tmp_nonce_lo)[0] != ((UINT32 *)pc->nonce)[1]) || (((const UINT32 *)nonce)[0] != ((UINT32 *)pc->nonce)[0]) ) { ((UINT32 *)pc->nonce)[0] = ((const UINT32 *)nonce)[0]; ((UINT32 *)pc->nonce)[1] = ((UINT32 *)t.tmp_nonce_lo)[0]; aes_encryption(pc->nonce, pc->cache, pc->prf_key); } #if (UMAC_OUTPUT_LEN == 4) *((UINT32 *)buf) ^= ((UINT32 *)pc->cache)[ndx]; #elif (UMAC_OUTPUT_LEN == 8) *((UINT64 *)buf) ^= ((UINT64 *)pc->cache)[ndx]; #elif (UMAC_OUTPUT_LEN == 12) ((UINT64 *)buf)[0] ^= ((UINT64 *)pc->cache)[0]; ((UINT32 *)buf)[2] ^= ((UINT32 *)pc->cache)[2]; #elif (UMAC_OUTPUT_LEN == 16) ((UINT64 *)buf)[0] ^= ((UINT64 *)pc->cache)[0]; ((UINT64 *)buf)[1] ^= ((UINT64 *)pc->cache)[1]; #endif }