Botan
1.11.15
|
00001 /* 00002 * GCM Mode Encryption 00003 * (C) 2013 Jack Lloyd 00004 * 00005 * Botan is released under the Simplified BSD License (see license.txt) 00006 */ 00007 00008 #include <botan/gcm.h> 00009 #include <botan/internal/mode_utils.h> 00010 #include <botan/ctr.h> 00011 00012 #if defined(BOTAN_HAS_GCM_CLMUL) 00013 #include <botan/internal/clmul.h> 00014 #include <botan/cpuid.h> 00015 #endif 00016 00017 namespace Botan { 00018 00019 BOTAN_REGISTER_BLOCK_CIPHER_MODE_LEN(GCM_Encryption, GCM_Decryption, 16); 00020 00021 void GHASH::gcm_multiply(secure_vector<byte>& x) const 00022 { 00023 #if defined(BOTAN_HAS_GCM_CLMUL) 00024 if(CPUID::has_clmul()) 00025 return gcm_multiply_clmul(&x[0], &m_H[0]); 00026 #endif 00027 00028 static const u64bit R = 0xE100000000000000; 00029 00030 u64bit H[2] = { 00031 load_be<u64bit>(&m_H[0], 0), 00032 load_be<u64bit>(&m_H[0], 1) 00033 }; 00034 00035 u64bit Z[2] = { 0, 0 }; 00036 00037 // SSE2 might be useful here 00038 00039 for(size_t i = 0; i != 2; ++i) 00040 { 00041 const u64bit X = load_be<u64bit>(&x[0], i); 00042 00043 for(size_t j = 0; j != 64; ++j) 00044 { 00045 if((X >> (63-j)) & 1) 00046 { 00047 Z[0] ^= H[0]; 00048 Z[1] ^= H[1]; 00049 } 00050 00051 const u64bit r = (H[1] & 1) ? R : 0; 00052 00053 H[1] = (H[0] << 63) | (H[1] >> 1); 00054 H[0] = (H[0] >> 1) ^ r; 00055 } 00056 } 00057 00058 store_be<u64bit>(&x[0], Z[0], Z[1]); 00059 } 00060 00061 void GHASH::ghash_update(secure_vector<byte>& ghash, 00062 const byte input[], size_t length) 00063 { 00064 const size_t BS = 16; 00065 00066 /* 00067 This assumes if less than block size input then we're just on the 00068 final block and should pad with zeros 00069 */ 00070 while(length) 00071 { 00072 const size_t to_proc = std::min(length, BS); 00073 00074 xor_buf(&ghash[0], &input[0], to_proc); 00075 00076 gcm_multiply(ghash); 00077 00078 input += to_proc; 00079 length -= to_proc; 00080 } 00081 } 00082 00083 void GHASH::key_schedule(const byte key[], size_t length) 00084 { 00085 m_H.assign(key, key+length); 00086 m_H_ad.resize(16); 00087 m_ad_len = 0; 00088 m_text_len = 0; 00089 } 00090 00091 void GHASH::start(const byte nonce[], size_t len) 00092 { 00093 m_nonce.assign(nonce, nonce + len); 00094 m_ghash = m_H_ad; 00095 } 00096 00097 void GHASH::set_associated_data(const byte input[], size_t length) 00098 { 00099 zeroise(m_H_ad); 00100 00101 ghash_update(m_H_ad, input, length); 00102 m_ad_len = length; 00103 } 00104 00105 void GHASH::update(const byte input[], size_t length) 00106 { 00107 BOTAN_ASSERT(m_ghash.size() == 16, "Key was set"); 00108 00109 m_text_len += length; 00110 00111 ghash_update(m_ghash, input, length); 00112 } 00113 00114 void GHASH::add_final_block(secure_vector<byte>& hash, 00115 size_t ad_len, size_t text_len) 00116 { 00117 secure_vector<byte> final_block(16); 00118 store_be<u64bit>(&final_block[0], 8*ad_len, 8*text_len); 00119 ghash_update(hash, &final_block[0], final_block.size()); 00120 } 00121 00122 secure_vector<byte> GHASH::final() 00123 { 00124 add_final_block(m_ghash, m_ad_len, m_text_len); 00125 00126 secure_vector<byte> mac; 00127 mac.swap(m_ghash); 00128 00129 mac ^= m_nonce; 00130 m_text_len = 0; 00131 return mac; 00132 } 00133 00134 secure_vector<byte> GHASH::nonce_hash(const byte nonce[], size_t nonce_len) 00135 { 00136 BOTAN_ASSERT(m_ghash.size() == 0, "nonce_hash called during wrong time"); 00137 secure_vector<byte> y0(16); 00138 00139 ghash_update(y0, nonce, nonce_len); 00140 add_final_block(y0, 0, nonce_len); 00141 00142 return y0; 00143 } 00144 00145 void GHASH::clear() 00146 { 00147 zeroise(m_H); 00148 zeroise(m_H_ad); 00149 m_ghash.clear(); 00150 m_text_len = m_ad_len = 0; 00151 } 00152 00153 /* 00154 * GCM_Mode Constructor 00155 */ 00156 GCM_Mode::GCM_Mode(BlockCipher* cipher, size_t tag_size) : 00157 m_tag_size(tag_size), 00158 m_cipher_name(cipher->name()) 00159 { 00160 if(cipher->block_size() != BS) 00161 throw std::invalid_argument("GCM requires a 128 bit cipher so cannot be used with " + 00162 cipher->name()); 00163 00164 m_ghash.reset(new GHASH); 00165 00166 m_ctr.reset(new CTR_BE(cipher)); // CTR_BE takes ownership of cipher 00167 00168 if(m_tag_size != 8 && m_tag_size != 16) 00169 throw Invalid_Argument(name() + ": Bad tag size " + std::to_string(m_tag_size)); 00170 } 00171 00172 void GCM_Mode::clear() 00173 { 00174 m_ctr->clear(); 00175 m_ghash->clear(); 00176 } 00177 00178 std::string GCM_Mode::name() const 00179 { 00180 return (m_cipher_name + "/GCM"); 00181 } 00182 00183 size_t GCM_Mode::update_granularity() const 00184 { 00185 return 4096; // CTR-BE's internal block size 00186 } 00187 00188 Key_Length_Specification GCM_Mode::key_spec() const 00189 { 00190 return m_ctr->key_spec(); 00191 } 00192 00193 void GCM_Mode::key_schedule(const byte key[], size_t keylen) 00194 { 00195 m_ctr->set_key(key, keylen); 00196 00197 const std::vector<byte> zeros(BS); 00198 m_ctr->set_iv(&zeros[0], zeros.size()); 00199 00200 secure_vector<byte> H(BS); 00201 m_ctr->encipher(H); 00202 m_ghash->set_key(H); 00203 } 00204 00205 void GCM_Mode::set_associated_data(const byte ad[], size_t ad_len) 00206 { 00207 m_ghash->set_associated_data(ad, ad_len); 00208 } 00209 00210 secure_vector<byte> GCM_Mode::start_raw(const byte nonce[], size_t nonce_len) 00211 { 00212 if(!valid_nonce_length(nonce_len)) 00213 throw Invalid_IV_Length(name(), nonce_len); 00214 00215 secure_vector<byte> y0(BS); 00216 00217 if(nonce_len == 12) 00218 { 00219 copy_mem(&y0[0], nonce, nonce_len); 00220 y0[15] = 1; 00221 } 00222 else 00223 { 00224 y0 = m_ghash->nonce_hash(nonce, nonce_len); 00225 } 00226 00227 m_ctr->set_iv(&y0[0], y0.size()); 00228 00229 secure_vector<byte> m_enc_y0(BS); 00230 m_ctr->encipher(m_enc_y0); 00231 00232 m_ghash->start(&m_enc_y0[0], m_enc_y0.size()); 00233 00234 return secure_vector<byte>(); 00235 } 00236 00237 void GCM_Encryption::update(secure_vector<byte>& buffer, size_t offset) 00238 { 00239 BOTAN_ASSERT(buffer.size() >= offset, "Offset is sane"); 00240 const size_t sz = buffer.size() - offset; 00241 byte* buf = &buffer[offset]; 00242 00243 m_ctr->cipher(buf, buf, sz); 00244 m_ghash->update(buf, sz); 00245 } 00246 00247 void GCM_Encryption::finish(secure_vector<byte>& buffer, size_t offset) 00248 { 00249 update(buffer, offset); 00250 auto mac = m_ghash->final(); 00251 buffer += std::make_pair(&mac[0], tag_size()); 00252 } 00253 00254 void GCM_Decryption::update(secure_vector<byte>& buffer, size_t offset) 00255 { 00256 BOTAN_ASSERT(buffer.size() >= offset, "Offset is sane"); 00257 const size_t sz = buffer.size() - offset; 00258 byte* buf = &buffer[offset]; 00259 00260 m_ghash->update(buf, sz); 00261 m_ctr->cipher(buf, buf, sz); 00262 } 00263 00264 void GCM_Decryption::finish(secure_vector<byte>& buffer, size_t offset) 00265 { 00266 BOTAN_ASSERT(buffer.size() >= offset, "Offset is sane"); 00267 const size_t sz = buffer.size() - offset; 00268 byte* buf = &buffer[offset]; 00269 00270 BOTAN_ASSERT(sz >= tag_size(), "Have the tag as part of final input"); 00271 00272 const size_t remaining = sz - tag_size(); 00273 00274 // handle any final input before the tag 00275 if(remaining) 00276 { 00277 m_ghash->update(buf, remaining); 00278 m_ctr->cipher(buf, buf, remaining); 00279 } 00280 00281 auto mac = m_ghash->final(); 00282 00283 const byte* included_tag = &buffer[remaining]; 00284 00285 if(!same_mem(&mac[0], included_tag, tag_size())) 00286 throw Integrity_Failure("GCM tag check failed"); 00287 00288 buffer.resize(offset + remaining); 00289 } 00290 00291 }