最近一直在做字符串加密,对原理做了一些调研,所以在此记录一下。
1.ASCII码
ASCII (American Standard Code for Information Interchange):美国信息交换标准代码是基于拉丁字母的一套电脑编码系统,主要用于显示现代英语和其他西欧语言。它是最通用的信息交换标准,并等同于国际标准 ISO/IEC 646。ASCII第一次以规范标准的类型发表是在1967年,最后一次更新则是在1986年,到目前为止共定义了128个字符
2.ASCII码表达方式
ASCII 码使用指定的7 位或8 位二进制数组合来表示128 或256 种可能的字符。标准ASCII 码也叫基础ASCII码,使用7 位二进制数(剩下的1位二进制为0)来表示所有的大写和小写字母,数字0 到9、标点符号,以及在美式英语中使用的特殊控制字符 [1] 。其中:
0~31及127(共33个)是控制字符或通信专用字符(其余为可显示字符)
如控制符:LF(换行)、CR(回车)、FF(换页)、DEL(删除)、BS(退格)、BEL(响铃)等;
通信专用字符:SOH(文头)、EOT(文尾)、ACK(确认)等;
ASCII值为8、9、10 和13 分别转换为退格、制表、换行和回车字符。它们并没有特定的图形显示,但会依不同的应用程序,而对文本显示有不同的影响 [1] 。
32~126(共95个)是字符(32是空格),其中48~57为0到9十个阿拉伯数字。
65~90为26个大写英文字母,97~122号为26个小写英文字母,其余为一些标点符号、运算符号等。
3.ASCII码表
4.获取字符串的ASCII码
// 输出十进制ASCII码:97
"a".charCodeAt()
// 输出十六进制ASCII码:61
"a".charCodeAt().toString(16)
// 输出十进制ASCII码:20320
"你".charCodeAt()
// 输出十六进制ASCII码:4f60
"你".charCodeAt().toString(16)
验证
5.常见的编码格式
# '你好'URL编码后结果
\xe4\xbd\xa0\xe5\xa5\xbd
# '你好'URL编码后结果
%E4%BD%A0%E5%A5%BD
# '你好'转UTF8后结果
%u4F60%u597D
# '你好'转Unicode编码后结果
\u4f60\u597d
6.将你好
转换成16进制字符串后,如何进行反解析?
// '你好'转16进制后
Buffer.from(Date.now() + str).toString('hex')
// 输出结果
e4bda0e5a5bd
// 将16进制字符串解码
Buffer.from('e4bda0e5a5bd', 'hex').toString()
// 输出结果
你好
7.e4bda0e5a5bd
字符串是如何解码的?他是几个字符作为一组开始解析的?如何确定字符的开始和结束位置的?
解码时,是以字节为单位
1字节(Byte)=8位(bit)
(一字节是由8个二进制位组成,8个二进制最大可以表示的数字是:2^8=256,区间0-255),而最大的两个16进制FF
可以表达的数字是:16*16=256,区间最大数字刚好是255,所以两个16进制字符为一组刚好可以表示8个二进制位,同理,一个16进制位可以表达4个二进制位,按此特性将2个16进制还原成8个二进制位数据:
e4
转换为二进制为:11100100
bd
转换为二进制为:10111101
a0
转换为二进制为:10100000
e5
转换为二进制为:11100101
a5
转换为二进制为:10100101
bd
转换为二进制为:10111101
e4bda0
组成了字符你
e5a5bd
组成了字符好
那么他们是怎么确定一个中文字符由几个十六进制组成呢?
8.什么是UTF-8?
UTF-8的特点是对不同范围的字符使用不同长度的编码。
上表表示如何从一个从Unicode 转化到UTF-8 , 对于前0x7F的字符,UTF-8编码和ASCII码是一一对应的。如果一个字符在000800-00FFFF 之间,那转化到UTF-8 需要用三字节模板,使用16个码位,每个x 就是一个码位。
比如『汉』这个字的Unicode编码是0x6C49。0x6C49在0x0800-0xFFFF之间,使用3字节模板:1110xxxx 10xxxxxx 10xxxxxx。将0x6C49写成二进制是:0110 1100 0100 1001, 用这个比特流依次代替模板中的x,得到:11100110 10110001 10001001。
当然如果用16位更节约空间。对于中文而言,Unicode 16编码里面已经包含了GB18030里面的所有汉字(27484个字)。
9.UTF-8长度确定
由此可见,16进制解码时,是两位为一组得到二进制位,再根据首位数字中有多少个连续的
1
来确定后续几组属于同一个字符,比如:
e4bda0e5a5bd
中,解析到首位e4
得到二进制位11100100
,由于二进制中首位连续3个1
,所以这个字符需要连续三组16进制数字表示,所以e4bda0
共同表示一个字符你
10.字符运算进行加密
所以我们可以把字符串转换为各种进制的数字,然后进行运算,提交到服务器后,再反运算进行还原就可以达到加密的效果。
在go中见到过如下移位
写法,原理也是利用二进制实现的:
maxMultipartMemory := 8 << 20 // 8 MiB
在java中见到过如下异或运算
写法,其本质也是二进制计算得到的:
int a = c ^ b