|
12 | 12 | #include <openssl/ssl.h> |
13 | 13 | #include <openssl/x509.h> |
14 | 14 |
|
| 15 | +#ifdef OPENSSL_IS_BORINGSSL |
| 16 | +#include <openssl/aead.h> |
| 17 | +#endif |
| 18 | + |
15 | 19 | #include <stdint.h> |
16 | 20 | #include <cstddef> |
17 | 21 | #include <cstdio> |
|
21 | 25 | #include <optional> |
22 | 26 | #include <string> |
23 | 27 | #include <string_view> |
| 28 | +#include <unordered_map> |
24 | 29 | #include <utility> |
25 | 30 |
|
26 | 31 | #if NCRYPTO_DEVELOPMENT_CHECKS |
@@ -257,6 +262,8 @@ class ECKeyPointer; |
257 | 262 | class Dsa; |
258 | 263 | class Rsa; |
259 | 264 | class Ec; |
| 265 | +class Aead; |
| 266 | +class AeadCtxPointer; |
260 | 267 |
|
261 | 268 | struct StackOfXASN1Deleter { |
262 | 269 | void operator()(STACK_OF(ASN1_OBJECT) * p) const { |
@@ -311,7 +318,25 @@ DataPointer xofHashDigest(const Buffer<const unsigned char>& data, |
311 | 318 | const EVP_MD* md, |
312 | 319 | size_t length); |
313 | 320 |
|
314 | | -class Cipher final { |
| 321 | +template <typename T> |
| 322 | +class ModeMixin { |
| 323 | + public: |
| 324 | + std::string_view getModeLabel() const; |
| 325 | + |
| 326 | + bool isGcmMode() const { return self().getMode() == EVP_CIPH_GCM_MODE; } |
| 327 | + bool isWrapMode() const { return self().getMode() == EVP_CIPH_WRAP_MODE; } |
| 328 | + bool isCtrMode() const { return self().getMode() == EVP_CIPH_CTR_MODE; } |
| 329 | + bool isCcmMode() const { return self().getMode() == EVP_CIPH_CCM_MODE; } |
| 330 | + bool isOcbMode() const { return self().getMode() == EVP_CIPH_OCB_MODE; } |
| 331 | + bool isStreamMode() const { |
| 332 | + return self().getMode() == EVP_CIPH_STREAM_CIPHER; |
| 333 | + } |
| 334 | + |
| 335 | + private: |
| 336 | + const T& self() const { return static_cast<const T&>(*this); } |
| 337 | +}; |
| 338 | + |
| 339 | +class Cipher final : public ModeMixin<Cipher> { |
315 | 340 | public: |
316 | 341 | static constexpr size_t MAX_KEY_LENGTH = EVP_MAX_KEY_LENGTH; |
317 | 342 | static constexpr size_t MAX_IV_LENGTH = EVP_MAX_IV_LENGTH; |
@@ -344,15 +369,9 @@ class Cipher final { |
344 | 369 | int getIvLength() const; |
345 | 370 | int getKeyLength() const; |
346 | 371 | int getBlockSize() const; |
347 | | - std::string_view getModeLabel() const; |
| 372 | + |
348 | 373 | const char* getName() const; |
349 | 374 |
|
350 | | - bool isGcmMode() const; |
351 | | - bool isWrapMode() const; |
352 | | - bool isCtrMode() const; |
353 | | - bool isCcmMode() const; |
354 | | - bool isOcbMode() const; |
355 | | - bool isStreamMode() const; |
356 | 375 | bool isChaCha20Poly1305() const; |
357 | 376 |
|
358 | 377 | bool isSupportedAuthenticatedMode() const; |
@@ -1734,6 +1753,137 @@ class KEM final { |
1734 | 1753 |
|
1735 | 1754 | #endif // OPENSSL_VERSION_MAJOR >= 3 |
1736 | 1755 |
|
| 1756 | +// ============================================================================ |
| 1757 | +// AEAD (Authenticated Encryption with Associated Data) |
| 1758 | +// Note that the underlying EVP_AEAD interface is specific to BoringSSL. AEAD |
| 1759 | +// primitives are accessed through the Cipher class instead, if using OpenSSL. |
| 1760 | + |
| 1761 | +#ifdef OPENSSL_IS_BORINGSSL |
| 1762 | +class Aead final : public ModeMixin<Aead> { |
| 1763 | + private: |
| 1764 | + // BoringSSL does not keep a list of AEADs, so we need to maintain our own. |
| 1765 | + struct AeadInfo { |
| 1766 | + std::string name; |
| 1767 | + int mode; |
| 1768 | + int nid = 0; // Note: BoringSSL only defines NIDs for some AEADs |
| 1769 | + }; |
| 1770 | + |
| 1771 | + public: |
| 1772 | + Aead() = default; |
| 1773 | + Aead(const AeadInfo* info, const EVP_AEAD* aead) : info_(info), aead_(aead) {} |
| 1774 | + Aead(const Aead&) = default; |
| 1775 | + Aead& operator=(const Aead&) = default; |
| 1776 | + NCRYPTO_DISALLOW_MOVE(Aead) |
| 1777 | + |
| 1778 | + inline const EVP_AEAD* get() const { return aead_; } |
| 1779 | + inline operator const EVP_AEAD*() const { return aead_; } |
| 1780 | + inline operator bool() const { return aead_ != nullptr; } |
| 1781 | + |
| 1782 | + int getMode() const; |
| 1783 | + int getNonceLength() const; |
| 1784 | + int getKeyLength() const; |
| 1785 | + int getBlockSize() const; |
| 1786 | + int getMaxOverhead() const; |
| 1787 | + int getMaxTagLength() const; |
| 1788 | + std::string_view getName() const; |
| 1789 | + |
| 1790 | + static const Aead FromName(std::string_view name); |
| 1791 | + |
| 1792 | + // TODO(npaun): BoringSSL does not define NIDs for all AEADs. |
| 1793 | + // This method is included only for implementing getCipherInfo and can't be |
| 1794 | + // used to construct an Aead instance. |
| 1795 | + int getNid() const; |
| 1796 | + // static const AEAD FromNid(int nid); |
| 1797 | + |
| 1798 | + static const Aead FromCtx(std::string_view name, const AeadCtxPointer& ctx); |
| 1799 | + |
| 1800 | + using AeadNameCallback = std::function<void(std::string_view name)>; |
| 1801 | + |
| 1802 | + // Iterates the known ciphers if the underlying implementation |
| 1803 | + // is able to do so. |
| 1804 | + static void ForEach(AeadNameCallback callback); |
| 1805 | + |
| 1806 | + // Utilities to get various AEADs by type. |
| 1807 | + |
| 1808 | + static const Aead EMPTY; |
| 1809 | + static const Aead AES_128_GCM; |
| 1810 | + static const Aead AES_192_GCM; |
| 1811 | + static const Aead AES_256_GCM; |
| 1812 | + static const Aead CHACHA20_POLY1305; |
| 1813 | + static const Aead XCHACHA20_POLY1305; |
| 1814 | + static const Aead AES_128_CTR_HMAC_SHA256; |
| 1815 | + static const Aead AES_256_CTR_HMAC_SHA256; |
| 1816 | + static const Aead AES_128_GCM_SIV; |
| 1817 | + static const Aead AES_256_GCM_SIV; |
| 1818 | + static const Aead AES_128_GCM_RANDNONCE; |
| 1819 | + static const Aead AES_256_GCM_RANDNONCE; |
| 1820 | + static const Aead AES_128_CCM_BLUETOOTH; |
| 1821 | + static const Aead AES_128_CCM_BLUETOOTH_8; |
| 1822 | + static const Aead AES_128_CCM_MATTER; |
| 1823 | + static const Aead AES_128_EAX; |
| 1824 | + static const Aead AES_256_EAX; |
| 1825 | + |
| 1826 | + private: |
| 1827 | + const EVP_AEAD* aead_ = nullptr; |
| 1828 | + const AeadInfo* info_ = nullptr; |
| 1829 | + |
| 1830 | + using AeadConstructor = const EVP_AEAD* (*)(); |
| 1831 | + static const std::unordered_map<AeadConstructor, AeadInfo> aeadIndex; |
| 1832 | + static const Aead FromConstructor(AeadConstructor construct); |
| 1833 | +}; |
| 1834 | + |
| 1835 | +class AeadCtxPointer final { |
| 1836 | + public: |
| 1837 | + static AeadCtxPointer New( |
| 1838 | + const Aead& aead, |
| 1839 | + bool encrypt, |
| 1840 | + const unsigned char* key = nullptr, |
| 1841 | + size_t keyLen = 0, |
| 1842 | + size_t tagLen = EVP_AEAD_DEFAULT_TAG_LENGTH /* = 0 */); |
| 1843 | + |
| 1844 | + AeadCtxPointer() = default; |
| 1845 | + explicit AeadCtxPointer(EVP_AEAD_CTX* ctx); |
| 1846 | + AeadCtxPointer(AeadCtxPointer&& other) noexcept; |
| 1847 | + AeadCtxPointer& operator=(AeadCtxPointer&& other) noexcept; |
| 1848 | + NCRYPTO_DISALLOW_COPY(AeadCtxPointer) |
| 1849 | + ~AeadCtxPointer(); |
| 1850 | + |
| 1851 | + inline bool operator==(std::nullptr_t) const noexcept { |
| 1852 | + return ctx_ == nullptr; |
| 1853 | + } |
| 1854 | + inline operator bool() const { return ctx_ != nullptr; } |
| 1855 | + inline EVP_AEAD_CTX* get() const { return ctx_.get(); } |
| 1856 | + inline operator EVP_AEAD_CTX*() const { return ctx_.get(); } |
| 1857 | + void reset(EVP_AEAD_CTX* ctx = nullptr); |
| 1858 | + EVP_AEAD_CTX* release(); |
| 1859 | + |
| 1860 | + bool init(const Aead& aead, |
| 1861 | + bool encrypt, |
| 1862 | + const unsigned char* key = nullptr, |
| 1863 | + size_t keyLen = 0, |
| 1864 | + size_t tagLen = EVP_AEAD_DEFAULT_TAG_LENGTH /* = 0 */); |
| 1865 | + |
| 1866 | + // TODO(npaun): BoringSSL does not define NIDs for all AEADs. |
| 1867 | + // Decide if we will even implement this method. |
| 1868 | + // int getNid() const; |
| 1869 | + |
| 1870 | + bool encrypt(const Buffer<const unsigned char>& in, |
| 1871 | + Buffer<unsigned char>& out, |
| 1872 | + Buffer<unsigned char>& tag, |
| 1873 | + const Buffer<const unsigned char>& nonce, |
| 1874 | + const Buffer<const unsigned char>& aad); |
| 1875 | + |
| 1876 | + bool decrypt(const Buffer<const unsigned char>& in, |
| 1877 | + Buffer<unsigned char>& out, |
| 1878 | + const Buffer<const unsigned char>& tag, |
| 1879 | + const Buffer<const unsigned char>& nonce, |
| 1880 | + const Buffer<const unsigned char>& aad); |
| 1881 | + |
| 1882 | + private: |
| 1883 | + DeleteFnPtr<EVP_AEAD_CTX, EVP_AEAD_CTX_free> ctx_; |
| 1884 | +}; |
| 1885 | +#endif |
| 1886 | + |
1737 | 1887 | // ============================================================================ |
1738 | 1888 | // Version metadata |
1739 | 1889 | #define NCRYPTO_VERSION "0.0.1" |
|
0 commit comments