thinking_of_encrypt_design_model

前段时间接到一个实现可搜索加密的任务,用着顺其自然的设计模式完成了代码的编写。但是今天回头看,感觉还是有诸多问题,写一篇博客记录加密算法开发的心路历程。

功能实现

该算法是一种代理重加密的公钥加密算法,主要用于用户之间的数据共享。首先用户可以将文件用私钥加密后上传到云端,并且该文件会附带关键词,其他用户可以使用该关键词检索到该文件,并向文件拥有者申请授权。该算法需要实现的关键接口函数如下:

  • Setup:根据安全参数,生成一个公共参数;
  • KeyGen:生成一对用户密钥,包括公钥和私钥;
  • ReKeyGen:生成一个重加密密钥,用于向其他用户授权查看;
  • Enc:对数据进行加密;
  • Trapdoor:生成一个陷门,和搜索关键字有关;
  • Test:对关键词进行测试,即比较两个关键词是否相等;
  • ReEnc:使用重加密密钥对一个密文进行重加密,从而授权;
  • Dec1:解密普通密文;
  • Dec2:解密重加密密文;

类的设计

按照上述的描述,可以先考虑将哪些数据用Java的原始数据表达,哪些数据需要用类来封装。实际上,由于这个加密算法是基于椭圆曲线群来实现的,所以要引入依赖来简化实现,从而必须使用类的封装。

举几个典型的例子:用户的密钥就需要封装为UserKey类,而UserKey类中包含两个数据成员,分别为UserPubkeyUserPrikey;为了分别字符串的运算,将byte[]数组封装为ByteString;为了方便分块,将明文类封装为Plaintext,密文封装为CipherText

最初的实践

最初的思路非常的直,但是应该说充分利用了语言特性。就拿加密和解密为例,既然加密后才有密文,那就是说密文是从明文那里“获取”来的,那就直接将明文对象作为密文类的构造函数的参数。声明方法为:

1
2
3
4
5
6
7
public class CipherText
{
public CipherText(Plaintext plain, UserPrikey prikey)
{
// ...
}
}

调用方式如下:

1
Ciphertext cipherText = new CipherText(plaintext, prikey);

虽然看上去非常合理,但是使用起来是非常奇怪的,总觉得“密文依赖于明文”这个地方太不优雅了,而且从硬盘读取密文时也不能使用这个构造函数。

实践之二

另一种思路是将对应的操作封装起来,以成员函数形式存在。还是以加密来举例,现在加密的调用方法是这样的:

1
Cipihertext ciphertext = plaintext.encrypt(prikey);

这个设计方法好像合理了一点,但是在设计Test这个功能时还是遇到了问题。Test需要对比两个关键字是否一致,并且需要将密文的陷门也作为输入,这就意味着Test需要有四个输入。这时候如果把Test作为密文类的成员函数,那么调用形式是这样的,非常奇怪:

1
ciphertext1.test(td1,ciphertext2,td2);

明明是很对称的四个参数,却强行将其中一个作为this指针(C++叫法)传入,比上面的方法更奇怪。

实践之三

现在想的是将这个算法重新设计一遍,使用策略模式来做。使用一个Context来表示加密的上下文,并将所有算法的功能全部用静态方法实现,用户在使用时只需要调用这些静态方法即可。


thinking_of_encrypt_design_model
http://zhouhf.top/2024/11/27/thinking-of-encrypt-design-model/
作者
周洪锋
发布于
2024年11月27日
许可协议