📄 sha256.cpp
字号:
/******************************************************************* * * Copyright (c) 1994-2005 Jetico, Inc., Finland * All rights reserved. * * File: sha256.cpp * Revision: * Created: * Description: implementation of SHA-256 (SHA-2) Secure Hash Algorithm * *******************************************************************///#include "stdafx.h"//#include <windows.h>#include <stddef.h>#include <stdlib.h>#include <malloc.h>#include <memory.h>#include <bc_types.h>#include "sha256.h"/* Initial hash values */#define A_init 0x6a09e667 #define B_init 0xbb67ae85 #define C_init 0x3c6ef372 #define D_init 0xa54ff53a #define E_init 0x510e527f #define F_init 0x9b05688c #define G_init 0x1f83d9ab #define H_init 0x5be0cd19 static const DWORD CONST_K[64] = { 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2};/* SHA-256's set of functions * * * According to SHA-2 specification: * * Ch(x,y,z) = (x & y) ^ ((~x) & z) * Maj(x,y,z) = (x & y) ^ (x & z) ^ (y & z) * * SHA-2 specification states: "Each of the algorithm include Ch and Maj * functions; the Exclusive-OR operation (^) in these functions may be replaced * by a bitwise OR operation (|) and produce identical results". Hence * * Ch(x,y,z) = (x & y) | ((~x) & z) * Maj(x,y,z) = (x & y) | (x & z) ^ (y & z) * * * According to Rich Schroeppel: * (X & Y) | (~X & Z) == Z ^ (X & (Y ^ Z)) // the last does not require ~ operation * And obvious enough: * (X & Y) | (X & Z) | (Y & Z) == (X & (Y | Z)) | (Y & Z) */#define Ch(X,Y,Z) ((Z) ^ ((X) & ((Y) ^ (Z))))#define Maj(X,Y,Z) (((X) & ((Y) | (Z))) | ((Y) & (Z)))/* * Shift and Rotate and Rotate right */#define SHR(number_bits, variable) ((variable) >> (number_bits))#define ROTR(number_bits,variable) (((variable) >> (number_bits)) | ((variable) << (32 - (number_bits))))/* * SHA-256 SUM functions */#define SUM_0_256(x) (ROTR(2, (x)) ^ ROTR(13, (x)) ^ ROTR(22, (x)))#define SUM_1_256(x) (ROTR(6, (x)) ^ ROTR(11, (x)) ^ ROTR(25, (x)))#define sum_0_256(x) (ROTR(7, (x)) ^ ROTR(18, (x)) ^ SHR(3 , (x)))#define sum_1_256(x) (ROTR(17, (x)) ^ ROTR(19, (x)) ^ SHR(10, (x)))static void SHA256_UpdateDigest( DWORD *Digest, DWORD *MessageBlock ) { DWORD a, b, c, d, e, f, g, h, tmp0, tmp1, sum0, sum1; DWORD T1, T2, *W; int i; a = Digest[0]; b = Digest[1]; c = Digest[2]; d = Digest[3]; e = Digest[4]; f = Digest[5]; g = Digest[6]; h = Digest[7]; W = MessageBlock; for (i=0; i<16; i++) { W[i] = *MessageBlock++; T1 = h + SUM_1_256(e) + Ch(e, f, g) + CONST_K[i] + W[i]; T2 = SUM_0_256(a) + Maj(a, b, c); h = g; g = f; f = e; e = d + T1; d = c; c = b; b = a; a = T1 + T2; } // i starts from 17 == 10001 for ( ; i<64; i++ ) { tmp0 = W[ (i+1) & 0x0f ]; // W[i-15] sum0 = sum_0_256( tmp0 ); tmp1 = W[ (i+14) & 0x0f ]; // W[i-2] sum1 = sum_1_256(tmp1); W[ i & 0x0f ] += sum1 + W[ (i+9) & 0x0f ] + sum0; // W[ (i+9) & 0x0f ] is the same as W[ t - 7 ] in SHA-256 specification T1 = h + SUM_1_256(e) + Ch(e, f, g) + CONST_K[i] + W[ i & 0x0f ]; // T2 and further calculation is the same as in the loop 0 < i < 16 T2 = SUM_0_256(a) + Maj(a, b, c); h = g; g = f; f = e; e = d + T1; d = c; c = b; b = a; a = T1 + T2; } /* Calculate new Message Digest */ Digest[0] = (Digest[0] + a) & 0xffffffff; Digest[1] = (Digest[1] + b) & 0xffffffff; Digest[2] = (Digest[2] + c) & 0xffffffff; Digest[3] = (Digest[3] + d) & 0xffffffff; Digest[4] = (Digest[4] + e) & 0xffffffff; Digest[5] = (Digest[5] + f) & 0xffffffff; Digest[6] = (Digest[6] + g) & 0xffffffff; Digest[7] = (Digest[7] + h) & 0xffffffff;}/************************************************************************ * * Two useful functions: * ReverseDWORDs - worries about Big and Little Endians * copyDigestToByteArray - may be, we want to copy digest from Context to * independent byte array *************************************************************************/static void copyDigestToByteArray(DWORD *dwInp, byte *bOut ){ int i, j; for(i = 0, j = 0; j < 32; i++, j += 4) /* 32 - is the SHA-256 Digest length in bytes */ { bOut[j+3] = (byte)( dwInp[i] & 0xff); bOut[j+2] = (byte)((dwInp[i] >> 8) & 0xff); bOut[j+1] = (byte)((dwInp[i] >> 16) & 0xff); bOut[j] = (byte)((dwInp[i] >> 24) & 0xff); }}/* The function automatically defines if we are Big or Little Endian */static void ReverseDWORDs( DWORD *Data, int Number_of_DWORDs ){ int i; DWORD dwTmp; if((*(DWORD *)("ABCD") >> 24) == 'A') return; // Nothing to do for(i=0; i<Number_of_DWORDs; i++) { dwTmp = (Data[i] << 16) | (Data[i] >> 16); Data[i] = ((dwTmp & 0xFF00FF00L) >> 8) | ((dwTmp & 0x00FF00FFL) << 8); }}/************************************************************************* * * SHA256_Init() initializes a context of the message digest calculations. * The memory to store the context is reserved before and the pointer * on the context's memory stored in FSHashAlgorithm element * *************************************************************************/int SHA256_Init(void *context){ SHA256Context *sha_ctx = (SHA256Context *)context; sha_ctx->digest[0] = A_init; sha_ctx->digest[1] = B_init; sha_ctx->digest[2] = C_init; sha_ctx->digest[3] = D_init; sha_ctx->digest[4] = E_init; sha_ctx->digest[5] = F_init; sha_ctx->digest[6] = G_init; sha_ctx->digest[7] = H_init; /* Initialise bit count */ sha_ctx->countLo = sha_ctx->countHi = 0; memset( sha_ctx->data, 0, 64 ); return SHA256_ERROR_NO;}/************************************************************************* * * SHA256_Process() is called multiple times (if needed) until our message * buffer is not empty * *************************************************************************/int SHA256_Process(void *context, byte *data, size_t length){ DWORD dwTmp, dataCount, len; byte *bPtr, *msgPtr; SHA256Context *sha_ctx = (SHA256Context *)context; /* Update byte count */ /* Check if the overflow occured in the countLo */ dwTmp = sha_ctx->countLo; if ((sha_ctx->countLo = dwTmp + length) < dwTmp) (sha_ctx->countHi)++; /* If the previous Message was not multiply of 64 bytes, * we store remain of the previous Message in SHA_CTX->data[] array. * Calculate, how many bytes we currently store in SHA_CTX->data[] */ /* calculate in dataCount number of BUSY bytes in sha_ctx->data buffer */ dataCount = dwTmp & 0x3F; msgPtr = data; len = length; if (dataCount) { bPtr = (byte *)sha_ctx->data + dataCount; /* calculate in dataCount number of FREE bytes in sha_ctx->data buffer */ dataCount = 64 - dataCount; /* 64 bytes == 512 bites == SHA-256 block size */ if ( length < dataCount ) { memcpy( bPtr, data, length ); return SHA256_ERROR_NO; } /* in dataCount - number of free bytes in sha_ctx->data buffer */ memcpy( bPtr, data, dataCount ); ReverseDWORDs( sha_ctx->data, 16 ); SHA256_UpdateDigest( sha_ctx->digest, sha_ctx->data ); msgPtr += dataCount; len -= dataCount; } /* Process data in 64-bytes (512 bites) blocks */ while( len >= 64 ) { memcpy( sha_ctx->data, msgPtr, 64 ); ReverseDWORDs( sha_ctx->data, 16 ); SHA256_UpdateDigest( sha_ctx->digest, sha_ctx->data ); msgPtr += 64; len -= 64; } /* Save remaining bytes of Message. */ if (len > 0) memcpy( sha_ctx->data, msgPtr, len ); return SHA256_ERROR_NO;}/*************************************************************************** * * SHA256_Final(): All message buffer is transformed using SHA256_Process(). * To get the final Message Digest, we have to call SHA256_Final() * ***************************************************************************/int SHA256_Final(void *context, byte *digest) /* 'digest' array must be >= 32 bytes */{ DWORD count; byte *dataPtr; SHA256Context *sha_ctx = (SHA256Context *)context; /* Calculate number of BUSY bytes in sha_ctx->data buffer */ count = sha_ctx->countLo & 0x3F; /* Set the first char of padding to 0x80. This is safe since there is always at least one byte free */ dataPtr = (byte *)sha_ctx->data + count; *dataPtr++ = 0x80; /* Calculate number of FREE bytes in sha_ctx->data buffer */ count = 63 - count; /* sha_ctx->data is 64 bytes, but we already used one byte for 0x80 */ /* If count is more than 8, it means that we have the place for * 2 DWORDS to place the length of message. * If no, we have to pad the current 64-byte block by 0, re-calculate * digest, then fill the first 56 bytes in sha_ctx->data by 0, place * the length of Message to the last 8 bytes and calculate final Digest */ if( count < 8 ) { memset( dataPtr, 0, count ); ReverseDWORDs( sha_ctx->data, 16 ); SHA256_UpdateDigest( sha_ctx->digest, sha_ctx->data ); /* prepare to calculate final digest, where the length will be written in last 8 bytes */ memset( sha_ctx->data, 0, 56 ); } else if (count > 8) memset(dataPtr, 0, count - 8); // size of digest is in bits, hence, we should multiply count by 8 or shift left on 3 sha_ctx->data[14] = (((sha_ctx->countHi) << 3) & 0xffffffff) | (((sha_ctx->countLo) >> 29) & 0x7); sha_ctx->data[15] = ((sha_ctx->countLo) << 3) & 0xffffffff; ReverseDWORDs( sha_ctx->data, 14 ); // Do not reverse last 8 bytes (or 2 DWORDs) SHA256_UpdateDigest( sha_ctx->digest, sha_ctx->data ); copyDigestToByteArray( sha_ctx->digest, digest ); return SHA256_ERROR_NO;}/************************************************************************* * * SHA256_Update() - call the function if (and only if) the size of byte * array "data" is equal to the block size of SHA-256 algorithm, i.e. * 512 bits == 64 bytes * *************************************************************************/int SHA256_Update(void *context, byte *data){ SHA256Context *sha_ctx; sha_ctx = (SHA256Context *)context; /* 16 * sizeof(DWORD) == 64 bytes */ memcpy( sha_ctx->data, data, 16 ); ReverseDWORDs( sha_ctx->data, 16 ); SHA256_UpdateDigest( sha_ctx->digest, sha_ctx->data ); return SHA256_ERROR_NO;}/*************************************************************************** * * SHA256_Allocate() - allocates memory needed for SHA256Context structure * ***************************************************************************/int SHA256_Allocate(void **context){ *context = malloc(sizeof(SHA256Context)); if (*context) { return SHA256_ERROR_NO; } return SHA256_ERROR_INTERNAL_ERROR;}/********************************************************************** * * SHA256_Free() - Frees resources allocated in SHA256_Allocate * **********************************************************************/int SHA256_Free(void **context){ free(*context); *context = 0; return SHA256_ERROR_NO;}/************************************************************************ * * SHA256_MakeDigest() - Helpful function if the whole message is in the * memory and we have to create digest for it. * ************************************************************************/int SHA256_MakeDigest( byte *message, int messageLength, byte *digest ){ SHA256Context *context; if ( SHA256_Allocate((void **)(&context)) != SHA256_ERROR_NO ) return SHA256_ERROR_INTERNAL_ERROR; if ( SHA256_Init(context) != SHA256_ERROR_NO) { SHA256_Free((void **)(&context)); return SHA256_ERROR_INTERNAL_ERROR; } if ( SHA256_Process(context, message, messageLength) != SHA256_ERROR_NO ) { SHA256_Free((void **)(&context)); return SHA256_ERROR_INTERNAL_ERROR; } if ( SHA256_Final(context, digest) != SHA256_ERROR_NO ) { SHA256_Free((void **)(&context)); return SHA256_ERROR_INTERNAL_ERROR; } SHA256_Free((void **)(&context)); return SHA256_ERROR_NO;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -