Loading

python 加密 解密 签名 验证签名 公钥 私钥 非对称加密 RSA

加密与解密,这很重要,我们已经可以用pypcap+npcap简单嗅探到网络中的数据包了。而这个工具其实可以嗅探到更多的数据。
如果我们和别人之间传输的数据被别人嗅探到,那么信息泄漏,信息被篡改,将给我们造成比较大的困扰。
别以为这是什么高深的知识。
其实已经深入到我们经常使用的一些网站了。
尝试访问一下百度,用标准的浏览器地址‘http://www.baidu.com’。你会发现它自动跳转到了‘https://www.baidu.com’。
虽然我要求使用http协议访问,但是百度已经全面支持HTPS加密浏览模式。
还有我们做的密钥登录linux,不用输入密码。也是使用了加密技术。
简单介绍一下密码加密学的发展。纯个人理解,没专门学过。

一:明文替换加密。
这个就简单了。
假设我们要发送‘hello word’,中途被截获的时候不希望监听的人知道是什么。
简单做个密码表:
1234567890
abcdefghij
就是相互替换,很多电影找密码表,就是这个东西。

# 定义替换密码表
tabA = "abcdefghij"
tabB = "1234567890"
# 加密表
trant_en = str.maketrans(tabA, tabB)
# 解密表
trant_de = str.maketrans(tabB, tabA)

# 使用translate,来进行密码替换。
str = "hello word"

# 加密
encryption = str.translate(trant_en)  # 结果是85llo wor4
print(encryption)

# 解密
decrypt = encryption.translate(trant_de)
print(decrypt)

 



二:换位加密。
最简单的换位加密(前后倒序):

#倒序排列字符串
def msg_reverse(msg):
    msg_list = list(msg)
    msg_list.reverse()
    msg_en = ''.join(msg_list)
    return msg_en

message='hello jack'
print('信息是:',message)
#加密(倒序)
en_reverse = msg_reverse(message)
print('加密后:',en_reverse)
#解密(还是倒序)
de_reverse = msg_reverse(en_reverse)
print('解密后:',de_reverse)

 




高级一点的换位加密:
这个加密和解密使用的是不同的方法,但是原理是一样的。
只有一个加密参数,就是key,或称为位数。
加密时:
根据key值,把字符串分为key个值的列表。
把message逐位写入列表:
如:message:abcdef  key:2
写为 ['ace','bdf']
如:message:abcdef  key:3
写为 ['ad', 'be', 'cf']
就是说key分字符串,和打牌发牌差不多,把牌按顺序发给key个牌手。
再把列表拼合为字符串,即视为加密。
解密时:
首先根据字符串长度和key值,把字符串分解为列表1,即加密时,最后拼接前的字符串。
如:adbecf key:3
['ad', 'be', 'cf']
如:adbecf key:2
['ace', 'bdf']
根据列表中字符串的长度(字符串长度除以key值,可以算出来,不用去len),创建列表2.
如:adbecf key:3
['ad', 'be', 'cf']
列表2:['abc', 'def']
如:adbecf key:2
['ace', 'bdf']
列表2:['ab', 'cd', 'ef']
就是说牌手按顺序出牌。每一圈是列表2的一项。
最后再拼接列表2.
正好是原来的顺序。

'''
仅简单实现分组换位加密。
key长度必须是message长度的约数。
也就是说字符串长度能除尽key值
字符串长12,key可以为 2,3,4,6,
约数,初中数学。
cell函数是一个补齐函数。
如果不是约数,大于message长度的第一个倍数,在message后面补*
那么需要在解密时,再传入一个message长度的参数。
也不准备用换位加密。
写到这里可以了。
'''
import math


def cell(msg, key):
    # 根据msg长度和key位数来补齐msg
    Multiple = len(msg) / key
    print(Multiple)
    Multiple = math.ceil(Multiple)
    print(Multiple)
    return msg.ljust(key * Multiple, '*')


# 加密函数
def encryption(msg, key):
    # 根据位数创建一个空列表,有key项
    result = [""] * key
    print(result)
    for i in range(key):  # 把每一列元素按照顺序相加组成新的字符序列
        print('加密,分%i行,这是第%i行' % (key, i))
        j = i
        while j < len(msg):
            print(i, j)
            result[i] = result[i] + msg[j]
            j = j + key
    print(result)
    return ''.join(result)


# 解密函数
def decryption(msg, key):
        print('解密')
        res = [""] * key
        count = len(msg) // key
        result = [''] * count
        print(result)
        print(count)
        for i in range(key):
                res[i] = msg[i * count:(i + 1) * count]
                print(res[i])
                for j in range(count):
                        result[j] = result[j] + res[i][j]
        print(result)
        return ''.join(result)


def main():
    en_msg = encryption("abcdef", 3)  # 以4个字母为一行进行换位加密
    print(en_msg)
    de_msg = decryption(en_msg, 3)
    print(de_msg)


if __name__ == "__main__":
    main()
View Code

 


三:非对称加密:
前面所示的都是对称加密,也就是说知道怎么加密,就知道怎么解密。
1976年,美国学者Dime和Henman为解决信息公开传送和密钥管理问题,提出一种新的密钥交换协议,允许在不安全的媒体上的通讯双方交换信息,安全地达成一致的密钥,这就是“公开密钥系统”。
与对称加密算法不同,非对称加密算法需要两个密钥:公开密钥(publickey)和私有密钥(privatekey)。公开密钥与私有密钥是一对,如果用公开密钥对数据进行加密,只有用对应的私有密钥才能解密;如果用私有密钥对数据进行加密,那么只有用对应的公开密钥才能解密。因为加密和解密使用的是两个不同的密钥,所以这种算法叫作非对称加密算法。
我们用在免密码登录linux,使用的就是这种加密方法。在服务器配置了公钥,登录时配置私钥。具体的登录流程,就不明白了。


四:数字签名:

数字签名(又称公钥数字签名、电子签章)是一种类似写在纸上的普通的物理签名,但是使用了公钥加密领域的技术实现,用于鉴别数字信息的方法。一套数字签名通常定义两种互补的运算,一个用于签名,另一个用于验证。
数字签名,就是只有信息的发送者才能产生的别人无法伪造的一段数字串,这段数字串同时也是对信息的发送者发送信息真实性的一个有效证明。
数字签名是非对称密钥加密技术与数字摘要技术的应用。
保证信息传输的完整性、发送者的身份认证、防止交易中的抵赖发生。
数字签名技术是将摘要信息用发送者的私钥加密,与原文一起传送给接收者。接收者只有用发送者的公钥才能解密被加密的摘要信息,然后用HASH函数对收到的原文产生一个摘要信息,与解密的摘要信息对比。如果相同,则说明收到的信息是完整的,在传输过程中没有被修改,否则说明信息被修改过,因此数字签名能够验证信息的完整性。
数字签名是个加密的过程,数字签名验证是个解密的过程。

五:使用非对称加密技术

import rsa

# 生成密钥
(pubkey, privkey) = rsa.newkeys(1024)

# 保存密钥
with open('public.pem', 'w+') as f:
    f.write(pubkey.save_pkcs1().decode())

with open('private.pem', 'w+') as f:
    f.write(privkey.save_pkcs1().decode())

# 导入密钥
with open('public.pem', 'r') as f:
    pubkey = rsa.PublicKey.load_pkcs1(f.read().encode())

with open('private.pem', 'r') as f:
    privkey = rsa.PrivateKey.load_pkcs1(f.read().encode())

# 明文
message = 'hello'
print(message)

# 公钥加密
crypto = rsa.encrypt(message.encode(), pubkey)
print('pub encode',crypto)

# 私钥解密
message = rsa.decrypt(crypto, privkey).decode()
print('pri decode',message)

# 私钥签名
signature = rsa.sign(message.encode(), privkey, 'SHA-1')
print('sign',signature)

# 公钥验证
verify=rsa.verify(message.encode(), signature, pubkey)
print('verify ',verify)

六:实际使用方法。

这个貌似用起来可没那么轻松了。

web B/S技术,貌似是使用https方式。使用了某些认证的证书中心的证书做了认证。客户端浏览器,都有信任这些证书。

有趣的是12306,貌似为了省几个钱,自己做的证书,就像我上面的代码一样。自己的证书,浏览器默认不信任,它就让你导入一个什么证书。

对我们python日常编程,什么地方用呢?

C/S模式下,不管你是什么样的客户端,和服务器沟通的时候,就可以加密,在服务器解密,在服务器加密,在客户端解密。

还可以互相发送签名的数据。再进行验证。

貌似需要4套数字证书。

 

序号 公钥位置 私钥位置 加密内容 加密加签位置 解密验签位置
1 服务器 客户端 服务器加密发给客户段数据 服务器 客户端
2 客户端 服务器 加密客户端上传数据 客户端 服务器
3 服务器 客户端 签名服务器发给客户端数据 服务器 客户端
4 客户端 服务器 验证客户端上传数据 客户端 服务器

好吧,这样够不够安全呢?

反正我的django+RESTful API,准备加上这部分内容。

效率么,再考虑吧。也许只加密解密,也许只签名验证签名,也许加密加签名,解密加验证签名。

 

posted @ 2018-02-11 14:26  上官飞鸿  阅读(1727)  评论(0编辑  收藏  举报