libQuotient
A Qt library for building matrix clients
Loading...
Searching...
No Matches
e2ee_common.h
Go to the documentation of this file.
1// SPDX-FileCopyrightText: 2019 Alexey Andreyev <aa13q@ya.ru>
2// SPDX-FileCopyrightText: 2019 Kitsune Ral <Kitsune-Ral@users.sf.net>
3// SPDX-FileCopyrightText: 2021 Carl Schwan <carlschwan@kde.org>
4// SPDX-License-Identifier: LGPL-2.1-or-later
5
6#pragma once
7
8#include "../converters.h"
9
10#include <QtCore/QMetaType>
11#include <QtCore/QStringBuilder>
12
13#include <array>
14#include <span>
15#include <variant>
16
17namespace Quotient {
18
19constexpr inline auto AlgorithmKeyL = "algorithm"_L1;
20constexpr inline auto RotationPeriodMsKeyL = "rotation_period_ms"_L1;
21constexpr inline auto RotationPeriodMsgsKeyL = "rotation_period_msgs"_L1;
22
23constexpr inline auto AlgorithmKey = "algorithm"_L1;
24constexpr inline auto RotationPeriodMsKey = "rotation_period_ms"_L1;
25constexpr inline auto RotationPeriodMsgsKey = "rotation_period_msgs"_L1;
26
27constexpr inline auto Ed25519Key = "ed25519"_L1;
28constexpr inline auto Curve25519Key = "curve25519"_L1;
29constexpr inline auto SignedCurve25519Key = "signed_curve25519"_L1;
30
31constexpr inline auto OlmV1Curve25519AesSha2AlgoKey = "m.olm.v1.curve25519-aes-sha2"_L1;
32
33constexpr std::array SupportedAlgorithms { OlmV1Curve25519AesSha2AlgoKey,
34 MegolmV1AesSha2AlgoKey };
35
36inline bool isSupportedAlgorithm(const QString& algorithm)
37{
38 return std::ranges::find(SupportedAlgorithms, algorithm) != SupportedAlgorithms.cend();
39}
40
41// Can't use std::byte normally recommended for the purpose because both Olm
42// and OpenSSL get uint8_t* pointers, and std::byte* is not implicitly
43// convertible to uint8_t* (and adding explicit casts in each case kinda defeats
44// the purpose of all the span machinery below meant to replace reinterpret_ or
45// any other casts).
46
47using byte_t = uint8_t;
48
49template <size_t N = std::dynamic_extent>
50using byte_view_t = std::span<const byte_t, N>;
51
52template <size_t N = std::dynamic_extent>
54
55namespace _impl {
56 QUOTIENT_API void checkForSpanShortfall(QByteArray::size_type inputSize, int neededSize);
57
58 template <typename SpanT>
59 inline auto spanFromBytes(auto& byteArray)
60 {
61 // OpenSSL only handles int sizes; Release builds will cut the tail off
62 Q_ASSERT_X(std::in_range<int>(std::size(byteArray)), __func__, "Too long array for OpenSSL");
63 if constexpr (SpanT::extent != std::dynamic_extent) {
64 static_assert(std::in_range<int>(SpanT::extent));
65 checkForSpanShortfall(std::size(byteArray), static_cast<int>(SpanT::extent));
66 }
67 return SpanT(std::bit_cast<typename SpanT::pointer>(std::data(byteArray)),
68 std::min(SpanT::extent, unsignedSize(byteArray)));
69 }
70} // namespace _impl
71
72//! \brief Obtain a std::span<const byte_t, N> looking into the passed buffer
73//!
74//! This function returns an adaptor object that is suitable for OpenSSL/Olm
75//! invocations (via std::span<>::data() accessor) so that you don't have
76//! to wrap your containers into reinterpret/bit_casts on every OpenSSL call.
77//! \note The caller is responsible for making sure that bytes.size() is small
78//! enough to fit into an int (OpenSSL only handles int sizes atm) but
79//! also large enough to have at least N bytes if N is not `std::dynamic_extent`
80//! \sa asWritableCBytes for the case when you need to pass a buffer for writing
81template <size_t N = std::dynamic_extent>
82inline auto asCBytes(const auto& buf)
83{
84 return _impl::spanFromBytes<byte_view_t<N>>(buf);
85}
86
87//! Non-template base for owning byte span classes
89public:
91
94
95 static constexpr auto TotalSecureHeapSize = 65'536;
96
97 auto size() const { return data_ == nullptr ? 0 : size_; }
98 auto empty() const { return data_ == nullptr || size_ == 0; }
99
100 void clear();
101
102 //! \brief Access the bytes of the fixed buffer via QByteArray interface
103 //!
104 //! This uses QByteArray::fromRawData() to create a QByteArray object that
105 //! refers to the original fixed buffer, without copying.
106 //! \warning the lifetime of the returned QByteArray should not exceed the
107 //! lifetime of the underlying buffer; in particular, you should
108 //! never try using the result of viewAsByteArray() as a return
109 //! value of your function
110 //! \sa copyToByteArray
112 {
114 return QByteArray::fromRawData(std::bit_cast<const char*>(data_),
115 static_cast<QByteArray::size_type>(size_));
116 }
117
118 //! \brief Copy the contents of the buffer to a QByteArray
119 //!
120 //! Unlike viewAsByteArray(), this function actually copies the buffer to
121 //! non-secure memory.
123 {
124 if (untilPos < 0 || static_cast<size_type>(untilPos) > size_)
125 untilPos = static_cast<QByteArray::size_type>(size_);
126 return { std::bit_cast<const char*>(data_), untilPos };
127 }
128
131 {
133 }
134
137
138protected:
141
143 : data_(std::exchange(other.data_, nullptr)), size_(other.size_)
144 {}
145
147
149 const value_type* data() const { return data_; }
150
151private:
152 value_type* data_ = nullptr;
153 size_type size_ = 0;
154};
155
156template <size_t ExtentN = std::dynamic_extent, bool DataIsWriteable = true>
158public:
159 static constexpr auto extent = ExtentN; // Matching std::span
160 static_assert(extent == std::dynamic_extent
161 || (extent < TotalSecureHeapSize / 2 && extent % 4 == 0));
162
166 {}
170 {}
174 {}
175
178
180 {
181 return byte_view_t<ExtentN>(data(), size());
182 }
183
186 {
188 }
189};
190
191//! \brief Fill the buffer with the securely generated random bytes
192//!
193//! You should use this throughout Quotient where pseudo-random generators
194//! are not enough (i.e. in crypto cases). Don't use it when proper randomness
195//! is not critical; it tries to rely on system entropy that is in (somewhat)
196//! limited supply.
197//! There's no fancy stuff internally, it's just a way to unify secure RNG usage
198//! in Quotient. See the function definition for details if you want/need.
200
201class PicklingKey : public FixedBuffer<128, /*DataIsWriteable=*/false> {
202private:
203 // `using` would have exposed the constructor as it's public in the parent
204 explicit PicklingKey(InitOptions options) : FixedBuffer(options)
205 {
206 Q_ASSERT(options != FillWithZeros);
207 }
208
209public:
210 static PicklingKey generate() { return PicklingKey(FillWithRandom); }
211 static PicklingKey fromByteArray(QByteArray&& keySource)
212 {
213 PicklingKey k(Uninitialized);
214 k.fillFrom(std::move(keySource));
215 return k;
216 }
217 static PicklingKey mock() { return PicklingKey(Uninitialized); }
218};
219
221public:
223 const QString& deviceId,
224 const QByteArray& signature)
225 : payload{
226 { "key"_L1, unsignedKey },
227 { "signatures"_L1,
229 { userId, QJsonObject{ { "ed25519:"_L1 % deviceId,
230 QString::fromUtf8(signature) } } } } }
231 }
232 {}
233 explicit SignedOneTimeKey(const QJsonObject& jo = {})
234 : payload(jo)
235 {}
236
237
238 //! Whether the key is a fallback key
239 auto toJson() const { return payload; }
240
241private:
243};
244
246
247} // namespace Quotient
Non-template base for owning byte span classes.
Definition e2ee_common.h:88
static PicklingKey fromByteArray(QByteArray &&keySource)
static PicklingKey mock()
static PicklingKey generate()
constexpr auto Ed25519Key
Definition e2ee_common.h:27
constexpr auto OlmV1Curve25519AesSha2AlgoKey
Definition e2ee_common.h:31
bool isSupportedAlgorithm(const QString &algorithm)
Definition e2ee_common.h:36
constexpr auto SignedCurve25519Key
Definition e2ee_common.h:29
constexpr auto RotationPeriodMsKeyL
Definition e2ee_common.h:20
constexpr auto AlgorithmKey
Definition e2ee_common.h:23
constexpr auto Curve25519Key
Definition e2ee_common.h:28
constexpr auto RotationPeriodMsgsKeyL
Definition e2ee_common.h:21
auto asCBytes(const auto &buf)
Obtain a std::span<const byte_t, N> looking into the passed buffer.
Definition e2ee_common.h:82
constexpr auto RotationPeriodMsgsKey
Definition e2ee_common.h:25
constexpr auto AlgorithmKeyL
Definition e2ee_common.h:19
QUOTIENT_API void fillFromSecureRng(std::span< byte_t > bytes)
Fill the buffer with the securely generated random bytes.
constexpr std::array SupportedAlgorithms
Definition e2ee_common.h:33
constexpr auto RotationPeriodMsKey
Definition e2ee_common.h:24
#define QUOTIENT_API