如果你被敌人严刑拷打,逼你交出机密情报的解密密码……

幻想一下,如果在抗日战争时期,你有一份重要情报要送给八路军,你把情报内容用密码加密了,把密文写在纸上贴身藏好,密码则记在心里,不料在路上被鬼子抓住,鬼子翻到你在纸上写的密文,虽然看不懂,但也知道一定是重要信息,于是对你严刑拷打,逼你交出解密密码。如果你大喊“太君啊、皇军啊、你们搞错了啊,我真的什么都不知道啊……”一般来说效果不大,残忍的鬼子是宁可错杀而不会放过的。胡乱说个密码?也不行,敌人会拿你的密码去解密,如果密文解不出来,便证明你胡说八道,同样危险。

那么,在这种危机关头,你有既不泄密、又能保命的办法吗?

答案是:

没有!


以上设想的场景,是为了引出CnPack开发组近日实现的基于RSA非对称加密算法的双密钥加解密功能,但想来想去并不能很成功地引出来。

如果敌人讲武德,你给个密码,他们解密成功,拿到情报明文,这种时候可能饶你一命,但用脚趾头想想就知道,你一个普通人,竟然有八路军的通讯密码,这种时候咋可能放你走?让你去赶紧报告八路,让刚刚拷问得来的密码作废吗?那还不得继续拷问以获取更多信息?熬不住还是会挂,还不能指望鬼子使用美人计。

那我们放低要求,如何在不泄密的前提下,舒服地活久一点,这就是我们今天“RSA双密钥加解密”机制所能达到的目标。

这个机制的功能说起来很简单:用两对RSA公私钥中的两个公钥,和两个明文,一起加密生成一个密文,这个密文用这个私钥解密,就得到这个明文,用那个私钥解密,就得到那个明文。

比如,你的重要情报是“二月三日晚区游击队五分队拔掉小高庄炮楼”,你再整一条不靠谱的情报“二月四日给皇协军贾队长送肥羊十头”,结合两个RSA公钥加密后得到一条比较长的密文,然后你得多费点心思,记住两个RSA私钥。

鬼子抓住你的时候,你不想挨打,行,赶紧交出后面那个私钥,并告诉鬼子,说八路军大队长说了,密文拿这个私钥数字乘方求余,就能得到明文,但具体机制我也不知道怎么搞的。

鬼子设备精良,自然(可能)有大整数计算器,一算,得到明文“二月四日给皇协军贾队长送肥羊十头”,哟西,贾队长有这好事,竟然不向皇军报告,八嘎!

鬼子怎样找贾队长敲竹杠先不管,他们拍拍你的肩膀,说你的良心大大的有,今天就先不打你了,意思是明天还得继续打。

挨打的事儿明天再说,那么,RSA双密钥加密隐藏真正信息的机制,又是怎样实现的呢?


大伙也许还记得,RSA的核心算法就是明文和密文间,用私钥或公钥乘方求余。

也就是说:

  • 密文=明文^公钥指数 mod 素数积

  • 明文=密文^私钥指数 mod 素数积

举个最简单的例子:两个素数13和17,素数积221,公钥指数取5,私钥指数算出来77,那么这对RSA公私钥就是(221,5)和(221,77)。

我们的明文取42。

那么公钥加密明文得到密文,42^5 mod 221 = 9

私钥解密密文还原回明文:9^77 mod 221 = 42

假设另有一对RSA公私钥和明文,我们同样可以重复以上计算:

两个素数11和19,素数积209,公钥指数取7,私钥指数算出来103,那么这对RSA公私钥就是(209,7)和(209,103)。

我们的明文取17。

那么公钥加密明文得到密文,17^7 mod 209 = 195

私钥解密密文还原回明文:195^103 mod 209 = 17

在上面的例子中,有两个密文,9和195,他俩分别除以各自的私钥,就能算出各自的明文。

注意,9^77 mod 221 = 42,在这个式子里,9并不是唯一的解。也就是说,某未知数除以某个特定的除数余某个特定的余数,这个未知数的解一般来说不唯一,甚至有无限多个。

那么,我们能不能找到一个这样的数,它不仅除以221余42,它除以209也能余17?

甚至,再来一个公私钥和一个明文,这个新密文除以新素数积,也能等于新明文?

答案是肯定的。


我们要求一个数,“这个数除以这个除数余这个余数,除以那个除数余那个余数,除以另一个除数余另一个余数……”

眼熟不?大家有没有想起小学数学?有没有想起《孙子算经》?

对,就是那道著名的“今有物不知其数,三三数之剩二,五五数之剩三,七七数之剩二。问物几何?”

这针对同余方程组的解法,正是古代中国留给现代人类的数学瑰宝:中国剩余定理(Chinese Remainder Theorem, CRT)!

简而言之,利用中国剩余定理解这两个或三个或更多个的同余方程组,就能得到同时满足两个或三个或更多个指定余数的新密文。

以上两个密文9和195,利用中国剩余定理的解法,可以简述如下:

求两个素数积209和221的积,得到46189。

再求两个素数积分别针对另一个素数积的模逆元,得到92和122。

那么新密文=(9×209×92+195×221×122)mod46189 = 26529

验证:

私钥一解出明文一:26529^77 mod 221 = 42

私钥二解出明文二:26529^103 mod 209 = 17

完整实现了“一个密文分别用俩私钥解出俩明文”。


CnRSA.pas里近期实现了CnRSA2*系列函数,提供了大数范围内的双公钥加密以及单私钥解密,可用于实战。

啥?你问为什么不实现双私钥解密?

加密需要两个公钥和两个明文共同参与,可解出一个明文只需要一个私钥就行,你要双私钥解密,不会调用两回吗?

具体函数如下:

function CnRSA2EncryptBytes(PlainData1, PlainData2: TBytes; PublicKey1, PublicKey2: TCnRSAPublicKey;  PaddingMode: TCnRSAPaddingMode = cpmPKCS1): TBytes;{* 使用两个 RSA 公钥分别加密两个明文,合并成一个大密文,返回密文字节数组。   加密前可指定使用 PKCS1 填充或 OAEP 填充。   参数:     PlainData1: TBytes                   - 待加密的第一个明文字节数组     PlainData2: TBytes                   - 待加密的第二个明文字节数组     PublicKey1: TCnRSAPublicKey          - 用于加密第一个明文字节数组的 RSA 公钥     PublicKey2: TCnRSAPublicKey          - 用于加密第二个明文字节数组的 RSA 公钥     PaddingMode: TCnRSAPaddingMode       - 指定对齐模式   返回值:TBytes                           - 返回密文字节数组}
function CnRSA2DecryptBytes(EnData: TBytes; PrivateKey: TCnRSAPrivateKey;  PaddingMode: TCnRSAPaddingMode = cpmPKCS1): TBytes;{* 使用单个 RSA 私钥解密双密钥加密的大密文字节数组,并解开其 PKCS1 填充或 OAEP 填充,返回解密的字节数组。   参数:     EnData: TBytes                       - 待解密的双密钥密文字节数组     PrivateKey: TCnRSAPrivateKey         - 用于解密的 RSA 私钥     PaddingMode: TCnRSAPaddingMode       - 指定对齐模式,需和密文的实际情况一致   返回值:TBytes                           - 返回明文字节数组}

回到最开头。听说过了几天,鬼子拉贾队长来找你算账了,因为那十头肥羊压根没人送过来……

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值