70 行 Python 代码理解加密、安全的前世今生

小七学习网,助您升职加薪,遇问题可联系:客服微信【1601371900】 备注:来自网站

信息是如何加密、解密和安全传输的?如今加密货币满天飞,其中公钥、私钥、非对称加密,到底什么意思呢?数据库中存储的密码又是什么样子?什么是彩虹表?为什么数字签名能能确认签字人? 本文使用 70 行 Py…

信息是如何加密、解密和安全传输的?如今加密货币满天飞,其中公钥、私钥、非对称加密,到底什么意思呢?数据库中存储的密码又是什么样子?什么是彩虹表?为什么数字签名能能确认签字人?

本文使用 70 行 Python 代码来逐个演示常见加密、安全技术。

特点:

  • 码说“加密”:代码是程序员的本能,一码胜千言!
  • Python:几行代码,就可实现对称加密、非对称加密功能,大大减轻认知负担。
  • 共七十行代码:七十行代码,带你一窥加密的前世今生。

主要内容:

  • 明文字符串编码
  • 字节文件在文本协议中传输
  • 哈希函数和其功用:验证完整性及存储密码,及两种改进。
  • 对称加密
  • 秘钥交换
  • 非对称加密
  • 数字签名

适合人群 :对加密、安全感兴趣的小白用户。

定位:本文定位较简单,从宏观上认识安全技术,大家可以动手自己敲一敲代码。



一、引言

信息如何加密、解密?我们可能知道诸如对称加密、非对称加密、密钥对等只言片语,但尚未对加密手段有清晰、完整的认识。

本文用 70 行 Python 代码来逐个演示常见加密技术,完成各种加密、解密、签名、防伪的功能。本文定位较简单,大家可以动手自己敲一敲。

加密、解密建立在数学理论之上。从原理上理解加密即可,不建议大家自己实现,日常使用时直接调用相应库即可。

二、爱情故事

很久很久以前,程序员小明和隔壁公司小红在谈恋爱,两个人在小明 DIY 的线上聊天室聊得火热。我们的故事,从这里开始。

三、编码

plain

聊天室里,小明对小红说:’I love you!’。这是典型的字符串,计算机并不能直接传输,需要编码成相应字节序列,字节序列是由 0 和 1 组成的序列,0 和 1 又可以由电平信号高低表示,如此网线、路由器等设备才能传输。

plain = \'小红:I love you!\'plain_byte = plain.encode(\'utf-8\')print(plain_byte)

结果为 b\'\\xe5\\xb0\\x8f\\xe7\\xba\\xa2\\xef\\xbc\\x9aI love you!\'。这是 UTF-8 编码的字节序列。你也可以试试比如GB2312UTF-32` 之类编码形式。

如果有太多 \\x 转义字符,看起来比较乱。可用 binascii 库 b2ahex 方法来将转义字符去掉,转为字符串。用 a2bhex 将字符串转为转义字符串。binascii.b2a_hex(plain.encode(\'utf-8\')) 输出结果为:b\'e5b08fe7baa2efbc9a49206c6f766520796f7521\'

encode

简单理解:字符串是人读写的,字节序列是计算机处理、传输的。

小明 DIY 的聊天室是一个基于浏览器的 web 应用,这需要一些特殊编码方法。

四、urlencode 和 Base64

urlenode 和 Base64 应用于 web 程序,非常常见。

4.1 urlencode 用于 URL 参数构造

这个聊天室,采用 HTTP web 技术,消息都是构造到 URL 里面的,形式是这样的:http://www.chatroom.com?from=ming&to=hong&message=I love you!。问题出现了:上部分编码的字节序列,里面有些字符,URL 规则不兼容,为了构造兼容的 URL,我们应该这么做。

from urllib.parse import urlencode dict_plain = {\'from_\': ‘ming\', \'to\': \'hong\', \'plain\': \'小红:I love you!\'}urlencode_plain = urlencode(dict_plain) 

结果如下,汉字转为%开头的十六进制数据。这里的 urlencode_plain 是构造好的 URL 的参数部分,在聊天室的地址栏里,填上服务器地址和 urlencode_plain,请求后,消息就发送给小红了。

http://www.chatroom.com?from_=ming&to=hong&plain=%E5%B0%8F%E7%BA%A2%EF%BC%9AI+love+you%21

urlencode

解析的时候,服务器使用 parse_qs 函数读取、解析成原数据。

from urllib.parse import  parse_qsmess = parse_qs(urlencode_plain)

4.2 Base64 用于二进制文件文本化

小明想给小红发送一个照片,这其实有些复杂:HTTP 是文本协议,内容都是文本字符,不是字节序列。想要对二进制文件进行传输,需要把它转化为文本。

这里采用 Base64 编码,该编码用 64 个字符来表示二进制数据:每四个字节转为一个字符。如下为 Base64 编码程序。

from base64 import b64encode, b64decodewith open(\'love.png\', \'rb\')as f:    b64_en = b64encode(f.read())

文件 love.png 被 Base64 编码成一个文本文件。当小红收到文本文件时,只需要 b64decode,再写入文件,就可以恢复成二进制文件。如下为解码程序。

base64

with open(\'receive.png\', \'wb\')as f:    f.write(b64decode(b64_en))    f.close()

邮箱协议也是文本协议,这就是我们用 smtplib 发送附件时,需要引入 Base64 来编码邮件的原因。另外,由于二进制数据空间被压缩为 64 个字符空间,导致文件在 Base64 编码之后会变大。

至此,可以在聊天室里聊天、发送照片了。

很快,小明和小红聊天遇到问题了:网络经常丢包,导致小明说话有时候缺头少尾,小红经常误会小明的话,这该怎么办呢?

五、哈希函数

哈希函数也称为消息摘要函数,见名知意,这是把一段内容提要出来。这个提要很有特点:

  • 不论输入多长,输出长度固定,输出看起来像乱码。
  • 输入变一点,输出有很大不同。
  • 输入求输出很快,输出不可能反推出输入。

hash

哈希有什么用呢?其一是验证完整性。

5.1 验证完整性

靠着以上特性,小明可以把消息哈希一下,把哈希值和消息都给小红。小红也把消息哈希一下,如果两个值一样, 表明这句话内容完整,没有篡改和丢掉信息。

from hashlib import md5 hash_ = md5(plain.encode(\'utf-8\')).hexdigest()

结果这样:f0cba77cecfab51d466d8a92298fda25。如果小红也对这条消息哈希,结果相同的话,说明这条信息完整。

如果改动一点点:hash_ = md5(\'I Love you!\'.encode(\'utf-8\')).hexdigest()

结果是:3289c995276e8016a0d5b33e73a32c96,仅仅改动了 love 大小写,导致哈希结果不一致。

hahs2

所以,我们下载文件时常见 MD5 哈希值,用于验证文件完整性,保证文件没被黑客修改、嵌入恶意代码。

第二个用处是保密存储密码

5.2 存储密码

不久,小明发现聊天室被黑客拖库了,密码还是明文!这很尴尬!痛定思痛,小明学习了 MD5 函数在密码存储中的应用。

借助哈希函数特性,小明把密码哈希之后的字符串,存进数据表里的密码栏。登录验证时,使用 hash(登录密码) == 数据表中存储的哈希值 来验证用户输入的密码。而数据库中存储的哈希值,依上文可知,不能反推出原始密码信息。

hash_ = md5(pwd.encode(\'utf-8\')).hexdigest()if hash_ == db.password_hash:    do_something()

没过多久,小明发现聊天室再次被黑。难道传说中哈希函数也不灵了么?原来,小明虽然没有使用已经破解的 SHA1 算法,但是他使用了弱密码。

诸如 12345619900123 此类的密码,黑客先用哈希函数算出常见数字、字母、组合的哈希值,然后存储在一个表里,这叫做彩虹表,黑客拖库拿到的,虽是哈希后的值,不可直接使用,但只要和彩虹表一一比对即可。

弱密码首当其冲,很快被攻破。一个形如 a12$%^*1af909 的密码,彩虹表包含其哈希值的概率很低,这就是复杂密码好处。

回到小明的聊天室,该怎么保证弱密码的安全性呢?虽然可以强迫用户构造复杂密码,但小红可没耐心,还是小明出手吧。

5.2.1 Hmac 算法

Hmac 算法(Hash-based Message Authentication Code),这是基于哈希的消息认证码。在哈希过程中,给消息加了一个 key, key 和消息本身一块参与哈希,这样有了 key 参与,相当于构建了复杂密码,彩虹表很难找到对应的原信息。这个过程也称为加盐 salt。

import hmachash_ = hmac.new(b\'abc\', msg=pwd.encode(\'utf-8\'),digestmod=encry).hexdigest()

这个调用中,b\'abc\' 是添加到 mes 中的 key(salt盐),和消息 msg 一块参加哈希。验证的时候,服务端也通过同样的 key,完成哈希和验证。

如此,即便是弱密码,也能提供较好保护。

5.2.2 口令加密算法 pbkdf2

pbkdf2 算法,相当于在加盐哈希基础上进行多次哈希运算,加盐使彩虹表建表难度增加,多次哈希更增加建表难度。盐长度一般不少于 8 字节,哈希次数至少也要 1000 次。如此,想要靠彩虹表穷举攻破加密,基本是不可能了。

Python 当中进行 pbkdf2 加密如下。

secret = pbkdf2_hmac(\'SHA256\', plain.encode(\'utf-8\'), b\'12345678\', 100000)print(f\'{binascii.hexlify(secret)}\')

哈希函数依然采用上文中的 SHA256,加盐为 b\'12345678\',哈希次数为 100000 次。

而且,小明将 salt 单独存放在一个 U 盘中,每次登录时需要插入 U 盘,输入密码之后,密码和 U 盘中的 salt 结合,然后算出密码的密文,这就是简单的 U-key。

终于,聊天室妥善完成了密码保护,小明和小红的聊天可以继续下去……

走过风风雨雨的两个人,很快进入热恋期,随着两人共同约会、生活、出游增多,小红提出建立情侣聊天室的想法,这其实是加强版私聊。难度较小,小明很快实现了。

由于网络攻击存在,情侣聊天室内信息都要加密,以免第三人窥测和篡改。

小明很快想到了对称加密。

六、对称加密

对称加密:加密和解密双方使用同一个秘钥。比如这里,key = \'1234567887654321\'.encode(\'utf-8\'),这个 key 是小明和小红共同的密钥。当小明发消息时,他需要如下操作完成加密。

from Crypto.Cipher import AEScryptor = AES.new(key, AES.MODE_ECB)secret = cryptor.encrypt(plain.encode(\'utf-8\'))secret = b64encode(secret)

AES 是对称加密的一种算法,AES.MODE_ECB 是信息填充模式,完成 encrypt 加密后的信息再经由 b64encode 编码之后,发送给小红。小红收到信息之后,进行如下解码、解密操作。

secret = b64decode(secret)plain = cryptor.decrypt(secret).decode(\'utf-8\')

plain 是小明发来的明文信息。注意,两个人用同一个秘钥来加密、解密。

aes

加密问题得到解决了,可是密码怎么传递给小红呢?生活中当然可以线下传递密码,但聊天室已经有很多网友使用了,总不能要求每个想在线聊天的人,先在线下交换密码吧?

七、秘钥交换算法

秘钥交换,解决这个问题:如何在不安全网络里传递秘钥?

秘钥交换算法,实际是在双方没有共识前提下,产生一个随机秘钥的过程。小明任选两个很大的素数和一个随机数 a,然后做如下计算 A = 素数 1 ^ 随机数 mod 素数 2,计算后,将计算结果 A、素数 1 和素数 2 传递给小红。小红也选择一个随机数计算 B = 素数 1 ^ 随机数 mod 素数 2,然后计算秘钥 key 为 A ^ 随机数 b mod 素数 2,将 B 回传给小明,由小明计算秘钥 key 为 B ^随机数 a mod 素数 2。

过程啰里啰嗦,其实质其实很简单,大素数相乘容易,分解因式很难。这保证了小明和小红,虽然谁也没指定一个秘钥,只是传递了两个素数和计算结果,但最后两人都得到一个相同的秘钥,而且拿到数据的第三人,是没办法推算出 key 的。

当小明选择素数 3 和 15,同时随机数选 25,小红随机数选 7,可得计算结果如下。

print((3 ^ 25 % 15) ^ 7 % 15, (3 ^ 7 % 15) ^ 25 % 15) print(((99999971 ^ 12125) ^ 31118) % 100001059,((99999971 ^ 31118) ^ 12125) % 100001059) 

第一行是例子。第二行,我们选了比较大的素数,可以看到效果。14 14 99989040 99989040

小红和小明使用对称加密,对自己的信息进行加密保护,对称加密虽然简单易用,秘钥交换也解决了传输秘钥问题,但依然存在安全性问题。如果加密秘钥泄露的话,任何人都可以查看、修改、伪造传递的消息。小红不能确认消息是小明发出的。

需要非对称加密登场了。

八、非对称加密

非对称加密,就是加密和解密秘钥不是一个,是一对。自己持有的称为私钥,交给对方的称为公钥。

非对称加密的特点是:

  • 私钥加密后,只有公钥才能解密。
  • 公钥加密后,只有私钥才能解密。
  • 私钥可以推导出公钥,公钥无法推导出私钥。

利用以上特点,我们可以实现安全的加密算法。

类比上文秘钥交换算法时的乘法,两个大素数作为私钥,其计算结果作为公钥。

小明有一对秘钥:ming_prikey 是小明的私钥,自己稳妥存放。ming_pubkey 是小明的公钥,交给小红和其他好友存放。同时,小红也有一对秘钥:hong_prikey 是小红的私钥,密不告人。hong_pubkey 是公钥,交给小明和其他好友。

小明产生密钥对并保存为 PEM 文件时:

import rsaming_pubkey, ming_privkey = rsa.newkeys(512)with open(\'ming-pri.pem\', \'wb\')as mprif, open(\'ming-pub.pem\', \'wb\')as mpubf:    mprif.write(ming_privkey.save_pkcs1())    mpubf.write(ming_pubkey.save_pkcs1())

小红也采用如上方法,产生自己的私钥 hong_prikey 和公钥 hong_pubkey

小明发送信息给小红时,使用小红的公钥加密:secret = rsa.encrypt(plain_byte, hong_pubkey),小红使用自己的私钥,来对小明发来的信息进行解密:plain = rsa.decrypt(secret, hong_prikey).decode(\'utf-8\')

feiduichen

至此,小明和小红实现了安全的通信,他们用对方公钥加密,用自己的私钥解密发给自己的信息。

非对称加密虽好,效率却不高,只能加密很少信息。当需要加密较多内容怎么办呢?

九、数字签名

非对称加密时,通常用公钥加密,私钥解密。如果用私钥加密,其实相当与签名了。因为只有私钥持有者才能加密,且被公钥解密。所以私钥加密相当于私钥持有者确认签名——该消息来自私钥持有人。

因为非对称加密的效率,一般不对原始信息进行加密,而是对其哈希之后的值进行加密,根据上文哈希特性,这保证了原始信息唯一、未篡改。对其摘要进行私钥加密,称为数字签名。

这里,小明发送一大段信息前,首先计算其 MD5 哈希值,再对哈希值进行私钥加密(数字签名),小红收到信息后,使用小明的公钥解密,产生一个待验证哈希值,然后计算消息哈希值,如果两个哈希值能够对上,说明发送者必然是持有私钥的小明,且消息未修改。

signature = rsa.sign(plain_byte, ming_prikey, \'SHA-256\')status = rsa.verify(plain_byte, signature, ming_pubkey)

注意上例 sign 方法中签名的是小明的私钥,而检查时则使用小明的公钥。小明无法抵赖他签名的信息,因为只有他持有自己的私钥,别人无法签名(私钥加密)一个这样的信息。

sigature

同时,对传递文件进行签名可以如下;

with open(\'iloveyou.jpg\', \'rb\')as f:    signature = rsa.sign(f, ming_prikey, \'SHA-256\')

同样采用上例代码验证签名。

十、总结

本文用 70 行 Python 代码来演示常见加密技术,完成各种加密、解密、签名、防伪的功能。 小明和小红的爱情故事还在继续,未来走向我们谁都不知道。在构建聊天室过程中,我们知道了:

  • 编码的意思。
  • 了解了用于 URL 编码的 urlencode 方法和用于二进制文件文本化的 Base64 方法。
  • 哈希函数,是可以提取消息数字指纹的工具,他可以验证数据完整性、安全存储和校验密码。
  • 为了更安全使用密码,还介绍了 HMAC 加盐以及 pbkdf2 来循环哈希。
  • 对称加密简单实用。
  • 秘钥交换算法,实现了不安全网络下传递密钥。
  • 借助非对称加密,我们实现了安全通信,而数字签名使得对方无法再抵赖。

本文定位较简单,通过代码一览加密、安全梗概。大家可以动手自己敲一敲,以加深理解。

小七学习网,助您升职加薪,遇问题可联系:客服微信【1601371900】 备注:来自网站

免责声明: 1、本站信息来自网络,版权争议与本站无关 2、本站所有主题由该帖子作者发表,该帖子作者与本站享有帖子相关版权 3、其他单位或个人使用、转载或引用本文时必须同时征得该帖子作者和本站的同意 4、本帖部分内容转载自其它媒体,但并不代表本站赞同其观点和对其真实性负责 5、用户所发布的一切软件的解密分析文章仅限用于学习和研究目的;不得将上述内容用于商业或者非法用途,否则,一切后果请用户自负。 6、您必须在下载后的24个小时之内,从您的电脑中彻底删除上述内容。 7、请支持正版软件、得到更好的正版服务。 8、如有侵权请立即告知本站(邮箱:1099252741@qq.com,备用微信:1099252741),本站将及时予与删除 9、本站所发布的一切破解补丁、注册机和注册信息及软件的解密分析文章和视频仅限用于学习和研究目的;不得将上述内容用于商业或者非法用途,否则,一切后果请用户自负。本站信息来自网络,版权争议与本站无关。您必须在下载后的24个小时之内,从您的电脑中彻底删除上述内容。如果您喜欢该程序,请支持正版软件,购买注册,得到更好的正版服务。如有侵权请邮件与我们联系处理。