8 #include <Quotient/converters.h>
9 #include <Quotient/expected.h>
11 #include <QtCore/QMetaType>
12 #include <QtCore/QStringBuilder>
18 #include <olm/error.h>
22 constexpr inline auto AlgorithmKeyL =
"algorithm"_ls;
23 constexpr inline auto RotationPeriodMsKeyL =
"rotation_period_ms"_ls;
24 constexpr inline auto RotationPeriodMsgsKeyL =
"rotation_period_msgs"_ls;
26 constexpr inline auto AlgorithmKey =
"algorithm"_ls;
27 constexpr inline auto RotationPeriodMsKey =
"rotation_period_ms"_ls;
28 constexpr inline auto RotationPeriodMsgsKey =
"rotation_period_msgs"_ls;
30 constexpr inline auto Ed25519Key =
"ed25519"_ls;
31 constexpr inline auto Curve25519Key =
"curve25519"_ls;
32 constexpr inline auto SignedCurve25519Key =
"signed_curve25519"_ls;
34 constexpr inline auto OlmV1Curve25519AesSha2AlgoKey =
"m.olm.v1.curve25519-aes-sha2"_ls;
35 constexpr inline auto MegolmV1AesSha2AlgoKey =
"m.megolm.v1.aes-sha2"_ls;
37 constexpr std::array SupportedAlgorithms { OlmV1Curve25519AesSha2AlgoKey,
38 MegolmV1AesSha2AlgoKey };
40 inline bool isSupportedAlgorithm(
const QString& algorithm)
42 return std::find(SupportedAlgorithms.cbegin(), SupportedAlgorithms.cend(),
44 != SupportedAlgorithms.cend();
47 #define QOLM_INTERNAL_ERROR_X(Message_, LastError_)
48 qFatal("%s, internal error: %s", Message_, LastError_)
50 #define QOLM_INTERNAL_ERROR(Message_)
53 #define QOLM_FAIL_OR_LOG_X(InternalCondition_, Message_, LastErrorText_)
55 const QString errorMsg{ (Message_) };
56 if (InternalCondition_)
58 qWarning(E2EE).nospace() << errorMsg << ": " << (LastErrorText_);
61 #define QOLM_FAIL_OR_LOG(InternalFailureValue_, Message_)
66 using QOlmExpected = Expected<T, OlmErrorCode>;
77 inline size_t unsignedSize(
const auto& qtBuffer)
79 return static_cast<size_t>(qtBuffer.size());
88 using byte_t = uint8_t;
90 template <size_t N = std::dynamic_extent>
91 using byte_view_t = std::span<
const byte_t, N>;
93 template <size_t N = std::dynamic_extent>
94 using byte_span_t = std::span<byte_t, N>;
97 QUOTIENT_API void checkForSpanShortfall(QByteArray::size_type inputSize,
int neededSize);
99 template <
typename SpanT>
100 inline auto spanFromByteArray(
auto& byteArray)
103 Q_ASSERT_X(std::in_range<
int>(byteArray.size()),
__func__,
"Too long array for OpenSSL");
104 if constexpr (SpanT::extent != std::dynamic_extent) {
105 static_assert(std::in_range<
int>(SpanT::extent));
106 checkForSpanShortfall(byteArray.size(),
static_cast<
int>(SpanT::extent));
108 return SpanT(
reinterpret_cast<
typename SpanT::pointer>(byteArray.data()),
109 std::min(SpanT::extent, unsignedSize(byteArray)));
123 template <size_t N = std::dynamic_extent>
124 inline auto asCBytes(
const QByteArray& bytes)
126 return _impl::spanFromByteArray<byte_view_t<N>>(bytes);
129 template <size_t N = std::dynamic_extent>
130 inline auto asCBytes(QLatin1String bytes)
132 return _impl::spanFromByteArray<byte_view_t<N>>(bytes);
136 template <size_t N = std::dynamic_extent>
137 inline auto asWritableCBytes(QByteArray& bytes)
139 return _impl::spanFromByteArray<byte_span_t<N>>(bytes);
143 template <
class BufferT>
144 inline auto asWritableCBytes(BufferT& buf) ->
auto
145 requires(!std::is_const_v<
typename BufferT::value_type>)
147 return byte_span_t<BufferT::extent>(buf);
150 template <
class BufferT>
151 inline auto asCBytes(
const BufferT& buf) ->
auto
153 return byte_view_t<BufferT::extent>(buf);
156 inline auto viewAsByteArray(
const auto& aRange) ->
auto
157 requires (
sizeof(*aRange.data()) ==
sizeof(
char))
159 return QByteArray::fromRawData(
reinterpret_cast<
const char*>(
161 static_cast<
int>(std::size(aRange)));
167 enum InitOptions { Uninitialized, FillWithZeros, FillWithRandom };
169 using value_type = byte_t;
170 using size_type = size_t;
172 static constexpr auto TotalSecureHeapSize = 65'536;
174 auto size()
const {
return data_ ==
nullptr ? 0 : size_; }
175 auto empty()
const {
return data_ ==
nullptr || size_ == 0; }
188 QByteArray viewAsByteArray()
const
190 static_assert(std::in_range<QByteArray::size_type>(TotalSecureHeapSize));
191 return QByteArray::fromRawData(
reinterpret_cast<
const char*>(data_),
192 static_cast<QByteArray::size_type>(size_));
199 QByteArray copyToByteArray(QByteArray::size_type untilPos = -1)
const
201 if (untilPos < 0 ||
static_cast<size_type>(untilPos) > size_)
202 untilPos =
static_cast<QByteArray::size_type>(size_);
203 return {
reinterpret_cast<
const char*>(data_), untilPos };
208 QByteArray toBase64()
const {
return viewAsByteArray().toBase64(); }
209 QByteArray toBase64(QByteArray::Base64Options options)
const
211 return viewAsByteArray().toBase64(options);
214 Q_DISABLE_COPY(FixedBufferBase)
215 FixedBufferBase& operator=(FixedBufferBase&&) =
delete;
218 FixedBufferBase(size_t bufferSize, InitOptions options);
219 ~FixedBufferBase() { clear(); }
221 FixedBufferBase(FixedBufferBase&& other)
222 : data_(std::exchange(other.data_,
nullptr)), size_(other.size_)
225 void fillFrom(QByteArray&& source);
227 uint8_t* dataForWriting() {
return data_; }
228 const uint8_t* data()
const {
return data_; }
231 uint8_t* data_ =
nullptr;
235 template <size_t ExtentN = std::dynamic_extent,
bool DataIsWriteable =
true>
238 static constexpr auto extent = ExtentN;
239 static_assert(extent == std::dynamic_extent
240 || (extent < TotalSecureHeapSize / 2 && extent % 4 == 0));
243 requires(extent != std::dynamic_extent)
244 : FixedBuffer(FillWithZeros)
246 explicit FixedBuffer(InitOptions fillMode)
247 requires(extent != std::dynamic_extent)
248 : FixedBufferBase(ExtentN, fillMode)
250 explicit FixedBuffer(size_t bufferSize)
251 requires(extent == std::dynamic_extent)
252 : FixedBuffer(bufferSize, FillWithZeros)
254 explicit FixedBuffer(size_t bufferSize, InitOptions fillMode)
255 requires(extent == std::dynamic_extent)
256 : FixedBufferBase(bufferSize, fillMode)
259 using FixedBufferBase::data;
260 uint8_t* data() requires DataIsWriteable {
return dataForWriting(); }
265 return byte_view_t<ExtentN>(data(), size());
270 requires DataIsWriteable
272 return byte_span_t<ExtentN>(dataForWriting(), size());
276 inline auto getRandom(size_t bytes)
278 return FixedBuffer<>{ bytes, FixedBufferBase::FillWithRandom };
281 template <size_t SizeN>
282 inline auto getRandom()
284 return FixedBuffer<SizeN>{ FixedBufferBase::FillWithRandom };
297 class PicklingKey :
public FixedBuffer<128,
false> {
300 explicit PicklingKey(InitOptions options) : FixedBuffer(options)
302 Q_ASSERT(options != FillWithZeros);
306 static PicklingKey generate() {
return PicklingKey(FillWithRandom); }
307 static PicklingKey fromByteArray(QByteArray&& keySource)
309 PicklingKey k(Uninitialized);
310 k.fillFrom(std::move(keySource));
313 static PicklingKey mock() {
return PicklingKey(Uninitialized); }
326 struct UnsignedOneTimeKeys
328 QHash<QString, QHash<QString, QString>> keys;
331 QHash<QString, QString> curve25519()
const {
return keys[Curve25519Key]; }
336 explicit SignedOneTimeKey(
const QString& unsignedKey,
const QString& userId,
337 const QString& deviceId,
338 const QByteArray& signature)
340 {
"key"_ls, unsignedKey },
343 { userId, QJsonObject{ {
"ed25519:"_ls % deviceId,
344 QString::fromUtf8(signature) } } } } }
347 explicit SignedOneTimeKey(
const QJsonObject& jo = {})
352 QByteArray key()
const {
return payload[
"key"_ls].toString().toLatin1(); }
358 auto signatures()
const
360 return fromJson<QHash<QString, QHash<QString, QString>>>(
361 payload[
"signatures"_ls]);
364 QByteArray signature(QStringView userId, QStringView deviceId)
const
366 return payload[
"signatures"_ls][userId][
"ed25519:"_ls % deviceId]
372 bool isFallback()
const {
return payload[
"fallback"_ls].toBool(); }
373 auto toJson()
const {
return payload; }
374 auto toJsonForVerification()
const
377 json.remove(
"signatures"_ls);
378 json.remove(
"unsigned"_ls);
379 return QJsonDocument(json).toJson(QJsonDocument::Compact);
386 using OneTimeKeys = QHash<QString, std::variant<QString, SignedOneTimeKey>>;
390 Q_DECLARE_METATYPE(Quotient::SignedOneTimeKey)