/************************************************* * CTR-BE Encryption/Decryption * *************************************************/ void CTR_BE::write(const byte input[], u32bit length) { u32bit copied = std::min(BLOCK_SIZE - position, length); xor_buf(buffer + position, input, copied); send(buffer + position, copied); input += copied; length -= copied; position += copied; if(position == BLOCK_SIZE) increment_counter(); while(length >= BLOCK_SIZE) { xor_buf(buffer, input, BLOCK_SIZE); send(buffer, BLOCK_SIZE); input += BLOCK_SIZE; length -= BLOCK_SIZE; increment_counter(); } xor_buf(buffer + position, input, length); send(buffer + position, length); position += length; }
/* * Finish encrypting in XTS mode */ void XTS_Encryption::end_msg() { const u32bit BLOCK_SIZE = cipher->BLOCK_SIZE; if(position < BLOCK_SIZE) throw Exception("XTS_Encryption: insufficient data to encrypt"); else if(position == BLOCK_SIZE) { encrypt(buffer); } else if(position == 2*BLOCK_SIZE) { encrypt(buffer); encrypt(buffer + BLOCK_SIZE); } else { // steal ciphertext xor_buf(buffer, tweak, cipher->BLOCK_SIZE); cipher->encrypt(buffer); xor_buf(buffer, tweak, cipher->BLOCK_SIZE); poly_double(tweak, cipher->BLOCK_SIZE); for(u32bit i = 0; i != position - cipher->BLOCK_SIZE; ++i) std::swap(buffer[i], buffer[i + cipher->BLOCK_SIZE]); xor_buf(buffer, tweak, cipher->BLOCK_SIZE); cipher->encrypt(buffer); xor_buf(buffer, tweak, cipher->BLOCK_SIZE); send(buffer, position); } position = 0; }
size_t CBC_Decryption::process(uint8_t buf[], size_t sz) { const size_t BS = cipher().block_size(); BOTAN_ASSERT(sz % BS == 0, "Input is full blocks"); size_t blocks = sz / BS; while(blocks) { const size_t to_proc = std::min(BS * blocks, m_tempbuf.size()); cipher().decrypt_n(buf, m_tempbuf.data(), to_proc / BS); xor_buf(m_tempbuf.data(), state_ptr(), BS); xor_buf(&m_tempbuf[BS], buf, to_proc - BS); copy_mem(state_ptr(), buf + (to_proc - BS), BS); copy_mem(buf, m_tempbuf.data(), to_proc); buf += to_proc; blocks -= to_proc / BS; } return sz; }
/************************************************* * OFB Encryption/Decryption * *************************************************/ void OFB::write(const byte input[], u32bit length) { u32bit copied = std::min(BLOCK_SIZE - position, length); xor_buf(buffer, input, state + position, copied); send(buffer, copied); input += copied; length -= copied; position += copied; if(position == BLOCK_SIZE) { cipher->encrypt(state); position = 0; } while(length >= BLOCK_SIZE) { xor_buf(buffer, input, state, BLOCK_SIZE); send(buffer, BLOCK_SIZE); input += BLOCK_SIZE; length -= BLOCK_SIZE; cipher->encrypt(state); } xor_buf(buffer, input, state + position, length); send(buffer, length); position += length; }
void CCM_Decryption::finish(secure_vector<byte>& buffer, size_t offset) { BOTAN_ASSERT(buffer.size() >= offset, "Offset is sane"); buffer.insert(buffer.begin() + offset, msg_buf().begin(), msg_buf().end()); const size_t sz = buffer.size() - offset; byte* buf = buffer.data() + offset; BOTAN_ASSERT(sz >= tag_size(), "We have the tag"); const secure_vector<byte>& ad = ad_buf(); BOTAN_ASSERT(ad.size() % BS == 0, "AD is block size multiple"); const BlockCipher& E = cipher(); secure_vector<byte> T(BS); E.encrypt(format_b0(sz - tag_size()), T); for(size_t i = 0; i != ad.size(); i += BS) { xor_buf(T.data(), &ad[i], BS); E.encrypt(T); } secure_vector<byte> C = format_c0(); secure_vector<byte> S0(BS); E.encrypt(C, S0); inc(C); secure_vector<byte> X(BS); const byte* buf_end = &buf[sz - tag_size()]; while(buf != buf_end) { const size_t to_proc = std::min<size_t>(BS, buf_end - buf); E.encrypt(C, X); xor_buf(buf, X.data(), to_proc); inc(C); xor_buf(T.data(), buf, to_proc); E.encrypt(T); buf += to_proc; } T ^= S0; if(!same_mem(T.data(), buf_end, tag_size())) throw Integrity_Failure("CCM tag check failed"); buffer.resize(buffer.size() - tag_size()); }
void EAX_Encryption::finish(secure_vector<byte>& buffer, size_t offset) { update(buffer, offset); secure_vector<byte> data_mac = m_cmac->final(); xor_buf(data_mac, m_nonce_mac, data_mac.size()); xor_buf(data_mac, m_ad_mac, data_mac.size()); buffer += std::make_pair(data_mac.data(), tag_size()); }
/* * Decrypt a block */ void XTS_Decryption::decrypt(const byte block[]) { xor_buf(buffer, block, tweak, cipher->BLOCK_SIZE); cipher->decrypt(buffer); xor_buf(buffer, tweak, cipher->BLOCK_SIZE); poly_double(tweak, cipher->BLOCK_SIZE); send(buffer, cipher->BLOCK_SIZE); }
/* * Finish decrypting in CTS mode */ void CTS_Decryption::end_msg() { cipher->decrypt(buffer, temp); xor_buf(temp, buffer + BLOCK_SIZE, position - BLOCK_SIZE); SecureVector<byte> xn = temp; copy_mem(buffer + position, xn + (position - BLOCK_SIZE), BUFFER_SIZE - position); cipher->decrypt(buffer + BLOCK_SIZE, temp); xor_buf(temp, state, BLOCK_SIZE); send(temp, BLOCK_SIZE); send(xn, position - BLOCK_SIZE); }
/* * Combine cipher stream with message */ void ARC4::cipher(const byte in[], byte out[], size_t length) { while(length >= buffer.size() - position) { xor_buf(out, in, &buffer[position], buffer.size() - position); length -= (buffer.size() - position); in += (buffer.size() - position); out += (buffer.size() - position); generate(); } xor_buf(out, in, &buffer[position], length); position += length; }
void aont_package(RandomNumberGenerator& rng, BlockCipher* cipher, const byte input[], size_t input_len, byte output[]) { const size_t BLOCK_SIZE = cipher->block_size(); if(!cipher->valid_keylength(BLOCK_SIZE)) throw Invalid_Argument("AONT::package: Invalid cipher"); // The all-zero string which is used both as the CTR IV and as K0 const std::string all_zeros(BLOCK_SIZE*2, '0'); SymmetricKey package_key(rng, BLOCK_SIZE); Pipe pipe(new StreamCipher_Filter(new CTR_BE(cipher), package_key)); pipe.process_msg(input, input_len); pipe.read(output, pipe.remaining()); // Set K0 (the all zero key) cipher->set_key(SymmetricKey(all_zeros)); SecureVector<byte> buf(BLOCK_SIZE); const size_t blocks = (input_len + BLOCK_SIZE - 1) / BLOCK_SIZE; byte* final_block = output + input_len; clear_mem(final_block, BLOCK_SIZE); // XOR the hash blocks into the final block for(size_t i = 0; i != blocks; ++i) { const size_t left = std::min<size_t>(BLOCK_SIZE, input_len - BLOCK_SIZE * i); zeroise(buf); copy_mem(&buf[0], output + (BLOCK_SIZE * i), left); for(size_t j = 0; j != sizeof(i); ++j) buf[BLOCK_SIZE - 1 - j] ^= get_byte(sizeof(i)-1-j, i); cipher->encrypt(buf); xor_buf(final_block, buf, BLOCK_SIZE); } // XOR the random package key into the final block xor_buf(final_block, package_key.begin(), BLOCK_SIZE); }
void OFB::cipher(const byte in[], byte out[], size_t length) { while(length >= m_buffer.size() - m_buf_pos) { xor_buf(out, in, &m_buffer[m_buf_pos], m_buffer.size() - m_buf_pos); length -= (m_buffer.size() - m_buf_pos); in += (m_buffer.size() - m_buf_pos); out += (m_buffer.size() - m_buf_pos); m_cipher->encrypt(m_buffer); m_buf_pos = 0; } xor_buf(out, in, &m_buffer[m_buf_pos], length); m_buf_pos += length; }
/************************************************* * HMAC Key Schedule * *************************************************/ void HMAC::key(const byte key[], u32bit length) { hash->clear(); std::fill(i_key.begin(), i_key.end(), 0x36); std::fill(o_key.begin(), o_key.end(), 0x5C); SecureVector<byte> hmac_key(key, length); if(hmac_key.size() > hash->HASH_BLOCK_SIZE) hmac_key = hash->process(hmac_key); xor_buf(i_key, hmac_key, hmac_key.size()); xor_buf(o_key, hmac_key, hmac_key.size()); hash->update(i_key); }
void CCM_Encryption::finish(secure_vector<byte>& buffer, size_t offset) { BOTAN_ASSERT(buffer.size() >= offset, "Offset is sane"); buffer.insert(buffer.begin() + offset, msg_buf().begin(), msg_buf().end()); const size_t sz = buffer.size() - offset; byte* buf = buffer.data() + offset; const secure_vector<byte>& ad = ad_buf(); BOTAN_ASSERT(ad.size() % BS == 0, "AD is block size multiple"); const BlockCipher& E = cipher(); secure_vector<byte> T(BS); E.encrypt(format_b0(sz), T); for(size_t i = 0; i != ad.size(); i += BS) { xor_buf(T.data(), &ad[i], BS); E.encrypt(T); } secure_vector<byte> C = format_c0(); secure_vector<byte> S0(BS); E.encrypt(C, S0); inc(C); secure_vector<byte> X(BS); const byte* buf_end = &buf[sz]; while(buf != buf_end) { const size_t to_proc = std::min<size_t>(BS, buf_end - buf); xor_buf(T.data(), buf, to_proc); E.encrypt(T); E.encrypt(C, X); xor_buf(buf, X.data(), to_proc); inc(C); buf += to_proc; } T ^= S0; buffer += std::make_pair(T.data(), tag_size()); }
/************************************************* * Refill the internal state * *************************************************/ void ANSI_X931_RNG::update_buffer() { const u32bit BLOCK_SIZE = cipher->BLOCK_SIZE; SecureVector<byte> DT(BLOCK_SIZE); prng->randomize(DT, DT.size()); cipher->encrypt(DT); xor_buf(R, V, DT, BLOCK_SIZE); cipher->encrypt(R); xor_buf(V, R, DT, BLOCK_SIZE); cipher->encrypt(V); }
/** * Refill the internal state */ void ANSI_X931_RNG::update_buffer() { SecureVector<byte> DT(cipher->BLOCK_SIZE); prng->randomize(DT, DT.size()); cipher->encrypt(DT); xor_buf(R, V, DT, cipher->BLOCK_SIZE); cipher->encrypt(R); xor_buf(V, R, DT, cipher->BLOCK_SIZE); cipher->encrypt(V); position = 0; }
/* * Refill the internal state */ void ANSI_X931_RNG::update_buffer() { const size_t BLOCK_SIZE = m_cipher->block_size(); secure_vector<byte> DT = m_prng->random_vec(BLOCK_SIZE); m_cipher->encrypt(DT); xor_buf(m_R.data(), m_V.data(), DT.data(), BLOCK_SIZE); m_cipher->encrypt(m_R); xor_buf(m_V.data(), m_R.data(), DT.data(), BLOCK_SIZE); m_cipher->encrypt(m_V); m_R_pos = 0; }
/* * Combine cipher stream with message */ void RC4::cipher(const uint8_t in[], uint8_t out[], size_t length) { verify_key_set(m_state.empty() == false); while(length >= m_buffer.size() - m_position) { xor_buf(out, in, &m_buffer[m_position], m_buffer.size() - m_position); length -= (m_buffer.size() - m_position); in += (m_buffer.size() - m_position); out += (m_buffer.size() - m_position); generate(); } xor_buf(out, in, &m_buffer[m_position], length); m_position += length; }
void XMSS_WOTS_PublicKey::chain(secure_vector<uint8_t>& result, size_t start_idx, size_t steps, XMSS_Address& adrs, const secure_vector<uint8_t>& seed, XMSS_Hash& hash) { for(size_t i = start_idx; i < (start_idx + steps) && i < m_wots_params.wots_parameter(); i++) { adrs.set_hash_address(i); //Calculate tmp XOR bitmask adrs.set_key_mask_mode(XMSS_Address::Key_Mask::Mask_Mode); xor_buf(result, hash.prf(seed, adrs.bytes()), result.size()); // Calculate key adrs.set_key_mask_mode(XMSS_Address::Key_Mask::Key_Mode); //Calculate f(key, tmp XOR bitmask) hash.f(result, hash.prf(seed, adrs.bytes()), result); } }
/* * Decrypt a block */ void CTS_Decryption::decrypt(const byte block[]) { cipher->decrypt(block, temp); xor_buf(temp, state, BLOCK_SIZE); send(temp, BLOCK_SIZE); state.copy(block, BLOCK_SIZE); }
void cbc_decrypt(cbc_state_t *state, aes_ctx_t *ctx) { uint8_t this_cipher[AES_BUF_LEN]; memcpy(this_cipher, state->data, AES_BUF_LEN); aes128_dec(state->data, ctx); xor_buf(state->data, state->iv, AES_BUF_LEN); memcpy(state->iv, this_cipher, AES_BUF_LEN); }
/* * Combine cipher stream with message */ void ChaCha::cipher(const byte in[], byte out[], size_t length) { while(length >= m_buffer.size() - m_position) { xor_buf(out, in, &m_buffer[m_position], m_buffer.size() - m_position); length -= (m_buffer.size() - m_position); in += (m_buffer.size() - m_position); out += (m_buffer.size() - m_position); chacha_x4(m_buffer.data(), m_state.data(), m_rounds); m_position = 0; } xor_buf(out, in, &m_buffer[m_position], length); m_position += length; }
/* * Finish decrypting in EAX mode */ void EAX_Decryption::end_msg() { if((queue_end - queue_start) != TAG_SIZE) throw Decoding_Error(name() + ": Message authentication failure"); const byte* included_mac = &queue[queue_start]; SecureVector<byte> computed_mac = cmac->final(); xor_buf(&computed_mac[0], &nonce_mac[0], TAG_SIZE); xor_buf(&computed_mac[0], &header_mac[0], TAG_SIZE); if(!same_mem(included_mac, &computed_mac[0], TAG_SIZE)) throw Decoding_Error(name() + ": Message authentication failure"); queue_start = queue_end = 0; }
/* * XOR Operation for OctetStrings */ OctetString operator^(const OctetString& k1, const OctetString& k2) { secure_vector<uint8_t> out(std::max(k1.length(), k2.length())); copy_mem(out.data(), k1.begin(), k1.length()); xor_buf(out.data(), k2.begin(), k2.length()); return OctetString(out); }
/************************************************* * Add user-supplied entropy * *************************************************/ void Randpool::add_entropy(const byte input[], u32bit length) { SecureVector<byte> mac_val = mac->process(input, length); xor_buf(pool, mac_val, mac_val.size()); mix_pool(); entropy += entropy_estimate(input, length); }
void XTS_Encryption::encrypt(const byte block[]) { /* * We can always use the first 16 bytes of buffer as temp space, * since either the input block is buffer (in which case this is * just buffer ^= tweak) or it not, in which case we already read * and used the data there and are processing new input. Kind of * subtle/nasty, but saves allocating a distinct temp buf. */ xor_buf(buffer, block, tweak, cipher->BLOCK_SIZE); cipher->encrypt(buffer); xor_buf(buffer, tweak, cipher->BLOCK_SIZE); poly_double(tweak, cipher->BLOCK_SIZE); send(buffer, cipher->BLOCK_SIZE); }
/** * Add user-supplied entropy */ void Randpool::add_entropy(const byte input[], u32bit length) { SecureVector<byte> mac_val = mac->process(input, length); xor_buf(pool, mac_val, mac_val.size()); mix_pool(); if(length) seeded = true; }
void XTS_Decryption::finish(secure_vector<uint8_t>& buffer, size_t offset) { BOTAN_ASSERT(buffer.size() >= offset, "Offset is sane"); const size_t sz = buffer.size() - offset; uint8_t* buf = buffer.data() + offset; BOTAN_ASSERT(sz >= minimum_final_size(), "Have sufficient final input in XTS decrypt"); const size_t BS = cipher().block_size(); if(sz % BS == 0) { update(buffer, offset); } else { // steal ciphertext const size_t full_blocks = ((sz / BS) - 1) * BS; const size_t final_bytes = sz - full_blocks; BOTAN_ASSERT(final_bytes > BS && final_bytes < 2*BS, "Left over size in expected range"); secure_vector<uint8_t> last(buf + full_blocks, buf + full_blocks + final_bytes); buffer.resize(full_blocks + offset); update(buffer, offset); xor_buf(last, tweak() + BS, BS); cipher().decrypt(last); xor_buf(last, tweak() + BS, BS); for(size_t i = 0; i != final_bytes - BS; ++i) { last[i] ^= last[i + BS]; last[i + BS] ^= last[i]; last[i] ^= last[i + BS]; } xor_buf(last, tweak(), BS); cipher().decrypt(last); xor_buf(last, tweak(), BS); buffer += last; } }
void CTS_Decryption::finish(secure_vector<uint8_t>& buffer, size_t offset) { BOTAN_ASSERT(buffer.size() >= offset, "Offset is sane"); const size_t sz = buffer.size() - offset; uint8_t* buf = buffer.data() + offset; const size_t BS = cipher().block_size(); if(sz < BS + 1) throw Encoding_Error(name() + ": insufficient data to decrypt"); if(sz % BS == 0) { // swap last two blocks for(size_t i = 0; i != BS; ++i) std::swap(buffer[buffer.size()-BS+i], buffer[buffer.size()-2*BS+i]); update(buffer, offset); } else { const size_t full_blocks = ((sz / BS) - 1) * BS; const size_t final_bytes = sz - full_blocks; BOTAN_ASSERT(final_bytes > BS && final_bytes < 2*BS, "Left over size in expected range"); secure_vector<uint8_t> last(buf + full_blocks, buf + full_blocks + final_bytes); buffer.resize(full_blocks + offset); update(buffer, offset); cipher().decrypt(last.data()); xor_buf(last.data(), &last[BS], final_bytes - BS); for(size_t i = 0; i != final_bytes - BS; ++i) std::swap(last[i], last[i + BS]); cipher().decrypt(last.data()); xor_buf(last.data(), state_ptr(), BS); buffer += last; } }
void SHAKE_128_Cipher::cipher(const uint8_t in[], uint8_t out[], size_t length) { verify_key_set(m_state.empty() == false); while(length >= m_buffer.size() - m_buf_pos) { xor_buf(out, in, &m_buffer[m_buf_pos], m_buffer.size() - m_buf_pos); length -= (m_buffer.size() - m_buf_pos); in += (m_buffer.size() - m_buf_pos); out += (m_buffer.size() - m_buf_pos); SHA_3::permute(m_state.data()); copy_out_le(m_buffer.data(), m_buffer.size(), m_state.data()); m_buf_pos = 0; } xor_buf(out, in, &m_buffer[m_buf_pos], length); m_buf_pos += length; }
/* * Combine cipher stream with message */ void Salsa20::cipher(const uint8_t in[], uint8_t out[], size_t length) { while(length >= m_buffer.size() - m_position) { xor_buf(out, in, &m_buffer[m_position], m_buffer.size() - m_position); length -= (m_buffer.size() - m_position); in += (m_buffer.size() - m_position); out += (m_buffer.size() - m_position); salsa20(m_buffer.data(), m_state.data()); ++m_state[8]; m_state[9] += (m_state[8] == 0); m_position = 0; } xor_buf(out, in, &m_buffer[m_position], length); m_position += length; }