Home | History | Annotate | Download | only in source
      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 
     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 
    106 struct 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 
    151 class 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 
    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 
    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