Vidalia 0.2.10
|
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 ** \version $Id: crypto.cpp 3818 2009-06-06 17:46:49Z edmanm $ 00050 ** \brief Provides support for pseuodrandom number generation. 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 /** Returns up to <b>len</b> bytes of pseudorandom data on success, or an empty 00067 * QByteArray on failure. The caller should verify that the returned 00068 * QByteArray contains the requested number of bytes. This function is based on 00069 * crypto_seed_rng() from Tor's crypto.c. See LICENSE for details on Tor's 00070 * license. */ 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 /** Returns a pseudorandom integer, chosen uniformly from the the values in 00126 * the range [0, max). This function is based on crypto_rand_int() from Tor's 00127 * crypto.c. See LICENSE for details on Tor's license. */ 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 /** Generates a pseudorandom string of length <b>len</b> containing printable 00149 * ASCII characters from the range '!' (0x21) to '~' (0x7e). */ 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 /** Generates a salted hash of <b>secret</b> using the random <b>salt</b> 00162 * according to the iterated and salted S2K algorithm in RFC 2440. <b>c</b> 00163 * is the one-octet coded count value that specifies how much data to hash. 00164 * <b>salt</b> must contain at least 8 bytes, otherwise this method will 00165 * return a default-constructed QByteArray. */ 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