计算量超500KB报错
OTA升级中可能会涉及到CRC、hash校验等算法,小编从网上抄到了HASH256的源码,拿来使用的时候却发现了一个问题,当源文件约大于500KB的时候会发现其计算出的hash值出现错误。
经过实际测试得知,当源文件大于约500kb时,用开源代码计算的hash值存在概率不正确的情况,而且发现其源文件大小/8byte为整数时计算出的结果是正确的(如下图计算出来的就是错误的)。
本着快速解决项目问题的想法,想到了将源文件大小补齐/8byte为整数的操作。(实际是小编暂时没能力找到问题所在哈哈哈)
若大家有更好的解决办法请指出~
代码片(.C)
c
/*
* @Description:
* @Author: shimianxiang
* @Date: 2023-10-11 08:27:06
* @LastEditTime: 2023-10-25 11:28:06
* @LastEditors: shimianxiang
*/
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include "mcuhash2.h"
#include<time.h>
#include <math.h>
uint32_t TW[16];
uint8_t bitbuff[512/8];
uint32_t bitbuff_num=0;
uint32_t fill_data[64]={ 0x80000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000 };
uint32_t data[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-------------------------------------------------------*/
uint32_t Ch(uint32_t x, uint32_t y, uint32_t z)
{
return (x & y) ^ (~x & z);
}
uint32_t cycle_rshift(uint32_t x,uint32_t n)
{
return ((x & (((uint32_t)1 << n) - 1)) << (32 - n))|(x >> n);
}
uint32_t Sum0(uint32_t x)
{
return cycle_rshift(x, 2) ^ cycle_rshift(x, 13) ^ cycle_rshift(x, 22);
}
uint32_t Sum1(uint32_t x)
{
return cycle_rshift(x, 6) ^ cycle_rshift(x, 11) ^ cycle_rshift(x, 25);
}
uint32_t Sigma0(uint32_t x)
{
return cycle_rshift(x, 7) ^ cycle_rshift(x, 18) ^ (x>>3);
}
uint32_t Sigma1(uint32_t x)
{
return cycle_rshift(x, 17) ^ cycle_rshift(x, 19) ^ (x >> 10);
}
uint32_t Ma(uint32_t x, uint32_t y, uint32_t z)
{
return (x & y) ^ (x & z)^ (y & z);
}
void sha_init(struct sha256 *s)
{
s->hash[0] = H0;
s->hash[1] = H1;
s->hash[2] = H2;
s->hash[3] = H3;
s->hash[4] = H4;
s->hash[5] = H5;
s->hash[6] = H6;
s->hash[7] = H7;
s->hash_length = 0;
s->index = 0;
s->offset = 0;
}
void sha_caculator(struct sha256* s)//先补齐 Wt,然后循环64次加密
{
uint8_t i = 0;
uint32_t m0, s0, s1,c1,t1;
uint32_t temp[8];
for(i=0;i<8;i++)
temp[i]=s->hash[i];
for (i = 0; i < 16; i++)
Wt[i] = s->block[i];
for (i = 16; i < 64; i++)
Wt[i] = Sigma1(Wt[i-2])+ Wt[i-7]+Sigma0(Wt[i - 15])+ Wt[i - 16];
for (i = 0; i < 64; i++)
{
s0 = Sum0(temp[0]);
s1 = Sum1(temp[4]);
m0 = Ma(temp[0], temp[1], temp[2]);
c1 = Ch(temp[4], temp[5], temp[6]);
t1 = s1+c1+temp[7]+Wt[i] + Kt[i];
temp[7] = temp[6];
temp[6] = temp[5];
temp[5] = temp[4];
temp[4] = temp[3]+ t1;
temp[3] = temp[2];
temp[2] = temp[1];
temp[1] = temp[0];
temp[0] = t1+m0+s0;
}
for (i = 0; i < 8; i++)
s->hash[i]+=temp[i];
}
void sha_updata(struct sha256* s,unsigned char *str,uint64_t len)
{
uint64_t i = 0;
uint64_t count;
s->hash_length += len;
if (s->offset!=0)//说明没有4字节对齐
{
if (s->offset + len < 4)
{
for (i = s->offset; i < s->offset+len; i++)
{
s->block[s->index] |= (((uint32_t)(*str)) << (8 * (3 - i)));
str++;
}
s->offset += len;
return;
}
else
{
len = len + s->offset - 4;
for (i = s->offset; i < 4; i++)
{
s->block[s->index] |= (((uint32_t)(*str)) << (8 * (3 - i)));
str++;
}
s->index++;
if (s->index == 16)
{
sha_caculator(s);//满足512bit 16Word加密一次
s->index = 0;
}
}
}
count = (len >> 2);//计算这次加密有多少个Word
s->offset = len % 4;//对齐Word剩余的byte
for(i=0;i<count;i++)
{
s->block[s->index] = (((uint32_t)(*str)) << 24) |
((*(str + 1)) << 16) |
((*(str + 2)) << 8) |
(*(str + 3));
s->index++;
str += 4;
if (s->index == 16)
{
sha_caculator(s);//满足512bit 16Word加密一次
s->index = 0;
}
}
s->block[s->index] = 0;//对齐Word剩余的byte写在 s->index 位置上,供下一次update使用
for (i = 0; i < s->offset; i++)
{
s->block[s->index] |= (((uint32_t)(*str)) << (8 * (3 - i)));
str++;
}
}
void sha_final(struct sha256* s)
{
uint8_t temp=s->hash_length % 64;//计算需要填充多少byte
uint8_t fill[4] = { 0x80,0x0,0x0,0x0 };
uint32_t i;
if (temp == 56)//则需要填充一个512bit
{
//补齐前一次的512bit
if (s->offset != 0)
{
for (i = 0; i < 4-s->offset; i++)
s->block[s->index] |= (fill[i]<< (8 * (3 - i-s->offset)));
s->index++;
}
else
{
s->block[s->index] = 0x80000000;
s->index++;
}
for (i = s->index; i < 16; i++)
s->block[i] = 0;
sha_caculator(s);
for(i=0;i<14;i++)
s->block[i] = 0;
s->block[14] = s->hash_length >> 29;
s->block[15] = s->hash_length << 3 & 0xffffffff;
sha_caculator(s);
}
else
{
if (s->offset != 0)
{
for (i = 0; i < 4-s->offset; i++)
s->block[s->index] |= (fill[i] << (8 * ( 3 - i - s->offset)));
s->index++;
}
else
{
s->block[s->index] = 0x80000000;
s->index++;
}
for (i = s->index; i < 14; i++)
s->block[i] = 0;
s->block[14] = s->hash_length>> 29;
s->block[15] = s->hash_length<<3 & 0xffffffff;
sha_caculator(s);
}
}
/*-----------------------------------------------------------------------sort-------------------------------------------------------*/
uint32_t FlashASH_256(uint8_t *outdata,uint8_t *data,uint32_t length)
{
uint32_t bitnum = (length+bitbuff_num) % 64;
uint32_t hash_times = (length+bitbuff_num)/64;
uint32_t offset_num = 0;
uint32_t bitbuff_num_or = 0;
while (hash_times)
{
if(bitbuff_num == 0)
{
memcpy(&outdata[0],&data[0]+64*offset_num+bitbuff_num_or,64);
hash_times--;
offset_num++;
// for(int i=0;i<4;i++)
// {
// printf("%x %x %x %x ",TW[i*4+0],TW[i*4+1],TW[i*4+2],TW[i*4+3]);
// }
// printf("\n-----------------\n");
}
else
{
bitbuff_num_or = 64-bitbuff_num;
memcpy(&outdata[0],&bitbuff[0],bitbuff_num);
memcpy(&outdata[0]+bitbuff_num,&data[0]+64*offset_num,bitbuff_num_or);
// memcpy(&outdata[0]+1,&data[0]+64*offset_num,bitbuff_num_or);
hash_times--;
bitbuff_num = 0;
// for(int i=0;i<4;i++)
// {
// printf("%x %x %x %x ",TW[i*4+0],TW[i*4+1],TW[i*4+2],TW[i*4+3]);
// }
// printf("\n+----------------\n");
}
}
if(bitnum != 0)
{
memcpy(&bitbuff[0]+bitbuff_num,&data[0]+64*offset_num+bitbuff_num_or,bitnum);
bitbuff_num = bitnum;
// printf("\n get %d\n",bitnum);
bitnum = 0;
}
else
{
bitbuff_num = 0;
}
return bitbuff_num;
}
int main(int argc, char const *argv[])
{
printf("start \n");
#if 0
for(int i=1;i<16;i++)
{
TW[i]=0xffffffff+i;
}
uint8_t* inaddr_end=&fill_data[0];
uint8_t* inaddr=&data[0];
// memcpy(&TW[0],&Kt[0],65);
FlashASH_256(&TW[0],&inaddr[0],120);
FlashASH_256(&TW[0],&inaddr[120],1);
FlashASH_256(&TW[0],&inaddr[121],4);
FlashASH_256(&TW[0],&inaddr[125],35);
uint32_t num=FlashASH_256(&TW[0],&inaddr[160],36);
// FlashASH_256(&Kt[0]+129,63);
FlashASH_256(&TW[0],&inaddr_end[0],(uint32_t)64-num);
printf("last_num= %d\n",num);
#elif 0
FILE *fp = fopen("./tesths.c", "rb");
if(fp == NULL)
{
printf("can not open file\n");
return -1;
}
fseek(fp, 0, SEEK_END);
uint32_t size = ftell(fp);
char encrypt[1024*1024];
fseek(fp, 0, SEEK_SET);
printf("\n size: %d \n",size);
int len = fread(encrypt, sizeof(char), size, fp);
fclose(fp);
struct sha256 testsha;
// uint8_t* inaddr=&data[0];
sha_init(&testsha);
sha_updata(&testsha, &encrypt[0], size);
sha_final(&testsha);
for (int i = 0; i < 8; i++)
printf("%08x ", testsha.hash[i]);
printf("\n");
/* 验证通过 */
#elif 1
clock_t start,end;
FILE *fp2 = fopen("./dest_hash.bin", "w");
if(fp2 == NULL)
{
printf("can not mkdir file\n");
return -1;
}
fclose(fp2);
FILE *fp3 = fopen("./dest_hash.bin", "rb+");
FILE *fp = fopen("./source.bin", "rb+");
if(fp == NULL)
{
printf("can not open file\n");
return -1;
}
fseek(fp, 0, SEEK_END);
uint32_t size = ftell(fp);
char encrypt[1024*1024];
uint8_t* size_u8 = &size;
/*如果源文件大小除8byte除不尽*/
uint8_t buding=size%8;
if(buding != 0)
{
buding = 8 - buding;
}
fseek(fp, 0, SEEK_SET);
printf("size of bin: %d &add length=%d\n",size,size + 32);
int len = fread(encrypt, sizeof(char), size, fp);
size = buding + size;
struct sha256 testsha;
// uint8_t* inaddr=&data[0];
sha_init(&testsha);
start=clock();
sha_updata(&testsha, &encrypt[0], size);
// sha_updata(&testsha, &encrypt[size/2], size/2);
// sleep(2);
sha_final(&testsha);
end=clock();
float time=(float)(end-start);
printf("time=%lf ms\n",time);
fseek(fp3, 0, SEEK_END);
fwrite(encrypt, sizeof(char), size, fp3);
/* 文件结尾hash值输出开关 */
#if 1
/* 大小端切换开关 */
#if 0
// fseek(fp3, size + 4, SEEK_SET);
printf("write hash num byte=%d\nHASH:\n",fwrite(testsha.hash, sizeof(char), 32, fp3));
fclose(fp);
fclose(fp3);
#else
uint8_t* hashfinal = &testsha.hash[0];
// fseek(fp, size, SEEK_SET);
int i,k;
for(i=0;i<8;i++)
for(k=0;k<4;k++)
fwrite(&hashfinal[i*4+(3-k)], sizeof(char), 1, fp3);
printf("write hash num byte=32\nHASH:\n");
#endif
fclose(fp3);
#else
fwrite(encrypt, sizeof(char), size, fp3);
fclose(fp);
fclose(fp3);
#endif
for (int i = 0; i < 8; i++)
printf("%08x ", testsha.hash[i]);
printf("\nhash_finish!\n");
// system("pause");
/* 验证通过 */
#elif 1
struct sha256 testsha;
uint8_t* inaddr_end=&fill_data[0];
uint8_t* inaddr=&data[0];
// memcpy(&TW[0],&Kt[0],65);
sha_init(&testsha);
// FlashASH_256(&testsha.block[0],&inaddr[0],14);
uint32_t num=FlashASH_256(&testsha.block[0],&inaddr[0],14);
// FlashASH_256(&Kt[0]+129,63);
sha_caculator(&testsha);
for (int i = 0; i < 8; i++)
printf("%08x ", testsha.hash[i]);
printf("\n");
// FlashASH_256(&TW[0],&inaddr_end[0],(uint32_t)64-num);
// printf("last_num= %d\n",num);
#endif
return 0;
}
代码片(.H)
c
/*
* @Description:
* @Author: shimianxiang
* @Date: 2023-10-11 09:27:35
* @LastEditTime: 2023-10-12 13:33:24
* @LastEditors: shimianxiang
*/
#ifndef HASHASH256_H_
#define HASHASH256_H_
#define H0 0x6a09e667
#define H1 0xbb67ae85
#define H2 0x3c6ef372
#define H3 0xa54ff53a
#define H4 0x510e527f
#define H5 0x9b05688c
#define H6 0x1f83d9ab
#define H7 0x5be0cd19
uint32_t Wt[64];
uint32_t Kt[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 };
struct sha256
{
uint32_t block[16]; //加密的measage
uint32_t hash[8]; //hash的结果
uint64_t hash_length;//总共hash的byte数
uint8_t offset; //一个update未对齐Word(4字节)的字节数
uint8_t index; //当前已经写到block的位置
};
#endif