为什么需要加密?
为了安全,有些数据不想也不能让别人知道。
加密的两大核心要素
算法 — 就像是锁的结构密钥 — 锁的钥匙数据加密,简单来说就是给数据上一把锁一样,加密的对象数据有文本、图像等多种形式,我们来看文本数据的加密。
文本数据与字符编码文本数据由各种字符构成,每个字符都被分配了一个数字,我们称之为字符编码。
字符集你可以先理解成“很多字符的集合”,常见的有:
ASCII 字符集JIS 字符集Shift-JIS 字符集EUC 字符集Unicode 字符集明文 → 密文先把明文加密成"密文"再传输。对于计算机而言,密文和明文没有区别,都是数字;但对于人来说,密文是看不懂的,比如:
代码语言:javascript复制VWx0cmEgc2VjcmV0IG1lc3NhZ2UuIEVuY29kZWQgaW4gQmFzZTY0Lg==
基本思路就是字符编码的变换,把这个变换过程反过来,就是解密了。
加密技术演化史加密技术大致是这样一路发展过来的:
古代:斯基泰密码棒
物理加密古典:凯撒密码
替换加密近代:维吉尼亚密码
多表替换,难度一下就上去了二战:恩尼格玛机
机械加密,二战里的核心技术之一计算机时代:DES
计算机时代第一个标准加密1976:公钥加密革命
这算是划时代的一步现代:AES
现代加密标准未来:量子加密
未来边界下面讲解一下 公钥加密革命、AES,其他的就不说了。
公钥加密革命不得不说,这真是天才。之前的加密方式都必须要交换密钥才能解密,但在 1976 年,迪菲和赫尔曼打破了这种方式。这里用颜色来举例:
代码语言:javascript复制第一步:双方公开约定一个"公共颜色"
公共颜色 = 黄色
(全世界都知道,无所谓)
第二步:各自秘密选一个"私人颜色"
你的私人色 = 红色(只有你知道)
朋友私人色 = 蓝色(只有他知道)
第三步:各自混合,公开发送混合结果
你发出:黄+红 = 橙色 ──────→ 朋友收到橙色
朋友发:黄+蓝 = 绿色 ──────→ 你收到绿色
第四步:再各自加入自己的私人颜色
你:绿色 + 红色 = 黄+蓝+红 = 棕色
朋友:橙色 + 蓝色 = 黄+红+蓝 = 棕色
✨ 你们得到了同一种颜色!✨
窃听者只看到:黄色、橙色、绿色
他无法还原出棕色,因为他不知道
你们各自的私人颜色!
数学原理:单向陷阱门你可以这样理解这个数学原理:
正向:
这个很容易算17 × 19 = 323反向:
这个就没那么轻松了,通常得一个个去试323 = ? × ?这就是 RSA 加密,所以有了:
公钥:可以公开给全世界私钥:永远只有自己知道AES(现代加密标准)AES的核心是反复混淆。
举例:把一封信重复 16 次地撕碎、重排、替换、混合。
流程大致为:
加密:明文->第1轮->第2轮 ... ->第16轮->密文文
解密:密文->第16轮-> ...第2轮->第1轮->明文
每一轮,密钥参与进来:
原文修改 1 个比特 → 对应密文改变约 50%
但注意,AES只有1把主密钥,主密钥会自动衍生出16把子密钥,加密 1-16,解密 16-1,所以 AES 属于“对称加密”
AES-256 的密钥空间数量大概有多少呢? 2^{256}
CA(证书颁发机构,证书颁发机构)CA 不是证书本身,而是负责发证书、做担保的机构。证书,相当于公钥的身份证。
公钥加密会有一个漏洞:
你接受到了一个号称"谷歌"的公钥,你如何去知道他是真的谷歌?那么就需要引入一个权威的第三方机构来做担保
CA的工作流程:
网址 -> CA -> 审核身份 -> 符合身份(盖章) -> 给该网址颁发证书
那么问题就解决了,检查是否有 CA 盖的章, CA在不在信任名单里,都符合就通过
HTTPS那么把 CA、DNS、公钥加密、AES 结合起来,就是一个 HTTPS 的完整流程
DNS找地址(找到对方为止)CA验证身份(确定对方身份)公钥交换暗号(安全交换 AES 密钥)AES正式通信(加密所有真正的数据)到这里为止,前面讲的基本还是“把东西藏起来,以后还能再解开”。
但数据安全不只有这一种思路。还有一种思路,不是把东西藏起来,而是给它做一个“指纹”,这就接到了下面的哈希函数。
哈希函数前面说的 AES、公钥加密,本质上都是:把东西藏起来,需要的时候再还原出来。
但哈希函数不一样,它不是拿来“还原”的,而是拿来“留指纹”的。
你可以把哈希函数想象成一个超级碎纸机:
什么内容都可以扔进去出来的是一串固定长度的结果这个结果很容易算出来但几乎不可能反推出原文比如你输入:
hello
它就会吐出来一串哈希值。
如果你只改一个字母,比如变成:
hellp
那出来的结果往往就会完全不一样。
所以哈希函数你可以先记住这几个特点:
同样的输入,永远得到同样的输出输入哪怕只改一点点,输出也会变化很大输出长度通常是固定的很难从结果反推出原文注意,这里是“很难反推”,不是“绝对不可能”。
理论上,不同输入有可能撞出同一个结果,这叫“碰撞”。但好的哈希函数,会把这种事情压到非常非常难发生。
那哈希函数拿来干什么呢?
最常见的用途有两个:
检查文件有没有被改动存密码比如你下载一个安装包,官网给了你一个哈希值。你本地也算一遍,如果两边一样,说明这个文件大概率没被动过手脚。
所以你会发现,哈希函数和加密,根本不是一回事:
加密:是为了以后还能解开哈希:是故意不让你解开,只留下一个“指纹”密码存储那网站为什么不能直接把密码存起来呢?
因为如果直接存明文密码,数据库一旦泄露,别人看到的就不是“乱码”,而是你的原始密码。
更麻烦的是,很多人喜欢在不同网站里用同一个密码。那一个网站一泄露,别的网站也可能跟着遭殃。
所以正常的网站,不会直接存“密码本身”,而是存“密码的哈希值”。
流程大致是这样:
你注册账号,输入密码网站先生成一段随机字符串,这东西叫 salt(盐)把 “密码 + 盐” 一起送进哈希函数数据库里保存的是 “哈希结果 + 盐”,而不是原密码那登录的时候怎么办呢?
也很简单:
你再次输入密码网站把数据库里那段盐拿出来再把 “你刚输入的密码 + 盐” 算一遍哈希拿新的结果去和数据库里保存的哈希值对比一样就通过,不一样就拒绝这里的关键就在于:
网站其实从头到尾都不需要知道你的原密码,它只需要看“你这次算出来的指纹”,和“以前存下来的指纹”是不是一样。
那为什么还要加盐呢?
因为如果不加盐,会有两个很现实的问题:
两个用户如果用了同样的密码,数据库里存出来的哈希值也会一模一样攻击者可以拿现成的常见密码表,也就是所谓的“彩虹表”,直接来撞加了盐之后,就算两个人密码一样,最后存下来的结果也会不一样。
比如:
张三密码是123456李四密码也是123456如果没有盐,那他们数据库里的结果通常就是一样的。
但如果:
张三的盐是abc李四的盐是xyz那最后算出来的哈希值就不一样了。
这样攻击者就没办法拿一张表打天下。
但这里还要再说一个很关键的点:
存密码,不是随便拿个哈希函数一算就完事了。
为什么?
因为现代显卡算得太快了。像普通的 SHA-256,虽然本身没问题,但它“太快”了。对密码存储来说,太快反而不是好事,因为攻击者暴力猜密码也会很快。
所以真正存密码的时候,一般会用专门给“密码存储”设计的算法,比如:
墓穴斯克鲁特阿尔贡2它们的特点不是“更高级更花哨”,而是故意让计算变慢、变吃资源。
你可以把它理解成:
平时的哈希函数,像一台很快的机器
密码哈希算法,像一台故意调慢的机器
目的就是:你正常登录时慢一点没关系,但攻击者想一秒钟试几亿次密码,就没那么容易了。
所以密码存储最后可以记成这样:
不存明文密码不建议只做一次普通哈希要加盐最好用专门的密码哈希算法说白了,网站并不是把你的密码“藏起来”了,而是从一开始就不该把你的原密码留下来,只留下它的“指纹”。