00001 /**************************************************************** 00002 * Vidalia is distributed under the following license: 00003 * 00004 * Copyright (C) 2007, Matt Edman, Justin Hipple 00005 * 00006 * This program is free software; you can redistribute it and/or 00007 * modify it under the terms of the GNU General Public License 00008 * as published by the Free Software Foundation; either version 2 00009 * of the License, or (at your option) any later version. 00010 * 00011 * This program is distributed in the hope that it will be useful, 00012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00014 * GNU General Public License for more details. 00015 * 00016 * You should have received a copy of the GNU General Public License 00017 * along with this program; if not, write to the Free Software 00018 * Foundation, Inc., 51 Franklin Street, Fifth Floor, 00019 * Boston, MA 02110-1301, USA. 00020 * 00021 * * * * 00022 * 00023 * Pseudorandom number generation support in this file is derived from 00024 * Tor's crypto.[ch]. Tor is distributed under this license. 00025 * 00026 * Copyright (c) 2001-2004, Roger Dingledine 00027 * Copyright (c) 2004-2007, Roger Dingledine, Nick Mathewson 00028 * 00029 * Redistribution and use in source and binary forms, with or without 00030 * modification, are permitted provided that the following conditions are 00031 * met: 00032 * 00033 * * Redistributions of source code must retain the above copyright 00034 * notice, this list of conditions and the following disclaimer. 00035 * 00036 * * Redistributions in binary form must reproduce the above 00037 * copyright notice, this list of conditions and the following disclaimer 00038 * in the documentation and/or other materials provided with the 00039 * distribution. 00040 * 00041 * * Neither the names of the copyright owners nor the names of its 00042 * contributors may be used to endorse or promote products derived from 00043 * this software without specific prior written permission. 00044 * 00045 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 00046 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 00047 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 00048 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 00049 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 00050 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 00051 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 00052 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 00053 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 00054 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 00055 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 00056 ****************************************************************/ 00057 00058 /** 00059 * \file crypto.cpp 00060 * \version $Id: crypto.cpp 1847 2007-08-21 05:38:31Z edmanm $ 00061 * \brief Provides support for pseuodrandom number generation. 00062 */ 00063 00064 #include <QFile> 00065 #include <QStringList> 00066 #include <QtDebug> 00067 #include "crypto.h" 00068 00069 #if defined(Q_OS_WIN32) 00070 #include <windows.h> 00071 #include <wincrypt.h> 00072 #endif 00073 00074 00075 /** Returns <b>len</b> bytes of pseudorandom data on success, or an empty 00076 * QByteArray on failure. This function is based on crypto_seed_rng() from 00077 * Tor's crypto.c. See LICENSE for details on Tor's license. */ 00078 QByteArray 00079 crypto_rand_bytes(int len) 00080 { 00081 QByteArray buf(len, 0); 00082 #if defined(Q_OS_WIN32) 00083 static int provider_set = 0; 00084 static HCRYPTPROV provider; 00085 #else 00086 static QStringList filenames = 00087 QStringList() << "/dev/srandom" << "/dev/urandom" << "/dev/random"; 00088 #endif 00089 Q_ASSERT(len > 0); 00090 00091 #if defined(Q_OS_WIN32) 00092 if (!provider_set) { 00093 if (!CryptAcquireContext(&provider, NULL, NULL, PROV_RSA_FULL, 00094 CRYPT_VERIFYCONTEXT)) { 00095 if ((unsigned long)GetLastError() != (unsigned long)NTE_BAD_KEYSET) { 00096 qWarning("Can't get CryptoAPI provider."); 00097 return QByteArray(); 00098 } 00099 } 00100 provider_set = 1; 00101 } 00102 if (!CryptGenRandom(provider, buf.size(), (BYTE *)buf.data())) { 00103 qWarning("Can't get entropy from CryptoAPI."); 00104 return QByteArray(); 00105 } 00106 return buf; 00107 #else 00108 foreach (QString fname, filenames) { 00109 QFile file(fname); 00110 if (!file.open(QIODevice::ReadOnly)) 00111 continue; 00112 00113 qint64 bytes_read; 00114 qint64 total = 0; 00115 while (total < buf.size()) { 00116 bytes_read = file.read(buf.data()+total, buf.size()-total); 00117 if (bytes_read < 0) 00118 return QByteArray(); 00119 else if (read == 0) { 00120 buf.resize(total); 00121 return buf; 00122 } 00123 total += bytes_read; 00124 } 00125 return buf; 00126 } 00127 qWarning("Can't read from /dev/*random."); 00128 return QByteArray(); 00129 #endif 00130 } 00131 00132 /** Returns a pseudorandom integer, chosen uniformly from the the values in 00133 * the range [0, max). This function is based on crypto_rand_int() from Tor's 00134 * crypto.c. See LICENSE for details on Tor's license. */ 00135 quint32 00136 crypto_rand_quint32(quint32 max) 00137 { 00138 QByteArray buf; 00139 quint32 val; 00140 quint32 cutoff; 00141 Q_ASSERT(max > 0); 00142 00143 cutoff = UINT_MAX - (UINT_MAX % max); 00144 forever { 00145 buf = crypto_rand_bytes(sizeof(quint32)); 00146 Q_ASSERT(buf.size() == sizeof(quint32)); 00147 00148 val = *((quint32 *)buf.constData()); 00149 if (val < cutoff) 00150 break; 00151 } 00152 return (val % max); 00153 } 00154 00155 /** Generates a pseudorandom string of length <b>len</b> containing printable 00156 * ASCII characters of length from the range '!' (0x21) to '~' (0x7e). */ 00157 QString 00158 crypto_rand_string(int len) 00159 { 00160 QString str; 00161 Q_ASSERT(len >= 0); 00162 00163 for (int i = 0; i < len; i++) 00164 str += QChar('!' + crypto_rand_quint32('~'-'!'+1)); 00165 return str; 00166 } 00167