crypto.cpp

Go to the documentation of this file.
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 
Generated on Mon Aug 30 22:58:54 2010 for Vidalia by  doxygen 1.6.3