//SHA1_Class.h#pragma once//RFC 3174 US Secure Hash Algorithm 1 (SHA1)/* * If you do not have the ISO standard stdint.h header file, then you * must typdef the following: * name meaning * uint32_t unsigned 32 bit integer * uint8_t unsigned 8 bit integer (i.e., unsigned char) * int_least16_t integer of >= 16 bits * */class CSHA1_Class{ typedef unsigned long uint32_t; typedef unsigned char uint8_t; typedef unsigned short int_least16_t; typedef unsigned long UINT4; #define SHA1HashSize 20 /* * This structure will hold context information for the SHA-1 * hashing operation */ typedef struct SHA1Context { uint32_t Intermediate_Hash[SHA1HashSize/4]; /* Message Digest */ uint32_t Length_Low; /* Message length in bits */ uint32_t Length_High; /* Message length in bits */ /* Index into message block array */ int_least16_t Message_Block_Index; uint8_t Message_Block[64]; /* 512-bit message blocks */ int Computed; /* Is the digest computed? */ int Corrupted; /* Is the message digest corrupted? */ } SHA1Context; SHA1Context m_SHA1Context;public: enum { shaSuccess = 0, shaNull, /* Null pointer parameter */ shaInputTooLong, /* input data too long */ shaStateError /* called Input after Result */ }; typedef struct _PROC_INFO { ULONGLONG uLL_TotalSize; //需要校正的總位元組數 ULONGLONG uLL_ProcessedSize; //已經校正的位元組數 double f_ProcPercent; //精度百分百 % TCHAR m_rawHash[2*SHA1HashSize+1]; //校正結果 BOOL bDone; //完成標誌 }PROC_INFO, *LPPROC_INFO; /* * Function Prototypes */ int SHA1Reset(); int SHA1Input(const uint8_t *, unsigned); int SHA1Result(uint8_t Message_Digest[SHA1HashSize]); int FileCalculate(LPCTSTR lpszFile, LPPROC_INFO pProcInfo=NULL);/* Local Function Prototyptes */private: void SHA1PadMessage(); void SHA1ProcessMessageBlock(); /* * Define the SHA1 circular left shift macro */ #define SHA1CircularShift(bits,word) \ (((word) << (bits)) | ((word) >> (32-(bits))))};
///////////////////////////////////////////////SHA1_Class.cpp#include "stdafx.h"#include "SHA1_Class.h"/* * sha1_class.cpp * * Description: * This file implements the Secure Hashing Algorithm 1 as * defined in FIPS PUB 180-1 published April 17, 1995. * * The SHA-1, produces a 160-bit message digest for a given * data stream. It should take about 2**n steps to find a * message with the same digest as a given message and * 2**(n/2) to find any two messages with the same digest, * when n is the digest size in bits. Therefore, this * algorithm can serve as a means of providing a * "fingerprint" for a message. * * Portability Issues: * SHA-1 is defined in terms of 32-bit "words". This code * uses <stdint.h> (included via "sha1.h" to define 32 and 8 * bit unsigned integer types. If your C compiler does not * support 32 bit unsigned integers, this code is not * appropriate. * * Caveats: * SHA-1 is designed to work with messages less than 2^64 bits * long. Although SHA-1 allows a message digest to be generated * for messages of any number of bits less than 2^64, this * implementation only works with messages with a length that is * a multiple of the size of an 8-bit character. * *//* * SHA1Reset * * Description: * This function will initialize the SHA1Context in preparation * for computing a new SHA1 message digest. * * Parameters: * context: [in/out] * The context to reset. * * Returns: * sha Error Code. * */int CSHA1_Class::SHA1Reset(){ memset(&m_SHA1Context, 0, sizeof(m_SHA1Context)); m_SHA1Context.Intermediate_Hash[0] = 0x67452301; m_SHA1Context.Intermediate_Hash[1] = 0xEFCDAB89; m_SHA1Context.Intermediate_Hash[2] = 0x98BADCFE; m_SHA1Context.Intermediate_Hash[3] = 0x10325476; m_SHA1Context.Intermediate_Hash[4] = 0xC3D2E1F0; m_SHA1Context.Computed = 0; m_SHA1Context.Corrupted = 0; return shaSuccess;}/* * SHA1Result * * Description: * This function will return the 160-bit message digest into the * Message_Digest array provided by the caller. * NOTE: The first octet of hash is stored in the 0th element, * the last octet of hash in the 19th element. * * Parameters: * context: [in/out] * The context to use to calculate the SHA-1 hash. * Message_Digest: [out] * Where the digest is returned. * * Returns: * sha Error Code. * */int CSHA1_Class::SHA1Result(uint8_t Message_Digest[SHA1HashSize]){ int i; if ( !Message_Digest ) { return shaNull; } if (m_SHA1Context.Corrupted) { return m_SHA1Context.Corrupted; } if (!m_SHA1Context.Computed) { SHA1PadMessage(); for(i=0; i<64; ++i) { /* message may be sensitive, clear it out */ m_SHA1Context.Message_Block[i] = 0; } m_SHA1Context.Length_Low = 0; /* and clear length */ m_SHA1Context.Length_High = 0; m_SHA1Context.Computed = 1; } for(i = 0; i < SHA1HashSize; ++i) { Message_Digest[i] = (uint8_t)( m_SHA1Context.Intermediate_Hash[i>>2] >> 8 * ( 3 - ( i & 0x03 ) ) ); } return shaSuccess;}/* * SHA1Input * * Description: * This function accepts an array of octets as the next portion * of the message. * * Parameters: * context: [in/out] * The SHA context to update * message_array: [in] * An array of characters representing the next portion of * the message. * length: [in] * The length of the message in message_array * * Returns: * sha Error Code. * */int CSHA1_Class::SHA1Input( const uint8_t *message_array, unsigned length){ if (!length) { return shaSuccess; } if (!message_array) { return shaNull; } if (m_SHA1Context.Computed) { m_SHA1Context.Corrupted = shaStateError; return shaStateError; } if (m_SHA1Context.Corrupted) { return m_SHA1Context.Corrupted; } while(length-- && !m_SHA1Context.Corrupted) { m_SHA1Context.Message_Block[m_SHA1Context.Message_Block_Index++] = (*message_array & 0xFF); m_SHA1Context.Length_Low += 8; if (m_SHA1Context.Length_Low == 0) { m_SHA1Context.Length_High++; if (m_SHA1Context.Length_High == 0) { /* Message is too long */ m_SHA1Context.Corrupted = 1; } } if (m_SHA1Context.Message_Block_Index == 64) { SHA1ProcessMessageBlock(); } message_array++; } return shaSuccess;}int CSHA1_Class::FileCalculate(LPCTSTR lpszFile, LPPROC_INFO pProcInfo/*=NULL*/){ SHA1Reset(); if(pProcInfo) { memset(pProcInfo, 0, sizeof(PROC_INFO)); } if(_tcslen( lpszFile ) > 0) { HANDLE hFile = CreateFile( lpszFile, GENERIC_READ ,// 如果要對應檔:此處必設定為唯讀(GENERIC_READ)或讀寫 0, // 此設為開啟檔案的任何嘗試均將失敗 NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, //|FILE_FLAG_WRITE_THROUGH,【解1】 NULL); if (hFile != INVALID_HANDLE_VALUE)// 檔案開啟失敗返回控制代碼為-1 { HANDLE hFileMap = CreateFileMapping( hFile, // 如果這值為INVALID_HANDLE_VALUE,是合法的,上步一定測試啊 NULL, // 預設安全性 PAGE_READONLY, //唯讀 0, // 2個32位元示1個64位元,最大檔案位元組數, 0,//dwFileSize, // 此為低位元組,也就是最主要的參數,如果為0,取檔案真實大小 NULL); if (hFileMap != NULL) { LARGE_INTEGER dwFileSize = {0}; GetFileSizeEx(hFile, &dwFileSize); if(pProcInfo) pProcInfo->uLL_TotalSize = dwFileSize.QuadPart; LARGE_INTEGER dwOffset = {0}; while(dwOffset.QuadPart < dwFileSize.QuadPart) { ULONGLONG partLen = dwFileSize.QuadPart - dwOffset.QuadPart; UINT4 dwLen = (64 * 1024) * 1024; //64M 64K對齊 if(partLen < dwLen) dwLen = (UINT4)partLen; LPVOID pvFile = MapViewOfFileEx( //pvFile就是得到的指標,用它來直接操作檔案 hFileMap, FILE_MAP_READ , //讀 dwOffset.HighPart, // 檔案指標頭位置 高位元組 dwOffset.LowPart, // 檔案指標頭位置 低位元組 必為分配粒度的整倍數,windows的粒度為64K dwLen, // 要映射的檔案尾,如果為0,則從指標頭到真實檔案尾 NULL); if (pvFile != NULL) { SHA1Input((unsigned char *)pvFile, dwLen);//calc UnmapViewOfFile(pvFile); // 釋放記憶體對應檔的頭指標 } else { TRACE( _T("MapViewOfFile Error=%d\n"), GetLastError()); } dwOffset.QuadPart += dwLen; if(pProcInfo) { pProcInfo->uLL_ProcessedSize = dwOffset.QuadPart; pProcInfo->f_ProcPercent = (double)pProcInfo->uLL_ProcessedSize/(double)pProcInfo->uLL_TotalSize * 100.0; } } CloseHandle(hFileMap); // 記憶體對應檔控制代碼 } else { TRACE( _T("CreateFileMapping Error=%d\n"), GetLastError()); } CloseHandle(hFile); // 關閉檔案 } else { TRACE( _T("CreateFile Error=%d\n"), GetLastError()); } } BYTE Message_Digest[SHA1HashSize]; SHA1Result( Message_Digest ); TCHAR m_sHash[2*SHA1HashSize + 1] = {0}; for(int i=0; i<SHA1HashSize; i++) { TCHAR buff[16]; _stprintf_s(buff, _T("%02X"), Message_Digest[i]); _tcscat_s(m_sHash, buff); } if(pProcInfo) { _tcscpy_s(pProcInfo->m_rawHash, m_sHash); pProcInfo->bDone = TRUE; } return shaSuccess;}/* * SHA1ProcessMessageBlock * * Description: * This function will process the next 512 bits of the message * stored in the Message_Block array. * * Parameters: * None. * * Returns: * Nothing. * * Comments: * Many of the variable names in this code, especially the * single character names, were used because those were the * names used in the publication. * * */void CSHA1_Class::SHA1ProcessMessageBlock(){ const uint32_t K[] = { /* Constants defined in SHA-1 */ 0x5A827999, 0x6ED9EBA1, 0x8F1BBCDC, 0xCA62C1D6 }; int t; /* Loop counter */ uint32_t temp; /* Temporary word value */ uint32_t W[80]; /* Word sequence */ uint32_t A, B, C, D, E; /* Word buffers */ /* * Initialize the first 16 words in the array W */ for(t = 0; t < 16; t++) { W[t] = m_SHA1Context.Message_Block[t * 4] << 24; W[t] |= m_SHA1Context.Message_Block[t * 4 + 1] << 16; W[t] |= m_SHA1Context.Message_Block[t * 4 + 2] << 8; W[t] |= m_SHA1Context.Message_Block[t * 4 + 3]; } for(t = 16; t < 80; t++) { W[t] = SHA1CircularShift(1,W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16]); } A = m_SHA1Context.Intermediate_Hash[0]; B = m_SHA1Context.Intermediate_Hash[1]; C = m_SHA1Context.Intermediate_Hash[2]; D = m_SHA1Context.Intermediate_Hash[3]; E = m_SHA1Context.Intermediate_Hash[4]; for(t = 0; t < 20; t++) { temp = SHA1CircularShift(5,A) + ((B & C) | ((~B) & D)) + E + W[t] + K[0]; E = D; D = C; C = SHA1CircularShift(30,B); B = A; A = temp; } for(t = 20; t < 40; t++) { temp = SHA1CircularShift(5,A) + (B ^ C ^ D) + E + W[t] + K[1]; E = D; D = C; C = SHA1CircularShift(30,B); B = A; A = temp; } for(t = 40; t < 60; t++) { temp = SHA1CircularShift(5,A) + ((B & C) | (B & D) | (C & D)) + E + W[t] + K[2]; E = D; D = C; C = SHA1CircularShift(30,B); B = A; A = temp; } for(t = 60; t < 80; t++) { temp = SHA1CircularShift(5,A) + (B ^ C ^ D) + E + W[t] + K[3]; E = D; D = C; C = SHA1CircularShift(30,B); B = A; A = temp; } m_SHA1Context.Intermediate_Hash[0] += A; m_SHA1Context.Intermediate_Hash[1] += B; m_SHA1Context.Intermediate_Hash[2] += C; m_SHA1Context.Intermediate_Hash[3] += D; m_SHA1Context.Intermediate_Hash[4] += E; m_SHA1Context.Message_Block_Index = 0;}/* * SHA1PadMessage * * Description: * According to the standard, the message must be padded to an even * 512 bits. The first padding bit must be a '1'. The last 64 * bits represent the length of the original message. All bits in * between should be 0. This function will pad the message * according to those rules by filling the Message_Block array * accordingly. It will also call the ProcessMessageBlock function * provided appropriately. When it returns, it can be assumed that * the message digest has been computed. * * Parameters: * context: [in/out] * The context to pad * ProcessMessageBlock: [in] * The appropriate SHA*ProcessMessageBlock function * Returns: * Nothing. * */void CSHA1_Class::SHA1PadMessage(){ /* * Check to see if the current message block is too small to hold * the initial padding bits and length. If so, we will pad the * block, process it, and then continue padding into a second * block. */ if (m_SHA1Context.Message_Block_Index > 55) { m_SHA1Context.Message_Block[m_SHA1Context.Message_Block_Index++] = 0x80; while(m_SHA1Context.Message_Block_Index < 64) { m_SHA1Context.Message_Block[m_SHA1Context.Message_Block_Index++] = 0; } SHA1ProcessMessageBlock(); while(m_SHA1Context.Message_Block_Index < 56) { m_SHA1Context.Message_Block[m_SHA1Context.Message_Block_Index++] = 0; } } else { m_SHA1Context.Message_Block[m_SHA1Context.Message_Block_Index++] = 0x80; while(m_SHA1Context.Message_Block_Index < 56) { m_SHA1Context.Message_Block[m_SHA1Context.Message_Block_Index++] = 0; } } /* * Store the message length as the last 8 octets */ m_SHA1Context.Message_Block[56] = (uint8_t)(m_SHA1Context.Length_High >> 24); m_SHA1Context.Message_Block[57] = (uint8_t)(m_SHA1Context.Length_High >> 16); m_SHA1Context.Message_Block[58] = (uint8_t)(m_SHA1Context.Length_High >> 8); m_SHA1Context.Message_Block[59] = (uint8_t)(m_SHA1Context.Length_High); m_SHA1Context.Message_Block[60] = (uint8_t)(m_SHA1Context.Length_Low >> 24); m_SHA1Context.Message_Block[61] = (uint8_t)(m_SHA1Context.Length_Low >> 16); m_SHA1Context.Message_Block[62] = (uint8_t)(m_SHA1Context.Length_Low >> 8); m_SHA1Context.Message_Block[63] = (uint8_t)(m_SHA1Context.Length_Low); SHA1ProcessMessageBlock();}
//應用舉例void CSHA1_CalculatorDlg::OnBnClickedStringCal(){ // TODO: 在此添加控制項通知處理常式代碼 CHAR szInput[2049]; GetDlgItemTextA(GetSafeHwnd(), IDC_STRING_EDIT, szInput, 2048); BYTE Message_Digest[SHA1HashSize]; CSHA1_Class m_SHA1; m_SHA1.SHA1Reset(); m_SHA1.SHA1Input((const unsigned char*)szInput, strlen(szInput)); m_SHA1.SHA1Result(Message_Digest); CString itemStr; for(int i=0; i<SHA1HashSize; i++) { TCHAR buff[16]; _stprintf_s(buff, _T("%02X"), Message_Digest[i]); itemStr += buff; } SetDlgItemText(IDC_STRING_RESULT, itemStr);}