crypto.cpp
Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053 #include "crypto.h"
00054
00055 #include <QFile>
00056 #include <QStringList>
00057 #include <QCryptographicHash>
00058 #include <QtDebug>
00059
00060 #if defined(Q_OS_WIN32)
00061 #include <windows.h>
00062 #include <wincrypt.h>
00063 #endif
00064
00065
00066
00067
00068
00069
00070
00071 QByteArray
00072 crypto_rand_bytes(int len)
00073 {
00074 QByteArray buf(len, 0);
00075 #if defined(Q_OS_WIN32)
00076 static int provider_set = 0;
00077 static HCRYPTPROV provider;
00078 #else
00079 static QStringList filenames =
00080 QStringList() << "/dev/srandom" << "/dev/urandom" << "/dev/random";
00081 #endif
00082 Q_ASSERT(len > 0);
00083
00084 #if defined(Q_OS_WIN32)
00085 if (!provider_set) {
00086 if (!CryptAcquireContext(&provider, NULL, NULL, PROV_RSA_FULL,
00087 CRYPT_VERIFYCONTEXT)) {
00088 if ((unsigned long)GetLastError() != (unsigned long)NTE_BAD_KEYSET) {
00089 qWarning("Can't get CryptoAPI provider.");
00090 return QByteArray();
00091 }
00092 }
00093 provider_set = 1;
00094 }
00095 if (!CryptGenRandom(provider, buf.size(), (BYTE *)buf.data())) {
00096 qWarning("Can't get entropy from CryptoAPI.");
00097 return QByteArray();
00098 }
00099 return buf;
00100 #else
00101 foreach (QString fname, filenames) {
00102 QFile file(fname);
00103 if (!file.open(QIODevice::ReadOnly))
00104 continue;
00105
00106 qint64 bytes_read;
00107 qint64 total = 0;
00108 while (total < buf.size()) {
00109 bytes_read = file.read(buf.data()+total, buf.size()-total);
00110 if (bytes_read < 0)
00111 return QByteArray();
00112 else if (bytes_read == 0) {
00113 buf.resize(total);
00114 return buf;
00115 }
00116 total += bytes_read;
00117 }
00118 return buf;
00119 }
00120 qWarning("Can't read from /dev/*random.");
00121 return QByteArray();
00122 #endif
00123 }
00124
00125
00126
00127
00128 quint32
00129 crypto_rand_quint32(quint32 max)
00130 {
00131 QByteArray buf;
00132 quint32 val;
00133 quint32 cutoff;
00134 Q_ASSERT(max > 0);
00135
00136 cutoff = 0xffffffffu - (0xffffffffu % max);
00137 forever {
00138 buf = crypto_rand_bytes(sizeof(quint32));
00139 Q_ASSERT(buf.size() == sizeof(quint32));
00140
00141 val = *((quint32 *)buf.constData());
00142 if (val < cutoff)
00143 break;
00144 }
00145 return (val % max);
00146 }
00147
00148
00149
00150 QString
00151 crypto_rand_string(int len)
00152 {
00153 QString str;
00154 Q_ASSERT(len >= 0);
00155
00156 for (int i = 0; i < len; i++)
00157 str += QChar('!' + crypto_rand_quint32('~'-'!'+1));
00158 return str;
00159 }
00160
00161
00162
00163
00164
00165
00166 QByteArray
00167 crypto_secret_to_key(const QString &secret, const QByteArray &salt, quint8 c)
00168 {
00169 if (salt.size() < 8)
00170 return QByteArray();
00171
00172 #define EXPBIAS 6
00173 int count = ((quint32)16 + (c & 15)) << ((c >> 4) + EXPBIAS);
00174 #undef EXPBIAS
00175
00176 QCryptographicHash hash(QCryptographicHash::Sha1);
00177 QByteArray tmp = salt.left(8).append(secret.toAscii());
00178 while (count) {
00179 if (count > tmp.length()) {
00180 hash.addData(tmp);
00181 count -= tmp.length();
00182 } else {
00183 hash.addData(tmp.left(count));
00184 count = 0;
00185 }
00186 }
00187
00188 return hash.result();
00189 }
00190