前言

最近都在搞移动存储介质的一些相关的东西。恰好,就有个磁盘加密的需求。这个需求是不是真的需要,我其实都不太清楚,哈哈哈。只不过是恰好想到了,然后就做了。因为想到了这个东西,但是不做出来,感觉不舒服~所以,花了一两天的时间去查阅相关资料,把它给整出来了。利用国密算法SM4对分区表进行一个加解密,实现加密后的磁盘怼到电脑上无法正常使用(其实是可以看到磁盘的,只不过打开不了而已)。

C++加密GPT|MBR分区表实现简单磁盘加密
这是GPT格式的效果

C++加密GPT|MBR分区表实现简单磁盘加密
这是MBR格式的效果

都是用不了,只显示插入了一个存储介质


存储管理器里面显示未分配空间

先简单研究一下下MBR和GPT的区别

C++加密GPT|MBR分区表实现简单磁盘加密
MBR结构

C++加密GPT|MBR分区表实现简单磁盘加密
GPT结构

MBR分区表与GPT分区表的关系
与支持最大卷为2 TB(Terabytes)并且每个磁盘最多有4个主分区(或3个主分区,1个扩展分区和无限制的逻辑驱动器)的MBR磁盘分区的样式相比,GPT磁盘分区样式支持最大为128个分割,一个分割最大18 EB(Exabytes),只受到操作系统限制(由于分区表本身需要占用一定空间,最初规划硬盘分区时,留给分区表的空间决定了最多可以有多少个分区,IA-64版Windows限制最多有128个分区,这也是EFI标准规定的分区表的最小尺寸)。与MBR分区的磁盘不同,至关重要的平台操作数据位于分区,而不是位于非分区或隐藏扇区。另外,GPT分区磁盘有备份分区表来提高分区数据结构的完整性。在UEFI系统上,通常是通过ESP分区中的EFI应用程序文件引导GPT硬盘上的操作系统,而不是活动主分区上的引导程序。
资料来源

总结来说,就是MBR支持4个主要分区,GPT支持128个。然后MBR中的分区表是写在第0个扇区,偏移在0x1BE上面的,一共4项,每项16个字节。GPT则在第2个扇区开始写,一共可以划分为128个分区,从偏移0x00就开始写,每项占用128个字节,即以0x80的距离进行偏移记录。然后按照常规512字节一共扇区计算的话,128个项就是占有32个扇区。

使用SM4国密对称加密算法对分区表进行加密

加密分区表可以有很多钟办法,采用对称、非对称加密、还是简单的异或值、左移右移来搞凯撒密码都可以。只要你喜欢的都可以
在这里,我会采用国密算法SM4进行一个加密操作。SM4的实现不是我写的,是从Github上面搞回来的,具体作者是谁,我并没有记录到,当时拿过来就用了,没有记录到作者,实在不好意思~

该怎么加密,加密之后的数据该放哪个位置。
在这里,采用的最简单的一个做法,不免显得有些蠢~
对于MBR分区则对上文中说到的64个字节的四个分区项加密,然后存放在36号扇区。
对于GPT分区,则对上文说到的 2——33 扇区进行加密,然后存在36号扇区起的连续32个扇区

接着对上面说到的那些原始分区表存的数据全部清零。对于GPT的话,还得在第一个扇区读取LBA备份的扇区位置,对备份扇区内的分区表项也给一同抹去才可以生效。因为当检测到主分区表不正常时,会自动读取备份分区表。

解密分区表的办法

由于磁盘被加密之后,系统就看到没有分区表了。那就会影响使用了,咱们就要将加密后的数据读取回来,读取位置如上文所说,利用SM4进行解密之后,然后再填回原来分区表的地方。约莫几秒中,系统便会识别出正常的分区表,资源管理器便可以正常使用该分区了。

怎么让分区表一直处于加密状态中呢

但是,想象一下,要是加密磁盘怼入计算机中,然后给他解密了分区表之后,突然拔出来了。会发生什么呢?
没错,是原来的分区表会保留住。下次他就可以拿着被解锁的磁盘随便用了。
所以,在这里,我们可以在插入磁盘,解密分区表之后,约莫等他几秒,让系统识别出来分区表之后,存在缓存之后,马上又给它给加密了。这样子他在后面使用的时候,突然拔出来,分区表也是加密好了的。

密钥的生成存放方法

SM4的密钥是128位的,即32个字符。我们可以怎么搞出这128位密钥呢

  • 随机的生成这个密钥,然后存在某个扇区中
  • 利用用户输入来实现这个密钥输入
  • 利用某种东西来派生出这个128位的密钥,例如利用移动存储介质的序列号(采用PID+VID+SerialNumber)来进行一个MD5运算,生成一个128位的消息摘要,利用这个MD5值进行一个加密。

Key=H(PID+VID+SerialNumber)Key=H(PID+VID+SerialNumber)

这里,我这里采用,第三种办法,毕竟128位的密钥着实不好记的对吧,利用国密算法SM3来生成256位的密钥。然后截取前128位作为密钥,存在某个扇区中,需要时再读取即可。

小小的做一下安全分析

利用 PID+VID+SerialNumber 来生成生成标识符来进行SM3消息摘要是真的安全了吗?并不是,假设我们的加密解密方法被发现了之后,别人还是可以很简单的就写出一个SM3来生成需要用到的消息摘要,用作SM4密钥。
所以,为了避免这个情况,我向服务器请求一个由服务器发送回来的秘密值,这秘密值可以是128位的,也可以1024位,也可以2048位,随意我们来进行生成。当别人想自己生成摘要时,这个秘密值就是他所不知道的,毕竟秘密值长度未知,知道长度也“无从下手”,够他愁了~

Key=H(PID+VID+SerialNumber+SecretValue)Key=H(PID+VID+SerialNumber+SecretValue)

补充说明

这个移动存储加密方案并不是理想中这么安全的。毕竟,真正的数据区域并没有被加密到。我们只是对分区表进行了一个操作。在加密后,对分区表进行一个清空操作。数据区域,还是明文的情况,如果有心去读取数据的话,可以利用diskgenius、easy recovery 这类软件进行一个数据恢复,进行提取。

因为全盘全分区加密是需要耗费大量时间的,这次用到这种方案只是适用于我当前的需求,各位大哥参考一下即可

代码有几百行,着实不好在博客中展示。就由GitHub这些专业的代码托管平台来展示吧,哈哈哈
项目的GitHub的位置: tmp_project_in_vs2017 的 encrypted_disk_partition 分支中

要是感觉不错的话,就留个言评论一下下呀,欢迎各位大哥指正