File indexing completed on 2025-01-19 03:54:58

0001 /*****************************************************************************/
0002 // Copyright 2006-2019 Adobe Systems Incorporated
0003 // All Rights Reserved.
0004 //
0005 // NOTICE:  Adobe permits you to use, modify, and distribute this file in
0006 // accordance with the terms of the Adobe license agreement accompanying it.
0007 /*****************************************************************************/
0008 
0009 /** \file
0010  * Fingerprint (cryptographic hashing) support for generating strong hashes of image
0011  * data.
0012  */
0013 
0014 /*****************************************************************************/
0015 
0016 #ifndef __dng_fingerprint__
0017 #define __dng_fingerprint__
0018 
0019 /*****************************************************************************/
0020 
0021 #include "dng_exceptions.h"
0022 #include "dng_types.h"
0023 #include "dng_stream.h"
0024 
0025 #include <cstring>
0026 
0027 /*****************************************************************************/
0028 
0029 /// \brief Container fingerprint (MD5 only at present).
0030 
0031 class dng_fingerprint
0032     {
0033 
0034     public:
0035 
0036         static const size_t kDNGFingerprintSize = 16;
0037 
0038         uint8 data [kDNGFingerprintSize];
0039 
0040     public:
0041 
0042         dng_fingerprint ();
0043 
0044         dng_fingerprint (const char *hex);
0045 
0046         /// Check if fingerprint is all zeros.
0047 
0048         bool IsNull () const;
0049 
0050         /// Same as IsNull but expresses intention of testing validity.
0051 
0052         bool IsValid () const
0053             {
0054             return !IsNull ();
0055             }
0056 
0057         /// Set to all zeros, a value used to indicate an invalid fingerprint.
0058 
0059         void Clear ()
0060             {
0061             *this = dng_fingerprint ();
0062             }
0063 
0064         /// Test if two fingerprints are equal.
0065 
0066         bool operator== (const dng_fingerprint &print) const;
0067 
0068         /// Test if two fingerprints are not equal.
0069 
0070         bool operator!= (const dng_fingerprint &print) const
0071             {
0072             return !(*this == print);
0073             }
0074 
0075         /// Comparision test for fingerprints.
0076 
0077         bool operator< (const dng_fingerprint &print) const;
0078 
0079         /// Produce a 32-bit hash value from fingerprint used for faster hashing of
0080         /// fingerprints.
0081 
0082         uint32 Collapse32 () const;
0083 
0084         /// Convert fingerprint to UTF-8 string.
0085         ///
0086         /// \param resultStr The output array to which the UTF-8 encoding of the
0087         /// fingerprint will be written.
0088 
0089         void ToUtf8HexString (char resultStr [2 * kDNGFingerprintSize + 1]) const;
0090 
0091         /// Convert UTF-8 string to fingerprint. Returns true on success, false on
0092         /// failure.
0093         ///
0094         /// \param inputStr The input array from which the UTF-8 encoding of the
0095         /// fingerprint will be read.
0096         ///
0097         /// \retval True indicates success.
0098 
0099         bool FromUtf8HexString (const char inputStr [2 * kDNGFingerprintSize + 1]);
0100 
0101     };
0102 
0103 /*****************************************************************************/
0104 
0105 /// \brief Utility to compare fingerprints (e.g., for sorting).
0106 
0107 struct dng_fingerprint_less_than
0108     {
0109 
0110     /// Less-than comparison.
0111 
0112     bool operator() (const dng_fingerprint &a,
0113                      const dng_fingerprint &b) const
0114         {
0115 
0116         return memcmp (a.data,
0117                        b.data,
0118                        sizeof (a.data)) < 0;
0119 
0120         }
0121 
0122     };
0123 
0124 /******************************************************************************/
0125 
0126 /// \brief Utility to hash fingerprints (e.g., for hashtables).
0127 
0128 struct dng_fingerprint_hash
0129     {
0130 
0131     /// Hash function.
0132 
0133     size_t operator () (const dng_fingerprint &digest) const
0134         {
0135 
0136         return (size_t) digest.Collapse32 ();
0137 
0138         }
0139 
0140     };
0141 
0142 /******************************************************************************/
0143 
0144 // Derived from the RSA Data Security, Inc. MD5 Message-Digest Algorithm.
0145 
0146 // Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
0147 // rights reserved.
0148 //
0149 // License to copy and use this software is granted provided that it
0150 // is identified as the "RSA Data Security, Inc. MD5 Message-Digest
0151 // Algorithm" in all material mentioning or referencing this software
0152 // or this function.
0153 //
0154 // License is also granted to make and use derivative works provided
0155 // that such works are identified as "derived from the RSA Data
0156 // Security, Inc. MD5 Message-Digest Algorithm" in all material
0157 // mentioning or referencing the derived work.
0158 //
0159 // RSA Data Security, Inc. makes no representations concerning either
0160 // the merchantability of this software or the suitability of this
0161 // software for any particular purpose. It is provided "as is"
0162 // without express or implied warranty of any kind.
0163 //
0164 // These notices must be retained in any copies of any part of this
0165 // documentation and/or software.
0166 
0167 /// \brief Class to hash binary data to a fingerprint using the MD5 Message-Digest
0168 /// Algorithm.
0169 
0170 class dng_md5_printer
0171     {
0172 
0173     public:
0174 
0175         dng_md5_printer ();
0176 
0177         virtual ~dng_md5_printer ()
0178             {
0179             }
0180 
0181         /// Reset the fingerprint.
0182 
0183         void Reset ();
0184 
0185         /// Append the data to the stream to be hashed.
0186         /// \param data The data to be hashed.
0187         /// \param inputLen The length of data, in bytes.
0188 
0189         void Process (const void *data,
0190                       uint32 inputLen);
0191 
0192         /// Append the string to the stream to be hashed.
0193         /// \param text The string to be hashed.
0194 
0195         void Process (const char *text)
0196             {
0197 
0198             Process (text, (uint32) strlen (text));
0199 
0200             }
0201 
0202         /// Get the fingerprint (i.e., result of the hash).
0203 
0204         const dng_fingerprint & Result ();
0205 
0206     private:
0207 
0208         static void Encode (uint8 *output,
0209                             const uint32 *input,
0210                             uint32 len);
0211 
0212         static void Decode (uint32 *output,
0213                             const uint8 *input,
0214                             uint32 len);
0215 
0216         // F, G, H and I are basic MD5 functions.
0217 
0218         static inline uint32 F (uint32 x,
0219                                 uint32 y,
0220                                 uint32 z)
0221             {
0222             return (x & y) | (~x & z);
0223             }
0224 
0225         static inline uint32 G (uint32 x,
0226                                 uint32 y,
0227                                 uint32 z)
0228             {
0229             return (x & z) | (y & ~z);
0230             }
0231 
0232         static inline uint32 H (uint32 x,
0233                                 uint32 y,
0234                                 uint32 z)
0235             {
0236             return x ^ y ^ z;
0237             }
0238 
0239         static inline uint32 I (uint32 x,
0240                                 uint32 y,
0241                                 uint32 z)
0242             {
0243             return y ^ (x | ~z);
0244             }
0245 
0246         // FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4.
0247 
0248         DNG_ATTRIB_NO_SANITIZE("unsigned-integer-overflow")
0249         static inline void FF (uint32 &a,
0250                                uint32 b,
0251                                uint32 c,
0252                                uint32 d,
0253                                uint32 x,
0254                                uint32 s,
0255                                uint32 ac)
0256             {
0257             a += F (b, c, d) + x + ac;
0258             a = (a << s) | (a >> (32 - s));
0259             a += b;
0260             }
0261 
0262         DNG_ATTRIB_NO_SANITIZE("unsigned-integer-overflow")
0263         static inline void GG (uint32 &a,
0264                                uint32 b,
0265                                uint32 c,
0266                                uint32 d,
0267                                uint32 x,
0268                                uint32 s,
0269                                uint32 ac)
0270             {
0271             a += G (b, c, d) + x + ac;
0272             a = (a << s) | (a >> (32 - s));
0273             a += b;
0274             }
0275 
0276         DNG_ATTRIB_NO_SANITIZE("unsigned-integer-overflow")
0277         static inline void HH (uint32 &a,
0278                                uint32 b,
0279                                uint32 c,
0280                                uint32 d,
0281                                uint32 x,
0282                                uint32 s,
0283                                uint32 ac)
0284             {
0285             a += H (b, c, d) + x + ac;
0286             a = (a << s) | (a >> (32 - s));
0287             a += b;
0288             }
0289 
0290         DNG_ATTRIB_NO_SANITIZE("unsigned-integer-overflow")
0291         static inline void II (uint32 &a,
0292                                uint32 b,
0293                                uint32 c,
0294                                uint32 d,
0295                                uint32 x,
0296                                uint32 s,
0297                                uint32 ac)
0298             {
0299             a += I (b, c, d) + x + ac;
0300             a = (a << s) | (a >> (32 - s));
0301             a += b;
0302             }
0303 
0304         static void MD5Transform (uint32 state [4],
0305                                   const uint8 block [64]);
0306 
0307     private:
0308 
0309         uint32 state [4];
0310 
0311         uint32 count [2];
0312 
0313         uint8 buffer [64];
0314 
0315         bool final;
0316 
0317         dng_fingerprint result;
0318 
0319     };
0320 
0321 /*****************************************************************************/
0322 
0323 /// \brief A dng_stream based interface to the MD5 printing logic.
0324 
0325 class dng_md5_printer_stream : public dng_stream, dng_md5_printer
0326     {
0327 
0328     private:
0329 
0330         uint64 fNextOffset;
0331 
0332     public:
0333 
0334         /// Create an empty MD5 printer stream.
0335 
0336         dng_md5_printer_stream ()
0337 
0338             :   fNextOffset (0)
0339 
0340             {
0341             }
0342 
0343         virtual uint64 DoGetLength ()
0344             {
0345 
0346             return fNextOffset;
0347 
0348             }
0349 
0350         virtual void DoRead (void * /* data */,
0351                              uint32 /* count */,
0352                              uint64 /* offset */)
0353             {
0354 
0355             ThrowProgramError ();
0356 
0357             }
0358 
0359         virtual void DoSetLength (uint64 length)
0360             {
0361 
0362             if (length != fNextOffset)
0363                 {
0364                 ThrowProgramError ();
0365                 }
0366 
0367             }
0368 
0369         virtual void DoWrite (const void *data,
0370                               uint32 count2,
0371                               uint64 offset)
0372             {
0373 
0374             if (offset != fNextOffset)
0375                 {
0376                 ThrowProgramError ();
0377                 }
0378 
0379             Process (data, count2);
0380 
0381             fNextOffset += count2;
0382 
0383             }
0384 
0385         const dng_fingerprint & Result ()
0386             {
0387 
0388             Flush ();
0389 
0390             return dng_md5_printer::Result ();
0391 
0392             }
0393 
0394     };
0395 
0396 /*****************************************************************************/
0397 
0398 #endif
0399 
0400 /*****************************************************************************/