• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 /*
17  * Description: 对单个文件或目录下多文件进行计算SHA256校验和
18  */
19 
20 #include "checksum_file.h"
21 
22 #include <dirent.h>
23 #include <errno.h>
24 #include <securec.h>
25 #include <stdio.h>
26 #include <string.h>
27 
28 #include "checksum_sha256.h"
29 
30 
31 #define BUFFER_SIZE 4096
32 int g_fileNums = 0;
33 
34 /**
35  * 该方法实现将十六进制的字节转成字符串
36  */
HexArrayToString(const unsigned char * hexarray,int length,unsigned char * string)37 void HexArrayToString(const unsigned char *hexarray, int length, unsigned char *string)
38 {
39     int byte = 4;
40     unsigned char value = 0x0f;
41     const unsigned char num2CharTable[16] = "0123456789ABCDEF";
42 
43     for (int i = 0; i < length; i++) {
44         *(string++) = num2CharTable[(hexarray[i] >> byte) & value];
45         *(string++) = num2CharTable[hexarray[i] & value];
46     }
47 
48     *string = 0x0;
49 }
50 
51 /**
52  * 获取文件校验和的最终结果
53  */
GetChecksumResult(MesgDigest * mesgd)54 unsigned char* GetChecksumResult(MesgDigest* mesgd)
55 {
56     unsigned int dataLen = mesgd->dataLen;
57     unsigned int totalLen = 64;
58     unsigned int len = 8;
59     unsigned int groupNum = 4;
60     int num = 24;
61     unsigned char pad0 = 0x80;
62     unsigned char pad1 = 0x00;
63     static unsigned char hash[32];
64     unsigned char bitNum = 0x000000ff;
65     unsigned int i, j;
66     errno_t err;
67 
68     // 0-dataLen之间元素保持不变,dataLen位填充1次1000 0000
69     mesgd->data[dataLen++] = pad0;
70 
71     // 剩余部分填充0000 0000
72     if (mesgd->dataLen < totalLen - len) {
73         for (; dataLen < totalLen - len; dataLen++) {
74             mesgd->data[dataLen] = pad1;
75         }
76     }
77 
78     if (mesgd->dataLen >= totalLen - len) {
79         for (; dataLen < totalLen; dataLen++) {
80             mesgd->data[dataLen] = pad1;
81         }
82 
83         CalcSha256(mesgd, mesgd->data);
84         err = memset_s(mesgd->data, sizeof(mesgd->data), 0, totalLen - len);
85         if (err != EOK) {
86             printf("memset_s failed, err = %d\n", err);
87         }
88     }
89 
90     mesgd->bitLen += mesgd->dataLen * len;
91 
92     // 填充长度的0-63位
93     for (i = 1; i <= len; i++) {
94         mesgd->data[totalLen - i] = mesgd->bitLen >> ((i - 1) * len);
95     }
96 
97     // 计算填充后数据的sha256
98     CalcSha256(mesgd, mesgd->data);
99 
100     for (i = 0; i < groupNum; ++i) {
101         for (j = 0; j < len; j++) {
102             hash[i + groupNum * j] = (mesgd->hash[j] >> (num - i * len)) & bitNum;
103         }
104     }
105 
106     return hash;
107 }
108 
109 
110 /**
111  * 该方法计算文件数据块的SHA256校验和
112  */
CalcFileChunkSha256(MesgDigest * mesgd,unsigned char data[],size_t len)113 void CalcFileChunkSha256(MesgDigest* mesgd, unsigned char data[], size_t len)
114 {
115     unsigned int dataLen = 64;
116     unsigned int bitLen = 512;
117 
118     for (size_t i = 0; i < len; i++) {
119         mesgd->data[mesgd->dataLen] = data[i];
120         mesgd->dataLen++;
121         if (mesgd->dataLen == dataLen) {
122             CalcSha256(mesgd, mesgd->data);
123             mesgd->bitLen += bitLen;
124             mesgd->dataLen = 0;
125         }
126     }
127 }
128 
129 /**
130  * 该方法计算单个文件的SHA256校验和
131  */
CalcSingleFileSha256(char * fileName)132 int CalcSingleFileSha256(char* fileName)
133 {
134     unsigned int outputLen = 32;
135     unsigned char *output = NULL;
136     unsigned char outputStr[64];
137 
138     FILE *fp = NULL;
139     if ((fp = fopen(fileName, "rb")) == NULL) {
140         printf("error: fail to open file %s: %s.\n", fileName, strerror(errno));
141     }
142 
143     MesgDigest mesgd;
144     InitSha256(&mesgd);
145 
146     unsigned char buffer[BUFFER_SIZE];
147     while (!feof(fp)) {
148         size_t size = fread(buffer, 1, BUFFER_SIZE, fp);
149         CalcFileChunkSha256(&mesgd, buffer, size);
150     }
151     fclose(fp);
152 
153     output = GetChecksumResult(&mesgd);
154     HexArrayToString(output, outputLen, outputStr);
155 
156     g_fileNums++;
157     printf("%s:%s\n", fileName, outputStr);
158     return RESULT_SUCCESS;
159 }
160 
CreatePathName(char * base,int len,char * name0,char * name1,char * name2)161 char* CreatePathName(char *base, int len, char *name0, char *name1, char *name2)
162 {
163     errno_t err;
164 
165     err = memset_s(base, len, '\0', len);
166     if (err != EOK) {
167         printf("memset_s failed, err = %d\n", err);
168     }
169 
170     err = strcpy_s(base, len, name0);
171     if (err != EOK) {
172         printf("strcpy_s failed, err = %d\n", err);
173     }
174 
175     err = strcat_s(base, len, name1);
176     if (err != EOK) {
177         printf("strcat_s failed, err = %d\n", err);
178     }
179 
180     err = strcat_s(base, len, name2);
181     if (err != EOK) {
182         printf("strcat_s failed, err = %d\n", err);
183     }
184 
185     return base;
186 }
187 
188 /**
189  * 该方法计算当前目录下所有文件的SHA256校验和
190  */
CalcMultiFilesSha256(char * dirPathName)191 int CalcMultiFilesSha256(char* dirPathName)
192 {
193     DIR *dir;
194     struct dirent *ptr = NULL;
195     int maxLen = 1000;
196     static char pathName[1000], fileName[1000];
197     char *fileNewName = NULL;
198     char *pathNewName = NULL;
199     int typeFile = 8;
200     int typeDir = 4;
201 
202     if ((dir = opendir(dirPathName)) == NULL) {
203         printf("error:fail to open dir %s: %s.\n", dirPathName, strerror(errno));
204     }
205 
206     while ((ptr = readdir(dir)) != NULL) {
207         if (strcmp(ptr->d_name, ".") == 0 || strcmp(ptr->d_name, "..") == 0) {
208             continue;
209         } else if (ptr->d_type == typeFile) {
210             // 获取的类型为文件,计算文件的校验和
211             fileNewName = CreatePathName(fileName, maxLen, dirPathName, "/", ptr->d_name);
212             CalcSingleFileSha256(fileNewName);
213         } else if (ptr->d_type == typeDir) {
214             // 获取的类型为目录,递归方式遍历所有子目录
215             pathNewName = CreatePathName(pathName, maxLen, dirPathName, "/", ptr->d_name);
216             CalcMultiFilesSha256(pathNewName);
217         }
218     }
219     closedir(dir);
220     return RESULT_SUCCESS;
221 }
222 
223 /**
224  * 该方法获取文件的个数
225  */
GetFileTotalNum(void)226 int GetFileTotalNum(void)
227 {
228     return g_fileNums;
229 }