"字符"、"字符集"、"进制"、"编码"、"加密" 给我们带来了哪些困惑?
对于大多数搞安全的来说,应该是能理解上面几个名次的,不过如果我说GBK ,Unicode, UTF-8, GB2312, ISO-xxxx, 二进制,八进制,十六进制 ASCII, BIG5, UTF-16,UTF-32,UTF-DOM,半角字符,全角字符 等等,这回你还能分清楚吗?
如果这个你也清楚,那说明你的基础还是不错的,那各种字符集,编码之间的先后存在关系呢?
上面你也清晰,那么说明,对于字符的发展历史真的是很了解了,那么接下来要了解的就是为什么会发展了,也就是一些基本的占位的问题了
其实这些知识之前学过很多次,学了忘,忘了以为记得。
这回就写一篇文章来记录一下吧!
PS:关于这个知识点,网络上有很多人已经写的非常好了,我也会摘抄其中的部分,最后在文章结尾会注明!
从源头开始吧!
众所周知,计算机只认识二进制,即 0和1 两个"数字"
这里说数字并不准确,我个人觉得说两个状态更好,不过为了直观,直接说数字了
学习任何语言我们都是从打印hello world 开始,后来学会开发各种程序,程序运行起来依赖我们的系统(系统也是一个程序),系统把程序执行转化为汇编,汇编再到计算机认识的二进制,所以QQ在硬件眼里也就是
011011010101010111110110110101010 这种状态,当然要比这个大得多,所以在谈什么字符之前,先明确以下本宗
关于进制大家在高中和大学肯定学过很多了,所以这里就不需要讲故事了
大家只需要明确,二进制可以表示计算机世界的任何东西(当然不包括什么硬件,这里不要较真)
刚才说了,QQ用二进制表示的话,实在是太长了,而且人类可读性差,这里就有了 八进制,十进制,十六进制
二进制,八进制,十进制,十六进制 都是为了表示其他东西而存在,而不是所谓的什么编码,这只是一种表示之间的关系(进制转换)
进制转换我在这里就不详细说了,毕竟我想留着其他篇幅去写别的东西
字符是什么?
字符的概念很容易理解,就是字母加上符号
大家都知道计算机系统是美国发明的,人家最开始就没想到大家会都用上
所以,在他们眼里,字符就是26个英文字母,加上一些符号,比如 - <> 等等,这个可以完美的在美国的环境中使用
如今,计算机全世界都在用,很多国家又有甚至不止一种语言,所以字符的概念就更加广大了,包括所有的字母,数字,文字,图标,符号等等
有些国家的语言就是用类似图画来表示的,比如象形文字,那这个也在字符的范畴内
所以字符的概念也很好理解!
字符集是什么?
这个概念也很好理解,字符集就是字符的集合,所谓的码表
1 2 3 4 5 6 7 8 9 0
上面的每一项单拿出来都可以成为一个字符
如果把他们凑在一起就成了一个字符集,甚至我们可以起一个名字数字集,洋气点叫 num集
所以大家应该可以明白,世界上肯定有非常非常多的字符集
编码是什么?
上帝给了我黑色的眼睛,我要用它寻找光明
编码是一种工作方式(不用疑惑,我娓娓道来)
1234567890ileyvodufg
上面是一个字符集,现在我要和一个女孩说 I love you
这就是一种编码,我把字符集中的字符按照一定的方式组合了
为了更好理解,我还是举一些比较明显的例子吧
摩尔斯电码
https://baike.baidu.com/item/摩尔斯电码/1527853?fr=aladdin
打过CTF的同学或者了解历史的同学肯定是接触过的,不了解的可以通过上面的百度百科了解一下
摩尔斯电码中只有点,横,停顿(对应声音 滴答停)
摩尔斯电码设计的初衷就是为了通信而来的,解决了军用和民用的需求
战争时代,情报往往能左右战争的胜利,所以大家在情报的准确性和及时性上面想尽了办法
传递的方法就是无线电,不过无线电是没有办法传递我们现在的abcd 这种字符的,能发出声音就已经不错了
所以我们需要把abcd 等等一系列的转换为 机器能传递的语言,这样就解决了传递的问题
下面就是通信的问题,如何表达呢?
此时把a 编码为 ·- 就是我们说的编码了
有编码自然也就有解码了,没错,就是根据编码的那张表(字符集),我们以同样的方式进行解码
这样就完成了通信与交流
此时大家应该明确一件事,编码也不只一种
并且中国汉字要是都转化为摩尔斯电码,无论是发的人还是收的人都会疯掉的(放在过去)
编码的目的就是为了交流
加密是什么?
加密就是把原本谁都能理解的东西变成只有特定人能理解的东西
就好像你手机的开机密码一样,没有设置密码,谁都可以操作你的手机
设置了密码,只有知道你的密码的才能操作
没错,加密和编码的定义有些相似,其实可以说加密是其中一种编码的固化形式
如果仅仅把加密这个概念局限在计算机中来看的话,我们可以用勒索病毒来形象的说明一下
勒索病毒的原理就是将字符以一种大家都不知道的编码方式来进行加密
因为缺少编码方式,即使我们知道字符集也是没有办法直接解密的
加解密更多是在密码学,二进制安全,逆向等中涉及比较多
所以在这里就不做过多的介绍
我们说说发展
发展肯定是根据需求来的
古代战争需要传递信息,所以有了烽火
现代战争需要传递信息,所以有了无线电
现在世界互联,需要相互交流,所以有了统一的字符集和编码方式
字符的发展就不说了,甲骨文到现在的繁体简体(中国)
直奔主题,像摩尔斯电码等等一系列历史我就跳过了,我们直接说计算机字符集
在这之前我还是说一下 byte(字节) 和 bit(位)的区别,以方便后面的理解
我们经常知道大小用什么 GB,MB,KB等进行表示,或者直接把B省略掉
1 GB = 1024 MB
1 MB = 1024 KB
1 KB = 1024(1000) B
1B = 8 bit
具体可以查看下面的链接
https://baike.baidu.com/item/字节/1096318?fr=aladdin
一般我们都以字节为最小单位来描述文件大小
其实一个字节byte 是这样组成的 :0000 0000
其中的每一个0都是一个bit(位)
所以每一个bit不一样都是一种不同的byte
大家了解到这里就好了,更多的去上面的链接里面学习吧
【ASCii 字符集】
(American Standard Code for Information Interchange,美国信息交换标准代码)
这个是根据拉丁字母而来的,具体可以参见下面的百度百科
https://baike.baidu.com/item/ASCII/309296?fr=aladdin
ascii 是用一个字节来表示字符的一种字符集
既然是用一个字节,那么最多能有多少种可能呢?
0000 0000 --- 1111 1111
2的8次方对吧,很显然,只有256中可能
虽然只有128中可能,但是美国人(以及一些西欧)根本没有那么多字符,拉丁字母26个,以及一些标点符号 ,.;':"/[]-=等等,反正根本就用不完256个
所以人家设计时候根本就没有把8bit全用了,仅仅用了后7个bit就把拉丁字母和标点符号以及一些控制字符 就表示全了
换行,删除,退格等等控制字符占用了 0-31 以及 127 这33 个字符,这些字符可以说都是不可显示字符
剩下的那些就都是可显示字符了
关键在于空着的一位用来做些什么呢?
为了保证传输完整性,空着的一位用来做奇偶校验
所谓奇偶校验,是指在代码传送过程中用来检验是否出现错误的一种方法,一般分奇校验和偶校验两种。奇校验规定:正确的代码一个字节中1的个数必须是奇数,若非奇数,则在最高位b7添1;偶校验规定:正确的代码一个字节中1的个数必须是偶数,若非偶数,则在最高位b7添1
就这样,美国老铁实现了自己完美运行,在一些终端机上使用一点问题都没有
【EASCII】1981年左右
计算机发展是非常快的,很快在一些英文字符,俄语,汉语语系根本表达不了
于是美国老铁觉得是时候把剩下的128个字符利用起来了,此时128-255 被赋予了新的意义,被称为 扩展ASCII,及EASCII
需要注意的是,EASCII字符集依旧是用一个字节来表示字符的
这回美国和欧洲的一些国家基本上是够用了
【GB2312】1981年5月
计算机在这个时候也来到了中国
来到中国以后就妥了,即使是把256种可能都给中国也不够基本汉字的呀
所以我们国家就出台了我们自己的一套码表《信息交换用汉字编码字符集》
编号为 GB2312-1980
详情可以查看
https://baike.baidu.com/item/信息交换用汉字编码字符集/8074272?fr=aladdin
这套字符集里面都收集了什么字符呢
包括汉字和一些日文,俄文,拉丁字母等
当然我们关注的还是它是如何存储的呢?
6000多个字符如直接用阿拉伯数字来表示未免太过于繁杂,而且不利于查找,所以gb2312采用了一种分区的方式来表达,跟中国的省市制度划分一样
所以采用两个字节来存储每一个字符,存储方法称为EUC,具体如下
因为一个字节最大不会超过两位16进制数,所以都用16进制数来分别表示这两个字节
比如 A1FE
【BIG5】1983年左右
GB2312 中并没有对繁体中文进行编码,所以说我们的港澳台地区就没有办法使用gb2312 ,所以BIG5 应运而生,收录了13060 个汉字
我们来看一下存储方式
BIG5 选择的存储方式和gb2312 基本类似,同样是采用两个高低字节的方式
BIG5 字符集还是存在一些问题,主要是一些特殊字符,具体可以查看下面链接
https://baike.baidu.com/item/大五码?fromtitle=Big5&fromid=1780793
【Unicode】1990年
其实Unicode算得上是一个里程碑,因为从这以后,编码和字符集的概念开始有了明显区分。
https://baike.baidu.com/item/Unicode/750500?fr=aladdin
首先先对之前的讨论进行一个简单的总结:
之前都是一个地区用一个字符集,所以所谓的编码也就是基于各个地区的字符集的一个编码,所以我们也经常听到gb2312编码,ascii编码等
所以几乎就是一个一一对应关系,有点 “解铃还须系铃人” 的意思。
不过这一个现状从Unicode的出现有了改观,开始了“大一统”和地区字符集并存的情况
大家可以通过刚才的链接详细的学习以下Unicode的前世今生,接下来我简单的说一说
由于各个国家之间的访问需求量增加,使用不同字符集就会出现乱码,所以为了解决这个问题,出现了对通用字符集(UCS)的探索,这个通用字符集有ISO根据ISO 10646 进行制定
经过几个版本的发展,最终形成了Unicode 字符集,这个字符集是想把全世界所有的字符都放在其中(实际上应该不全,毕竟中文有很多生僻字,其他国家的语言也是,不过这里包含了绝大部分)
有了字符集,下面就是如何编码的问题了,我们已知的是每一个字符都存在一个数字位置,比如 汉字“字”对应的数字是23383(十进制),十六进制表示为5B57,此时用多少个字节来表示呢?
此时就会出现了比较常见的编码方式 UTF-8,UTF-16,UTF-32,其实也就是如何把unicode定义的数字转换为程序可以识别的数据
UTF-32
32 其实是4个字节的意思,根据之前的知识,四个字节,每个字节八位,所以就是 32位
UTF-32 是将每一个字符都用 4 个字节来表示,无论这个字符对应的数字的多大,所以这是一种及其浪费空间的表示方式,极端一点可以出现:
0000-0000 0000-0000 0000-0000 0000-0001
不过UTF-32 这种固定长度,可以比较容易在一串字符中确定某一个字符的位置,可能你现在不明白什么意思,等讲完UTF-8 你就应该明白了
UTF-16
UTF-16 顾名思义,是通过两个字节来表示字符的方式。说到这里大家肯定会很疑惑:
2的16次方是 65536,去掉 1111-1111 这种情况,总共65535个字符,这个字符量应该不足以把全世界的字符都表示出来吧
没错,这种编码只对我们较常使用的前65535个字符进行编码
BOM
https://baike.baidu.com/item/BOM/2790364
经常我们会遇到UTF-16 with BOM 之类的,那么这个BOM是什么呢?
BOM 字节顺序标记(Byte Order Mark)
这个标记是用来告诉程序两个或者四个字节那个在前,哪些在后,以免造成混乱
比如 56E7 和 E756 这两个就可能出错,用 FE FF 或者 FF FE 标记以下顺序就不会错了
UTF-8
https://baike.baidu.com/item/UTF-8
UTF-8 是一个大家都认可的编码,也是现在使用最多的一种编码
UTF-8 是一种可变字节长度的编码方式
根据USC发展历史来说,UTF-8 这种编码,从一个字节到六个字节都存在,其中5,6 字节并不是Unicode 字符,是USC-4 ,后来就只用到1-4字节来表示
这里截取百度百科的一部分给大家看一下规则
从这个规则可以看出,UTF-8是兼容ASCII的,而且根据字节数来定位字符是一件比较困难的事。
【GBK】1995年
https://baike.baidu.com/item/GBK字库
GBK字符集是对GB2312字符集的一个扩展,支持ISO10646.1国际标准,与Unicode完全兼容
GBK字符集采用两个字节编码,包含了21003个汉字,其中包含繁体字
【GB18030】2000
https://baike.baidu.com/item/gb18030/3204518
GB18030是国家标准,在技术上是GBK的超集,并且与其兼容。
GB18030 字符集分为2000版本和2005版本,采用单字节,双字节和四字节三种方式对字符进行编码,具体可以参照上面的百度百科
其实还有很多编码在这里没有说明到,比如 UTF-7,UTF-7.5 GB12345等等,在以后的文章中可能会适当的说明
这篇文章只是一个知识的梳理,更多的细节没有论述,比如操作系统与字符集的关系,程序与系统与字符集的关系,传输与字符集的关系等,带我研究清楚再来向大家讲述!
有态度,不苟同