thinking_of_encrypt_design_model
前段时间接到一个实现可搜索加密的任务,用着顺其自然的设计模式完成了代码的编写。但是今天回头看,感觉还是有诸多问题,写一篇博客记录加密算法开发的心路历程。
功能实现
该算法是一种代理重加密的公钥加密算法,主要用于用户之间的数据共享。首先用户可以将文件用私钥加密后上传到云端,并且该文件会附带关键词,其他用户可以使用该关键词检索到该文件,并向文件拥有者申请授权。该算法需要实现的关键接口函数如下:
Setup
:根据安全参数,生成一个公共参数;KeyGen
:生成一对用户密钥,包括公钥和私钥;ReKeyGen
:生成一个重加密密钥,用于向其他用户授权查看;Enc
:对数据进行加密;Trapdoor
:生成一个陷门,和搜索关键字有关;Test
:对关键词进行测试,即比较两个关键词是否相等;ReEnc
:使用重加密密钥对一个密文进行重加密,从而授权;Dec1
:解密普通密文;Dec2
:解密重加密密文;
类的设计
按照上述的描述,可以先考虑将哪些数据用Java的原始数据表达,哪些数据需要用类来封装。实际上,由于这个加密算法是基于椭圆曲线群来实现的,所以要引入依赖来简化实现,从而必须使用类的封装。
举几个典型的例子:用户的密钥就需要封装为UserKey
类,而UserKey
类中包含两个数据成员,分别为UserPubkey
和UserPrikey
;为了分别字符串的运算,将byte[]
数组封装为ByteString
;为了方便分块,将明文类封装为Plaintext
,密文封装为CipherText
。
最初的实践
最初的思路非常的直,但是应该说充分利用了语言特性。就拿加密和解密为例,既然加密后才有密文,那就是说密文是从明文那里“获取”来的,那就直接将明文对象作为密文类的构造函数的参数。声明方法为:
1 |
|
调用方式如下:
1 |
|
虽然看上去非常合理,但是使用起来是非常奇怪的,总觉得“密文依赖于明文”这个地方太不优雅了,而且从硬盘读取密文时也不能使用这个构造函数。
实践之二
另一种思路是将对应的操作封装起来,以成员函数形式存在。还是以加密来举例,现在加密的调用方法是这样的:
1 |
|
这个设计方法好像合理了一点,但是在设计Test
这个功能时还是遇到了问题。Test
需要对比两个关键字是否一致,并且需要将密文的陷门也作为输入,这就意味着Test
需要有四个输入。这时候如果把Test
作为密文类的成员函数,那么调用形式是这样的,非常奇怪:
1 |
|
明明是很对称的四个参数,却强行将其中一个作为this
指针(C++叫法)传入,比上面的方法更奇怪。
实践之三
现在想的是将这个算法重新设计一遍,使用策略模式来做。使用一个Context
来表示加密的上下文,并将所有算法的功能全部用静态方法实现,用户在使用时只需要调用这些静态方法即可。