Initial commit
[keepassx] / src / lib / random.cpp
1 /***************************************************************************
2  *   Copyright (C) 2005 by Tarek Saidi                                     *
3  *   mail@tarek-saidi.de                                                   *
4  *                                                                         *
5  *   This program is free software; you can redistribute it and/or modify  *
6  *   it under the terms of the GNU General Public License as published by  *
7  *   the Free Software Foundation; version 2 of the License.               *
8
9  *                                                                         *
10  *   This program is distributed in the hope that it will be useful,       *
11  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
12  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
13  *   GNU General Public License for more details.                          *
14  *                                                                         *
15  *   You should have received a copy of the GNU General Public License     *
16  *   along with this program; if not, write to the                         *
17  *   Free Software Foundation, Inc.,                                       *
18  *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
19  ***************************************************************************/
20
21 #include "random.h"
22
23
24 #if defined(Q_WS_X11) || defined(Q_WS_MAC)
25         #include <QFile>
26 #elif defined(Q_WS_WIN)
27         #include <windows.h>
28         #include <wincrypt.h>
29         #include <QSysInfo>
30 #endif
31
32 #include <QCryptographicHash>
33 #include <QCursor>
34 #include <QDataStream>
35 #include <QTime>
36
37 void initStdRand();
38 bool getNativeEntropy(quint8* buffer, int length);
39
40 void getEntropy(quint8* buffer, int length){
41         if (!getNativeEntropy(buffer, length)) {
42                 qWarning("Entropy collection failed, using fallback");
43                 initStdRand();
44                 for(int i=0;i<length;i++){
45                         ((quint8*)buffer)[i] = (quint8) (qrand()%256);
46                 }
47         }
48 }
49
50 quint32 randint(quint32 limit){
51         quint32 rand;
52         randomize(&rand, 4);
53         return (rand % limit);
54 }
55
56 quint32 randintRange(quint32 min, quint32 max){
57         return min + randint(max-min+1);
58 }
59
60 #if defined(Q_WS_X11) || defined(Q_WS_MAC)
61
62 extern bool getNativeEntropy(quint8* buffer, int length) {
63         QFile dev_urandom("/dev/urandom");
64         if (!dev_urandom.open(QIODevice::ReadOnly|QIODevice::Unbuffered))
65                 return false;
66         return (dev_urandom.read((char*)buffer,length) == length);
67 }
68
69 #elif defined(Q_WS_WIN)
70
71 extern bool getNativeEntropy(quint8* buffer, int length) {
72         HCRYPTPROV handle;
73         if (!CryptAcquireContext(&handle, 0, 0,  PROV_RSA_FULL, CRYPT_VERIFYCONTEXT))
74                 return false;
75         
76         CryptGenRandom(handle, length, buffer);
77         CryptReleaseContext(handle, 0);
78         
79         return true;
80 }
81
82 #endif
83
84 extern void initStdRand(){
85         static bool initalized = false;
86         if (initalized)
87                 return;
88         
89         QByteArray buffer;
90         QDataStream stream(&buffer, QIODevice::WriteOnly);
91         
92         stream << QCursor::pos();
93         stream << QDateTime::currentDateTime().toTime_t();
94         stream << QTime::currentTime().msec();
95 #ifdef Q_WS_WIN
96         stream << (quint32) GetCurrentProcessId();
97 #else
98         stream << getpid();
99 #endif
100         /* On a modern OS code, stack and heap base are randomized */
101         quint64 code_value = (quint64)initStdRand;
102         stream << code_value;
103         stream << (quint64)&code_value;
104         
105         QByteArray hash = QCryptographicHash::hash(buffer, QCryptographicHash::Sha1);
106         
107         qsrand( *((uint*) hash.data()) );
108         initalized = true;
109 }