任务目标

一、设计一个本地文件处理协议,基于open PGP实现本地加密文件夹:

  • 1.对目标文件实现对存储者和调阅者的基于pgp的真实性认证和文件加密;
  • 2.上述文件安全性不依赖于本地系统,即
    • a)本地其他非授权用户(即便是系统管理员)无法以可理解的方式读出该文件夹中文件内容;
    • b)对处理过程中可能涉及的临时存储至少实现可靠的敏感信息残留覆盖;

二、选择linux或MS windows,实现该协议的一个C++实现实例。包括软件设计文档、源代码及注释、可执行安装包、自测用例和测试分析报告、第三方资源及其说明。

OpenPGP介绍

OpenPGP定义

一种协议,定义了加密消息、签名、私钥和用于交换公钥的证书统一标准。

OpenPGP的加密与解密原理

  OpenPGP加密过程:随机生成一个的Key,并通过对称加密算法使用这个Key加密数据,最后通过非对称加密算法(RSA)用接收者的公钥加密前者的Key,得到加密的数据。

OpenPGP的加密与解密原理

OpenPGP的数字签名

  数字签名是OpenPGP的重要组成部分,数字签名是一个数学过程,与现实世界的签名功能相似,但更严谨、更安全且容易验证。数字签名保证了以下情况:

  • 验证发送者身份:确认发送者确实是他声称的身份。
  • 完整性:文件/邮件传输过程中未被更改。
  • 不可否认:发送者不可否认已发送的文件/邮件。

  数字签名的原理:发送者先通过加密散列函数获取数据的哈希,然后使用发送者的私钥加密哈希,得到数字签名。接收者使用发送者的公钥解密数字签名得到一个哈希,并与自己计算的数据的哈希值对比,一致则数字签名有效且数据完整。

OpenPGP的签名与验证原理

OpenPGP的公钥发布与吊销证书

  我们知道公钥用于加密,可以公开发布,公钥可以点对点发送,也可以上传到密钥服务器。需要格外注意的是公钥中包含邮箱信息,如果你将公钥发布到密钥服务器(各个公钥服务器会互相同步),那么你将永远无法从密钥服务器上删除你的公钥信息。在某天你忘记密码口令或丢失私钥,你想要从密钥服务器上吊销你的公钥,唯一的补救措施是:你事先生成了吊销证书,使用吊销证书可以吊销公钥证书,使公钥其显示“吊销”字样,但依然无法从密钥服务器上删除公钥信息!所以务必要谨慎上传公钥,务必生成吊销证书备用!

OpenPGP库的安装

失败经验:

最开始我使用的是calccrypto/OpenPGP,一个在github上的库,然后在主机用VS编译了一下,出现报错,后来就直接在Ubuntu下用VScode编译了,其中安装了:

结果他还是报错,我的猜想应该是和Ubuntu系统上的gcc有关系。因为搞了太久,都没办法解决,因此我充分发动VPN连接外网的能动性,去外网碰碰运气,最终找到了个好东西。

成功经验:

经过一番查找,我发现VS中存在OpenPGP一个实现好的拓展,于是就下载安装了。

我的步骤如下:

  1. 先下载OpenPGP Library for .NET - Visual Studio Marketplace中的拓展包

  2. 在VS中安装拓展.NET桌面开发,以及Helper Viewer

  3. 在VS的Helper Viewer中安装OpenPGP的help files,具体步骤打开OpenPGP Library for .NET 1.9.3\Help\Register_Help_VS.bat,点击发现成功运行即可

  4. 接下来就是库的引入过程了。新建一个项目,这里我是控制台应用.NET(最简单的)。然后添加对应的引用和将对应.NET版本的两个dll文件安装到全局程序集缓存,具体可参考:

    使用 .NET 设置 OpenPGP 库 - 使用 .NET 进行 PGP 示例 (didisoft.com)

    解决安装VS2019后没有gacutil.exe或gacutil不是内部命令的问题

测试

这两个被成功引用,没有报错,应该是成功了。👏👏👏

image-20211212145554478

文件处理协议设计

前提条件

  • 在该文件系统内,每个用户有一对公钥和私钥。

  • 用户的公钥是公开的,系统内的所有用户都可以获得其他用户的公钥信息

  • 用户的私钥是私密的,仅该用户可以访问,其他用户不可访问。

用语说明

  • 签名:签名是为了验证发件人的身份,以及内容的一致性(不被篡改),签名通常用于文件创建者的身份,或校验调阅文件的一致性(不被中间人篡改)等等。   

  • 加密和解密:加密和解密即使用密钥对中的公钥加密、私钥解密。如果我们需要将自己的文件加密保存,那么就使用自己的公钥加密、自己的私钥解密。如果我们需要给其他用户授权调阅文件,我们将使用对方的公钥加密文件内容,对方使用自己的私钥解密。加密(或签名并加密)后将得到.gpg文件。

功能设计

存储功能

单用户授权

目标:A用户想要存储自己的文件,并仅自己拥有调阅权限。

步骤:

  • A用户对文件签名:将文件数据通过MD5加密方式获得哈希值,再将哈希值通过A用户的私钥加密,附在文件末尾。

  • A用户对文件加密:将第一步得到的文件通过\A用户的公钥**加密保存为.gpg文件。

多用户授权

目标:A用户想要存储自己的文件,并保证自己和B用户都拥有调阅权限。

步骤:

  • A用户对文件签名:将文件数据通过MD5加密方式获得哈希值,再将哈希值通过A用户的私钥加密,附在文件末尾。

  • A用户对文件加密:将第一步得到的文件通过A用户的公钥和B用户的公钥加密保存为.gpg文件。

调阅功能

目标:A用户调阅以.gpg后缀结尾的文件。

步骤:

  • A用户对文件解密:用自己的私钥解密文件,通过比对私钥的key id和加密文件的公钥的key id是否相同,相同则解密成功,不同则解密失败。

  • A用户验证签名:用公钥库中的公钥对文件中的签名进行验证,如果验证成功,则输出文件创建者(签名者)的身份。

安全问题

存储者的真实性认证

A用户创建文件必须有用户A的身份认证,即A用户对文件进行数字签名。

在前提条件中,用户的公钥是公开的。假设B用户以A用户的名义创建文件,则B用户使用了A用户的公钥对文件进行加密,但由于B用户没有A的私钥,因此无法对文件进行签名。

在创建文件的过程中,我们的文件系统会进行身份核验,即

  1. 计算文件的哈希值得到$h_{1}$

  2. 使用A用户的公钥解密签名$h_{2}$

  3. 判断是否相等($h_{1}$==$h_{2}$),相等则身份认证通过。

因此,B用户无法以A用户的身份创建文件。

img

调阅者的真实性认证

用户B只能够查看用户B创建的,以及其他用户授权的文件。

在前提假设中,用户的私钥是私密的。假设B想查看A的文件,那么有两种情况:

l 用户A给用户B授权:即用户A用自己的公钥和用户B的公钥对文件进行加密,因此用户B能够用自己的私钥进行解密,则能够查看用户A创建的文件。

l 用户A未给用户B授权:即用户A用自己的公钥对文件进行加密,因此用户B不能够用自己的私钥进行解密,则不能够查看用户A创建的文件。

因此,用户B能否查看文件取决于用户A有没有授权给用户B。

img

私钥保护

用户的私钥属于该文件系统的敏感信息。假设,用户B拥有了用户A的私钥,加之公钥是公开的,则用户B就能够伪装成用户A,从而以A的名义存储文件和调阅文件,这对整个系统会造成较大的危害。

因此,我们引入了私钥的密码机制,以MD5(用户名+用户安全序列号)作为识别不同用户的指纹,以该指纹作为解锁私钥的密码。

1
2
//密码唯一,且由用户的用户名和安全序列号唯一生成
string passwd = (user.get_username()+ user.get_sid()).GetHashcode(). Tostring();

我们的密钥文件是以key.store的文件格式存储,用记事本打开后为乱码,只有拥有此指纹的用户才能够解锁私钥。

在用户执行exe可执行程序的过程中,我们也对用户的私钥信息进行了保护。代码的运行机制是先导出私钥文件,然后调用该文件的生成路径,进行签名或者解密等操作,最后清空原有文件内容和文件长度信息,彻底删除文件并无法恢复。同时,我们使用了c++中的析构函数,在读取完私钥信息后,确保缓冲区信息能够及时删除,无法被其他用户读取到敏感信息。

软件功能测试

可执行文件的下载地址

启动运行

img

配置用户初始信息及密钥生成

首先打开文件夹,双击OpenPGP_File_Manager.exe文件打开软件。

软件初始界面为:

img

此处我们选择默认文件夹路径——D:\,故键入q

img

接着在用户界面当中呈现以下信息:

1、应用所创建的文件夹信息,如本例中在本地创建的所创建的用于存储活动及密钥的文件夹D:\OpenPGP_File_Manage_show

img

可以看到在本地成功生成的存储用户加密文件以及加密密钥的相关信息路径和信息。可以看到成功创建的用于PGP加密解密所使用的公钥信息:

img

功能展示面板

在创建好了当前用户的公钥和私钥之后,进入功能展示面板。在该面板中用户有三个可选择的选项,分别为原理展示、存储管理、文件调阅三个部分。

img

原理展示

键入1之后输入希望加密的内容

img

下图为PGP加密的原理展示,首先通过私钥进行签名,其次通过公钥对于需要加密的内容进行加密,得到加密后的字符串。

img

对于加密者进行身份验证。这之后开始进入解密模式,首先根据当前系统用户进行验证,通过公钥验证身份、私钥进行解密后得到解密后的字符串如上图所示。

文件存储

我们键入2进行进入到文件存储的部分,对于文件存储的部分,我们构建了两种安全模式的涉及——“单用户模式”以及“多用户模式”。在单用户模式当中,我们允许用户本身进行文件的存储管理;在多用户模式当中,我们允许用户进行多用户访问其中某一个用户加密的文件。

这里为了方便演示,我们使用单用户模式进行操作演示。首先我们键入1进入到单用户的安全模式进行演示。

img

在本例中,我们的用户名是本机lenovo,此处基于系统检测到当前操作的用户名,并根据提示要求输入待加密的文件的位置:

img

我们在磁盘D下创建PGPtest.txt用于存储PGP加密相关的验证信息,便于后续加密与解密的验证。

img

img

输入刚刚创建好的文件的路径,由编写好的PGP加密算法对于当前lenovo用户进行签名,最后将加密后的结果输出都目录:

D:\OpenPGP_File_Manage_show\lenovo\File\PGPtesttzlsfrt4.txt.gpg

我们打开对应的文件夹进行验证,加密结果成功输出到对应文件,密文如下所示:

img

文件调阅

返回掉目录界面之后,我们键入3进入文件调阅模块,提示输入对应的pgp加密文件进行调阅。输入刚刚在对应文件夹下创建好的pgp文件的路径到控制台窗口当中:

img

程序对于登陆者的身份进行认证,同时将最终解密结果输出到目录:

D:\OpenPGP_File_Manage_show\lenovo\File\PGPtesttzlsfrt4.txt

img

用户在对应输出文件目录当中找到解密后的文件,并可打开查阅其中的内容。

img

安全性测试

存储者的安全性认证

在Windows系统下新建一个普通用户B。

img

我们假设用户B想要以用户A的身份创建文件,B使用用户A的公钥对文件加密。用户B将自己的公钥替换为用户A的公钥。

img

用户B使用用户A的公钥创建文件。

img

出现报错,无法创建文件,用户B的签名不匹配,身份认证失败。

img

因此B不能够以A的身份创建文件。

调阅者的安全性认证

用户A分别以单用户和多用户的模式创建文件。

单用户模式下创建文件(没有给B用户授权)

img

B用户调阅该文件:

img

用户B的私钥不能解密该文件,无法调阅该文件。

多用户模式(给B用户授权):

img

B用户调阅该文件:

img

调阅成功,并通过签名验证检测到是用户A创建的。因此,调阅者只能够调阅存储者授权的文件。

参考文献

OpenPGP(PGP/GPG)深入浅出,完全入门指南 (rmnof.com)

如何在Ubuntu 20.04上添加和删除用户 - IPlayIO中文网

(185条消息) ubuntu 的管理员切换_tietao的专栏-CSDN博客_ubuntu切换管理员

(186条消息) Linux/Ubuntu中Vs Code配置C++/C环境_zimuzi2019的博客-CSDN博客_linux下vscode配置c环境

(186条消息) Linux环境下使用 VScode + CMake +CMakeTools开发调试 C++ 程序_雨田2017的博客-CSDN博客_cmake tools

(186条消息) ubuntu18.04 安装 gmp_慢慢变小佬的博客-CSDN博客_ubuntu安装gmp

ubuntu如何安装bzip2 - 问答 - 亿速云 (yisu.com)

(186条消息) ubuntu下安装zlib的方法_wu_cai_的专栏-CSDN博客_ubuntu zlib安装

【CMake】CMake ERROR:could not find git for clone of - esCharacter - 博客园 (cnblogs.com)

使用 .NET 设置 OpenPGP 库 - 使用 .NET 进行 PGP 示例 (didisoft.com)

(186条消息) 解决安装VS2019后没有gacutil.exe或gacutil不是内部命令的问题_燕归去兮的博客-CSDN博客_gacutil未找到命令

.NET OpenPGP Examples (didisoft.com)

如何创建文件或文件夹 - C# 编程指南 | Microsoft Docs

(186条消息) C# 获取文件名、目录、后缀、无后缀文件名、扩展名_weixin_30681121的博客-CSDN博客