Vidalia 0.2.12
|
00001 /* 00002 ** This file is part of Vidalia, and is subject to the license terms in the 00003 ** LICENSE file, found in the top level directory of this distribution. If you 00004 ** did not receive the LICENSE file with this file, you may obtain it from the 00005 ** Vidalia source package distributed by the Vidalia Project at 00006 ** http://www.vidalia-project.net/. No part of Vidalia, including this file, 00007 ** may be copied, modified, propagated, or distributed except according to the 00008 ** terms described in the LICENSE file. 00009 ** 00010 ** * * * 00011 ** 00012 ** Pseudorandom number generation support in this file is derived from 00013 ** Tor's crypto.[ch]. Tor is distributed under this license. 00014 ** 00015 ** Copyright (c) 2001-2004, Roger Dingledine 00016 ** Copyright (c) 2004-2007, Roger Dingledine, Nick Mathewson 00017 ** 00018 ** Redistribution and use in source and binary forms, with or without 00019 ** modification, are permitted provided that the following conditions are 00020 ** met: 00021 ** 00022 ** * Redistributions of source code must retain the above copyright 00023 ** notice, this list of conditions and the following disclaimer. 00024 ** 00025 ** * Redistributions in binary form must reproduce the above 00026 ** copyright notice, this list of conditions and the following disclaimer 00027 ** in the documentation and/or other materials provided with the 00028 ** distribution. 00029 ** 00030 ** * Neither the names of the copyright owners nor the names of its 00031 ** contributors may be used to endorse or promote products derived from 00032 ** this software without specific prior written permission. 00033 ** 00034 ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 00035 ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 00036 ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 00037 ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 00038 ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 00039 ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 00040 ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 00041 ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 00042 ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 00043 ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 00044 ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 00045 */ 00046 00047 /* 00048 ** \file crypto.cpp 00049 ** \brief Provides support for pseuodrandom number generation. 00050 */ 00051 00052 #include "crypto.h" 00053 00054 #include <QFile> 00055 #include <QStringList> 00056 #include <QCryptographicHash> 00057 #include <QtDebug> 00058 00059 #if defined(Q_OS_WIN32) 00060 #include <windows.h> 00061 #include <wincrypt.h> 00062 #endif 00063 00064 00065 /** Returns up to <b>len</b> bytes of pseudorandom data on success, or an empty 00066 * QByteArray on failure. The caller should verify that the returned 00067 * QByteArray contains the requested number of bytes. This function is based on 00068 * crypto_seed_rng() from Tor's crypto.c. See LICENSE for details on Tor's 00069 * license. */ 00070 QByteArray 00071 crypto_rand_bytes(int len) 00072 { 00073 QByteArray buf(len, 0); 00074 #if defined(Q_OS_WIN32) 00075 static int provider_set = 0; 00076 static HCRYPTPROV provider; 00077 #else 00078 static QStringList filenames = 00079 QStringList() << "/dev/srandom" << "/dev/urandom" << "/dev/random"; 00080 #endif 00081 Q_ASSERT(len > 0); 00082 00083 #if defined(Q_OS_WIN32) 00084 if (!provider_set) { 00085 if (!CryptAcquireContext(&provider, NULL, NULL, PROV_RSA_FULL, 00086 CRYPT_VERIFYCONTEXT)) { 00087 if ((unsigned long)GetLastError() != (unsigned long)NTE_BAD_KEYSET) { 00088 qWarning("Can't get CryptoAPI provider."); 00089 return QByteArray(); 00090 } 00091 } 00092 provider_set = 1; 00093 } 00094 if (!CryptGenRandom(provider, buf.size(), (BYTE *)buf.data())) { 00095 qWarning("Can't get entropy from CryptoAPI."); 00096 return QByteArray(); 00097 } 00098 return buf; 00099 #else 00100 foreach (QString fname, filenames) { 00101 QFile file(fname); 00102 if (!file.open(QIODevice::ReadOnly)) 00103 continue; 00104 00105 qint64 bytes_read; 00106 qint64 total = 0; 00107 while (total < buf.size()) { 00108 bytes_read = file.read(buf.data()+total, buf.size()-total); 00109 if (bytes_read < 0) 00110 return QByteArray(); 00111 else if (bytes_read == 0) { 00112 buf.resize(total); 00113 return buf; 00114 } 00115 total += bytes_read; 00116 } 00117 return buf; 00118 } 00119 qWarning("Can't read from /dev/*random."); 00120 return QByteArray(); 00121 #endif 00122 } 00123 00124 /** Returns a pseudorandom integer, chosen uniformly from the the values in 00125 * the range [0, max). This function is based on crypto_rand_int() from Tor's 00126 * crypto.c. See LICENSE for details on Tor's license. */ 00127 quint32 00128 crypto_rand_quint32(quint32 max) 00129 { 00130 QByteArray buf; 00131 quint32 val; 00132 quint32 cutoff; 00133 Q_ASSERT(max > 0); 00134 00135 cutoff = 0xffffffffu - (0xffffffffu % max); 00136 forever { 00137 buf = crypto_rand_bytes(sizeof(quint32)); 00138 Q_ASSERT(buf.size() == sizeof(quint32)); 00139 00140 val = *((quint32 *)buf.constData()); 00141 if (val < cutoff) 00142 break; 00143 } 00144 return (val % max); 00145 } 00146 00147 /** Generates a pseudorandom string of length <b>len</b> containing printable 00148 * ASCII characters from the range '!' (0x21) to '~' (0x7e). */ 00149 QString 00150 crypto_rand_string(int len) 00151 { 00152 QString str; 00153 Q_ASSERT(len >= 0); 00154 00155 for (int i = 0; i < len; i++) 00156 str += QChar('!' + crypto_rand_quint32('~'-'!'+1)); 00157 return str; 00158 } 00159 00160 /** Generates a salted hash of <b>secret</b> using the random <b>salt</b> 00161 * according to the iterated and salted S2K algorithm in RFC 2440. <b>c</b> 00162 * is the one-octet coded count value that specifies how much data to hash. 00163 * <b>salt</b> must contain at least 8 bytes, otherwise this method will 00164 * return a default-constructed QByteArray. */ 00165 QByteArray 00166 crypto_secret_to_key(const QString &secret, const QByteArray &salt, quint8 c) 00167 { 00168 if (salt.size() < 8) 00169 return QByteArray(); 00170 00171 #define EXPBIAS 6 00172 int count = ((quint32)16 + (c & 15)) << ((c >> 4) + EXPBIAS); 00173 #undef EXPBIAS 00174 00175 QCryptographicHash hash(QCryptographicHash::Sha1); 00176 QByteArray tmp = salt.left(8).append(secret.toAscii()); 00177 while (count) { 00178 if (count > tmp.length()) { 00179 hash.addData(tmp); 00180 count -= tmp.length(); 00181 } else { 00182 hash.addData(tmp.left(count)); 00183 count = 0; 00184 } 00185 } 00186 00187 return hash.result(); 00188 } 00189