关于信息安全的一点瞎扯淡

谁叫咱肚子里也没有多少墨水……

信息安全的几个方面?

(个人认为)大概有这么几个:

  • 防御各种入侵(骇客,不怀好意的邻居或者上级,政权和国家等等)
  • 个人隐私和隐匿性保护(特别是在搞大新闻的时候)
  • 容灾措施(主要是备份)
  • 社会工程
  • ……

当然,搞这些的话,没有充分的知识储备(例如密码学)是不行滴……

黑客和骇客到底有啥区别?

黑客是指享受智慧乐趣的人们——并不一定与计算机有关。在 20 世纪 60 至 70 年代,麻省理工学院(MIT)的自由软件社区的程序员称他们自己为黑客。大约在 1980 年,那些发现了黑客社区的记者们错误地将这一词语用于指代“安全破坏者”。

请不要散播这种错误。那些破坏安全的人称为骇客(cracker)。

加密,解密,签名和散列(哈希)都是啥?

加密与解密

加密就是把明文变成密文的过程,解密就是把密文变成明文的过程。此二者是互逆的,就好似减法是加法的逆运算一样。在加密和解密的过程中,需要一个 "密钥" 来参与数学运算,这个密钥就好像是你的钥匙一样,正确的钥匙能够打开锁头,正确的密钥才能够把密文转变成(具有意义的)明文。

对称密码

对称密钥加密(英语:Symmetric-key algorithm)又称为对称加密、私钥加密、共享密钥加密,是密码学中的一类加密算法。 所谓对称密码(对称加密),这类算法在加密和解密时使用相同的密钥,或是使用两个可以简单地相互推算的密钥。这个很好理解,就像你用 WinRAR 啥玩意压缩一个文件的时候设置了一个口令,解压缩的时候也要用这个密码才能成功提取文件一样,这个 "口令" 就相当于我们上面说的密钥。

对称密码可以分为两类:分组加密(英语:Block cipher,又称分块加密或块密码)、流加密(英语:Stream cipher,又译为流加密、数据流加密)。所谓分组加密,就是把明文按照一定大小分成组,并对分组进行加密然后组合,常见的 AES 就是这种加密;所谓流加密,则是每次加密数据流的一位 (bit) 或者一个字节,RC4、Salsa20 就属于流加密。 我们平常提到对称密码,更多情况下指的是分组加密。

分组密码拥有严谨的数学结构,此结构被称作 Feistel cipher

分组密码常见的共有五种分组模式,分别为 ECB、CBC、CFB、OFB、CTR,其中的差别是使用如何应用初始化向量(IV)对分组的块进行加密与组合。我们暂时只要知道 ECB 模式是不安全的就好了,具体原因在之后的文章中可能会详细介绍。 我们常用的对称密码有 DES、3DES、AES、Blowfish、IDEA、RC5、RC6 等。美国国家标准与技术研究院(NIST)在竞标时,最后入围共有五种算法:Rijndael、Serpent、 Twofish、MARS 和 RC6,最后 Rijndael 被选作 AES。所以我们现在提到 AES,指的就是 Rijndael 啦。需要注意的是,在标准化之前,Rijndael 的分组长度是 128 比特,密钥长度可以是 32 以 32 比特为单位在 128-256 进行选择;标准化成为 AES 之后,密钥长度固定为 128、192 和 256 三种,分组长度还是 128 比特。

常见的流密码

常见的分组密码

非对称密码

公开密钥加密(英语:Public-key cryptography),也称为非对称加密(英语:asymmetric cryptography),是密码学的一种算法,它需要两个密钥,一个是公开密钥,另一个是私有密钥;一个用作加密的时候,另一个则用作解密。使用其中一个密钥把明文加密后所得的密文,只能用相对应的另一个密钥才能解密得到原本的明文。

由于加密和解密需要两个不同的密钥,故被称为非对称加密;不同于加密和解密都使用同一个密钥的对称加密。虽然两个密钥在数学上相关,但如果知道了其中一个,并不能凭此计算出另外一个;因此其中一个可以公开,称为公钥,任意向外发布;不公开的密钥为私钥,必须由用户自行严格秘密保管,绝不通过任何途径向任何人提供。

这么说一堆很难理解,咱在这里只要知道,非对称密码有一组密钥,这组密钥中,公开的被称为公钥,私有的被称作私钥;使用公钥加密的文件只有使用对应的私钥才能解开;使用私钥加密(签名)的文件只有使用对应的公钥才能解开;每一对公钥和私钥之间有着严谨的数学关系,很难通过一个密钥计算推导出对应的另一个密钥(但是……)。

公钥密码领域使用单向函数原理。单向函数指的是正向操作非常简单,而逆向操作非常困难的函数。举个简单的例子,7×9=63,但是我给你 63 让你猜出来我的 7 和 9…… 好像也很简单,那么给你 2511563340 让你找出 65535×38324 好像就有一丢丢困难了。这种函数往往提供一种难解或怀疑难解的数学问题。

非对称密码中比较出名的有 RSA 和椭圆曲线(ECC),其中 RSA 应用的难解(怀疑难解)是质数分解,ECC 自然就是椭圆曲线啦。

总结:对称密码和非对称密码的优缺点咱能看出来,对称密码的实现比较简单,速度快,但是如何进行密钥交换却变成了一个先有鸡先有蛋的问题;公钥密码的设计通常要涉及到一些比较复杂的数学问题,所以公钥密码的速度通常要比对称密码差几个数量级,但是密钥交换却比较容易;并且,公钥密码需要比较长的密钥长度才能够保证类似等同于对称密码的加密强度。

NIST 建议的最低密钥长度,RSA 和 DSA 是 1024 位,ECC 是 160 位,相应的对称分组密码(比如说 AES)的密钥长度是 80 位;NIST 建议实际使用密钥长度 AES 为 128 位、RSA 2048 和 ECC 256 位。

散列函数

散列函数(或散列算法,又称哈希函数,英语:Hash Function)是一种从任何一种数据中创建小的数字“指纹”的方法。

就是说,散列函数就相当于消息的指纹,指纹这东西嘛,就是接近独一无二的咯。咱把一个消息(文件)使用单向散列函数处理一下,就会有一个定长的 "指纹"(也被称作散列值、摘要),我们就可以用这段摘要来唯一的代表这个消息;假如某天这个消息变化了哪怕是 1 比特,那么这个摘要也会变得面目全非(完全不一样),这样咱就能知道原来的消息被篡改了。

散列函数是单向的,咱把一个文件散列了,之后就 不太可能 再给还原了(hash 本身就是捣碎剁碎的意思,你把镜子打碎了,还怎么还原嘛)

咱前面说了,“接近独一无二”,那么就是说可能有两个不同的消息,在某种散列算法处理之后,拥有相同的散列值。这是完全可能的,这种情况我们称之为散列函数发生了碰撞。这是必然会发生的,因为散列值是定长的,你把无穷的东西转换成有限的东西,自然会有重复的(鸽巢原理)。当然啦,2^256 已经是个天文数字了……

碰撞可以分为两种,已知明文,找到另一个明文,使得此二者散列值相同,称作弱碰撞;找到任意两个明文,使得两个散列值相同,称作强碰撞。

换句话说,(理想状态下)单向散列函数可以用来验证消息的完整性。 咱常用的单向散列函数有 MD5、SHA 家族的 SHA1、SHA2 等等。对呢,散列函数 通常 都很快很快。

消息认证码(HMAC)

密钥散列消息认证码(英语:Keyed-hash message authentication code,缩写为 HMAC),又称散列消息认证码(Hash-based message authentication code),是一种通过特别计算方式之后产生的消息认证码(MAC),使用散列函数,同时结合一个加密密钥。它可以用来保证数据的完整性,同时可以用来作某个消息的身份验证。

消息认证码就是一种能够确定消息的完整性并且能够进行认证的技术。所谓 "完整性"、"一致性",就是消息没有被篡改;所谓 "认证",就是消息来自正确的发送者。消息认证码是一种结合了单向散列函数和对称密码的密码学技术。我们常用的 HMAC 就是其中之一。

当然了,也有些脑残的设计是把用户密码 HMAC 之后存入数据库中。

数字签名

数字签名(又称公钥数字签名,英语:Digital Signature)是一种类似写在纸上的普通的物理签名,但是使用了公钥加密领域的技术实现,用于鉴别数字信息的方法。

一言以蔽之,数字签名就是将公钥密码反过来使用。我们知道公钥是公开的、私钥是私有的,如果我们使用私钥对某个文件进行加密(实际上应该被称作签名),那么任何人都可以对此进行解密,看似这里似乎失去了加密的意义,但这实际上可以证明一点:只有持有私钥的人才能够进行加密,这也意味着我们可以认证(这东西是私钥持有者发的)、防止否认(理想状态下私钥持有者不能说这东西不是他发的)、完整性(解密一旦无意义,则意味着被篡改)。

因此,可靠的公钥密码算法均能构建出可靠的数字签名,只不过咱一般都是对消息的散列进行 "签名",因为公钥密码比较慢嘛,万一给一个 GB 级别的东西签名,那就惨了。

随机数不随机是为啥?

随机数是骗人的!

如果读者学习过某些程序设计语言,可能记得他们的标准库中都有个类似 random 的东西可以生成某个范围内的随机数。我们看那个随机数似乎是统计学上随机的,但实际上咱要认识到一件非常残酷的事实:计算机是无法生成真正的随机数的,真不能,所以我们称随机数算法为 "伪随机数算法"。

伪随机性(英语:Pseudorandomness)是指一个过程似乎是随机的,但实际上并不是。例如伪随机数(或称伪乱数),是使用一个确定性的算法计算出来的似乎是随机的数序,因此伪随机数实际上并不随机。这好像挺难理解的,咱只要知道吧,只要随机数算法是固定的,在给一个固定的 "种子",那么每次生成的随机数也就是固定的、有规律可循的。比如所,咱用 C/C++ 的线性随余算法生成伪随机数,往往就用时间做种子了,如果你给种子一个固定值,那么这随机数肯定是相同的。

那这随机数有啥用啊?还记得上面提到的密钥吗,在密码学中,随机数可是无处不在的,你那密钥实际上就是有伪随机数生成器搞出来的啊,真以为是你键盘上输入 123456 就把 123456 用作密钥了啊(当然了,和 123456 是有关系的)。

由于伪随机数不是真的随机数,在有些方面它们不能被使用,例如在密码学中使用伪随机数要小心,因为其可计算性是一个可以攻击的地方,所以啊,拿时间做种子是不行的,因为时间是可以预测的。

随机数有一些比较重要的性质:随机性(不存在统计学偏差)、不可预测性(不能根据过去的随机数序列预测未来的随机数序列)、不可重现性(不能重现该序列),密码学上使用的伪随机数算法至少也要做到前两点。

咱要记得,凡是线性随余算法的随机数算法都不能作为密码学应用;请使用语言的标准库中提供的密码学算法,或者是使用 OpenSSL、/dev/randomCryptGenRandom()这类安全的实现。

为啥加密算法都是公开的?

在密码学上,有一个原则被称作“柯克霍夫原则(Kerckhoffs's principle)”,意思是即使密码系统的任何细节已为人悉知,只要密匙(key,又称密钥或密钥)未泄漏,它也应是安全的。

很多人以为,只要在传统上传统上使用隐密的设计、实现、或其他等等来提供加密的隐蔽式安全(Security through obscurity)即可达到保密的效果。实际上这样的想法是错误的。要知道,只要代码在运行,就可能会被逆向,使用隐蔽式安全依赖的是算法的保密性,保密的加密算法只要被使用,迟早会公诸于世,想依靠对密码算法本身进行保密来确保机密性的密码系统也就土崩瓦解了。相反,如果加密算法从一开始就没设想过要保密,则它会得到各种攻击的洗礼,从而实现更强的保密性。因此现代密码学的加密方式基本以“公开加密算法+保密密钥”组成。

不相信是么?想想当初DVD的加密算法、DRM,你就懂了。隐蔽式安全是不靠谱的。

我真的有必要保护自己不断泄露的隐私嘛?

汝认为有就有, 这篇文章大概讲的比较清楚这里有个中文翻译

results matching ""

    No results matching ""