mirror of
https://github.com/zerotier/ZeroTierOne.git
synced 2025-04-28 09:53:44 +02:00
143 lines
3.6 KiB
C++
143 lines
3.6 KiB
C++
/*
|
|
* Copyright (c)2013-2021 ZeroTier, Inc.
|
|
*
|
|
* Use of this software is governed by the Business Source License included
|
|
* in the LICENSE.TXT file in the project's root directory.
|
|
*
|
|
* Change Date: 2026-01-01
|
|
*
|
|
* On the date above, in accordance with the Business Source License, use
|
|
* of this software will be governed by version 2.0 of the Apache License.
|
|
*/
|
|
/****/
|
|
|
|
#ifndef ZT_SYMMETRICKEY_HPP
|
|
#define ZT_SYMMETRICKEY_HPP
|
|
|
|
#include "Constants.hpp"
|
|
#include "Utils.hpp"
|
|
#include "AES.hpp"
|
|
#include "Address.hpp"
|
|
|
|
namespace ZeroTier {
|
|
|
|
/**
|
|
* Container for symmetric keys and ciphers initialized with them.
|
|
*/
|
|
class SymmetricKey
|
|
{
|
|
public:
|
|
/**
|
|
* Construct an uninitialized key (init() must be called)
|
|
*/
|
|
ZT_INLINE SymmetricKey():
|
|
m_secret(),
|
|
m_ts(-1),
|
|
m_initialNonce(0),
|
|
m_cipher(),
|
|
m_nonce(0)
|
|
{}
|
|
|
|
/**
|
|
* Construct a new symmetric key
|
|
*
|
|
* SECURITY: the MSB of the nonce is always 0 because this bit is set to 0
|
|
* or 1 depending on which "direction" data is moving. See nextMessage().
|
|
*
|
|
* @param ts Key timestamp
|
|
* @param key Key (must be 48 bytes / 384 bits)
|
|
*/
|
|
ZT_INLINE SymmetricKey(const int64_t ts, const void *const key) noexcept:
|
|
m_secret(key),
|
|
m_ts(ts),
|
|
m_initialNonce(Utils::getSecureRandomU64() >> 1U),
|
|
m_cipher(key),
|
|
m_nonce(m_initialNonce)
|
|
{}
|
|
|
|
ZT_INLINE SymmetricKey(const SymmetricKey &k) noexcept:
|
|
m_secret(k.m_secret),
|
|
m_ts(k.m_ts),
|
|
m_initialNonce(k.m_initialNonce),
|
|
m_cipher(k.m_secret.data),
|
|
m_nonce(k.m_nonce.load(std::memory_order_relaxed))
|
|
{}
|
|
|
|
ZT_INLINE ~SymmetricKey() noexcept
|
|
{ Utils::burn(m_secret.data, ZT_SYMMETRIC_KEY_SIZE); }
|
|
|
|
ZT_INLINE SymmetricKey &operator=(const SymmetricKey &k) noexcept
|
|
{
|
|
m_secret = k.m_secret;
|
|
m_ts = k.m_ts;
|
|
m_initialNonce = k.m_initialNonce;
|
|
m_cipher.init(k.m_secret.data);
|
|
m_nonce.store(k.m_nonce.load(std::memory_order_relaxed), std::memory_order_relaxed);
|
|
return *this;
|
|
}
|
|
|
|
/**
|
|
* Initialize or re-initialize a symmetric key
|
|
*
|
|
* @param ts Key timestamp
|
|
* @param key Key (must be 48 bytes / 384 bits)
|
|
*/
|
|
ZT_INLINE void init(const int64_t ts, const void *const key) noexcept
|
|
{
|
|
Utils::copy< ZT_SYMMETRIC_KEY_SIZE >(m_secret.data, key);
|
|
m_ts = ts;
|
|
m_initialNonce = Utils::getSecureRandomU64() >> 1U;
|
|
m_cipher.init(key);
|
|
m_nonce.store(m_initialNonce, std::memory_order_relaxed);
|
|
}
|
|
|
|
/**
|
|
* Advance usage counter by one and return the next IV / packet ID.
|
|
*
|
|
* @param sender Sending ZeroTier address
|
|
* @param receiver Receiving ZeroTier address
|
|
* @return Next unique IV for next message
|
|
*/
|
|
ZT_INLINE uint64_t nextMessage(const Address sender, const Address receiver) noexcept
|
|
{ return m_nonce.fetch_add(1, std::memory_order_relaxed) ^ (((uint64_t)(sender > receiver)) << 63U); }
|
|
|
|
/**
|
|
* Get the number of times this key has been used.
|
|
*
|
|
* This is used along with the key's initial timestamp to determine key age
|
|
* for ephemeral key rotation.
|
|
*
|
|
* @return Number of times nextMessage() has been called since object creation
|
|
*/
|
|
ZT_INLINE uint64_t odometer() const noexcept
|
|
{ return m_nonce.load(std::memory_order_relaxed) - m_initialNonce; }
|
|
|
|
/**
|
|
* @return Key creation timestamp or -1 if this is a long-lived key
|
|
*/
|
|
ZT_INLINE int64_t timestamp() const noexcept
|
|
{ return m_ts; }
|
|
|
|
/**
|
|
* @return 48-byte / 384-bit secret key
|
|
*/
|
|
ZT_INLINE const uint8_t *key() const noexcept
|
|
{ return m_secret.data; }
|
|
|
|
/**
|
|
* @return AES cipher (already initialized with secret key)
|
|
*/
|
|
ZT_INLINE const AES &aes() const noexcept
|
|
{ return m_cipher; }
|
|
|
|
private:
|
|
Blob< ZT_SYMMETRIC_KEY_SIZE > m_secret;
|
|
int64_t m_ts;
|
|
uint64_t m_initialNonce;
|
|
AES m_cipher;
|
|
std::atomic< uint64_t > m_nonce;
|
|
};
|
|
|
|
} // namespace ZeroTier
|
|
|
|
#endif
|