用无理数加密,如何破解?
先说结论:题主设计的算法是没有应用价值的,但思路有可取之处。
现代密码学中的加密算法可以分为两大类,分组加密和流加密。分组加密例如DES、AES等等,是用同一个密钥对数据分块加密。而流密码例如RC4、RC5等,是通过一个流密钥发生器,不断产生新的密钥流,然后与原数据做异或运算实现加密。题主设计的这个算法,其实就是流密码的思路。这一点目前所有的回答都没有指出,我感到非常的意外和困惑。
题主的这个算法不具有实际意义的原因,大家基本都已经说得比较清楚了。那就是你无法有效地计算一个无理数。让我们来看一则新闻:
Yahoo科技公司的尼古拉斯·苏使用Yahoo的Hadoop云计算技术将以前的π值计算的记录位数整个翻了一番,达到2千万亿位,这次计算在Yahoo公司1000台电脑上运算了23天,相当于单台电脑运算500多年的工作量。
听起来好厉害,我们看看这个数有多长,2,000,000,000,000,000位,好厉害,假设加密一个字节用1位,可以加密2000TB的数据,好像又觉得不是很厉害了。一台电脑,算500年,只能加密2000TB的数据,那我要把我的2TB移动硬盘加密一下,要不间断地算上半年!
=======================================
这个问题至此就回答完了,重新贴一遍结论:
题主的这个算法没有应用价值,但思路有可取之处。
=======================================
=======================================
以下内容受到诸多网友质疑,我进一步说明一下
感谢各位知友的提醒,题主这个算法的主要问题在于试图使用一个[0, 9]的噪声去覆盖[1, 26]的字母甚至是[0, 255]的整个字节。要想隐藏原始信息,我们需要改变原始信息的分布特性,而一个[0, 9]的随机数是不足以做到这一点的。通过对图像像素的变换,我们可以清楚地看到这种不完全的覆盖,还是会让原始信息的一些蛛丝马迹泄漏出来,甚至是严重地泄漏出来。
我不认为我的答案是具有误导性的,我首先指出了题主的算法在性能上的巨大缺陷,开门见山地指出了其不具有实用价值的事实。第二,我使用了对图像像素进行『加密』的方法,直观地演示了用较小的随机数变换较大的原始数据会导致的安全问题。其中『计算无理数』和『(一个字节的)原始数据与(一个十进制位的)随机数做加法』两个关键点都是由题主明确指出的,不是由我恶意曲解的。其中『计算无理数』的主要问题是性能低,『做加法』的主要问题是会导致信息泄露。上面引用的新闻说明了第一点『性能低』,下面的实验说明了第二点,也就是『信息泄露』。
我说题主的算法是不安全的,我仍然这样认为,因为『算法』这两个字就表示了从随机数生成到应用随机数加密的整个过程。我没有试图说明OTP(一次性密码本)是不安全的,如果说我的回答有问题,那我只不过是没有指出恰当地应用OTP是安全的,而只是证明了不恰当地应用OTP是不安全的。而对OTP的不恰当应用,是题主的问题,我只不过是编程实现了题主描述的算法。
========================================
以下是原答案的后半部分,可以探讨,不要喷
========================================
然而遗憾的是,题主这个算法的问题还不仅如此。一个加密算法,其安全性的保障来自于2个特性。一是“混淆”,二是“扩散”。混淆大家都比较容易做到,然而扩散就不是那么容易了。为了证明题主的算法不具备“扩散”特性,我专门编写了一个程序来进行了实验。我去网上找到了圆周率100万位的数表,删掉了小数点,存在一个叫做pi.txt的文档里。我们要使用这个数表对512*512像素的Lena图进行加密。图片设置为灰度模式,每像素8位(1字节),每像素使用一个pi的数位来加密。
加密前的Lena女神是这样的~
加密之后的Lena女神是这样的:
。。。。。。。。。。。。
加密的核心代码大概是:
int c = fgetc(fp) - '0';pImg[0] = (pImg[0] + c) % 256;
加密后跟加密前几乎没有区别。如果你仔细观察,会发现加密后左上角的灰色背景上的一些噪声好像被增强了一些。这并不是因为我的程序写错了,而是因为对一个字节加密时,一个字节的取值范围是0~255,而加上的数字只可能是0~9,加上的数字比本身的数字可能小2个数量级,所以加上跟没加几乎没区别,照片看起来就没啥变化。
如果就这样否定了题主,我觉得还是不够有说服力,我们既然发现了问题,不如就解决一下。我们把一个字节拆成两半,也就是4位,然后分别加密,这样十进制的取值是0~15,跟0~9在一个数量级上了。也就是说每个字节使用2位pi的数值来加密,代码大概是这样的:
int c = fgetc(fp) - '0';unsigned char low = (pImg[0] & 0x0F);unsigned char high = (pImg[0] >> 4);low = ((low + c) % 0x10);c = fgetc(fp) - '0';high = ((high + c) % 0x10);pImg[0] = ((high 4) | low);
现在再来看看效果,加密后的图是这样的:
哇塞酷!变成一坨了!但是仔细看一下,其实还是能够看出图像中人脸的轮廓,这个加密过程其实主要破坏了图像的低频部分,而对高频部分影响较小,使得我们仍能识别出Lena的五官、头发、草帽穗等高频元素。
我们再试试另外一张图
加密之后变成:
尽管加密后文字变得很难识别,但是用力看,是可以大概识别出文字内容的。如果我们把上面的这张图扔到Photoshop里调整一下色阶:
呵呵。。。一个可以使用Photoshop破解的加密算法。。。
祝题主好运~
==========分割线===========
下面回答网友们的疑问~!
@笨蛋小明 说,把加法换成异或是不是就看不出来了。答案是否定的~!而且即使你找到了一个猥琐的运算,使得加密后的图看不出来原来的东西了,也并不能证明算法是安全的。一个算法不具备”扩散“的特性,不管你采用加法还是异或还是什么奇葩的方法,它都不具备”扩散“特性。我还就真的写了一个异或的版本,下面上图~!!
加密的程序核心部分是这样的:
unsigned char low = (pImg[0] & 0x0F);unsigned char high = (pImg[0] >> 4);low = ((low ^ c) % 0x10);c = fgetc(fp) - '0';high = ((high ^ c) % 0x10);pImg[0] = ((high 4) | low);
上面那两张图加密后的效果是这样的:
以及
这不还是坑爹吗!!!
感谢@刘巍然-学酥 大牛提出的算法,我又做了一个实验,每个字节使用8个数加密,奇数为1,偶数为0,8个小数位对应8个二进制位,形成一个字节,再与原图异或,确实取得了非常理想的加密效果,肉眼不能识别,而且直方图也基本上是均匀分布的。这样做应该是一个OTP的效果了,所以如果使用正确的话应该是可以安全加密的。
然后再附上加密程序的核心部分
unsigned char mask = 0;for(int b = 0; b 8; b++){ c = fgetc(fp) - '0'; mask 1; mask |= (c & 1);}pImg[0] ^= mask;