1 /************************************************************** 2 * 3 * Licensed to the Apache Software Foundation (ASF) under one 4 * or more contributor license agreements. See the NOTICE file 5 * distributed with this work for additional information 6 * regarding copyright ownership. The ASF licenses this file 7 * to you under the Apache License, Version 2.0 (the 8 * "License"); you may not use this file except in compliance 9 * with the License. You may obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 13 * Unless required by applicable law or agreed to in writing, 14 * software distributed under the License is distributed on an 15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 * KIND, either express or implied. See the License for the 17 * specific language governing permissions and limitations 18 * under the License. 19 * 20 *************************************************************/ 21 22 23 24 // MARKER(update_precomp.py): autogen include statement, do not remove 25 #include "precompiled_tools.hxx" 26 27 #include "md5.hxx" 28 29 #include <cstddef> 30 #include <stdio.h> 31 32 #include <tools/string.hxx> 33 34 #ifdef WNT 35 #define FILE_OPEN_READ "rb" 36 #else 37 #define FILE_OPEN_READ "r" 38 #endif 39 40 // Extended calc_md5_checksum to recognize Windows executables and libraries. To 41 // create the same md5 checksum for a (code/data) identical file it ignores a different 42 // date and header checksum. Please see crashrep/source/win32/soreport.cpp 43 // where the same method is also used. The crash reporter uses the MD5 44 // checksums to transfer them to the crash database. You have to make sure that both 45 // methods use the same algorithm otherwise there could be problems with stack reports. 46 47 void normalize_pe_image(sal_uInt8* buffer, size_t nBufferSize) 48 { 49 const int OFFSET_PE_OFFSET = 0x3c; 50 const int OFFSET_COFF_TIMEDATESTAMP = 4; 51 const int PE_SIGNATURE_SIZE = 4; 52 const int COFFHEADER_SIZE = 20; 53 const int OFFSET_PE_OPTIONALHEADER_CHECKSUM = 64; 54 55 // Check the header part of the file buffer 56 if (buffer[0] == sal_uInt8('M') && buffer[1] == sal_uInt8('Z')) 57 { 58 unsigned long PEHeaderOffset = (long)buffer[OFFSET_PE_OFFSET]; 59 if (PEHeaderOffset < nBufferSize-4) 60 { 61 if ( buffer[PEHeaderOffset+0] == sal_uInt8('P') && 62 buffer[PEHeaderOffset+1] == sal_uInt8('E') && 63 buffer[PEHeaderOffset+2] == 0 && 64 buffer[PEHeaderOffset+3] == 0 ) 65 { 66 PEHeaderOffset += PE_SIGNATURE_SIZE; 67 if (PEHeaderOffset+OFFSET_COFF_TIMEDATESTAMP < nBufferSize-4) 68 { 69 // Set timedatestamp and checksum fields to a normalized 70 // value to enforce the same MD5 checksum for identical 71 // Windows executables/libraries. 72 buffer[PEHeaderOffset+OFFSET_COFF_TIMEDATESTAMP+0] = 0; 73 buffer[PEHeaderOffset+OFFSET_COFF_TIMEDATESTAMP+1] = 0; 74 buffer[PEHeaderOffset+OFFSET_COFF_TIMEDATESTAMP+2] = 0; 75 buffer[PEHeaderOffset+OFFSET_COFF_TIMEDATESTAMP+3] = 0; 76 } 77 78 if (PEHeaderOffset+COFFHEADER_SIZE+OFFSET_PE_OPTIONALHEADER_CHECKSUM < nBufferSize-4) 79 { 80 // Set checksum to a normalized value 81 buffer[PEHeaderOffset+COFFHEADER_SIZE+OFFSET_PE_OPTIONALHEADER_CHECKSUM] = 0; 82 buffer[PEHeaderOffset+COFFHEADER_SIZE+OFFSET_PE_OPTIONALHEADER_CHECKSUM+1] = 0; 83 buffer[PEHeaderOffset+COFFHEADER_SIZE+OFFSET_PE_OPTIONALHEADER_CHECKSUM+2] = 0; 84 buffer[PEHeaderOffset+COFFHEADER_SIZE+OFFSET_PE_OPTIONALHEADER_CHECKSUM+3] = 0; 85 } 86 } 87 } 88 } 89 } 90 91 rtlDigestError calc_md5_checksum( const char *filename, ByteString &aChecksum ) 92 { 93 const size_t BUFFER_SIZE = 0x1000; 94 const size_t MINIMAL_SIZE = 512; 95 96 sal_uInt8 checksum[RTL_DIGEST_LENGTH_MD5]; 97 rtlDigestError error = rtl_Digest_E_None; 98 99 FILE *fp = fopen( filename, FILE_OPEN_READ ); 100 101 if ( fp ) 102 { 103 rtlDigest digest = rtl_digest_createMD5(); 104 105 if ( digest ) 106 { 107 size_t nBytesRead; 108 sal_uInt8 buffer[BUFFER_SIZE]; 109 bool bHeader(true); 110 111 while ( rtl_Digest_E_None == error && 112 0 != (nBytesRead = fread( buffer, 1, sizeof(buffer), fp )) ) 113 { 114 if (bHeader) 115 { 116 bHeader = false; 117 if (nBytesRead >= MINIMAL_SIZE && buffer[0] == sal_uInt8('M') && buffer[1] == sal_uInt8('Z') ) 118 normalize_pe_image(buffer, nBytesRead); 119 } 120 121 error = rtl_digest_updateMD5( digest, buffer, nBytesRead ); 122 } 123 124 if ( rtl_Digest_E_None == error ) 125 { 126 error = rtl_digest_getMD5( digest, checksum, sizeof(checksum) ); 127 } 128 129 rtl_digest_destroyMD5( digest ); 130 131 for ( std::size_t i = 0; i < sizeof(checksum); i++ ) 132 { 133 if ( checksum[i] < 16 ) 134 aChecksum.Append( "0" ); 135 aChecksum += ByteString::CreateFromInt32( checksum[i], 16 ); 136 } 137 } 138 139 fclose( fp ); 140 } 141 else 142 error = rtl_Digest_E_Unknown; 143 144 return error; 145 } 146