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 }