8#include <QtNetwork/private/qsslkey_p.h>
10#include <QtNetwork/qpassworddigestor.h>
12#include <QtCore/QMessageAuthenticationCode>
13#include <QtCore/qcryptographichash.h>
14#include <QtCore/qrandom.h>
16#include <QtCore/qdatastream.h>
17#include <QtCore/qbytearray.h>
18#include <QtCore/qdebug.h>
19#include <QtCore/qmap.h>
34const quint8 bits_table[256] = {
35 0,1,2,2,3,3,3,3,4,4,4,4,4,4,4,4,
36 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
37 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
38 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
39 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
40 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
41 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
42 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
43 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
44 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
45 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
46 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
47 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
48 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
49 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
50 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
53using OidLengthMap = QMap<QByteArray, int>;
92const QMap<QByteArray, QSslKeyPrivate::Cipher> oidCipherMap {
110 EncryptionData() =
default;
113 : initialized(
true), cipher(cipher),
key(
key), iv(iv)
116 bool initialized =
false;
122EncryptionData readPbes2(
const QList<QAsn1Element> &element,
const QByteArray &passPhrase)
139 static const QMap<QByteArray, QCryptographicHash::Algorithm> pbes2OidHashFunctionMap {
151 static const QMap<QSslKeyPrivate::Cipher, int> cipherKeyLengthMap {
152 {QSslKeyPrivate::Cipher::DesCbc, 8},
153 {QSslKeyPrivate::Cipher::DesEde3Cbc, 24},
155 {QSslKeyPrivate::Cipher::Rc2Cbc, 4}
159 const QList<QAsn1Element> keyDerivationContainer = element[0].toList();
160 if (keyDerivationContainer.size() != 2
166 const QByteArray keyDerivationAlgorithm = keyDerivationContainer[0].toObjectId();
167 const auto keyDerivationParams = keyDerivationContainer[1].toList();
169 const auto encryptionAlgorithmContainer = element[1].toList();
170 if (encryptionAlgorithmContainer.size() != 2
175 auto iterator = oidCipherMap.constFind(encryptionAlgorithmContainer[0].toObjectId());
176 if (iterator == oidCipherMap.cend()) {
178 <<
"QSslKey: Unsupported encryption cipher OID:" << encryptionAlgorithmContainer[0].toObjectId()
179 <<
"\nFile a bug report to Qt (include the line above).";
187 case QSslKeyPrivate::Cipher::DesCbc:
188 case QSslKeyPrivate::Cipher::DesEde3Cbc:
199 iv = encryptionAlgorithmContainer[1].value();
204 case QSslKeyPrivate::Cipher::Rc2Cbc: {
213 const auto rc2ParametersContainer = encryptionAlgorithmContainer[1].toList();
214 if ((rc2ParametersContainer.size() != 1 && rc2ParametersContainer.size() != 2)
218 iv = rc2ParametersContainer.
back().value();
223 case QSslKeyPrivate::Cipher::Aes128Cbc:
224 case QSslKeyPrivate::Cipher::Aes192Cbc:
225 case QSslKeyPrivate::Cipher::Aes256Cbc:
233 salt = keyDerivationParams[0].value();
245 int iterationCount = keyDerivationParams[1].toInteger();
249 if (keyDerivationParams.size() > vectorPos
251 keyLength = keyDerivationParams[vectorPos].toInteger(
nullptr);
254 keyLength = cipherKeyLengthMap[cipher];
259 if (keyDerivationParams.size() > vectorPos
261 const auto hashAlgorithmContainer = keyDerivationParams[vectorPos].toList();
262 hashAlgorithm = pbes2OidHashFunctionMap[hashAlgorithmContainer.front().toObjectId()];
266 Q_ASSERT(keyDerivationParams.size() == vectorPos);
271 <<
"QSslKey: Unsupported key derivation algorithm OID:" << keyDerivationAlgorithm
272 <<
"\nFile a bugreport to Qt (include the line above).";
275 return {cipher,
key, iv};
279const QMap<QByteArray, QCryptographicHash::Algorithm> pbes1OidHashFunctionMap {
280#ifndef QT_CRYPTOGRAPHICHASH_ONLY_SHA1
300EncryptionData readPbes1(
const QList<QAsn1Element> &element,
const QByteArray &encryptionScheme,
311 if (element.size() != 2
317 if (salt.size() != 8)
320 int iterationCount = element[1].toInteger();
321 if (iterationCount < 0)
325 auto iterator = pbes1OidHashFunctionMap.constFind(encryptionScheme);
326 if (iterator == pbes1OidHashFunctionMap.cend()) {
332 if (
key.size() != 16)
341 return {cipher,
key, iv};
346 const int length = oidLengthMap->value(oid);
353 for (
int i = 0;
i < modulus.
size(); ++
i) {
357 bits += bits_table[
b];
378 data.append(iv.data(), 8);
383 return hash.result();
391 return key.append(
hash.resultView().first(8));
393 return key.append(
hash.resultView());
401 hash.addData(passPhrase);
411 hash.addData(passPhrase);
421 return deriveAesKey(cipher, passPhrase, iv);
426int extractPkcs8KeyLength(
const QList<QAsn1Element> &
items,
TlsKey *that)
453 qWarning() <<
"QSslKey: Found RSA key when asked to use" << getName(that->algorithm())
454 <<
"\nLoading will fail.";
459 that->decodeDer(that->type(), that->algorithm(),
items[2].
value(), {},
true);
466 qWarning() <<
"QSslKey: Found EC key when asked to use" << getName(that->algorithm())
467 <<
"\nLoading will fail.";
474 keyLength = curveBits(pkcs8Info[1].toObjectId());
478 qWarning() <<
"QSslKey: Found DSA when asked to use" << getName(that->algorithm())
479 <<
"\nLoading will fail.";
486 const auto dsaInfo = pkcs8Info[1].toList();
489 keyLength = numberOfBits(dsaInfo[0].
value());
493 qWarning() <<
"QSslKey: Found DH when asked to use" << getName(that->algorithm())
494 <<
"\nLoading will fail.";
501 const auto dhInfo = pkcs8Info[1].toList();
504 keyLength = numberOfBits(dhInfo[0].
value());
507 qWarning() <<
"QSslKey: Unsupported PKCS#8 key algorithm:" <<
value
508 <<
"\nFile a bugreport to Qt (include the line above).";
528 QByteArray decryptedDer = decryptPkcs8(der, passPhrase);
539 const auto infoItems = elem.toList();
552 keyLength = numberOfBits(elem.value());
559 const auto params = infoItems[1].toList();
569 const auto params = infoItems[1].toList();
578 keyLength = curveBits(infoItems[1].toObjectId());
593 if (versionHex !=
"00" && versionHex !=
"01")
595 int pkcs8KeyLength = extractPkcs8KeyLength(
items,
this);
596 if (pkcs8KeyLength == -1)
599 keyLength = pkcs8KeyLength;
601 if (versionHex !=
"00")
607 if (versionHex !=
"00")
613 if (versionHex !=
"00")
619 if (versionHex !=
"01")
630 keyLength = curveBits(oidElem.toObjectId());
634 derData = decryptedDer;
644 QMap<QByteArray, QByteArray> headers;
647 if (headers.value(
"Proc-Type") ==
"4,ENCRYPTED") {
648 const QList<QByteArray> dekInfo = headers.value(
"DEK-Info").split(
',');
649 if (dekInfo.size() != 2) {
655 if (dekInfo.first() ==
"DES-CBC") {
657 }
else if (dekInfo.first() ==
"DES-EDE3-CBC") {
659 }
else if (dekInfo.first() ==
"RC2-CBC") {
661 }
else if (dekInfo.first() ==
"AES-128-CBC") {
663 }
else if (dekInfo.first() ==
"AES-192-CBC") {
665 }
else if (dekInfo.first() ==
"AES-256-CBC") {
683 QMap<QByteArray, QByteArray> headers;
694 headers.insert(
"Proc-Type",
"4,ENCRYPTED");
695 headers.insert(
"DEK-Info",
"DES-EDE3-CBC," + iv.toHex());
713 int headerIndex = der.indexOf(
header);
714 int footerIndex = der.indexOf(footer, headerIndex +
header.length());
716 if (headerIndex == -1 || footerIndex == -1) {
719 headerIndex = der.indexOf(
header);
720 footerIndex = der.indexOf(footer, headerIndex +
header.length());
722 if (headerIndex == -1 || footerIndex == -1) {
725 headerIndex = der.indexOf(
header);
726 footerIndex = der.indexOf(footer, headerIndex +
header.length());
729 if (headerIndex == -1 || footerIndex == -1)
732 der = der.mid(headerIndex +
header.size(), footerIndex - (headerIndex +
header.size()));
734 if (der.contains(
"Proc-Type:")) {
737 while (
i < der.length()) {
738 int j = der.indexOf(
':',
i);
746 i = der.indexOf(
'\n',
j);
749 if (!
value.isEmpty())
752 bool hasCR = (
i && der[
i-1] ==
'\r');
756 }
while (
i < der.length() && (der.at(
i) ==
' ' || der.at(
i) ==
'\t'));
760 headers->insert(field,
value);
778 std::memset(derData.
data(), 0, derData.
size());
804 const auto encryptionSchemeContainer =
items[0].
toList();
806 if (encryptionSchemeContainer.size() != 2
812 const QByteArray encryptionScheme = encryptionSchemeContainer[0].toObjectId();
813 const auto schemeParameterContainer = encryptionSchemeContainer[1].toList();
815 if (schemeParameterContainer.size() != 2
823 data = readPbes2(schemeParameterContainer, passPhrase);
824 }
else if (pbes1OidHashFunctionMap.contains(encryptionScheme)) {
825 data = readPbes1(schemeParameterContainer, encryptionScheme, passPhrase);
826 }
else if (encryptionScheme.startsWith(
PKCS12_OID)) {
831 <<
"QSslKey: Unsupported encryption scheme OID:" << encryptionScheme
832 <<
"\nFile a bugreport to Qt (include the line above).";
836 if (!
data.initialized) {
844 return decryptedKeyElement.value();
QByteArray trimmed() const &
char * data()
\macro QT_NO_CAST_FROM_BYTEARRAY
qsizetype size() const noexcept
Returns the number of bytes in this byte array.
static QByteArray fromHex(const QByteArray &hexEncoded)
Returns a decoded copy of the hex encoded array hexEncoded.
QByteArray right(qsizetype n) const &
void truncate(qsizetype pos)
Truncates the byte array at index position pos.
static QByteArray fromBase64(const QByteArray &base64, Base64Options options=Base64Encoding)
void clear()
Clears the contents of the byte array and makes it null.
QByteArray mid(qsizetype index, qsizetype len=-1) const &
static QByteArray fromRawData(const char *data, qsizetype size)
Constructs a QByteArray that uses the first size bytes of the data array.
\inmodule QtCore\reentrant
qsizetype size() const noexcept
bool isEmpty() const noexcept
QList< T > toList() const noexcept
T value(qsizetype i) const
static Q_DECL_CONST_FUNCTION QRandomGenerator * system()
\threadsafe
KeyType type() const override
QByteArray pemFromDer(const QByteArray &der, const QMap< QByteArray, QByteArray > &headers) const override
KeyAlgorithm algorithm() const override
static QByteArray pkcs8Footer(bool encrypted)
static QByteArray pkcs8Header(bool encrypted)
KeyAlgorithm keyAlgorithm
QByteArray derFromPem(const QByteArray &pem, QMap< QByteArray, QByteArray > *headers) const override
QByteArray toPem(const QByteArray &passPhrase) const override
void decodePem(KeyType type, KeyAlgorithm algorithm, const QByteArray &pem, const QByteArray &passPhrase, bool deepClear) override
void fromHandle(Qt::HANDLE opaque, KeyType expectedType) override
Qt::HANDLE handle() const override
void clear(bool deep) override
void decodeDer(KeyType type, KeyAlgorithm algorithm, const QByteArray &der, const QByteArray &passPhrase, bool deepClear) override
TlsKey is an abstract class, that allows a TLS plugin to provide an underlying implementation for the...
virtual QByteArray encrypt(Cipher cipher, const QByteArray &data, const QByteArray &key, const QByteArray &iv) const =0
QByteArray pemHeader() const
QByteArray pemFooter() const
virtual QByteArray decrypt(Cipher cipher, const QByteArray &data, const QByteArray &passPhrase, const QByteArray &iv) const =0
QHash< int, QWidget * > hash
[35multi]
Q_NETWORK_EXPORT QByteArray deriveKeyPbkdf1(QCryptographicHash::Algorithm algorithm, const QByteArray &data, const QByteArray &salt, int iterations, quint64 dkLen)
Q_NETWORK_EXPORT QByteArray deriveKeyPbkdf2(QCryptographicHash::Algorithm algorithm, const QByteArray &data, const QByteArray &salt, int iterations, quint64 dkLen)
KeyType
Describes the two types of keys QSslKey supports.
KeyAlgorithm
Describes the different key algorithms supported by QSslKey.
Combined button and popup list for selecting options.
Namespace containing onternal types that TLS backends implement.
static OidNameMap createOidMap()
#define PKCS5_MD5_DES_CBC_OID
#define EC_ENCRYPTION_OID
#define RC2_CBC_ENCRYPTION_OID
#define PKCS5_PBES2_ENCRYPTION_OID
#define HMAC_WITH_SHA512_256
#define DSA_ENCRYPTION_OID
#define RSA_ENCRYPTION_OID
#define PKCS5_PBKDF2_ENCRYPTION_OID
#define DH_ENCRYPTION_OID
#define PKCS5_SHA1_RC2_CBC_OID
#define DES_CBC_ENCRYPTION_OID
#define DES_EDE3_CBC_ENCRYPTION_OID
#define PKCS5_MD5_RC2_CBC_OID
#define HMAC_WITH_SHA512_224
#define PKCS5_SHA1_DES_CBC_OID
#define QByteArrayLiteral(str)
static QString header(const QString &name)
typedef QByteArray(EGLAPIENTRYP PFNQGSGETDISPLAYSPROC)()
EGLOutputLayerEXT EGLint EGLAttrib value
[5]
#define Q_GLOBAL_STATIC_WITH_ARGS(TYPE, NAME, ARGS)
GLboolean GLboolean GLboolean b
GLuint64 GLenum void * handle
GLenum GLuint GLenum GLsizei length
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLenum GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const void * bits
#define Q_UNIMPLEMENTED()
unsigned long long quint64