/* Copyright (c) 2009-2010 Christopher A. Taylor. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of LibCat nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* The ChaCha cipher is a symmetric stream cipher based on Salsa20. http://cr.yp.to/chacha.html */ #ifndef CAT_CHACHA_HPP #define CAT_CHACHA_HPP #include namespace cat { /* To initialize the ChaCha cipher, you must specify a 256-bit key. Code example: ChaChaKey cck; char key[32]; // fill key here cck.Key(key, sizeof(key)); Before each encryption or decryption with the ChaCha cipher, a 64-bit Initialization Vector (IV) must be specified. Every time a message is encrypted, the IV must be incremented by 1. The IV is then sent along with the encrypted message. Encryption code example: char message[19], ciphertext[19]; // message filled here u64 iv = 125125; u64 message_iv = iv; iv = iv + 1; ChaChaOutput cco(cck, message_iv); cco.Crypt(message, ciphertext, sizeof(ciphertext)); Decryption code example: char ciphertext[19], decrypted[19]; // ciphertext filled here ChaChaOutput cco(cck, message_iv); cco.Crypt(ciphertext, decrypted, sizeof(decrypted)); Sending all 8 bytes of the IV in every packet is not necessary. Instead, only a few of the low bits of the IV need to be sent, if the IV is incremented by 1 each time. How many? It depends on how many messages can get lost. If < 32768 messages can get lost in a row, then CAT_IV_BITS = 16 (default) I have provided a function to handle rollover/rollunder of the IV, which also works if the same IV is sent twice for some reason. It needs to know how many of the low bits are sent across, so be sure to change CAT_IV_BITS in this header if you send more or less than 16. Code example: u64 last_accepted_iv; u32 new_iv_low_bits; u64 new_iv = ChaCha::ReconstructIV(last_accepted_iv, new_iv_low_bits); -------------------------READ THIS BEFORE USING-------------------------- Never use the same IV twice. Otherwise: An attacker can recover the plaintext without the key. Never use the same key twice. Otherwise: An attacker can recover the plaintext without the key. If you have two hosts talking to eachother securely with ChaCha encryption, then be sure that each host is encrypting with a DIFFERENT key. Otherwise: An attacker can recover the plaintext without the key. Remember that an attacker can impersonate the remote computer, so be sure not to accept the new IV until the message authentication code has been verified if your protocol uses a message authentication code (MAC). Otherwise: An attacker could desynchronize the IVs. */ //// ChaChaKey class CAT_EXPORT ChaChaKey { friend class ChaChaOutput; u32 state[16]; public: ~ChaChaKey(); // Key up to 384 bits void Set(const void *key, int bytes); }; //// ChaChaOutput class CAT_EXPORT ChaChaOutput { u32 state[16]; void GenerateKeyStream(u32 *out); public: ChaChaOutput(const ChaChaKey &key, u64 iv); ~ChaChaOutput(); // Message with any number of bytes void Crypt(const void *in, void *out, int bytes); }; } // namespace cat #endif // CAT_CHACHA_HPP