diff options
Diffstat (limited to 'src/network/ssl/qsslkey_qt.cpp')
-rw-r--r-- | src/network/ssl/qsslkey_qt.cpp | 78 |
1 files changed, 70 insertions, 8 deletions
diff --git a/src/network/ssl/qsslkey_qt.cpp b/src/network/ssl/qsslkey_qt.cpp index feeb7d6f87..c14cf0250c 100644 --- a/src/network/ssl/qsslkey_qt.cpp +++ b/src/network/ssl/qsslkey_qt.cpp @@ -43,6 +43,8 @@ #include "qsslkey_p.h" #include "qasn1element_p.h" +#include <QtCore/qcryptographichash.h> + QT_USE_NAMESPACE static const quint8 bits_table[256] = { @@ -78,6 +80,31 @@ static int numberOfBits(const QByteArray &modulus) return bits; } +static QByteArray deriveKey(QSslKeyPrivate::Cipher cipher, const QByteArray &passPhrase, const QByteArray &iv) +{ + QByteArray key; + QCryptographicHash hash(QCryptographicHash::Md5); + hash.addData(passPhrase); + hash.addData(iv); + switch (cipher) { + case QSslKeyPrivate::DesCbc: + key = hash.result().left(8); + break; + case QSslKeyPrivate::DesEde3Cbc: + key = hash.result(); + hash.reset(); + hash.addData(key); + hash.addData(passPhrase); + hash.addData(iv); + key += hash.result().left(8); + break; + case QSslKeyPrivate::Rc2Cbc: + key = hash.result(); + break; + } + return key; +} + void QSslKeyPrivate::clear(bool deep) { Q_UNUSED(deep); @@ -155,12 +182,32 @@ void QSslKeyPrivate::decodeDer(const QByteArray &der, bool deepClear) void QSslKeyPrivate::decodePem(const QByteArray &pem, const QByteArray &passPhrase, bool deepClear) { - if (type == QSsl::PrivateKey && !passPhrase.isEmpty()) { - Q_UNIMPLEMENTED(); - return; - } + QMap<QByteArray, QByteArray> headers; + QByteArray data = derFromPem(pem, &headers); + if (headers.value("Proc-Type") == "4,ENCRYPTED") { + QList<QByteArray> dekInfo = headers.value("DEK-Info").split(','); + if (dekInfo.size() != 2) { + clear(deepClear); + return; + } + + Cipher cipher; + if (dekInfo.first() == "DES-CBC") { + cipher = DesCbc; + } else if (dekInfo.first() == "DES-EDE3-CBC") { + cipher = DesEde3Cbc; + } else if (dekInfo.first() == "RC2-CBC") { + cipher = Rc2Cbc; + } else { + clear(deepClear); + return; + } - decodeDer(derFromPem(pem), deepClear); + const QByteArray iv = QByteArray::fromHex(dekInfo.last()); + const QByteArray key = deriveKey(cipher, passPhrase, iv); + data = decrypt(cipher, data, key, iv); + } + decodeDer(data, deepClear); } int QSslKeyPrivate::length() const @@ -170,12 +217,27 @@ int QSslKeyPrivate::length() const QByteArray QSslKeyPrivate::toPem(const QByteArray &passPhrase) const { + QByteArray data; + QMap<QByteArray, QByteArray> headers; + if (type == QSsl::PrivateKey && !passPhrase.isEmpty()) { - Q_UNIMPLEMENTED(); - return QByteArray(); + // ### use a cryptographically secure random number generator + QByteArray iv; + iv.resize(8); + for (int i = 0; i < iv.size(); ++i) + iv[i] = (qrand() & 0xff); + + Cipher cipher = DesEde3Cbc; + const QByteArray key = deriveKey(cipher, passPhrase, iv); + data = encrypt(cipher, derData, key, iv); + + headers.insert("Proc-Type", "4,ENCRYPTED"); + headers.insert("DEK-Info", "DES-EDE3-CBC," + iv.toHex()); + } else { + data = derData; } - return pemFromDer(derData); + return pemFromDer(data, headers); } Qt::HANDLE QSslKeyPrivate::handle() const |