diff options
author | Timur Pocheptsov <timur.pocheptsov@qt.io> | 2019-03-04 16:11:20 +0100 |
---|---|---|
committer | Timur Pocheptsov <timur.pocheptsov@qt.io> | 2019-03-08 05:36:14 +0000 |
commit | 01a54342521de9994ef54f4a01916b8782c685f6 (patch) | |
tree | 0e461db5863612954c47385f0fb1f61c87b36cb3 /src | |
parent | f91aae6397378f7f86a3dd320f4e2caa3843a5de (diff) |
QSslKey - add a support for AES encrypted keys
for SecureTransport backend. OpenSSL, while reading
RSA/DSA, is internally calling EVP_BytesToKey that
essentially does the same thing this patch does in
'deriveAesKey' and thus able to correctly decrypt
whatever it first encrypted (while generating/
encrypting keys).
Fixes: QTBUG-54422
Change-Id: Ia9f7599c5b19bf364c179f2abd2aab7ea5359a65
Reviewed-by: MÃ¥rten Nordheim <marten.nordheim@qt.io>
Diffstat (limited to 'src')
-rw-r--r-- | src/network/ssl/qsslkey_mac.cpp | 8 | ||||
-rw-r--r-- | src/network/ssl/qsslkey_openssl.cpp | 8 | ||||
-rw-r--r-- | src/network/ssl/qsslkey_p.h | 5 | ||||
-rw-r--r-- | src/network/ssl/qsslkey_qt.cpp | 48 | ||||
-rw-r--r-- | src/network/ssl/qsslkey_schannel.cpp | 1 |
5 files changed, 68 insertions, 2 deletions
diff --git a/src/network/ssl/qsslkey_mac.cpp b/src/network/ssl/qsslkey_mac.cpp index b0f726a2e6..814fe1c4bc 100644 --- a/src/network/ssl/qsslkey_mac.cpp +++ b/src/network/ssl/qsslkey_mac.cpp @@ -66,7 +66,13 @@ static QByteArray wrapCCCrypt(CCOperation ccOp, blockSize = kCCBlockSizeRC2; ccAlgorithm = kCCAlgorithmRC2; break; - }; + case QSslKeyPrivate::Aes128Cbc: + case QSslKeyPrivate::Aes192Cbc: + case QSslKeyPrivate::Aes256Cbc: + blockSize = kCCBlockSizeAES128; + ccAlgorithm = kCCAlgorithmAES; + break; + } size_t plainLength = 0; QByteArray plain(data.size() + blockSize, 0); CCCryptorStatus status = CCCrypt( diff --git a/src/network/ssl/qsslkey_openssl.cpp b/src/network/ssl/qsslkey_openssl.cpp index 99c1a39c73..dfb80bd829 100644 --- a/src/network/ssl/qsslkey_openssl.cpp +++ b/src/network/ssl/qsslkey_openssl.cpp @@ -333,6 +333,14 @@ static QByteArray doCrypt(QSslKeyPrivate::Cipher cipher, const QByteArray &data, type = q_EVP_rc2_cbc(); #endif break; + case QSslKeyPrivate::Aes128Cbc: + case QSslKeyPrivate::Aes192Cbc: + case QSslKeyPrivate::Aes256Cbc: + // Just to avoid compiler warnings/errors. OpenSSL uses a different + // codepath when reading encrypted keys, and they all correctly + // deduce the cipher and know how to derive a key. + Q_UNREACHABLE(); + break; } if (type == nullptr) diff --git a/src/network/ssl/qsslkey_p.h b/src/network/ssl/qsslkey_p.h index 06403b5479..1f2b59904a 100644 --- a/src/network/ssl/qsslkey_p.h +++ b/src/network/ssl/qsslkey_p.h @@ -105,7 +105,10 @@ public: enum Cipher { DesCbc, DesEde3Cbc, - Rc2Cbc + Rc2Cbc, + Aes128Cbc, + Aes192Cbc, + Aes256Cbc }; Q_AUTOTEST_EXPORT static QByteArray decrypt(Cipher cipher, const QByteArray &data, const QByteArray &key, const QByteArray &iv); diff --git a/src/network/ssl/qsslkey_qt.cpp b/src/network/ssl/qsslkey_qt.cpp index 5ebd8ac3bd..61251b641b 100644 --- a/src/network/ssl/qsslkey_qt.cpp +++ b/src/network/ssl/qsslkey_qt.cpp @@ -124,6 +124,37 @@ static int numberOfBits(const QByteArray &modulus) return bits; } +static QByteArray deriveAesKey(QSslKeyPrivate::Cipher cipher, const QByteArray &passPhrase, const QByteArray &iv) +{ + // This is somewhat simplified and shortened version of what OpenSSL does. + // See, for example, EVP_BytesToKey for the "algorithm" itself and elsewhere + // in their code for what they pass as arguments to EVP_BytesToKey when + // deriving encryption keys (when reading/writing pems files with encrypted + // keys). + + Q_ASSERT(iv.size() >= 8); + + QCryptographicHash hash(QCryptographicHash::Md5); + + QByteArray data(passPhrase); + data.append(iv.data(), 8); // AKA PKCS5_SALT_LEN in OpenSSL. + + hash.addData(data); + + if (cipher == QSslKeyPrivate::Aes128Cbc) + return hash.result(); + + QByteArray key(hash.result()); + hash.reset(); + hash.addData(key); + hash.addData(data); + + if (cipher == QSslKeyPrivate::Aes192Cbc) + return key.append(hash.result().constData(), 8); + + return key.append(hash.result()); +} + static QByteArray deriveKey(QSslKeyPrivate::Cipher cipher, const QByteArray &passPhrase, const QByteArray &iv) { QByteArray key; @@ -145,6 +176,10 @@ static QByteArray deriveKey(QSslKeyPrivate::Cipher cipher, const QByteArray &pas case QSslKeyPrivate::Rc2Cbc: key = hash.result(); break; + case QSslKeyPrivate::Aes128Cbc: + case QSslKeyPrivate::Aes192Cbc: + case QSslKeyPrivate::Aes256Cbc: + return deriveAesKey(cipher, passPhrase, iv); } return key; } @@ -378,6 +413,15 @@ void QSslKeyPrivate::decodePem(const QByteArray &pem, const QByteArray &passPhra cipher = DesEde3Cbc; } else if (dekInfo.first() == "RC2-CBC") { cipher = Rc2Cbc; +// TODO: Add SChannel version too! +#ifdef QT_SECURETRANSPORT + } else if (dekInfo.first() == "AES-128-CBC") { + cipher = Aes128Cbc; + } else if (dekInfo.first() == "AES-192-CBC") { + cipher = Aes192Cbc; + } else if (dekInfo.first() == "AES-256-CBC") { + cipher = Aes256Cbc; +#endif // QT_SECURETRANSPORT } else { clear(deepClear); return; @@ -554,6 +598,10 @@ static EncryptionData readPbes2(const QVector<QAsn1Element> &element, const QByt return {}; break; } // @todo(?): case (RC5 , AES) + case QSslKeyPrivate::Cipher::Aes128Cbc: + case QSslKeyPrivate::Cipher::Aes192Cbc: + case QSslKeyPrivate::Cipher::Aes256Cbc: + Q_UNREACHABLE(); } if (Q_LIKELY(keyDerivationAlgorithm == PKCS5_PBKDF2_ENCRYPTION_OID)) { diff --git a/src/network/ssl/qsslkey_schannel.cpp b/src/network/ssl/qsslkey_schannel.cpp index 5694068860..9dfbc87e9a 100644 --- a/src/network/ssl/qsslkey_schannel.cpp +++ b/src/network/ssl/qsslkey_schannel.cpp @@ -57,6 +57,7 @@ const wchar_t *getName(QSslKeyPrivate::Cipher cipher) return BCRYPT_3DES_ALGORITHM; case QSslKeyPrivate::Cipher::Rc2Cbc: return BCRYPT_RC2_ALGORITHM; + default:; } Q_UNREACHABLE(); } |