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 
36 class 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 
IsValid()55 		bool IsValid () const
56 			{
57 			return !IsNull ();
58 			}
59 
60 		/// Set to all zeros, a value used to indicate an invalid fingerprint.
61 
Clear()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 
106 struct dng_fingerprint_less_than
107 	{
108 
109 	/// Less-than comparison.
110 
operatordng_fingerprint_less_than111 	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 
151 class dng_md5_printer
152 	{
153 
154 	public:
155 
156 		dng_md5_printer ();
157 
~dng_md5_printer()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 
Process(const char * text)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 
F(uint32 x,uint32 y,uint32 z)199 		static inline uint32 F (uint32 x,
200 								uint32 y,
201 								uint32 z)
202 			{
203 			return (x & y) | (~x & z);
204 			}
205 
G(uint32 x,uint32 y,uint32 z)206 		static inline uint32 G (uint32 x,
207 								uint32 y,
208 								uint32 z)
209 			{
210 			return (x & z) | (y & ~z);
211 			}
212 
H(uint32 x,uint32 y,uint32 z)213 		static inline uint32 H (uint32 x,
214 								uint32 y,
215 								uint32 z)
216 			{
217 			return x ^ y ^ z;
218 			}
219 
I(uint32 x,uint32 y,uint32 z)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
FF(uint32 & a,uint32 b,uint32 c,uint32 d,uint32 x,uint32 s,uint32 ac)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
GG(uint32 & a,uint32 b,uint32 c,uint32 d,uint32 x,uint32 s,uint32 ac)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
HH(uint32 & a,uint32 b,uint32 c,uint32 d,uint32 x,uint32 s,uint32 ac)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
II(uint32 & a,uint32 b,uint32 c,uint32 d,uint32 x,uint32 s,uint32 ac)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 
322 class 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 
dng_md5_printer_stream()333 		dng_md5_printer_stream ()
334 
335 			:	fNextOffset (0)
336 
337 			{
338 			}
339 
DoGetLength()340 		virtual uint64 DoGetLength ()
341 			{
342 
343 			return fNextOffset;
344 
345 			}
346 
DoRead(void *,uint32,uint64)347 		virtual void DoRead (void * /* data */,
348 							 uint32 /* count */,
349 							 uint64 /* offset */)
350 			{
351 
352 			ThrowProgramError ();
353 
354 			}
355 
DoSetLength(uint64 length)356 		virtual void DoSetLength (uint64 length)
357 			{
358 
359 			if (length != fNextOffset)
360 				{
361 				ThrowProgramError ();
362 				}
363 
364 			}
365 
DoWrite(const void * data,uint32 count2,uint64 offset)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 
Result()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