libQuotient
A Qt library for building matrix clients
cryptoutils.h
Go to the documentation of this file.
1 // SPDX-FileCopyrightText: 2023 Tobias Fella <tobias.fella@kde.org>
2 // SPDX-License-Identifier: LGPL-2.0-or-later
3 
4 #pragma once
5 
6 #include "e2ee_common.h"
7 #include "../expected.h"
8 
9 #include "../quotient_export.h"
10 
11 #include <QtCore/QByteArray>
12 #include <QtCore/QString>
13 
14 namespace Quotient {
15 
16 // Common remark: OpenSSL is a private dependency of libQuotient, meaning that
17 // headers of libQuotient can't include OpenSSL headers. Instead, alias
18 // the value or type along with a comment (see SslErrorCode e.g.) and add
19 // static_assert in the .cpp file to check it against the OpenSSL definition.
20 
21 constexpr auto DefaultPbkdf2KeyLength = 32u;
22 constexpr auto Aes256KeySize = 32u;
23 constexpr auto AesBlockSize = 16u; // AES_BLOCK_SIZE
24 constexpr auto HmacKeySize = 32u;
25 
26 struct QUOTIENT_API HkdfKeys
27  : public FixedBuffer<Aes256KeySize + HmacKeySize> {
28  //! \brief Key to be used for AES encryption / decryption
29  auto aes() const { return asCBytes(*this).first<Aes256KeySize>(); }
30  //! \brief Key to be used for MAC creation / verification
31  auto mac() const { return asCBytes(*this).last<HmacKeySize>(); }
32 };
33 
34 struct QUOTIENT_API Curve25519Encrypted {
35  QByteArray ciphertext;
36  QByteArray mac;
37  QByteArray ephemeral;
38 };
39 
40 // NOLINTNEXTLINE(google-runtime-int): the type is copied from OpenSSL
41 using SslErrorCode = unsigned long; // decltype(ERR_get_error())
42 
43 template <size_t Size = DefaultPbkdf2KeyLength>
44 using key_material_t = std::array<byte_t, Size>;
45 using key_view_t = byte_view_t<DefaultPbkdf2KeyLength>;
46 
47 enum SslErrorCodes : SslErrorCode {
48  SslErrorUserOffset = 128, // ERR_LIB_USER; never use this bare
49  WrongDerivedKeyLength = SslErrorUserOffset + 1,
50  SslPayloadTooLong = SslErrorUserOffset + 2
51 };
52 
53 //! Same as QOlmExpected but for wrapping OpenSSL instead of Olm calls
54 template <typename T>
55 using SslExpected = Expected<T, SslErrorCode>;
56 
57 // TODO, 0.9: merge zeroedByteArray() into zeroes() and replace const QByteArray& with
58 // QByteArrayView where OpenSSL/Olm expect an array of signed chars
59 
60 inline QByteArray zeroedByteArray(QByteArray::size_type n = 32) { return { n, '\0' }; }
61 
62 template <size_t N, typename T = uint8_t> consteval std::array<T, N> zeroes() { return {}; }
63 
64 namespace _impl {
65  QUOTIENT_API SslErrorCode pbkdf2HmacSha512(const QByteArray& passphrase, const QByteArray& salt,
66  int iterations, byte_span_t<> output);
67 }
68 
69 //! Generate a key out of the given passphrase
70 template <size_t Size = DefaultPbkdf2KeyLength>
71 QUOTIENT_API inline SslExpected<key_material_t<Size>> pbkdf2HmacSha512(const QByteArray& passphrase,
72  const QByteArray& salt,
73  int iterations)
74 {
75  key_material_t<Size> result;
76  if (auto code = _impl::pbkdf2HmacSha512(passphrase, salt, iterations, result); code != 0)
77  return code;
78  return result;
79 }
80 
81 //! \brief Derive a key from the input data using HKDF-SHA256
82 //!
83 //! The info parameter should be either 0 or 32 bytes long
84 QUOTIENT_API SslExpected<HkdfKeys> hkdfSha256(key_view_t key, byte_view_t<32> salt,
85  byte_view_t<> info);
86 
87 //! Calculate a MAC from the given key and data
88 QUOTIENT_API SslExpected<QByteArray> hmacSha256(
89  byte_view_t<HmacKeySize> hmacKey,
90  const QByteArray& data);
91 
92 //! \brief Decrypt the data using Curve25519-AES-Sha256
93 //! \note ciphertext must be given as base64
94 QUOTIENT_API QOlmExpected<QByteArray> curve25519AesSha2Decrypt(
95  QByteArray ciphertext, const QByteArray& privateKey,
96  const QByteArray& ephemeral, const QByteArray& mac);
97 
98 //! \brief Encrypt the data using Curve25519-AES-Sha256
99 //! \note publicKey must be given as base64
100 QUOTIENT_API QOlmExpected<Curve25519Encrypted> curve25519AesSha2Encrypt(
101  const QByteArray& plaintext, const QByteArray& publicKey);
102 
103 //! \brief Encrypt data using AES-CTR-256
104 //!
105 //! key and iv have a length of 32 bytes
106 QUOTIENT_API SslExpected<QByteArray> aesCtr256Encrypt(
107  const QByteArray& plaintext, byte_view_t<Aes256KeySize> key,
108  byte_view_t<AesBlockSize> iv);
109 
110 //! \brief Decrypt data using AES-CTR-256
111 //!
112 //! key and iv have a length of 32 bytes
113 QUOTIENT_API SslExpected<QByteArray> aesCtr256Decrypt(
114  const QByteArray& ciphertext, byte_view_t<Aes256KeySize> key,
115  byte_view_t<AesBlockSize> iv);
116 
117 QUOTIENT_API std::vector<byte_t> base58Decode(const QByteArray& encoded);
118 
119 QUOTIENT_API QByteArray sign(const QByteArray &key, const QByteArray &data);
120 
121 } // namespace Quotient