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 32int g_fileNums = 0; 33 34/** 35 * 该方法实现将十六进制的字节转成字符串 36 */ 37void 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 */ 54unsigned 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 */ 113void 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 */ 132int 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 161char* 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 */ 191int 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 */ 226int GetFileTotalNum(void) 227{ 228 return g_fileNums; 229}