149 lines
5.7 KiB
C++
149 lines
5.7 KiB
C++
/*
|
|
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.
|
|
*/
|
|
|
|
#ifndef CAT_AUTHENTICATED_ENCRYPTION_HPP
|
|
#define CAT_AUTHENTICATED_ENCRYPTION_HPP
|
|
|
|
#include <cat/crypt/symmetric/ChaCha.hpp>
|
|
#include <cat/crypt/hash/Skein.hpp>
|
|
#include <cat/crypt/hash/HMAC_MD5.hpp>
|
|
|
|
namespace cat {
|
|
|
|
|
|
/*
|
|
Tunnel Authenticated Encryption "Calico" protocol:
|
|
|
|
Run after the Key Agreement protocol completes.
|
|
Uses a 1024-bit anti-replay sliding window, suitable for Internet file transfer over UDP.
|
|
|
|
Cipher: 12-round ChaCha with 256-bit or 384-bit keys
|
|
KDF: Key derivation function (Skein)
|
|
MAC: 64-bit truncated HMAC-MD5
|
|
IV: Initialization vector incrementing by 1 each time
|
|
|
|
c2sMKey = KDF(k) { "upstream-MAC" }
|
|
s2cMKey = KDF(k) { "downstream-MAC" }
|
|
c2sEKey = KDF(k) { "upstream-ENC" }
|
|
s2cEKey = KDF(k) { "downstream-ENC" }
|
|
c2sIV = KDF(k) { "upstream-IV" }
|
|
s2cIV = KDF(k) { "downstream-IV" }
|
|
|
|
To transmit a message, the client calculates a MAC with the c2sMKey of the IV concatenated with
|
|
the plaintext message and then appends the 8-byte MAC and low 3 bytes of the IV to the message,
|
|
which is encrypted using the c2sEKey and the IV.
|
|
|
|
c2s Encrypt(c2sEKey) { message || MAC(c2sMKey) { full-iv-us||message } } || Obfuscated { trunc-iv-us }
|
|
|
|
encrypted { MESSAGE(X) MAC(8by) } IV(3by) = 11 bytes overhead at end of packet
|
|
|
|
To transmit a message, the server calculates a MAC with the s2cMKey of the IV concatenated with
|
|
the plaintext message and then appends the 8-byte MAC and low 3 bytes of the IV to the message,
|
|
which is encrypted using the s2cEKey and the IV.
|
|
|
|
s2c Encrypt(s2cEKey) { message || MAC(s2cMKey) { full-iv-ds||message } } || Obfuscated { trunc-iv-ds }
|
|
|
|
encrypted { MESSAGE(X) MAC(8by) } IV(3by) = 11 bytes overhead at end of packet
|
|
|
|
The full 64-bit IVs are initialized to c2sIV and s2cIV, and the first one sent is IV+1.
|
|
*/
|
|
|
|
|
|
class KeyAgreementResponder;
|
|
class KeyAgreementInitiator;
|
|
|
|
|
|
// This class is NOT THREAD-SAFE.
|
|
class CAT_EXPORT AuthenticatedEncryption
|
|
{
|
|
friend class KeyAgreementResponder;
|
|
friend class KeyAgreementInitiator;
|
|
|
|
bool _is_initiator, _accept_out_of_order;
|
|
Skein key_hash;
|
|
|
|
HMAC_MD5 local_mac_key, remote_mac_key;
|
|
ChaChaKey local_cipher_key, remote_cipher_key;
|
|
u64 local_iv, remote_iv;
|
|
|
|
// 1024-bit anti-replay sliding window
|
|
static const int BITMAP_BITS = 1024;
|
|
static const int BITMAP_WORDS = BITMAP_BITS / 64;
|
|
u64 iv_bitmap[BITMAP_WORDS];
|
|
|
|
public:
|
|
CAT_INLINE AuthenticatedEncryption() {}
|
|
CAT_INLINE ~AuthenticatedEncryption() {}
|
|
|
|
// Tunnel overhead bytes
|
|
static const int MAC_BYTES = 8;
|
|
static const int IV_BYTES = 3;
|
|
static const u32 OVERHEAD_BYTES = IV_BYTES + MAC_BYTES;
|
|
|
|
// IV constants
|
|
static const int IV_BITS = IV_BYTES * 8;
|
|
static const u32 IV_MSB = (1 << IV_BITS);
|
|
static const u32 IV_MASK = (IV_MSB - 1);
|
|
static const u32 IV_FUZZ = 0xCA7DCA7D;
|
|
|
|
protected:
|
|
bool SetKey(int KeyBytes, Skein *key, bool is_initiator, const char *key_name);
|
|
|
|
bool IsValidIV(u64 iv);
|
|
void AcceptIV(u64 iv);
|
|
|
|
public:
|
|
// Generate a proof that the local host has the key
|
|
bool GenerateProof(u8 *local_proof, int proof_bytes);
|
|
|
|
// Validate a proof that the remote host has the key
|
|
bool ValidateProof(const u8 *remote_proof, int proof_bytes);
|
|
|
|
public:
|
|
void AllowOutOfOrder(bool allowed = true) { _accept_out_of_order = allowed; }
|
|
|
|
public:
|
|
// Overhead is OVERHEAD_BYTES bytes at the end of the packet
|
|
// Returns false if the message is invalid. Invalid messages should just be ignored as if they were never received
|
|
// buf_bytes: Number of bytes in the buffer, including the overhead
|
|
// If Decrypt() returns true, buf_bytes is set to the size of the decrypted message
|
|
bool Decrypt(u8 *buffer, u32 &buf_bytes);
|
|
|
|
// Overhead is OVERHEAD_BYTES bytes at the end of the packet
|
|
// buffer_bytes: Number of bytes in the buffer; will return false if buffer size too small
|
|
// msg_bytes: Number of bytes in the message, excluding the overhead
|
|
// If Encrypt() returns true, msg_bytes is set to the size of the encrypted message
|
|
bool Encrypt(u8 *buffer, u32 buffer_bytes, u32 &msg_bytes);
|
|
};
|
|
|
|
|
|
|
|
} // namespace cat
|
|
|
|
#endif // CAT_AUTHENTICATED_ENCRYPTION_HPP
|