基于python的加密和解密
加密解密
前言
密码学的基本思想是对信息进行隐藏,使未授权的用户无法了解其真正的含义。其中包含的概念有:
(1)加密(Encryption)
将明文变换为密文的过程。把可懂的语言变换成不可懂的语言。
(2)明文(Plaintext)
加密前的原始信息。
(3)解密(Decryption)
加密的逆过程,即由密文恢复出原明文的过程。把不可懂的语言变换成可懂的语言。
(4)密文(Ciphertext)
加密后的信息。
古典加密算法主要分为:
单表替代密码:Caesar密码;
多表替代密码:Playfair密码、Hill密码、Vigenere密码;
转轮密码:著名的Enigma密码
替代算法用明文的字母由其他字母或数字或符号所代替。最著名的替代算法是恺撒密码。凯撒密码的原理很简单,其实就是单字母替换。
例子:
明文:abcdefghijklmnopq
密文:defghijklmnopqrst
使用置换移位法的最著名的一种密码称为维吉尼亚密码。它以置换移位为基础的周期替换密码。在维吉尼亚密码中,加密密钥是一个可被任意指定的字符串。加密密钥字符依次逐个作用于明文信息字符。明文信息长度往往会大于密钥字符串长度,而明文的每一个字符都需要有一个对应的密钥字符,因此密钥就需要不断循环,直至明文每一个字符都对应一个密钥字符。
矩阵换位密码
把明文中的字母按给定的顺序安排在一个矩阵中,然后用另一种顺序选择矩阵的字母产生密文。在该方案中,矩阵的行数和列数,以及给定的置换矩阵就是密钥。
现代加密算法
DES:DES是一种分组加密算法,将一个需要加密的明文分为若干个长度为64比特的数据块,逐次对每一个数据块进行加密。其中反复使用到替换和换位的方法。输入的明文为64位,密钥为56位,生成的密文为64位。DES对64位的明文分组进行操作。通过一个初始置换,将明文分组分成左半部分和右半部分,各32位长。然后进行16轮完全相同的运算。
S-DES是DES算法的简化版,并没有什么实际使用的价值,只用于教学来理解DES算法的加密方法,这篇文章就是按照S-DES的算法来实际加密和解密的一段2进制数,演示了加密的运算过程.
下面从准备知识开始:
1)先讲一下置换,举例说明,对”ABCDEFGH”做一下”82641753″置换的结果就是”HBFDAGEC”,这样就能看懂是怎么置换的了吧.
2)然后是循环移位,继续举例,”ABCDEFGH”循环左移2位结果就是”CDEFGHAB”.
3)还有个S盒的替代选择,具体到S-DES来说就是输入的四位数”ABCD”在S盒中找第AD行BC列的数字作为输出,比如0101输入S0(见下)的话就是第1(01)行第2(10)列(0-3行,0-3列),输出为1即01,再比如1001输入S0的话就是第3(11)行第0(00)列,输出为3即11.
4)最后是按位异或,举例的话1^1=0,1^0=1,0^1=1,0^0=0,1100^1010=0110。
S-DES加密解密流程图:
RSA算法:
RSA算法是由Rivest、Shamir、Adleman于1977年提出的,RSA的取名就来自于这三个发明者的姓名的第一个字母,他们在1982年创办RSA公司,该公司在公钥密码系统的研制和商业应用推广方面有非常重要的地位。
RSA密钥生成算法
(1) 选取两个大素数 p, q
(2) 计算n= p×q,Φ(n)=(p-1)×(q-1)
(3) 随机选取e: 1<e<Φ(n),与Φ(n)互素
(4) 根据欧几里德算法计算e的逆 d=e-1:
1<e<Φ(n),e×d = 1 mod Φ(n).
(5) 公钥: PK=(n, e),私钥: SK=(p, q , d).
(6) 明文空间和密文空间:
Zn={0,1,2,…,n-1}
举例:
例 设p=11, q=13。 令
n=11×13=143, Φ(n)=(p-1)(q-1)=(11-1)(13-1)=120
取公钥: PK=(n, e)=(143, 17)
计算: d=e-1=17-1=113 -------((d×e)modΦ(n)=1)
(因为: 17×113=1921=16×120+1).
私钥: SK=(p, q , d) =(11, 13, 113)
对于明文: m=24
密文: c=EPK(m)=memod(n)=2417(mod 143)=7 密文: c=7
解密: m=DSK(c)=cdmod(n)=7113(mod 143 )=24
基于python的算法实现
DES
import numpy as np """ code by bak """ class DES: # 初始置换表,长度为64 IP_table = np.array([ 58,50,42,34,26,18,10,2, 60,52,44,36,28,20,12,4, 62,54,46,38,30,22,14,6, 64,56,48,40,32,24,16,8, 57,49,41,33,25,17, 9,1, 59,51,43,35,27,19,11,3, 61,53,45,37,29,21,13,5, 63,55,47,39,31,23,15,7, ]) # 初始置换表的逆置换表,长度为64 IP_table_reverse = np.array([ 40,8,48,16,56,24,64,32, 39,7,47,15,55,23,63,31, 38,6,46,14,54,22,62,30, 37,5,45,13,53,21,61,29, 36,4,44,12,52,20,60,28, 35,3,43,11,51,19,59,27, 34,2,42,10,50,18,58,26, 33,1,41, 9,49,17,57,25, ]) # f函数中的扩展运算E置换表,长度为48 E_table = np.array([ 32, 1, 2, 3, 4, 5, 4, 5, 6, 7, 8, 9, 8, 9,10,11,12,13, 12,13,14,15,16,17, 16,17,18,19,20,21, 20,21,22,23,24,25, 24,25,26,27,28,29, 28,29,30,31,32, 1, ]) # f函数中的置换运算P置换表,长度为32 P_table = np.array([ 16, 7,20,21, 29,12,28,17, 1,15,23,26, 5,18,31,10, 2, 8,24,14, 32,27, 3, 9, 19,13,30, 6, 22,11, 4,25, ]) # 8个S盒 S_BOXS = np.array([ [ [14,4,13,1,2,15,11,8,3,10,6,12,5,9,0,7], [0,15,7,4,14,2,13,1,10,6,12,11,9,5,3,8], [4,1,14,8,13,6,2,11,15,12,9,7,3,10,5,0], [15,12,8,2,4,9,1,7,5,11,3,14,10,0,6,13], ],[ [15,1,8,14,6,11,3,4,9,7,2,13,12,0,5,10], [3,13,4,7,15,2,8,14,12,0,1,10,6,9,11,5], [0,14,7,11,10,4,13,1,5,8,12,6,9,3,2,15], [13,8,10,1,3,15,4,2,11,6,7,12,0,5,14,9], ],[ [10,0,9,14,6,3,15,5,1,13,12,7,11,4,2,8], [13,7,0,9,3,4,6,10,2,8,5,14,12,11,15,1], [13,6,4,9,8,15,3,0,11,1,2,12,5,10,14,7], [1,10,13,0,6,9,8,7,4,15,14,3,11,5,2,12], ],[ [7,13,14,3,0,6,9,10,1,2,8,5,11,12,4,15], [13,8,11,5,6,15,0,3,4,7,2,12,1,10,14,9], [10,6,9,0,12,11,7,13,15,1,3,14,5,2,8,4], [3,15,0,6,10,1,13,8,9,4,5,11,12,7,2,14], ],[ [2,12,4,1,7,10,11,6,8,5,3,15,13,0,14,9], [14,11,2,12,4,7,13,1,5,0,15,10,3,9,8,6], [4,2,1,11,10,13,7,8,15,9,12,5,6,3,0,14], [11,8,12,7,1,14,2,13,6,15,0,9,10,4,5,3], ],[ [12,1,10,15,9,2,6,8,0,13,3,4,14,7,5,11], [10,15,4,2,7,12,9,5,6,1,13,14,0,11,3,8], [9,14,15,5,2,8,12,3,7,0,4,10,1,13,11,6], [4,3,2,12,9,5,15,10,11,14,1,7,6,0,8,13], ],[ [4,11,2,14,15,0,8,13,3,12,9,7,5,10,6,1], [13,0,11,7,4,9,1,10,14,3,5,12,2,15,8,6], [1,4,11,13,12,3,7,14,10,15,6,8,0,5,9,2], [6,11,13,8,1,4,10,7,9,5,0,15,14,2,3,12], ],[ [13,2,8,4,6,15,11,1,10,9,3,14,5,0,12,7], [1,15,13,8,10,3,7,4,12,5,6,11,0,14,9,2], [7,11,4,1,9,12,14,2,0,6,10,13,15,3,5,8], [2,1,14,7,4,10,8,13,15,12,9,0,3,5,6,11], ] ]) # 子密钥生成算法中的置换选择1的置换表 substitution_table_1 = np.array([ 57,49,41,33,25,17, 9, 1,58,50,42,34,26,18, 10, 2,59,51,43,35,27, 19,11, 3,60,52,44,36, 63,55,47,39,31,23,15, 7,62,54,46,38,30,22, 14, 6,61,53,45,37,29, 21,13, 5,28,20,12, 4, ]) # 子密钥生成算法中的置换选择2的置换表 substitution_table_2 = np.array([ 14,17,11,24, 1, 5, 3,28,15, 6,21,10, 23,19,12, 4,26, 8, 16, 7,27,20,13, 2, 41,52,31,37,47,55, 30,40,51,45,33,48, 44,49,39,56,34,53, 46,42,50,36,29,32, ]) def IP(self, bit64): """ 初始置换 """ return bit64[self.IP_table-1] def IP_reverse(self, bit64): """ 初始置换的逆置换 """ return bit64[self.IP_table_reverse-1] def f(self, R, K): """ 加密函数f,参数R为右32位待加密数据,参数K为本轮48位子密钥 """ def E(bit32): """ 扩展运算,用来32位数据扩展成48位数据以便于后续步骤运算 """ return bit32[self.E_table-1] def xor(bit48_a, bit48_b): """ 逐位异或 """ return np.array([(int(bit_a != bit_b)) for (bit_a, bit_b) in zip(bit48_a, bit48_b)]) def S(bit48): """ S盒置换,将48位输入数据经过8个S盒置换得到32位数据输出 """ bit32_After_Sub = np.ndarray(shape=(32,)) for i in range(0,48, 6): # 48位数据每6位分成一组,共分成了8组 bit6 = bit48[i:i+6] # 每一组的6位数据的第1、6比特组成行号 row_index = int("".join(map(str, bit6[[0,5]])), base=2) # 每一组的6位数据的第2、3、4、5比特组成列号 col_index = int("".join(map(str, bit6[[1,2,3,4]])), base=2) # 在当前组对应的那个S盒中依据行号列号取得对应数字 num_selected = self.S_BOXS[i//6][row_index][col_index] # 将取得数字(该数字小于16)转化为4比特保存到输出结果向量 bit4 = np.array([(num_selected&(1<<i))>>i for i in range(4)]) bit4 = bit4[::-1] bit32_After_Sub[(i//6)*4:(i//6)*4+4] = bit4 # 48位输入已经转成32位输出 return bit32_After_Sub def P(bit32): """ 置换运算P,将输入32数据打乱重排得到32位数据输出 """ return bit32[self.P_table-1] # 输入32位数据经过扩展得到48位输出 bit48 = E(R) # 得到的48位结果与48位子密钥逐位异或 bit48 = xor(bit48, K) # print(f"key xor {bit48}") # 得到的48位结果送入S盒中替换得到32位输出 bit32 = S(bit48) # print(f"after S {bit32}") # 得到的32位数据经过选择重排得到32位输出 output_bit32 = P(bit32) # print(f"after P {output}") return output_bit32.astype(np.int32) def key_generator(self, init_key_bit64): """ 子密钥生成算法,依据给定64位初始密钥生成16个48位子密钥 """ # 循环左移位数表 shift_table = [1,1,2,2,2,2,2,2,1,2,2,2,2,2,2,1] # 置换选择1 bit56 = init_key_bit64[self.substitution_table_1-1] # 取得 C0, D0 C, D = bit56[:28], bit56[28:] for i in range(16): # 按照循环左移位数表取得当前应该位移的位数 shift = shift_table[i] # C和D循环左移对应位数 C = np.concatenate([C[shift:], C[:shift]]) D = np.concatenate([D[shift:], D[:shift]]) # 拼接C、D bit56 = np.concatenate([C, D]) # 置换选择2 sub_key_bit48 = bit56[self.substitution_table_2-1] # 输出 yield sub_key_bit48 def encrypt_bit64(self, data_bit64, init_key_bit64): """ 应用DES算法加密64比特数据,参数init_key_bit64为指定的64位初始密钥 """ def xor(bit32_a, bit32_b): """ 逐位异或 """ return np.array([int(bit_a != bit_b) for (bit_a, bit_b) in zip(bit32_a, bit32_b)]) # 初始置换 bit64_After_IP = self.IP(data_bit64) # print(bit64_After_IP) # 取得L0, R0 L, R = bit64_After_IP[:32], bit64_After_IP[32:] # print(f"L0 {''.join(map(str, L))}") # print(f"R0 {''.join(map(str, R))}") # 取得本轮子密钥并进行加密迭代 for i, key in enumerate(self.key_generator(init_key_bit64)): if not i==16-1: L, R = R, xor(L, self.f(R, key)) else: # 按照DES规定,最后一轮L、R不互换 R, L = R, xor(L, self.f(R, key)) # print(f"L{i+1} {L}") # print(f"R{i+1} {R}") # 拼接L、R bit64 = np.concatenate([L, R]) # 初始置换的逆置换 output = self.IP_reverse(bit64) # print(f"IP reverse {output}") # 加密完成,输出 return output def decrypt_bit64(self, data_bit64_encrypted, init_key_bit64): """ 应用DES算法解密64比特数据,参数init_key_bit64为指定的64位初始密钥 """ def xor(bit32_a, bit32_b): return np.array([int(bit_a != bit_b) for (bit_a, bit_b) in zip(bit32_a, bit32_b)]) bit64_After_IP = self.IP(data_bit64_encrypted) # print(bit64_After_IP) L, R = bit64_After_IP[:32], bit64_After_IP[32:] # print(f"L0 {''.join(map(str, L))}") # print(f"R0 {''.join(map(str, R))}") # DES的解密相对于加密来说唯一的区别就是子密钥生成的顺序倒过来了 for i, key in enumerate(list(self.key_generator(init_key_bit64))[::-1]): if not i==16-1: L, R = R, xor(L, self.f(R, key)) else: R, L = R, xor(L, self.f(R, key)) # print(f"L{i+1} {L}") # print(f"R{i+1} {R}") bit64 = np.concatenate([L, R]) output = self.IP_reverse(bit64) # print(f"IP reverse {output}") return output if __name__ == "__main__": data_bit64 = np.array(list(map(int, "00110000 00110001 00110010 00110011 00110100 00110101 00110110 00110111".replace(" ", "")))) key_bit64 = np.array(list(map(int, "00110001 00110010 00110011 00110100 00110101 00110110 00110111 00111000".replace(" ", "")))) des = DES() data_bit64_encrypted = des.encrypt_bit64(data_bit64, key_bit64) print(data_bit64_encrypted) data_bit64_decrypted = des.decrypt_bit64(data_bit64_encrypted, key_bit64) print(data_bit64_decrypted)
AES
from Cryptodome.Cipher import AES from Cryptodome import Random from binascii import a2b_hex # 要加密的明文 data = '南来北往' # 密钥key必须为 16(AES-128), 24(AES-192), 32(AES-256) key = b'this is a 16 key' # 生成长度等于AES 块大小的不可重复的密钥向量 iv = Random.new().read(AES.block_size) print(iv) # 使用 key 和iv 初始化AES 对象, 使用MODE_CFB模式 mycipher = AES.new(key, AES.MODE_CFB, iv) print(mycipher) # 加密的明文长度必须为16的倍数, 如果长度不为16的倍数, 则需要补足为16的倍数 # 将iv(密钥向量)加到加密的密钥开头, 一起传输 ciptext = iv + mycipher.encrypt(data.encode()) # 解密的话需要用key 和iv 生成的AES对象 print(ciptext) mydecrypt = AES.new(key, AES.MODE_CFB, ciptext[:16]) # 使用新生成的AES 对象, 将加密的密钥解密 decrytext = mydecrypt.decrypt(ciptext[16:]) print(decrytext.decode())
RSA
# -*- coding:UTF-8 -*- import rsa # rsa加密 def rsaEncrypt(str): # 生成公钥、私钥 (pubkey, privkey) = rsa.newkeys(512) print("pub: ", pubkey) print("priv: ", privkey) # 明文编码格式 content = str.encode('utf-8') # 公钥加密 crypto = rsa.encrypt(content, pubkey) return (crypto, privkey) # rsa解密 def rsaDecrypt(str, pk): # 私钥解密 content = rsa.decrypt(str, pk) con = content.decode('utf-8') return con (a, b) = rsaEncrypt("hello") print('加密后密文:') print(a) content = rsaDecrypt(a, b) print('解密后明文:') print(content) # -*- coding:UTF-8 -*- __author__ = 'rxz' import rsa import binascii def rsa_encrypt(rsa_n, rsa_e, message): key = rsa.PublicKey(rsa_n, rsa_e) message = rsa.encrypt(message.encode(), key) message = binascii.b2a_hex(message) return message.decode() pubkey_n = '8d7e6949d411ce14d7d233d7160f5b2cc753930caba4d5ad24f923a505253b9c39b09a059732250e56c594d735077cfcb0c3508e9f544f101bdf7e97fe1b0d97f273468264b8b24caaa2a90cd9708a417c51cf8ba35444d37c514a0490441a773ccb121034f29748763c6c4f76eb0303559c57071fd89234d140c8bb965f9725' pubkey_e = '10001' rsa_n = int(pubkey_n, 16) rsa_e = int(pubkey_e, 16) message = '南北今天很忙' print("公钥n值长度:", len(pubkey_n)) aa = rsa_encrypt(rsa_n, rsa_e, message) print(aa) # -*- coding:UTF-8 -*- ''' RSA算法 ''' from Cryptodome.PublicKey import RSA from Cryptodome.Cipher import PKCS1_OAEP, PKCS1_v1_5 class MyRSA(): def create_rsa_key(self, password): """ 创建RSA密钥 步骤说明: 1、从 Crypto.PublicKey 包中导入 RSA,创建一个密码 2、生成 1024/2048 位的 RSA 密钥 3、调用 RSA 密钥实例的 exportKey 方法,传入密码、使用的 PKCS 标准以及加密方案这三个参数。 4、将私钥写入磁盘的文件。 5、使用方法链调用 publickey 和 exportKey 方法生成公钥,写入磁盘上的文件。 """ key = RSA.generate(1024) encrypted_key = key.exportKey(passphrase=password.encode("utf-8"), pkcs=8, protection="scryptAndAES128-CBC") with open("my_private_rsa_key.bin", "wb") as f: f.write(encrypted_key) with open("my_rsa_public.pem", "wb") as f: f.write(key.publickey().exportKey()) def encrypt(self, plaintext): # 加载公钥 recipient_key = RSA.import_key( open("my_rsa_public.pem").read() ) cipher_rsa = PKCS1_v1_5.new(recipient_key) en_data = cipher_rsa.encrypt(plaintext.encode("utf-8")) return en_data # print(len(en_data), en_data) def decrypt(self, en_data, password): # 读取密钥 private_key = RSA.import_key( open("my_private_rsa_key.bin").read(), passphrase=password ) cipher_rsa = PKCS1_v1_5.new(private_key) data = cipher_rsa.decrypt(en_data, None) return data # print(data) mrsa = MyRSA() mrsa.create_rsa_key('123456') e = mrsa.encrypt('hello') d = mrsa.decrypt(e, '123456') print(e) print(d)
凯撒加密
def kaisa(m):#加密函数 if m==" ": return ' ' elif 97<=ord(m)<123-key or 65<=ord(m)<91-key:#位移值不超过最后一个z字母 m=chr(ord(m)+key) return m elif ord(m)>=123-key or 91-key<=ord(m)<91: m=chr(ord(m)+key-26) return m out='' #求解算法 while 1: plaintext=input('请输入明文:') if plaintext=='退出': break key=eval(input('请输入位移值:')) for i in list(map(kaisa,plaintext)): out+=i print('加密结果为:',out)
凯撒解密
#凯撒解密 def jiema(m): for i in m: if i ==' ': return " " elif 97+key<=ord(m)<123 or 65+key<=ord(m)<92: m=chr(ord(m)-key) return m elif 97<=ord(m)<97+key or 65<=ord(m)<65+key: m=chr(ord(m)-key+26) return m m=input('请输入密文:') out='' for key in range(1,27): for n in list(map(jiema,m)): out = out + str(n) print('第%d个可能的结果是%s'%(key,out)) out=''