summaryrefslogtreecommitdiffstats
path: root/src/network/ssl/qsslkey_qt.cpp
diff options
context:
space:
mode:
authorJeremy Lainé <jeremy.laine@m4x.org>2014-08-31 14:55:06 +0300
committerRichard J. Moore <rich@kde.org>2014-09-02 23:16:25 +0200
commitcd3dece750aa30b15091f211a72b6fcf67d49853 (patch)
tree36594c8282b07fde103d893da48a94201d67a8c5 /src/network/ssl/qsslkey_qt.cpp
parentb17365cda91a6ecc8d12e995d83f4ff479c59b5f (diff)
ssl: common key parser support for encrypted keys
This adds the infrastructure for reading and writing encrypted private keys when using non-OpenSSL backends. Each platform must provide its cryptographic encrypt / decrypt functions. As WinRT already uses the common parser, this commit includes an implementation for that platform. Done-with: Andrew Knight <andrew.knight@digia.com> Task-number: QTBUG-40688 Change-Id: I0d153425ce63601ff03b784a111e13962061025f Reviewed-by: Richard J. Moore <rich@kde.org>
Diffstat (limited to 'src/network/ssl/qsslkey_qt.cpp')
-rw-r--r--src/network/ssl/qsslkey_qt.cpp78
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