Vidalia  0.3.1
crypto.cpp
Go to the documentation of this file.
1 /*
2 ** This file is part of Vidalia, and is subject to the license terms in the
3 ** LICENSE file, found in the top level directory of this distribution. If you
4 ** did not receive the LICENSE file with this file, you may obtain it from the
5 ** Vidalia source package distributed by the Vidalia Project at
6 ** http://www.torproject.org/projects/vidalia.html. No part of Vidalia,
7 ** including this file, may be copied, modified, propagated, or distributed
8 ** except according to the terms described in the LICENSE file.
9 **
10 ** * * *
11 **
12 ** Pseudorandom number generation support in this file is derived from
13 ** Tor's crypto.[ch]. Tor is distributed under this license.
14 **
15 ** Copyright (c) 2001-2004, Roger Dingledine
16 ** Copyright (c) 2004-2007, Roger Dingledine, Nick Mathewson
17 **
18 ** Redistribution and use in source and binary forms, with or without
19 ** modification, are permitted provided that the following conditions are
20 ** met:
21 **
22 ** * Redistributions of source code must retain the above copyright
23 ** notice, this list of conditions and the following disclaimer.
24 **
25 ** * Redistributions in binary form must reproduce the above
26 ** copyright notice, this list of conditions and the following disclaimer
27 ** in the documentation and/or other materials provided with the
28 ** distribution.
29 **
30 ** * Neither the names of the copyright owners nor the names of its
31 ** contributors may be used to endorse or promote products derived from
32 ** this software without specific prior written permission.
33 **
34 ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
35 ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
36 ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
37 ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
38 ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
39 ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
40 ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
41 ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
42 ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
43 ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
44 ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
45 */
46 
47 /*
48 ** \file crypto.cpp
49 ** \brief Provides support for pseuodrandom number generation.
50 */
51 
52 #include "crypto.h"
53 
54 #include <QFile>
55 #include <QStringList>
56 #include <QCryptographicHash>
57 #include <QtDebug>
58 
59 #if defined(Q_OS_WIN32)
60 #include <windows.h>
61 #include <wincrypt.h>
62 #endif
63 
64 
65 /** Returns up to <b>len</b> bytes of pseudorandom data on success, or an empty
66  * QByteArray on failure. The caller should verify that the returned
67  * QByteArray contains the requested number of bytes. This function is based on
68  * crypto_seed_rng() from Tor's crypto.c. See LICENSE for details on Tor's
69  * license. */
70 QByteArray
72 {
73  QByteArray buf(len, 0);
74 #if defined(Q_OS_WIN32)
75  static int provider_set = 0;
76  static HCRYPTPROV provider;
77 #else
78  static QStringList filenames =
79  QStringList() << "/dev/srandom" << "/dev/urandom" << "/dev/random";
80 #endif
81  Q_ASSERT(len > 0);
82 
83 #if defined(Q_OS_WIN32)
84  if (!provider_set) {
85  if (!CryptAcquireContext(&provider, NULL, NULL, PROV_RSA_FULL,
86  CRYPT_VERIFYCONTEXT)) {
87  if ((unsigned long)GetLastError() != (unsigned long)NTE_BAD_KEYSET) {
88  qWarning("Can't get CryptoAPI provider.");
89  return QByteArray();
90  }
91  }
92  provider_set = 1;
93  }
94  if (!CryptGenRandom(provider, buf.size(), (BYTE *)buf.data())) {
95  qWarning("Can't get entropy from CryptoAPI.");
96  return QByteArray();
97  }
98  return buf;
99 #else
100  foreach (QString fname, filenames) {
101  QFile file(fname);
102  if (!file.open(QIODevice::ReadOnly))
103  continue;
104 
105  qint64 bytes_read;
106  qint64 total = 0;
107  while (total < buf.size()) {
108  bytes_read = file.read(buf.data()+total, buf.size()-total);
109  if (bytes_read < 0)
110  return QByteArray();
111  else if (bytes_read == 0) {
112  buf.resize(total);
113  return buf;
114  }
115  total += bytes_read;
116  }
117  return buf;
118  }
119  qWarning("Can't read from /dev/*random.");
120  return QByteArray();
121 #endif
122 }
123 
124 /** Returns a pseudorandom integer, chosen uniformly from the the values in
125  * the range [0, max). This function is based on crypto_rand_int() from Tor's
126  * crypto.c. See LICENSE for details on Tor's license. */
127 quint32
129 {
130  QByteArray buf;
131  quint32 val;
132  quint32 cutoff;
133  Q_ASSERT(max > 0);
134 
135  cutoff = 0xffffffffu - (0xffffffffu % max);
136  forever {
137  buf = crypto_rand_bytes(sizeof(quint32));
138  Q_ASSERT(buf.size() == sizeof(quint32));
139 
140  val = *((quint32 *)buf.constData());
141  if (val < cutoff)
142  break;
143  }
144  return (val % max);
145 }
146 
147 /** Generates a pseudorandom string of length <b>len</b> containing printable
148  * ASCII characters from the range '!' (0x21) to '~' (0x7e). */
149 QString
151 {
152  QString str;
153  Q_ASSERT(len >= 0);
154 
155  for (int i = 0; i < len; i++)
156  str += QChar('!' + crypto_rand_quint32('~'-'!'+1));
157  return str;
158 }
159 
160 /** Generates a salted hash of <b>secret</b> using the random <b>salt</b>
161  * according to the iterated and salted S2K algorithm in RFC 2440. <b>c</b>
162  * is the one-octet coded count value that specifies how much data to hash.
163  * <b>salt</b> must contain at least 8 bytes, otherwise this method will
164  * return a default-constructed QByteArray. */
165 QByteArray
166 crypto_secret_to_key(const QString &secret, const QByteArray &salt, quint8 c)
167 {
168  if (salt.size() < 8)
169  return QByteArray();
170 
171 #define EXPBIAS 6
172  int count = ((quint32)16 + (c & 15)) << ((c >> 4) + EXPBIAS);
173 #undef EXPBIAS
174 
175  QCryptographicHash hash(QCryptographicHash::Sha1);
176  QByteArray tmp = salt.left(8).append(secret.toAscii());
177  while (count) {
178  if (count > tmp.length()) {
179  hash.addData(tmp);
180  count -= tmp.length();
181  } else {
182  hash.addData(tmp.left(count));
183  count = 0;
184  }
185  }
186 
187  return hash.result();
188 }
189 
#define EXPBIAS
QByteArray crypto_rand_bytes(int len)
Definition: crypto.cpp:71
quint32 crypto_rand_quint32(quint32 max)
Definition: crypto.cpp:128
QString i(QString str)
Definition: html.cpp:32
QString crypto_rand_string(int len)
Definition: crypto.cpp:150
QByteArray crypto_secret_to_key(const QString &secret, const QByteArray &salt, quint8 c)
Definition: crypto.cpp:166