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>
This commit is contained in:
parent
f91aae6397
commit
01a5434252
@ -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(
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
|
@ -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)) {
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -0,0 +1,30 @@
|
||||
-----BEGIN RSA PRIVATE KEY-----
|
||||
Proc-Type: 4,ENCRYPTED
|
||||
DEK-Info: AES-128-CBC,A2A6F6BA67CFB2A992BA4FD3A0984B59
|
||||
|
||||
L5G1mwcXwW30lFty1HaEHlswFXAGk9+qf0TdYYNAAvVrsTMgfMq/6xM5XWo3IgbN
|
||||
gG4K6T57gQkAywn+upqMHobB+7qc3DRzYlrm89gb74gHOe95l/iUJp4ii+ROLcmY
|
||||
fg/vNmDSB/D0eM91WfwId7ticYD29+BUbbnqSYyY2S7K7DytYLpXqg3u335GYCdT
|
||||
JwOsgcgbOICytkgK6c9ZDF3IrkzvWospVuiG5IfpLQkUXlJO3YGJ/oGf1BXnRd/b
|
||||
kTzUiimUVunX62muHaUXKkAmXS8FCdB0puI+52pzLJ5FHdFxCcnwSG09TmoXbwwa
|
||||
KoNM+IshNHPBGM7QxflVbSDxDaF1FWLwWSb8+Fhb2fTpfEGMxRCQ8HB1ZeMV4E5W
|
||||
DSiNhih8ziC0k957ZYv8iuLanoM1YYIdToHeBwjyBJA836eIcq/ElY2QtKUq5PRw
|
||||
+sU1BdG+f9rf4iAPHpgWZAKFmJ42ya71bEEVAmfysAOPuc4hpn3SsDTtihm9RKc9
|
||||
l7LWJHaTnTu6yJA+vMJwAmPWg+IdG5vntbb93X4cgl5ZadBySRtv37wWyQPnQcFh
|
||||
ytX8z2CJNIFJb0ik8bXc39zOxExoTu/o86IuVJ87jFdS1wz3PRek6dJdl15icx76
|
||||
yAT0YB2/ZlRcRrO9hSm0D6P+sLOh//dyhhFAlUrDxqrKngI3KF4kgIrSlva3wmx2
|
||||
t16SiUKu6FGQZk6/KYOV27Cy+8UJEqlrNJzy+wSFi26d6e6xWTIR2ItzQCxhYDmq
|
||||
Tpx0Mh0ml2+bgrKRoDAL5z6UNy0Pc6bYQjvMznIeiuGvL8bAKTDUFwbmrZqNScsl
|
||||
tW7yNZG9iSJnAZGMTxuOhSvJRpQkxIcLICd+lsUxWZ2YvFxtSORuRNSwaC7oxtTD
|
||||
gIXV08ayoDbDmcguqTXWuCxtguxNANjhsUOetNHL8iP8QFrzAd5Ith9FgASCIBJJ
|
||||
3X7vL2YGc3E6DlAJE01loqySU/cnu6/zQapLB9BIzdtoLliwdrJ7PS8FSsBDfZ2X
|
||||
i6/7gb1jxYkJAS1NqrUMJw6BphRAwF8ny+FtPJ23Oaf+1vRIGiHsh8qw6XBfwFw9
|
||||
vtsUUL19r+8zMpvIB6gf34TLuM7AW7idu3c/486EWgZBDL3mOTd3fsyADKv/HCk7
|
||||
c8M2dsafxI6QkTlWsB8G5vkZ8lCGKHjrmPWjfD7NXi+CvXIrDY+gOeVN3PlQCU/2
|
||||
zF2vIxKtR0CXuxLzIjFhIgTYR5G5ZnddMmHeVkZdPRl7szGtrxOA4QGJQ6ZT4W2e
|
||||
O1whVU2KB0aBYskhClimapM5ypRkcNQ97cUR6/iNgdgSLqxGHCGeMR9bEyLl7/wr
|
||||
M0XeDjdVfm/Tj548oHgb0SKLsfL6nnKwqB2viKj81moK9A/wO1Ec9RNaw0jtp2j3
|
||||
VIUnPj0GqEjnkHc2jWY2yt4SD6e2AZHwLyWi1q3pixZo1CFiEgFXxwNyYwyeJ6jV
|
||||
CJHPRzoNjZ8dkvgRjsXdnWwN316JBNVcH8k7CCmg/8Gq3yAojXG1z8VJZ06GHckd
|
||||
meCL1t89OgwIAmIsysKu7+DrKtSlhkQclZmdG6IrQzuPKaHzTPTDgg3ef3jQ4YQO
|
||||
-----END RSA PRIVATE KEY-----
|
@ -0,0 +1,30 @@
|
||||
-----BEGIN RSA PRIVATE KEY-----
|
||||
Proc-Type: 4,ENCRYPTED
|
||||
DEK-Info: AES-192-CBC,B408346ADE790F8CF0C902A4F0712B34
|
||||
|
||||
SwzPBGxmwW2JddOyug1LrWjlZn8siSp5yezjK1x/z2+J2r/vvH8OjGnA387tFtae
|
||||
WVTmhT1ixQXMDI1UJuKx0gzrG2449c+BUVe2VXFPLZ2ocSgoXbBpVkfhEqtLAn91
|
||||
MSOpQMxvobQKltKhxgXGvuBJwhwfT7yK5HamohFGbxLUh4Dh+NBXwoYH4Qt+kM7C
|
||||
kV8VIKvkr/QAL/SRxNoY8rVResPgYvUjdtiGSNZ6CZhNRu42Q2FqbH817cE0NDsN
|
||||
il/xvWu4T/6VY1KpwMad/v6BhO45EeKz7YjbF/3Y5jj2JV9r45uf79lM9htMBw0d
|
||||
L+Cc3YHeFffgU8NZo0+iUoroXcb7mjWNmgYksbkaZPbLG383YXAXwbkQS7zDMVIx
|
||||
QhXn9w+78hNmEV/7PQ8mGXHEFwnfSR05phXoj8IyL5v0grRMA2dsjfxCgfQjH+kc
|
||||
Miwr5pD/Flw175OpPFCb2qladdTKoIWiVShspbteoRC0EuiWHzkl5z6Tneyb/sam
|
||||
yduLmSYD+RA6OBgUPY95Xm4AowlFFsuV/fxYZ53rFf4cZn9Z6VBVmvIEmapV7CtB
|
||||
JzyIVclocwM0ag5u/esdEt/jndJq9chZlIsDS30y3gP6Rlqk5mj90DAs98l28FVG
|
||||
WY9jP0babk8mxjYCcnAy7ikUc0D+vJVO6OTmfO3dkGjLpMBM6OlvfhN/0qeXrMDI
|
||||
nU2qOshUrVna2kRe6FrcvosFTD8wvQ1/BjmCp1iWWsGdc/q1BqI3pgOlgq3TYfl6
|
||||
iUJoji3V2iexH+GPkHsrs+kii1clsO2tgIP7doIooSVkcTsRTHHxKeeHn3qL2028
|
||||
pTvieIFD/T4biLZ9Q8sX3XWiHNmXZlCx8lX8MDjTavWES8gY4H5Sr6FjRMy1qpZY
|
||||
5w1aAyJ9YZ0J/jLPmFxt8mWgqHPiPlrQkryBBE3l1MSQ/hCEwlf9dP8a+ayINfd7
|
||||
3yNkHKjZ5fuoA+TZUQb/fyVM5o1zJ8ML01PaXWrMEgr3b36QL+Ivo2Rpnp9FpwuH
|
||||
E405cwCEy5fNSyhHFqqatCbsPl80nkP8OpW6jdWvNy9u0Ap9PS+MbHGq/pfkaazl
|
||||
fbKGOckrENzEXi6Uj/yY/0sMtbTJuC70n09X3edHyhl/RJPPUoNnwDM5W1FHfS3r
|
||||
qqSOl/r3y5pEErRdBpR4wEgB7DCLBALGDPfXNAAga4ez/Z2X9Zj234+4ZbUzWoLN
|
||||
1ER0QYyxLN7oz1qMA15J7nRyRIhDXNlXjyISOqy26T6/d4X0M+6RhNWfT/MHAjJ8
|
||||
6ogoGlQUITV3gPO4R6+FGZMF4R6zZXuKVtOXyzRwWnCLfo4gzBHmq+5mmCjGWRq8
|
||||
rSSkc6334bYuZOaEoR5EM5sh6ewkjSDPRrKR7EHO02YbiscyT/99TwT5pdIOPK3u
|
||||
2T6/40fSmCWQyBLuWxV9CMD+rB/q8Ja5KisEseck7PgI2pMmHfiD5yQXhKR9eDrB
|
||||
sRqZxjgRYxup+/0CIBshL8s1R88xelhXyIKyqFfVudM09yAZxEJLQhpDZ27g45ea
|
||||
FMX2Ve+ah2NjYBgzAhwKouWg5RyWb6X99NsrCEU75fn/ek86LGs3FxRgB4Uv7Udv
|
||||
-----END RSA PRIVATE KEY-----
|
@ -0,0 +1,30 @@
|
||||
-----BEGIN RSA PRIVATE KEY-----
|
||||
Proc-Type: 4,ENCRYPTED
|
||||
DEK-Info: AES-256-CBC,0F2F4695C8FFA35F4076FA0273A3A4E3
|
||||
|
||||
GCnMcAhhGuNkJ7SSMBrgNOaDfRtG22J0mdf/0VbrMOJF40P13YBjN3Kd6LpTqBya
|
||||
TCIaxQqtfjH1ffhJk8qhwG7uJFGgcY9i0dkrEYklgThzTVqHp7FsQ2jjgJs5HKpc
|
||||
euuVD1bxtuc9qI2hq4miA7Z/uDe3M34n+3xcpqccWS1dLFNFZ+fIDwIazfDCu3ah
|
||||
fUQHDeWLwOqYiQxhUjjrHpZkI1FE2JYZFaf4zIagIIgzI2O+33fgbrTSoeN5meRs
|
||||
F7V2fhDpyEoIlchwAmp6HE6ngtKP4Ecju00yn99AO42fn097yEVwvGFClQTaIzur
|
||||
aPEtuKZ4kdc/lmzL2tqNcZckq28ZxpeMq0Fgdcpeg5sDcut811scOjQLFs551On1
|
||||
j3E1WfiLoBLKgd9cgmCrZb8hMO+UjcCaV7Jv3T9vDrbvhWs/YhTTwo8UFVplh7Vx
|
||||
R1h3cKfzlbtOC5WHXGNK5dBu7SnpEk0+pscY5cxTrzN0odjMbbsjZQmKDZXbmZON
|
||||
USzG3Qtafm6Nw/jwQeIjeqaxSho6xGdadTteGaURw6iGio3h0c6/dHayCsxye4tk
|
||||
vODa0ZdJASwVh1605qDk9n/iYUT5B46KJCYwO/iN2kUmOcUcZeBqEfV1GfRmepZJ
|
||||
bwM4sipzE15hOJ5DKSkHWnSlByRMAdSrMxZWraKUczn5frEBAqEFLlBAvf/FnjWa
|
||||
yZJitgryCI2Y2bww1DEMnTCX345kUQIFmmjbzTIXnM28gW+fR3Br9dCf2FAsLNKr
|
||||
tru1cYXocPaCUHEqS+XZqVb6BQVQ11YAAde0+x9RknJgsBc9Y7TLobaDBvrV5/nK
|
||||
T3vm8el08upum6qPTPh6Z0zBbjx4sp6DYT977N1dYeH4n+0JqcSwIeZg/VAdG0RL
|
||||
GzgZVADpiRlStmy65W95KExBjbO0tRTVk/nB1U1nfLbsswp9EKxXgwtpE/ECeTOi
|
||||
hzeJBSsXGZ/ZXu/y+NlIu0B/GasFbfrHKslSSrUPTjGEtaEbLNiOEu2Etu3lRcMZ
|
||||
oDtMxgNR0TUgCS5nte8lLauYYfB6IuxZXpvJdcI5ushqdOJvvYgJ9Yb2ZPlY8Bt5
|
||||
C92Ga69aPcMYk24BPpe15eBbXMsFF8RF+CprVoUPCc+PcuROtxdt+rqoqjQeZPmV
|
||||
WQqq+pT2bychpwD7U5jxQnu4u2m+zeBXyk80euBbwEld9BCgfk9mFj6CdBJSEiGV
|
||||
qL0ivxd3mDaIKPGd5tcbrOMK2uD7duZY7FrQpAYgryoQJoUHccL7cr9fDC75akHg
|
||||
AbrG1+vAYEla/y+SlOg5VTHhiuIl17ZGMViXSqh7iqnnD0dNsZ/HDvk3XouhNxQy
|
||||
RQmfdqyIqLuAcfWwQxCQ2E/oMUIHjNhyYmfLVLVGsfxuevMa1eJv7rZ5vIkD2Vpe
|
||||
4VveZkNDSpCCNqnvub8+bMW+UXyzbxEZbK5PLkRp7cvtKdA5CUbTlT4060IV0YZ1
|
||||
vfMtzXRw8JDD9c1F1WF14afk+y9kvZN88XOH12bSKj+Re06Xx7OzuYU8fclq/pZB
|
||||
UZVtRETFnLgb8neMuz3vCoPWK/DSHDZGAAicxq7vTljyoU/QP71Dw7UJIAuYx6Mc
|
||||
-----END RSA PRIVATE KEY-----
|
@ -466,15 +466,25 @@ void tst_QSslKey::toEncryptedPemOrDer()
|
||||
void tst_QSslKey::passphraseChecks_data()
|
||||
{
|
||||
QTest::addColumn<QString>("fileName");
|
||||
QTest::addColumn<QByteArray>("passphrase");
|
||||
|
||||
QTest::newRow("DES") << (testDataDir + "rsa-with-passphrase-des.pem");
|
||||
QTest::newRow("3DES") << (testDataDir + "rsa-with-passphrase-3des.pem");
|
||||
QTest::newRow("RC2") << (testDataDir + "rsa-with-passphrase-rc2.pem");
|
||||
const QByteArray pass("123");
|
||||
const QByteArray aesPass("1234");
|
||||
|
||||
QTest::newRow("DES") << QString(testDataDir + "rsa-with-passphrase-des.pem") << pass;
|
||||
QTest::newRow("3DES") << QString(testDataDir + "rsa-with-passphrase-3des.pem") << pass;
|
||||
QTest::newRow("RC2") << QString(testDataDir + "rsa-with-passphrase-rc2.pem") << pass;
|
||||
#if (!defined(QT_NO_OPENSSL) && !defined(OPENSSL_NO_AES)) || defined(QT_SECURETRANSPORT)
|
||||
QTest::newRow("AES128") << QString(testDataDir + "rsa-with-passphrase-aes128.pem") << aesPass;
|
||||
QTest::newRow("AES192") << QString(testDataDir + "rsa-with-passphrase-aes192.pem") << aesPass;
|
||||
QTest::newRow("AES256") << QString(testDataDir + "rsa-with-passphrase-aes256.pem") << aesPass;
|
||||
#endif
|
||||
}
|
||||
|
||||
void tst_QSslKey::passphraseChecks()
|
||||
{
|
||||
QFETCH(QString, fileName);
|
||||
QFETCH(QByteArray, passphrase);
|
||||
|
||||
QFile keyFile(fileName);
|
||||
QVERIFY(keyFile.exists());
|
||||
@ -507,7 +517,7 @@ void tst_QSslKey::passphraseChecks()
|
||||
keyFile.open(QIODevice::ReadOnly);
|
||||
else
|
||||
keyFile.reset();
|
||||
QSslKey key(&keyFile,QSsl::Rsa,QSsl::Pem, QSsl::PrivateKey, "123");
|
||||
QSslKey key(&keyFile,QSsl::Rsa,QSsl::Pem, QSsl::PrivateKey, passphrase);
|
||||
QVERIFY(!key.isNull()); // correct passphrase
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user