今天看到了一套加密解密算法,可以对任意数据流进行加密解密,实现很简单。
1 | [C++] |
这段代码看起来操作非常简单。
源数据上加了一个数,然后强转成 unsigned char。
解密时就是把加密数据减去之前加的那个数,然后再强转成 unsigned char。
恩,看起来他就是做了这点事儿。不过从字面上看,总感觉它加密之后没法正确的还原。
因为 a + ( i * i ) 之后很容易就超过1字节的上限(255),当强转回unsigned char时,超出上限的高位部分会被截断丢弃。
得出的这个结果无论怎么看都觉得不可能再还原成源数据。
##但神奇的是它真的能正常工作,而且不会出错!
###一点理解
源数据取值范围为0~255,但实际上源数据和加密数据数据只要保持相同类型公式就成立,如源数据改为unsigned short那么
加密数据只要相应的做unsigned short强制转换就可以保持公式的成立。后边参与加减计算的数实际上可以为任意自然数,这里是用平方数可能是为了使加密数据更加没有规律。
这个算法神奇之处在于强转类型截断高位后公式仍然成立。对于其中的原理我是这样理解的:
当计算出来的数值超过上限的时候,高位截断保留低位实际上是一种取模操作(模2^8)。
这个操作就像向前拨动表盘指针,向前拨动N个小时,无论转多少圈都无所谓,但是最终停留在了模12后的数字上。
而还原时就是将指针往回拨N个小时,同样在这过程中转了多少圈都无所谓,但它最终一定会停留在最初的数字上。
下面是我在思考这玩意儿时候补习的一些知识,留下来做个笔记:
高位截断操作:
258 = 0x102 0x100被截断丢弃 0x102 & 0xFF = 0x02 = 2 C = 2无符号数与有符号数的关系:
在限定的数据类型下,数字的二进制最高位为符号位,
无符号数与有符号数的区别在于是否使用符号位来判断负数。有符号数用最高位表示符号(0正或1负),其余位表示数值大小,无符号数则所有位都用于表示数的大小。
如:char类型,数据为1 byte(8 bit),其取值范围为
十六进制: 0 ~ 0xFF 二进制: 0000 0000 ~ 1111 1111 unsigned char: 0 ~ 255 signed char: -128 ~ 127由于有符号数的最高位作为了符号位,所以有符号数的正数范围变为了之前的一半,同时增加了一半的负数取值范围。
当127 + 1 时 0111 1111 变为 1000 0000 此时作为无符号数则是128 作为有符号数则是-128无符号数与有符号数二进制相同:
由上边的127 + 1的例子可以看出,128和-128其二进制数是相同的,只有分别作为有符号数和无符号数产生了区别。
整数补码的概念:
引自百度百科
在计算机系统中,数值一律用补码来表示和存储。其特性为:
- 一个负整数(或原码)与其补数(或补码)相加,和为模。
- 对一个正数的补码再求补码,等于该正数自身。
- 补码的正零与负零表示方法相同。
正整数补码是其二进制表示。
负整数补码为将其对应正整数二进制表示所有位取反(包括符号位)后加1。
模的概念:
模是指一个计量系统的计数范围。如时钟,他的计量范围是0
11,模=12.表示n位的计算机计量范围是02^(n)-1, 模=2^(n)。模实质上是计量器产生“溢出”的量,它的值在计量器上表示不出来,计量器上只能表示出模的余数。任何有模的计量器,均可化减法为加法运算。
如:假设当前时针指向10点,要调整时间到6点有两种方法:一种是倒拨4小时,即:10 - 4 = 6;另一种是顺拨8小时:10 + 8 = 12 + 6 = 6
在以12模的系统中,加8和减4效果是一样的,因此凡是减4的运算,都可以用加8来代替。对模而言,8和4互为补数。即两者相加等于模的数均是补数。
在计算机系统中 一个8位数所能表示的最大数为1111 1111,若再加1为 1 0000 0000,但因为只有8位,最高位1自然丢失,又回了0000 0000,
所以8位二进制系统的模为2^8。在这样的系统中减法问题也可以化成加法问题,只需把减数用响应的补数表示就可以了。把补数用到计算机对数的处理上,就是补码。
计算机整数减法:
依据上述补码的的概念,计算机在进行减法操作时,将减数化为加上减数的补数。
则 2 - 8 在计算时被化为 2 - 8补。
8的二进制表示是 0000 1000 对8进行求补: 二进制各位取反为 1111 0111, 再加1 8补 = 1111 1000此时再与2进行相加:
1111 1000 + 0000 0010 = 1111 10101111 1010 表示为十进制有符号数为 -6;表示为十进制无符号数则是 250。两者二进制是相同的。
此时源数据已被顺利还原。
在限定位数内二进制循环规则:
8位最大数为1111 1111,若再加1得 1 0000 0000,超出8位的最高位1丢失,数值又回了0000 0000;
在限定位数内,数值总是在2^(n)的范围内循环。
下面是对于上面算法的Python版本实现,用于验证算法的正确性:
1 | [python] |