Merge remote-tracking branch 'origin/master' into api_changes
[profile/ivi/qtbase.git] / src / corelib / tools / qcryptographichash.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
5 **
6 ** This file is part of the QtCore module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
16 **
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
20 **
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
28 **
29 ** Other Usage
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** conditions contained in a signed written agreement between you and Nokia.
32 **
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include <qcryptographichash.h>
43
44 #include "../../3rdparty/md5/md5.h"
45 #include "../../3rdparty/md5/md5.cpp"
46 #include "../../3rdparty/md4/md4.h"
47 #include "../../3rdparty/md4/md4.cpp"
48 #include "../../3rdparty/sha1/sha1.cpp"
49
50 /*
51     These #defines replace the typedefs needed by the RFC6234 code. Normally
52     the typedefs would come from from stdint.h, but since this header is not
53     available on all platforms (MSVC 2008, for example), we #define them to the
54     Qt equivalents.
55 */
56 #define uint64_t QT_PREPEND_NAMESPACE(quint64)
57 #define uint32_t QT_PREPEND_NAMESPACE(quint32)
58 #define uint8_t QT_PREPEND_NAMESPACE(quint8)
59 #define int_least16_t QT_PREPEND_NAMESPACE(qint16)
60
61 // Header from rfc6234 with 1 modification:
62 // sha1.h - commented out '#include <stdint.h>' on line 74
63 #include "../../3rdparty/rfc6234/sha.h"
64
65 /*
66     These 2 functions replace macros of the same name in sha224-256.c and
67     sha384-512.c. Originally, these macros relied on a global static 'addTemp'
68     variable. We do not want this for 2 reasons:
69
70     1. since we are including the sources directly, the declaration of the 2 conflict
71
72     2. static variables are not thread-safe, we do not want multiple threads
73     computing a hash to corrupt one another
74 */
75 static int SHA224_256AddLength(SHA256Context *context, unsigned int length);
76 static int SHA384_512AddLength(SHA512Context *context, unsigned int length);
77
78 // Sources from rfc6234, with 4 modifications:
79 // sha224-256.c - commented out 'static uint32_t addTemp;' on line 68
80 // sha224-256.c - appended 'M' to the SHA224_256AddLength macro on line 70
81 #include "../../3rdparty/rfc6234/sha224-256.c"
82 // sha384-512.c - commented out 'static uint64_t addTemp;' on line 302
83 // sha384-512.c - appended 'M' to the SHA224_256AddLength macro on line 304
84 #include "../../3rdparty/rfc6234/sha384-512.c"
85
86 #undef uint64_t
87 #undef uint32_t
88 #undef uint68_t
89 #undef int_least16_t
90
91 #include <qiodevice.h>
92
93 static inline int SHA224_256AddLength(SHA256Context *context, unsigned int length)
94 {
95   QT_PREPEND_NAMESPACE(quint32) addTemp;
96   return SHA224_256AddLengthM(context, length);
97 }
98 static inline int SHA384_512AddLength(SHA512Context *context, unsigned int length)
99 {
100   QT_PREPEND_NAMESPACE(quint64) addTemp;
101   return SHA384_512AddLengthM(context, length);
102 }
103
104 QT_BEGIN_NAMESPACE
105
106 class QCryptographicHashPrivate
107 {
108 public:
109     QCryptographicHash::Algorithm method;
110     union {
111         MD5Context md5Context;
112         md4_context md4Context;
113         Sha1State sha1Context;
114         SHA224Context sha224Context;
115         SHA256Context sha256Context;
116         SHA384Context sha384Context;
117         SHA512Context sha512Context;
118     };
119     QByteArray result;
120 };
121
122 /*!
123   \class QCryptographicHash
124
125   \brief The QCryptographicHash class provides a way to generate cryptographic hashes.
126
127   \since 4.3
128
129   \ingroup tools
130   \reentrant
131
132   QCryptographicHash can be used to generate cryptographic hashes of binary or text data.
133
134   Currently MD4, MD5, SHA-1, SHA-224, SHA-256, SHA-384, and SHA-512 are supported.
135 */
136
137 /*!
138   \enum QCryptographicHash::Algorithm
139
140   \value Md4 Generate an MD4 hash sum
141   \value Md5 Generate an MD5 hash sum
142   \value Sha1 Generate an SHA-1 hash sum
143   \value Sha224 Generate an SHA-224 hash sum
144   \value Sha256 Generate an SHA-256 hash sum
145   \value Sha384 Generate an SHA-384 hash sum
146   \value Sha512 Generate an SHA-512 hash sum
147 */
148
149 /*!
150   Constructs an object that can be used to create a cryptographic hash from data using \a method.
151 */
152 QCryptographicHash::QCryptographicHash(Algorithm method)
153     : d(new QCryptographicHashPrivate)
154 {
155     d->method = method;
156     reset();
157 }
158
159 /*!
160   Destroys the object.
161 */
162 QCryptographicHash::~QCryptographicHash()
163 {
164     delete d;
165 }
166
167 /*!
168   Resets the object.
169 */
170 void QCryptographicHash::reset()
171 {
172     switch (d->method) {
173     case Md4:
174         md4_init(&d->md4Context);
175         break;
176     case Md5:
177         MD5Init(&d->md5Context);
178         break;
179     case Sha1:
180         sha1InitState(&d->sha1Context);
181         break;
182     case Sha224:
183         SHA224Reset(&d->sha224Context);
184         break;
185     case Sha256:
186         SHA256Reset(&d->sha256Context);
187         break;
188     case Sha384:
189         SHA384Reset(&d->sha384Context);
190         break;
191     case Sha512:
192         SHA512Reset(&d->sha512Context);
193         break;
194     }
195     d->result.clear();
196 }
197
198 /*!
199     Adds the first \a length chars of \a data to the cryptographic
200     hash.
201 */
202 void QCryptographicHash::addData(const char *data, int length)
203 {
204     switch (d->method) {
205     case Md4:
206         md4_update(&d->md4Context, (const unsigned char *)data, length);
207         break;
208     case Md5:
209         MD5Update(&d->md5Context, (const unsigned char *)data, length);
210         break;
211     case Sha1:
212         sha1Update(&d->sha1Context, (const unsigned char *)data, length);
213         break;
214     case Sha224:
215         SHA224Input(&d->sha224Context, reinterpret_cast<const unsigned char *>(data), length);
216         break;
217     case Sha256:
218         SHA256Input(&d->sha256Context, reinterpret_cast<const unsigned char *>(data), length);
219         break;
220     case Sha384:
221         SHA384Input(&d->sha384Context, reinterpret_cast<const unsigned char *>(data), length);
222         break;
223     case Sha512:
224         SHA512Input(&d->sha512Context, reinterpret_cast<const unsigned char *>(data), length);
225         break;
226     }    
227     d->result.clear();
228 }
229
230 /*!
231   \overload addData()
232 */
233 void QCryptographicHash::addData(const QByteArray &data)
234 {
235     addData(data.constData(), data.length());
236 }
237
238 /*!
239   Reads the data from the open QIODevice \a device until it ends
240   and hashes it. Returns true if reading was successful.
241  */
242 bool QCryptographicHash::addData(QIODevice* device)
243 {
244     if (!device->isReadable())
245         return false;
246
247     if (!device->isOpen())
248         return false;
249
250     char buffer[1024];
251     int length;
252
253     while ((length = device->read(buffer,sizeof(buffer))) > 0)
254         addData(buffer,length);
255
256     return device->atEnd();
257 }
258
259
260 /*!
261   Returns the final hash value.
262
263   \sa QByteArray::toHex()
264 */
265 QByteArray QCryptographicHash::result() const
266 {
267     if (!d->result.isEmpty()) 
268         return d->result;
269
270     switch (d->method) {
271     case Md4: {
272         md4_context copy = d->md4Context;
273         d->result.resize(MD4_RESULTLEN);
274         md4_final(&copy, (unsigned char *)d->result.data());
275         break;
276     }
277     case Md5: {
278         MD5Context copy = d->md5Context;
279         d->result.resize(16);
280         MD5Final(&copy, (unsigned char *)d->result.data());
281         break;
282     }
283     case Sha1: {
284         Sha1State copy = d->sha1Context;
285         d->result.resize(20);
286         sha1FinalizeState(&copy);
287         sha1ToHash(&copy, (unsigned char *)d->result.data());
288         break;
289     }
290     case Sha224: {
291         SHA224Context copy = d->sha224Context;
292         d->result.resize(SHA224HashSize);
293         SHA224Result(&copy, reinterpret_cast<unsigned char *>(d->result.data()));
294         break;
295     }
296     case Sha256:{
297         SHA256Context copy = d->sha256Context;
298         d->result.resize(SHA256HashSize);
299         SHA256Result(&copy, reinterpret_cast<unsigned char *>(d->result.data()));
300         break;
301     }
302     case Sha384:{
303         SHA384Context copy = d->sha384Context;
304         d->result.resize(SHA384HashSize);
305         SHA384Result(&copy, reinterpret_cast<unsigned char *>(d->result.data()));
306         break;
307     }
308     case Sha512:{
309         SHA512Context copy = d->sha512Context;
310         d->result.resize(SHA512HashSize);
311         SHA512Result(&copy, reinterpret_cast<unsigned char *>(d->result.data()));
312         break;
313     }
314     }
315     return d->result;
316 }
317
318 /*!
319   Returns the hash of \a data using \a method.
320 */
321 QByteArray QCryptographicHash::hash(const QByteArray &data, Algorithm method)
322 {
323     QCryptographicHash hash(method);
324     hash.addData(data);
325     return hash.result();
326 }
327
328 QT_END_NAMESPACE