QtBase  v6.3.1
qtlskey_schannel.cpp
Go to the documentation of this file.
1 /****************************************************************************
2 **
3 ** Copyright (C) 2021 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of the QtNetwork module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see https://www.qt.io/terms-conditions. For further
15 ** information use the contact form at https://www.qt.io/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 3 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL3 included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 3 requirements
23 ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24 **
25 ** GNU General Public License Usage
26 ** Alternatively, this file may be used under the terms of the GNU
27 ** General Public License version 2.0 or (at your option) the GNU General
28 ** Public license version 3 or any later version approved by the KDE Free
29 ** Qt Foundation. The licenses are as published by the Free Software
30 ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31 ** included in the packaging of this file. Please review the following
32 ** information to ensure the GNU General Public License requirements will
33 ** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34 ** https://www.gnu.org/licenses/gpl-3.0.html.
35 **
36 ** $QT_END_LICENSE$
37 **
38 ****************************************************************************/
39 
40 #include <QtNetwork/private/qssl_p.h>
41 
42 #include "qtlsbackend_schannel_p.h"
43 #include "qtlskey_schannel_p.h"
44 
45 #include "../shared/qwincrypt_p.h"
46 
47 #include <QtNetwork/private/qtlsbackend_p.h>
48 #include <QtNetwork/private/qsslkey_p.h>
49 
50 #include <QtNetwork/qsslkey.h>
51 
52 #include <QtCore/qscopeguard.h>
53 #include <QtCore/qbytearray.h>
54 
56 
57 namespace {
58 const wchar_t *getName(QSslKeyPrivate::Cipher cipher)
59 {
60  switch (cipher) {
62  return BCRYPT_DES_ALGORITHM;
64  return BCRYPT_3DES_ALGORITHM;
66  return BCRYPT_RC2_ALGORITHM;
70  return BCRYPT_AES_ALGORITHM;
71  }
72  Q_UNREACHABLE();
73 }
74 
75 BCRYPT_ALG_HANDLE getHandle(QSslKeyPrivate::Cipher cipher)
76 {
77  BCRYPT_ALG_HANDLE handle;
78  NTSTATUS status = BCryptOpenAlgorithmProvider(
79  &handle, // phAlgorithm
80  getName(cipher), // pszAlgId
81  nullptr, // pszImplementation
82  0 // dwFlags
83  );
84  if (status < 0) {
85  qCWarning(lcTlsBackendSchannel, "Failed to open algorithm handle (%ld)!", status);
86  return nullptr;
87  }
88 
89  return handle;
90 }
91 
92 BCRYPT_KEY_HANDLE generateSymmetricKey(BCRYPT_ALG_HANDLE handle,
93  const QByteArray &key)
94 {
95  BCRYPT_KEY_HANDLE keyHandle;
96  NTSTATUS status = BCryptGenerateSymmetricKey(
97  handle, // hAlgorithm
98  &keyHandle, // phKey
99  nullptr, // pbKeyObject (can ignore)
100  0, // cbKeyObject (also ignoring)
101  reinterpret_cast<unsigned char *>(const_cast<char *>(key.data())), // pbSecret
102  ULONG(key.length()), // cbSecret
103  0 // dwFlags
104  );
105  if (status < 0) {
106  qCWarning(lcTlsBackendSchannel, "Failed to generate symmetric key (%ld)!", status);
107  return nullptr;
108  }
109 
110  status = BCryptSetProperty(
111  keyHandle, // hObject
112  BCRYPT_CHAINING_MODE, // pszProperty
113  reinterpret_cast<UCHAR *>(const_cast<wchar_t *>(BCRYPT_CHAIN_MODE_CBC)), // pbInput
114  ARRAYSIZE(BCRYPT_CHAIN_MODE_CBC), // cbInput
115  0 // dwFlags
116  );
117  if (status < 0) {
118  BCryptDestroyKey(keyHandle);
119  qCWarning(lcTlsBackendSchannel, "Failed to change the symmetric key's chaining mode (%ld)!",
120  status);
121  return nullptr;
122  }
123  return keyHandle;
124 }
125 
127  const QByteArray &iv, bool encrypt)
128 {
129  BCRYPT_ALG_HANDLE handle = getHandle(cipher);
130  if (!handle)
131  return {};
132  auto handleDealloc = qScopeGuard([&handle]() {
133  BCryptCloseAlgorithmProvider(handle, 0);
134  });
135 
136  BCRYPT_KEY_HANDLE keyHandle = generateSymmetricKey(handle, key);
137  if (!keyHandle)
138  return {};
139  auto keyHandleDealloc = qScopeGuard([&keyHandle]() {
140  BCryptDestroyKey(keyHandle);
141  });
142 
143  QByteArray ivCopy = iv; // This gets modified, so we take a copy
144 
145  ULONG sizeNeeded = 0;
147  auto cryptFunction = encrypt ? BCryptEncrypt : BCryptDecrypt;
148  for (int i = 0; i < 2; i++) {
149  output.resize(int(sizeNeeded));
150  auto input = reinterpret_cast<unsigned char *>(const_cast<char *>(data.data()));
151  // Need to call it twice because the first iteration lets us know the size needed.
152  NTSTATUS status = cryptFunction(
153  keyHandle, // hKey
154  input, // pbInput
155  ULONG(data.length()), // cbInput
156  nullptr, // pPaddingInfo
157  reinterpret_cast<unsigned char *>(ivCopy.data()), // pbIV
158  ULONG(ivCopy.length()), // cbIV
159  sizeNeeded ? output.data() : nullptr, // pbOutput
160  ULONG(output.length()), // cbOutput
161  &sizeNeeded, // pcbResult
162  BCRYPT_BLOCK_PADDING // dwFlags
163  );
164  if (status < 0) {
165  qCWarning(lcTlsBackendSchannel, "%s failed (%ld)!", encrypt ? "Encrypt" : "Decrypt",
166  status);
167  return {};
168  }
169  }
170 
171  return QByteArray(reinterpret_cast<const char *>(output.constData()), int(sizeNeeded));
172 }
173 } // anonymous namespace
174 
175 namespace QTlsPrivate {
176 
178  const QByteArray &iv) const
179 {
180  return doCrypt(cipher, data, key, iv, false);
181 }
182 
184  const QByteArray &iv) const
185 {
186  return doCrypt(cipher, data, key, iv, true);
187 }
188 
189 } // namespace QTlsPrivate
190 
192 
small capitals from c petite p scientific i
[1]
Definition: afcover.h:80
The QByteArray class provides an array of bytes.
Definition: qbytearray.h:85
QByteArray decrypt(Cipher cipher, const QByteArray &data, const QByteArray &key, const QByteArray &iv) const override
QByteArray encrypt(Cipher cipher, const QByteArray &data, const QByteArray &key, const QByteArray &iv) const override
void resize(qsizetype sz)
T * data() noexcept
const T * constData() const
qsizetype length() const
const wchar_t * getName(QSslKeyPrivate::Cipher cipher)
QByteArray doCrypt(QSslKeyPrivate::Cipher cipher, const QByteArray &data, const QByteArray &key, const QByteArray &iv, bool encrypt)
BCRYPT_ALG_HANDLE getHandle(QSslKeyPrivate::Cipher cipher)
BCRYPT_KEY_HANDLE generateSymmetricKey(BCRYPT_ALG_HANDLE handle, const QByteArray &key)
QByteArray doCrypt(QSslKeyPrivate::Cipher cipher, const QByteArray &data, const QByteArray &key, const QByteArray &iv, bool enc)
#define Q_UNREACHABLE()
typedef QByteArray(EGLAPIENTRYP PFNQGSGETDISPLAYSPROC)()
#define qCWarning(category,...)
GLuint64 GLenum void * handle
GLuint64 key
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLenum GLenum GLenum input
Definition: qopenglext.h:10816
QScopeGuard< typename std::decay< F >::type > qScopeGuard(F &&f)
[qScopeGuard]
Definition: qscopeguard.h:93