1 /************************************************************************* 2 * 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * Copyright 2000, 2010 Oracle and/or its affiliates. 6 * 7 * OpenOffice.org - a multi-platform office productivity suite 8 * 9 * This file is part of OpenOffice.org. 10 * 11 * OpenOffice.org is free software: you can redistribute it and/or modify 12 * it under the terms of the GNU Lesser General Public License version 3 13 * only, as published by the Free Software Foundation. 14 * 15 * OpenOffice.org is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU Lesser General Public License version 3 for more details 19 * (a copy is included in the LICENSE file that accompanied this code). 20 * 21 * You should have received a copy of the GNU Lesser General Public License 22 * version 3 along with OpenOffice.org. If not, see 23 * <http://www.openoffice.org/license.html> 24 * for a copy of the LGPLv3 License. 25 * 26 ************************************************************************/ 27 28 // MARKER(update_precomp.py): autogen include statement, do not remove 29 #include "precompiled_tools.hxx" 30 31 #include "md5.hxx" 32 33 #include <cstddef> 34 #include <stdio.h> 35 36 #include <tools/string.hxx> 37 38 #ifdef WNT 39 #define FILE_OPEN_READ "rb" 40 #else 41 #define FILE_OPEN_READ "r" 42 #endif 43 44 // Extended calc_md5_checksum to recognize Windows executables and libraries. To 45 // create the same md5 checksum for a (code/data) identical file it ignores a different 46 // date and header checksum. Please see crashrep/source/win32/soreport.cpp 47 // where the same method is also used. The crash reporter uses the MD5 48 // checksums to transfer them to the crash database. You have to make sure that both 49 // methods use the same algorithm otherwise there could be problems with stack reports. 50 51 void normalize_pe_image(sal_uInt8* buffer, size_t nBufferSize) 52 { 53 const int OFFSET_PE_OFFSET = 0x3c; 54 const int OFFSET_COFF_TIMEDATESTAMP = 4; 55 const int PE_SIGNATURE_SIZE = 4; 56 const int COFFHEADER_SIZE = 20; 57 const int OFFSET_PE_OPTIONALHEADER_CHECKSUM = 64; 58 59 // Check the header part of the file buffer 60 if (buffer[0] == sal_uInt8('M') && buffer[1] == sal_uInt8('Z')) 61 { 62 unsigned long PEHeaderOffset = (long)buffer[OFFSET_PE_OFFSET]; 63 if (PEHeaderOffset < nBufferSize-4) 64 { 65 if ( buffer[PEHeaderOffset+0] == sal_uInt8('P') && 66 buffer[PEHeaderOffset+1] == sal_uInt8('E') && 67 buffer[PEHeaderOffset+2] == 0 && 68 buffer[PEHeaderOffset+3] == 0 ) 69 { 70 PEHeaderOffset += PE_SIGNATURE_SIZE; 71 if (PEHeaderOffset+OFFSET_COFF_TIMEDATESTAMP < nBufferSize-4) 72 { 73 // Set timedatestamp and checksum fields to a normalized 74 // value to enforce the same MD5 checksum for identical 75 // Windows executables/libraries. 76 buffer[PEHeaderOffset+OFFSET_COFF_TIMEDATESTAMP+0] = 0; 77 buffer[PEHeaderOffset+OFFSET_COFF_TIMEDATESTAMP+1] = 0; 78 buffer[PEHeaderOffset+OFFSET_COFF_TIMEDATESTAMP+2] = 0; 79 buffer[PEHeaderOffset+OFFSET_COFF_TIMEDATESTAMP+3] = 0; 80 } 81 82 if (PEHeaderOffset+COFFHEADER_SIZE+OFFSET_PE_OPTIONALHEADER_CHECKSUM < nBufferSize-4) 83 { 84 // Set checksum to a normalized value 85 buffer[PEHeaderOffset+COFFHEADER_SIZE+OFFSET_PE_OPTIONALHEADER_CHECKSUM] = 0; 86 buffer[PEHeaderOffset+COFFHEADER_SIZE+OFFSET_PE_OPTIONALHEADER_CHECKSUM+1] = 0; 87 buffer[PEHeaderOffset+COFFHEADER_SIZE+OFFSET_PE_OPTIONALHEADER_CHECKSUM+2] = 0; 88 buffer[PEHeaderOffset+COFFHEADER_SIZE+OFFSET_PE_OPTIONALHEADER_CHECKSUM+3] = 0; 89 } 90 } 91 } 92 } 93 } 94 95 rtlDigestError calc_md5_checksum( const char *filename, ByteString &aChecksum ) 96 { 97 const size_t BUFFER_SIZE = 0x1000; 98 const size_t MINIMAL_SIZE = 512; 99 100 sal_uInt8 checksum[RTL_DIGEST_LENGTH_MD5]; 101 rtlDigestError error = rtl_Digest_E_None; 102 103 FILE *fp = fopen( filename, FILE_OPEN_READ ); 104 105 if ( fp ) 106 { 107 rtlDigest digest = rtl_digest_createMD5(); 108 109 if ( digest ) 110 { 111 size_t nBytesRead; 112 sal_uInt8 buffer[BUFFER_SIZE]; 113 bool bHeader(true); 114 115 while ( rtl_Digest_E_None == error && 116 0 != (nBytesRead = fread( buffer, 1, sizeof(buffer), fp )) ) 117 { 118 if (bHeader) 119 { 120 bHeader = false; 121 if (nBytesRead >= MINIMAL_SIZE && buffer[0] == sal_uInt8('M') && buffer[1] == sal_uInt8('Z') ) 122 normalize_pe_image(buffer, nBytesRead); 123 } 124 125 error = rtl_digest_updateMD5( digest, buffer, nBytesRead ); 126 } 127 128 if ( rtl_Digest_E_None == error ) 129 { 130 error = rtl_digest_getMD5( digest, checksum, sizeof(checksum) ); 131 } 132 133 rtl_digest_destroyMD5( digest ); 134 135 for ( std::size_t i = 0; i < sizeof(checksum); i++ ) 136 { 137 if ( checksum[i] < 16 ) 138 aChecksum.Append( "0" ); 139 aChecksum += ByteString::CreateFromInt32( checksum[i], 16 ); 140 } 141 } 142 143 fclose( fp ); 144 } 145 else 146 error = rtl_Digest_E_Unknown; 147 148 return error; 149 } 150