Botan
1.11.15
|
00001 /* 00002 * ChaCha20Poly1305 AEAD 00003 * (C) 2014 Jack Lloyd 00004 * 00005 * Botan is released under the Simplified BSD License (see license.txt) 00006 */ 00007 00008 #include <botan/internal/mode_utils.h> 00009 #include <botan/chacha20poly1305.h> 00010 00011 namespace Botan { 00012 00013 BOTAN_REGISTER_TRANSFORM_NOARGS(ChaCha20Poly1305_Encryption); 00014 BOTAN_REGISTER_TRANSFORM_NOARGS(ChaCha20Poly1305_Decryption); 00015 00016 bool ChaCha20Poly1305_Mode::valid_nonce_length(size_t n) const 00017 { 00018 return (n == 8 || n == 12); 00019 } 00020 00021 void ChaCha20Poly1305_Mode::clear() 00022 { 00023 m_chacha.reset(); 00024 m_poly1305.reset(); 00025 m_ad.clear(); 00026 m_ctext_len = 0; 00027 } 00028 00029 void ChaCha20Poly1305_Mode::key_schedule(const byte key[], size_t length) 00030 { 00031 if(!m_chacha.get()) 00032 m_chacha.reset(make_a<StreamCipher>("ChaCha")); 00033 m_chacha->set_key(key, length); 00034 } 00035 00036 void ChaCha20Poly1305_Mode::set_associated_data(const byte ad[], size_t length) 00037 { 00038 if(m_ctext_len) 00039 throw std::runtime_error("Too late to set AD for ChaCha20Poly1305"); 00040 m_ad.assign(ad, ad + length); 00041 } 00042 00043 void ChaCha20Poly1305_Mode::update_len(size_t len) 00044 { 00045 byte len8[8] = { 0 }; 00046 store_le(static_cast<u64bit>(len), len8); 00047 m_poly1305->update(len8, 8); 00048 } 00049 00050 secure_vector<byte> ChaCha20Poly1305_Mode::start_raw(const byte nonce[], size_t nonce_len) 00051 { 00052 if(!valid_nonce_length(nonce_len)) 00053 throw Invalid_IV_Length(name(), nonce_len); 00054 00055 m_ctext_len = 0; 00056 m_nonce_len = nonce_len; 00057 00058 m_chacha->set_iv(nonce, nonce_len); 00059 00060 secure_vector<byte> zeros(64); 00061 m_chacha->encrypt(zeros); 00062 00063 if(!m_poly1305.get()) 00064 m_poly1305.reset(make_a<MessageAuthenticationCode>("Poly1305")); 00065 m_poly1305->set_key(&zeros[0], 32); 00066 // Remainder of output is discard 00067 00068 m_poly1305->update(m_ad); 00069 00070 if(cfrg_version()) 00071 { 00072 std::vector<byte> padding(16 - m_ad.size() % 16); 00073 m_poly1305->update(padding); 00074 } 00075 else 00076 { 00077 update_len(m_ad.size()); 00078 } 00079 00080 return secure_vector<byte>(); 00081 } 00082 00083 void ChaCha20Poly1305_Encryption::update(secure_vector<byte>& buffer, size_t offset) 00084 { 00085 BOTAN_ASSERT(buffer.size() >= offset, "Offset is sane"); 00086 const size_t sz = buffer.size() - offset; 00087 byte* buf = &buffer[offset]; 00088 00089 m_chacha->cipher1(buf, sz); 00090 m_poly1305->update(buf, sz); // poly1305 of ciphertext 00091 m_ctext_len += sz; 00092 } 00093 00094 void ChaCha20Poly1305_Encryption::finish(secure_vector<byte>& buffer, size_t offset) 00095 { 00096 update(buffer, offset); 00097 if(cfrg_version()) 00098 { 00099 std::vector<byte> padding(16 - m_ctext_len % 16); 00100 m_poly1305->update(padding); 00101 update_len(m_ad.size()); 00102 } 00103 update_len(m_ctext_len); 00104 00105 const secure_vector<byte> mac = m_poly1305->final(); 00106 buffer += std::make_pair(&mac[0], tag_size()); 00107 m_ctext_len = 0; 00108 } 00109 00110 void ChaCha20Poly1305_Decryption::update(secure_vector<byte>& buffer, size_t offset) 00111 { 00112 BOTAN_ASSERT(buffer.size() >= offset, "Offset is sane"); 00113 const size_t sz = buffer.size() - offset; 00114 byte* buf = &buffer[offset]; 00115 00116 m_poly1305->update(buf, sz); // poly1305 of ciphertext 00117 m_chacha->cipher1(buf, sz); 00118 m_ctext_len += sz; 00119 } 00120 00121 void ChaCha20Poly1305_Decryption::finish(secure_vector<byte>& buffer, size_t offset) 00122 { 00123 BOTAN_ASSERT(buffer.size() >= offset, "Offset is sane"); 00124 const size_t sz = buffer.size() - offset; 00125 byte* buf = &buffer[offset]; 00126 00127 BOTAN_ASSERT(sz >= tag_size(), "Have the tag as part of final input"); 00128 00129 const size_t remaining = sz - tag_size(); 00130 00131 if(remaining) 00132 { 00133 m_poly1305->update(buf, remaining); // poly1305 of ciphertext 00134 m_chacha->cipher1(buf, remaining); 00135 m_ctext_len += remaining; 00136 } 00137 00138 if(cfrg_version()) 00139 { 00140 for(size_t i = 0; i != 16 - m_ctext_len % 16; ++i) 00141 m_poly1305->update(0); 00142 update_len(m_ad.size()); 00143 } 00144 00145 update_len(m_ctext_len); 00146 const secure_vector<byte> mac = m_poly1305->final(); 00147 00148 const byte* included_tag = &buf[remaining]; 00149 00150 m_ctext_len = 0; 00151 00152 if(!same_mem(&mac[0], included_tag, tag_size())) 00153 throw Integrity_Failure("ChaCha20Poly1305 tag check failed"); 00154 buffer.resize(offset + remaining); 00155 } 00156 00157 }