1/*****************************************************************************/
2// Copyright 2006-2007 Adobe Systems Incorporated
3// All Rights Reserved.
4//
5// NOTICE: Adobe permits you to use, modify, and distribute this file in
6// accordance with the terms of the Adobe license agreement accompanying it.
7/*****************************************************************************/
8
9/* $Id: //mondo/dng_sdk_1_4/dng_sdk/source/dng_fingerprint.h#2 $ */
10/* $DateTime: 2012/07/11 10:36:56 $ */
11/* $Change: 838485 $ */
12/* $Author: tknoll $ */
13
14/** \file
15 * Fingerprint (cryptographic hashing) support for generating strong hashes of image
16 * data.
17 */
18
19/*****************************************************************************/
20
21#ifndef __dng_fingerprint__
22#define __dng_fingerprint__
23
24/*****************************************************************************/
25
26#include "dng_exceptions.h"
27#include "dng_types.h"
28#include "dng_stream.h"
29
30#include <cstring>
31
32/*****************************************************************************/
33
34/// \brief Container fingerprint (MD5 only at present).
35
36class dng_fingerprint
37 {
38
39 public:
40
41 static const size_t kDNGFingerprintSize = 16;
42
43 uint8 data [kDNGFingerprintSize];
44
45 public:
46
47 dng_fingerprint ();
48
49 /// Check if fingerprint is all zeros.
50
51 bool IsNull () const;
52
53 /// Same as IsNull but expresses intention of testing validity.
54
55 bool IsValid () const
56 {
57 return !IsNull ();
58 }
59
60 /// Set to all zeros, a value used to indicate an invalid fingerprint.
61
62 void Clear ()
63 {
64 *this = dng_fingerprint ();
65 }
66
67 /// Test if two fingerprints are equal.
68
69 bool operator== (const dng_fingerprint &print) const;
70
71 /// Test if two fingerprints are not equal.
72
73 bool operator!= (const dng_fingerprint &print) const
74 {
75 return !(*this == print);
76 }
77
78 /// Produce a 32-bit hash value from fingerprint used for faster hashing of
79 /// fingerprints.
80
81 uint32 Collapse32 () const;
82
83 /// Convert fingerprint to UTF-8 string.
84 ///
85 /// \param resultStr The output array to which the UTF-8 encoding of the
86 /// fingerprint will be written.
87
88 void ToUtf8HexString (char resultStr [2 * kDNGFingerprintSize + 1]) const;
89
90 /// Convert UTF-8 string to fingerprint. Returns true on success, false on
91 /// failure.
92 ///
93 /// \param inputStr The input array from which the UTF-8 encoding of the
94 /// fingerprint will be read.
95 ///
96 /// \retval True indicates success.
97
98 bool FromUtf8HexString (const char inputStr [2 * kDNGFingerprintSize + 1]);
99
100 };
101
102/*****************************************************************************/
103
104/// \brief Utility to compare fingerprints (e.g., for sorting).
105
106struct dng_fingerprint_less_than
107 {
108
109 /// Less-than comparison.
110
111 bool operator() (const dng_fingerprint &a,
112 const dng_fingerprint &b) const
113 {
114
115 return memcmp (a.data,
116 b.data,
117 sizeof (a.data)) < 0;
118
119 }
120
121 };
122
123/******************************************************************************/
124
125// Derived from the RSA Data Security, Inc. MD5 Message-Digest Algorithm.
126
127// Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
128// rights reserved.
129//
130// License to copy and use this software is granted provided that it
131// is identified as the "RSA Data Security, Inc. MD5 Message-Digest
132// Algorithm" in all material mentioning or referencing this software
133// or this function.
134//
135// License is also granted to make and use derivative works provided
136// that such works are identified as "derived from the RSA Data
137// Security, Inc. MD5 Message-Digest Algorithm" in all material
138// mentioning or referencing the derived work.
139//
140// RSA Data Security, Inc. makes no representations concerning either
141// the merchantability of this software or the suitability of this
142// software for any particular purpose. It is provided "as is"
143// without express or implied warranty of any kind.
144//
145// These notices must be retained in any copies of any part of this
146// documentation and/or software.
147
148/// \brief Class to hash binary data to a fingerprint using the MD5 Message-Digest
149/// Algorithm.
150
151class dng_md5_printer
152 {
153
154 public:
155
156 dng_md5_printer ();
157
158 virtual ~dng_md5_printer ()
159 {
160 }
161
162 /// Reset the fingerprint.
163
164 void Reset ();
165
166 /// Append the data to the stream to be hashed.
167 /// \param data The data to be hashed.
168 /// \param inputLen The length of data, in bytes.
169
170 void Process (const void *data,
171 uint32 inputLen);
172
173 /// Append the string to the stream to be hashed.
174 /// \param text The string to be hashed.
175
176 void Process (const char *text)
177 {
178
179 Process (text, (uint32) strlen (text));
180
181 }
182
183 /// Get the fingerprint (i.e., result of the hash).
184
185 const dng_fingerprint & Result ();
186
187 private:
188
189 static void Encode (uint8 *output,
190 const uint32 *input,
191 uint32 len);
192
193 static void Decode (uint32 *output,
194 const uint8 *input,
195 uint32 len);
196
197 // F, G, H and I are basic MD5 functions.
198
199 static inline uint32 F (uint32 x,
200 uint32 y,
201 uint32 z)
202 {
203 return (x & y) | (~x & z);
204 }
205
206 static inline uint32 G (uint32 x,
207 uint32 y,
208 uint32 z)
209 {
210 return (x & z) | (y & ~z);
211 }
212
213 static inline uint32 H (uint32 x,
214 uint32 y,
215 uint32 z)
216 {
217 return x ^ y ^ z;
218 }
219
220 static inline uint32 I (uint32 x,
221 uint32 y,
222 uint32 z)
223 {
224 return y ^ (x | ~z);
225 }
226
227 // FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4.
228
229#if defined(__clang__) && defined(__has_attribute)
230#if __has_attribute(no_sanitize)
231 __attribute__((no_sanitize("unsigned-integer-overflow")))
232#endif
233#endif
234 static inline void FF (uint32 &a,
235 uint32 b,
236 uint32 c,
237 uint32 d,
238 uint32 x,
239 uint32 s,
240 uint32 ac)
241 {
242 a += F (b, c, d) + x + ac;
243 a = (a << s) | (a >> (32 - s));
244 a += b;
245 }
246
247#if defined(__clang__) && defined(__has_attribute)
248#if __has_attribute(no_sanitize)
249 __attribute__((no_sanitize("unsigned-integer-overflow")))
250#endif
251#endif
252 static inline void GG (uint32 &a,
253 uint32 b,
254 uint32 c,
255 uint32 d,
256 uint32 x,
257 uint32 s,
258 uint32 ac)
259 {
260 a += G (b, c, d) + x + ac;
261 a = (a << s) | (a >> (32 - s));
262 a += b;
263 }
264
265#if defined(__clang__) && defined(__has_attribute)
266#if __has_attribute(no_sanitize)
267 __attribute__((no_sanitize("unsigned-integer-overflow")))
268#endif
269#endif
270 static inline void HH (uint32 &a,
271 uint32 b,
272 uint32 c,
273 uint32 d,
274 uint32 x,
275 uint32 s,
276 uint32 ac)
277 {
278 a += H (b, c, d) + x + ac;
279 a = (a << s) | (a >> (32 - s));
280 a += b;
281 }
282
283#if defined(__clang__) && defined(__has_attribute)
284#if __has_attribute(no_sanitize)
285 __attribute__((no_sanitize("unsigned-integer-overflow")))
286#endif
287#endif
288 static inline void II (uint32 &a,
289 uint32 b,
290 uint32 c,
291 uint32 d,
292 uint32 x,
293 uint32 s,
294 uint32 ac)
295 {
296 a += I (b, c, d) + x + ac;
297 a = (a << s) | (a >> (32 - s));
298 a += b;
299 }
300
301 static void MD5Transform (uint32 state [4],
302 const uint8 block [64]);
303
304 private:
305
306 uint32 state [4];
307
308 uint32 count [2];
309
310 uint8 buffer [64];
311
312 bool final;
313
314 dng_fingerprint result;
315
316 };
317
318/*****************************************************************************/
319
320/// \brief A dng_stream based interface to the MD5 printing logic.
321
322class dng_md5_printer_stream : public dng_stream, dng_md5_printer
323 {
324
325 private:
326
327 uint64 fNextOffset;
328
329 public:
330
331 /// Create an empty MD5 printer stream.
332
333 dng_md5_printer_stream ()
334
335 : fNextOffset (0)
336
337 {
338 }
339
340 virtual uint64 DoGetLength ()
341 {
342
343 return fNextOffset;
344
345 }
346
347 virtual void DoRead (void * /* data */,
348 uint32 /* count */,
349 uint64 /* offset */)
350 {
351
352 ThrowProgramError ();
353
354 }
355
356 virtual void DoSetLength (uint64 length)
357 {
358
359 if (length != fNextOffset)
360 {
361 ThrowProgramError ();
362 }
363
364 }
365
366 virtual void DoWrite (const void *data,
367 uint32 count2,
368 uint64 offset)
369 {
370
371 if (offset != fNextOffset)
372 {
373 ThrowProgramError ();
374 }
375
376 Process (data, count2);
377
378 fNextOffset += count2;
379
380 }
381
382 const dng_fingerprint & Result ()
383 {
384
385 Flush ();
386
387 return dng_md5_printer::Result ();
388
389 }
390
391 };
392
393/*****************************************************************************/
394
395#endif
396
397/*****************************************************************************/
398