summaryrefslogtreecommitdiffstats
path: root/src/crypto-lib/cryptography.cpp
blob: 8537d2a361399943acae7f84f65491ddd909475b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
// Copyright (C) 2021 The Qt Company Ltd.
// Copyright (C) 2019 Luxoft Sweden AB
// Copyright (C) 2018 Pelagicore AG
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only

#include <QMutex>

#include "global.h"
#include "cryptography.h"

#if defined(Q_OS_UNIX)
#  include <QFile>
#elif defined(Q_OS_WIN)
// all this mess is needed to get RtlGenRandom()
#  include "windows.h"
#  define SystemFunction036 NTAPI SystemFunction036
#  include "ntsecapi.h"
#  undef SystemFunction036
#endif

#if defined(Q_OS_MACOS)
#  include <QtCore/private/qcore_mac_p.h>
#  include <Security/SecBase.h>
#  include <Availability.h>
#endif

#if defined(QT_AM_USE_LIBCRYPTO)
#  include "libcryptofunction.h"

QT_BEGIN_NAMESPACE_AM

Q_GLOBAL_STATIC(QMutex, initMutex)
static bool openSslInitialized = false;
static bool loadOpenSsl3LegacyProvider = false;

// clazy:excludeall=non-pod-global-static
// AXIVION DISABLE Qt-NonPodGlobalStatic

static QT_AM_LIBCRYPTO_FUNCTION(ERR_error_string_n, void(*)(unsigned long, char *, size_t));

QT_END_NAMESPACE_AM

#endif

using namespace Qt::StringLiterals;


QT_BEGIN_NAMESPACE_AM


QByteArray Cryptography::generateRandomBytes(int size)
{
    QByteArray result;

    if (size > 0) {
#if defined(Q_OS_UNIX)
        QFile f(u"/dev/urandom"_s);
        if (f.open(QIODevice::ReadOnly)) {
            result = f.read(size);
            if (result.size() != size)
                result.clear();
        }
#elif defined(Q_OS_WIN)
        result.resize(size);
        if (!RtlGenRandom(result.data(), size))
            result.clear();
#endif
    }
    return result;
}


void Cryptography::initialize()
{
#if defined(QT_AM_USE_LIBCRYPTO)
    QMutexLocker locker(initMutex());
    if (!openSslInitialized) {
        if (!LibCryptoFunctionBase::initialize(loadOpenSsl3LegacyProvider))
            qFatal("Could not load libcrypto");
        openSslInitialized = true;
    }
#endif
}

void Cryptography::enableOpenSsl3LegacyProvider()
{
#if defined(QT_AM_USE_LIBCRYPTO)
    QMutexLocker locker(initMutex());
    if (openSslInitialized)
        qCritical("Cryptography::enableOpenSsl3LegacyProvider() needs to be called before using any other crypto functions.");
    else
        loadOpenSsl3LegacyProvider = true;
#endif
}

QString Cryptography::errorString(qint64 osCryptoError, const char *errorDescription)
{
    QString result;
    if (errorDescription && *errorDescription) {
        result = QString::fromLatin1(errorDescription);
        result.append(u": "_s);
    }

#if defined(QT_AM_USE_LIBCRYPTO)
    if (osCryptoError) {
        char msg[512];
        msg[sizeof(msg) - 1] = 0;

        //void ERR_error_string_n(unsigned long e, char *buf, size_t len);
        am_ERR_error_string_n(static_cast<unsigned long>(osCryptoError), msg, sizeof(msg) - 1);
        result.append(QString::fromLocal8Bit(msg));
    }
#elif defined(Q_OS_WIN)
    if (osCryptoError) {
        LPWSTR msg = nullptr;
        FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
                       nullptr, osCryptoError, 0, (LPWSTR) &msg, 0, nullptr);
        // remove potential \r\n at the end
        result.append(QString::fromWCharArray(msg).trimmed());
        HeapFree(GetProcessHeap(), 0, msg);
    }
#elif defined(Q_OS_MACOS)
    if (osCryptoError) {
#  if QT_MACOS_IOS_PLATFORM_SDK_EQUAL_OR_ABOVE(100300, 110300)
        if (__builtin_available(macOS 10.3, iOS 12.3, *)) {
            QCFType<CFStringRef> msg = SecCopyErrorMessageString(qint32(osCryptoError), nullptr);
            result.append(QString::fromCFString(msg));
        }
#  else
        result.append(QString::number(osCryptoError));
#  endif
    }
#else
    Q_UNUSED(osCryptoError)
#endif

    return result;
}

QT_END_NAMESPACE_AM