diff options
author | Jack Lloyd <[email protected]> | 2016-09-01 13:40:26 -0400 |
---|---|---|
committer | Jack Lloyd <[email protected]> | 2016-09-01 14:16:38 -0400 |
commit | 507d926da825fbc1d9d74b4517dbab47702c66b9 (patch) | |
tree | 22ac0e4a9c85fb3583d478a41ba1c46aeced5ec3 /src/lib/modes/aead/gcm/gcm.cpp | |
parent | e4656be6a8e601b64c759906bacf543388b3cf22 (diff) |
Cipher_Mode API improvements
The Cipher_Mode::update API is more general than needed to just
support ciphers (this is due to it previously being an API of
Transform which before 8b85b780515 was Cipher_Mode's base class)
Define a less general interface `process` which either processes the
blocks in-place, producing exactly as much output as there was input,
or (SIV/CCM case) saves the entire message for processing in `finish`.
These two uses cover all current or anticipated cipher modes.
Leaves `update` for compatability with existing callers; all that is
needed is an inline function forwarding to `process`.
Removes the return type from `start` - in all cipher implementations,
this always returned an empty vector.
Adds BOTAN_ARG_CHECK macro; right now BOTAN_ASSERT is being used
for argument checking in some places, which is not right at all.
Diffstat (limited to 'src/lib/modes/aead/gcm/gcm.cpp')
-rw-r--r-- | src/lib/modes/aead/gcm/gcm.cpp | 63 |
1 files changed, 31 insertions, 32 deletions
diff --git a/src/lib/modes/aead/gcm/gcm.cpp b/src/lib/modes/aead/gcm/gcm.cpp index e23551cb4..78792b79a 100644 --- a/src/lib/modes/aead/gcm/gcm.cpp +++ b/src/lib/modes/aead/gcm/gcm.cpp @@ -17,6 +17,8 @@ namespace Botan { +static const size_t GCM_BS = 16; + void GHASH::gcm_multiply(secure_vector<byte>& x) const { #if defined(BOTAN_HAS_GCM_CLMUL) @@ -66,15 +68,13 @@ void GHASH::gcm_multiply(secure_vector<byte>& x) const void GHASH::ghash_update(secure_vector<byte>& ghash, const byte input[], size_t length) { - const size_t BS = 16; - /* This assumes if less than block size input then we're just on the final block and should pad with zeros */ while(length) { - const size_t to_proc = std::min(length, BS); + const size_t to_proc = std::min(length, GCM_BS); xor_buf(ghash.data(), input, to_proc); @@ -88,7 +88,7 @@ void GHASH::ghash_update(secure_vector<byte>& ghash, void GHASH::key_schedule(const byte key[], size_t length) { m_H.assign(key, key+length); - m_H_ad.resize(16); + m_H_ad.resize(GCM_BS); m_ad_len = 0; m_text_len = 0; } @@ -109,7 +109,7 @@ void GHASH::set_associated_data(const byte input[], size_t length) void GHASH::update(const byte input[], size_t length) { - BOTAN_ASSERT(m_ghash.size() == 16, "Key was set"); + BOTAN_ASSERT(m_ghash.size() == GCM_BS, "Key was set"); m_text_len += length; @@ -119,7 +119,7 @@ void GHASH::update(const byte input[], size_t length) void GHASH::add_final_block(secure_vector<byte>& hash, size_t ad_len, size_t text_len) { - secure_vector<byte> final_block(16); + secure_vector<byte> final_block(GCM_BS); store_be<u64bit>(final_block.data(), 8*ad_len, 8*text_len); ghash_update(hash, final_block.data(), final_block.size()); } @@ -139,7 +139,7 @@ secure_vector<byte> GHASH::final() secure_vector<byte> GHASH::nonce_hash(const byte nonce[], size_t nonce_len) { BOTAN_ASSERT(m_ghash.size() == 0, "nonce_hash called during wrong time"); - secure_vector<byte> y0(16); + secure_vector<byte> y0(GCM_BS); ghash_update(y0, nonce, nonce_len); add_final_block(y0, 0, nonce_len); @@ -162,15 +162,14 @@ GCM_Mode::GCM_Mode(BlockCipher* cipher, size_t tag_size) : m_tag_size(tag_size), m_cipher_name(cipher->name()) { - if(cipher->block_size() != m_BS) - throw Invalid_Argument("GCM requires a 128 bit cipher so cannot be used with " + - cipher->name()); + if(cipher->block_size() != GCM_BS) + throw Invalid_Argument("Invalid block cipher for GCM"); m_ghash.reset(new GHASH); m_ctr.reset(new CTR_BE(cipher, 4)); // CTR_BE takes ownership of cipher - if(m_tag_size != 8 && m_tag_size != 16) + if(m_tag_size != 8 && m_tag_size != GCM_BS) throw Invalid_Argument(name() + ": Bad tag size " + std::to_string(m_tag_size)); } @@ -187,7 +186,7 @@ std::string GCM_Mode::name() const size_t GCM_Mode::update_granularity() const { - return m_BS; + return GCM_BS; } Key_Length_Specification GCM_Mode::key_spec() const @@ -199,10 +198,10 @@ void GCM_Mode::key_schedule(const byte key[], size_t keylen) { m_ctr->set_key(key, keylen); - const std::vector<byte> zeros(m_BS); + const std::vector<byte> zeros(GCM_BS); m_ctr->set_iv(zeros.data(), zeros.size()); - secure_vector<byte> H(m_BS); + secure_vector<byte> H(GCM_BS); m_ctr->encipher(H); m_ghash->set_key(H); } @@ -212,12 +211,12 @@ void GCM_Mode::set_associated_data(const byte ad[], size_t ad_len) m_ghash->set_associated_data(ad, ad_len); } -secure_vector<byte> GCM_Mode::start_raw(const byte nonce[], size_t nonce_len) +void GCM_Mode::start_msg(const byte nonce[], size_t nonce_len) { if(!valid_nonce_length(nonce_len)) throw Invalid_IV_Length(name(), nonce_len); - secure_vector<byte> y0(m_BS); + secure_vector<byte> y0(GCM_BS); if(nonce_len == 12) { @@ -231,48 +230,48 @@ secure_vector<byte> GCM_Mode::start_raw(const byte nonce[], size_t nonce_len) m_ctr->set_iv(y0.data(), y0.size()); - secure_vector<byte> m_enc_y0(m_BS); + secure_vector<byte> m_enc_y0(GCM_BS); m_ctr->encipher(m_enc_y0); m_ghash->start(m_enc_y0.data(), m_enc_y0.size()); - - return secure_vector<byte>(); } -void GCM_Encryption::update(secure_vector<byte>& buffer, size_t offset) +size_t GCM_Encryption::process(uint8_t buf[], size_t sz) { - BOTAN_ASSERT(buffer.size() >= offset, "Offset is sane"); - const size_t sz = buffer.size() - offset; - byte* buf = buffer.data() + offset; - + BOTAN_ARG_CHECK(sz % update_granularity() == 0); m_ctr->cipher(buf, buf, sz); m_ghash->update(buf, sz); + return sz; } void GCM_Encryption::finish(secure_vector<byte>& buffer, size_t offset) { - update(buffer, offset); + BOTAN_ARG_CHECK(offset <= buffer.size()); + const size_t sz = buffer.size() - offset; + byte* buf = buffer.data() + offset; + + m_ctr->cipher(buf, buf, sz); + m_ghash->update(buf, sz); auto mac = m_ghash->final(); buffer += std::make_pair(mac.data(), tag_size()); } -void GCM_Decryption::update(secure_vector<byte>& buffer, size_t offset) +size_t GCM_Decryption::process(uint8_t buf[], size_t sz) { - BOTAN_ASSERT(buffer.size() >= offset, "Offset is sane"); - const size_t sz = buffer.size() - offset; - byte* buf = buffer.data() + offset; - + BOTAN_ARG_CHECK(sz % update_granularity() == 0); m_ghash->update(buf, sz); m_ctr->cipher(buf, buf, sz); + return sz; } void GCM_Decryption::finish(secure_vector<byte>& buffer, size_t offset) { - BOTAN_ASSERT(buffer.size() >= offset, "Offset is sane"); + BOTAN_ARG_CHECK(offset <= buffer.size()); const size_t sz = buffer.size() - offset; byte* buf = buffer.data() + offset; - BOTAN_ASSERT(sz >= tag_size(), "Have the tag as part of final input"); + if(sz < tag_size()) + throw Exception("Insufficient input for GCM decryption, tag missing"); const size_t remaining = sz - tag_size(); |