123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105 |
- /*
- * Copyright (c)2013-2020 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: 2025-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 "InetAddress.hpp"
- #include "AES.hpp"
- #include "SharedPtr.hpp"
- #include "Address.hpp"
- namespace ZeroTier {
- /**
- * Container for symmetric keys and ciphers initialized with them.
- */
- class SymmetricKey
- {
- friend class SharedPtr< SymmetricKey >;
- public:
- /**
- * Secret key
- */
- const uint8_t secret[ZT_SYMMETRIC_KEY_SIZE];
- /**
- * Symmetric cipher keyed with this key
- */
- const AES cipher;
- /**
- * Construct a new symmetric key
- *
- * SECURITY: we use a best effort method to construct the nonce's starting point so as
- * to avoid nonce duplication across invocations. The most significant bits are the
- * number of seconds since epoch but with the most significant bit masked to zero.
- * The least significant bits are random. Key life time is limited to 2^31 messages
- * per key as per the AES-GMAC-SIV spec, and this is a SIV mode anyway so nonce repetition
- * is non-catastrophic.
- *
- * The masking of the most significant bit is because we bisect the nonce space by
- * which direction the message is going. If the sender's ZeroTier address is
- * numerically greater than the receiver, this bit is flipped. This means that
- * two sides of a conversation that have created their key instances at the same
- * time are much less likely to duplicate nonces when sending pacekts from either
- * end.
- *
- * @param ts Current time
- * @param key 48-bit / 384-byte key
- */
- explicit ZT_INLINE SymmetricKey(const int64_t ts, const void *const key) noexcept:
- secret(),
- cipher(key), // AES-256 uses first 256 bits of 384-bit key
- m_initialNonce(((((uint64_t)ts / 1000ULL) << 32U) & 0x7fffffff00000000ULL) | (Utils::random() & 0x00000000ffffffffULL)),
- m_nonce(m_initialNonce),
- __refCount(0)
- {
- Utils::memoryLock(this, sizeof(SymmetricKey));
- Utils::copy< ZT_SYMMETRIC_KEY_SIZE >(const_cast<uint8_t *>(secret), key);
- }
- ZT_INLINE ~SymmetricKey() noexcept
- {
- Utils::burn(const_cast<uint8_t *>(secret), ZT_SYMMETRIC_KEY_SIZE);
- Utils::memoryUnlock(this, sizeof(SymmetricKey));
- }
- /**
- * 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) ^ (((uint64_t)(sender > receiver)) << 63U); }
- /**
- * @return Number of times nextMessage() has been called since object creation
- */
- ZT_INLINE uint64_t odometer() const noexcept
- { return m_nonce.load() - m_initialNonce; }
- private:
- const uint64_t m_initialNonce;
- std::atomic< uint64_t > m_nonce;
- std::atomic< int > __refCount;
- };
- } // namespace ZeroTier
- #endif
|