Add SHA-224, SHA-256, SHA-384, and SHA-512 support to QCryptographicHash
[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 2 functions replace macros of the same name in sha224-256.c and
52     sha384-512.c. Originally, these macros relied on a global static 'addTemp'
53     variable. We do not want this for 2 reasons:
54
55     1. since we are including the sources directly, the declaration of the 2 conflict
56
57     2. static variables are not thread-safe, we do not want multiple threads
58     computing a hash to corrupt one another
59 */
60 // Header from rfc6234 without modifications
61 #include "../../3rdparty/rfc6234/sha.h"
62 static int SHA224_256AddLength(SHA256Context *context, unsigned int length);
63 static int SHA384_512AddLength(SHA512Context *context, unsigned int length);
64
65 // Sources from rfc6234, with 4 modifications:
66 // sha224-256.c - commented out 'static uint32_t addTemp;' on line 68
67 // sha224-256.c - appended 'M' to the SHA224_256AddLength macro on line 70
68 #include "../../3rdparty/rfc6234/sha224-256.c"
69 // sha384-512.c - commented out 'static uint64_t addTemp;' on line 302
70 // sha384-512.c - appended 'M' to the SHA224_256AddLength macro on line 304
71 #include "../../3rdparty/rfc6234/sha384-512.c"
72
73 #include <qiodevice.h>
74
75 static inline int SHA224_256AddLength(SHA256Context *context, unsigned int length)
76 {
77   uint32_t addTemp;
78   return SHA224_256AddLengthM(context, length);
79 }
80 static inline int SHA384_512AddLength(SHA512Context *context, unsigned int length)
81 {
82   uint64_t addTemp;
83   return SHA384_512AddLengthM(context, length);
84 }
85
86 QT_BEGIN_NAMESPACE
87
88 class QCryptographicHashPrivate
89 {
90 public:
91     QCryptographicHash::Algorithm method;
92     union {
93         MD5Context md5Context;
94         md4_context md4Context;
95         Sha1State sha1Context;
96         SHA224Context sha224Context;
97         SHA256Context sha256Context;
98         SHA384Context sha384Context;
99         SHA512Context sha512Context;
100     };
101     QByteArray result;
102 };
103
104 /*!
105   \class QCryptographicHash
106
107   \brief The QCryptographicHash class provides a way to generate cryptographic hashes.
108
109   \since 4.3
110
111   \ingroup tools
112   \reentrant
113
114   QCryptographicHash can be used to generate cryptographic hashes of binary or text data.
115
116   Currently MD4, MD5, SHA-1, SHA-224, SHA-256, SHA-384, and SHA-512 are supported.
117 */
118
119 /*!
120   \enum QCryptographicHash::Algorithm
121
122   \value Md4 Generate an MD4 hash sum
123   \value Md5 Generate an MD5 hash sum
124   \value Sha1 Generate an SHA-1 hash sum
125   \value Sha224 Generate an SHA-224 hash sum
126   \value Sha256 Generate an SHA-256 hash sum
127   \value Sha384 Generate an SHA-384 hash sum
128   \value Sha512 Generate an SHA-512 hash sum
129 */
130
131 /*!
132   Constructs an object that can be used to create a cryptographic hash from data using \a method.
133 */
134 QCryptographicHash::QCryptographicHash(Algorithm method)
135     : d(new QCryptographicHashPrivate)
136 {
137     d->method = method;
138     reset();
139 }
140
141 /*!
142   Destroys the object.
143 */
144 QCryptographicHash::~QCryptographicHash()
145 {
146     delete d;
147 }
148
149 /*!
150   Resets the object.
151 */
152 void QCryptographicHash::reset()
153 {
154     switch (d->method) {
155     case Md4:
156         md4_init(&d->md4Context);
157         break;
158     case Md5:
159         MD5Init(&d->md5Context);
160         break;
161     case Sha1:
162         sha1InitState(&d->sha1Context);
163         break;
164     case Sha224:
165         SHA224Reset(&d->sha224Context);
166         break;
167     case Sha256:
168         SHA256Reset(&d->sha256Context);
169         break;
170     case Sha384:
171         SHA384Reset(&d->sha384Context);
172         break;
173     case Sha512:
174         SHA512Reset(&d->sha512Context);
175         break;
176     }
177     d->result.clear();
178 }
179
180 /*!
181     Adds the first \a length chars of \a data to the cryptographic
182     hash.
183 */
184 void QCryptographicHash::addData(const char *data, int length)
185 {
186     switch (d->method) {
187     case Md4:
188         md4_update(&d->md4Context, (const unsigned char *)data, length);
189         break;
190     case Md5:
191         MD5Update(&d->md5Context, (const unsigned char *)data, length);
192         break;
193     case Sha1:
194         sha1Update(&d->sha1Context, (const unsigned char *)data, length);
195         break;
196     case Sha224:
197         SHA224Input(&d->sha224Context, reinterpret_cast<const unsigned char *>(data), length);
198         break;
199     case Sha256:
200         SHA256Input(&d->sha256Context, reinterpret_cast<const unsigned char *>(data), length);
201         break;
202     case Sha384:
203         SHA384Input(&d->sha384Context, reinterpret_cast<const unsigned char *>(data), length);
204         break;
205     case Sha512:
206         SHA512Input(&d->sha512Context, reinterpret_cast<const unsigned char *>(data), length);
207         break;
208     }    
209     d->result.clear();
210 }
211
212 /*!
213   \overload addData()
214 */
215 void QCryptographicHash::addData(const QByteArray &data)
216 {
217     addData(data.constData(), data.length());
218 }
219
220 /*!
221   Reads the data from the open QIODevice \a device until it ends
222   and hashes it. Returns true if reading was successful.
223  */
224 bool QCryptographicHash::addData(QIODevice* device)
225 {
226     if (!device->isReadable())
227         return false;
228
229     if (!device->isOpen())
230         return false;
231
232     char buffer[1024];
233     int length;
234
235     while ((length = device->read(buffer,sizeof(buffer))) > 0)
236         addData(buffer,length);
237
238     return device->atEnd();
239 }
240
241
242 /*!
243   Returns the final hash value.
244
245   \sa QByteArray::toHex()
246 */
247 QByteArray QCryptographicHash::result() const
248 {
249     if (!d->result.isEmpty()) 
250         return d->result;
251
252     switch (d->method) {
253     case Md4: {
254         md4_context copy = d->md4Context;
255         d->result.resize(MD4_RESULTLEN);
256         md4_final(&copy, (unsigned char *)d->result.data());
257         break;
258     }
259     case Md5: {
260         MD5Context copy = d->md5Context;
261         d->result.resize(16);
262         MD5Final(&copy, (unsigned char *)d->result.data());
263         break;
264     }
265     case Sha1: {
266         Sha1State copy = d->sha1Context;
267         d->result.resize(20);
268         sha1FinalizeState(&copy);
269         sha1ToHash(&copy, (unsigned char *)d->result.data());
270         break;
271     }
272     case Sha224: {
273         SHA224Context copy = d->sha224Context;
274         d->result.resize(SHA224HashSize);
275         SHA224Result(&copy, reinterpret_cast<unsigned char *>(d->result.data()));
276         break;
277     }
278     case Sha256:{
279         SHA256Context copy = d->sha256Context;
280         d->result.resize(SHA256HashSize);
281         SHA256Result(&copy, reinterpret_cast<unsigned char *>(d->result.data()));
282         break;
283     }
284     case Sha384:{
285         SHA384Context copy = d->sha384Context;
286         d->result.resize(SHA384HashSize);
287         SHA384Result(&copy, reinterpret_cast<unsigned char *>(d->result.data()));
288         break;
289     }
290     case Sha512:{
291         SHA512Context copy = d->sha512Context;
292         d->result.resize(SHA512HashSize);
293         SHA512Result(&copy, reinterpret_cast<unsigned char *>(d->result.data()));
294         break;
295     }
296     }
297     return d->result;
298 }
299
300 /*!
301   Returns the hash of \a data using \a method.
302 */
303 QByteArray QCryptographicHash::hash(const QByteArray &data, Algorithm method)
304 {
305     QCryptographicHash hash(method);
306     hash.addData(data);
307     return hash.result();
308 }
309
310 QT_END_NAMESPACE