加解密的問題


 本文抄自,author 小明 2019-07-16

前言:

傳輸中控制:

在生成中,密碼或者重要的信息保密是非常重要的,如何對重要的信息進行加密防止網絡數據傳輸面臨的威脅,網絡安全涉及很多方面,而網絡數據的安全傳輸通常會面臨以下幾方面的威脅:

數據竊聽與機密性: 即怎樣保證數據不會因爲被截獲或竊聽而暴露。

數據篡改與完整性: 即怎樣保證數據不會被惡意篡改。

身份冒充與身份驗證: 即怎樣保證數據交互雙方的身份沒有被冒充。

相應的解決方案

針對以上幾個問題,可以用以下幾種數據加密方式來解決(每種數據加密方式又有多種不同的算法實現):

數據加密方式

描述

主要解決的問題

常用算法

對稱加密

指數據加密和解密使用相同的密鑰

數據的機密性

DES, AES

非對稱加密

也叫公鑰加密,指數據加密和解密使用不同的密鑰--密鑰對兒

身份驗證

DSA,RSA

單向加密

指只能加密數據,而不能解密數據

數據的完整性

MD5,SHA系列算法

相關名詞解釋:

  • HASH: 一般翻譯爲“散列”(也有直接音譯爲“哈希”),就是把任意長度的輸入(又叫做預映射,pre-image),通過散列算法,變成固定長度的輸出,該輸出值就是散列值。這種轉換是一種壓縮映射,也就是散列值的空間通常遠小於輸入的空間,不同的輸入可能會散列成相同的輸出,而不可能從散列值來唯一確認輸入值。簡單來說,hash算法就是一種將任意長度的消息壓縮爲某一固定長度的消息摘要的函數。

 

  • MD5: 全稱爲 Message Digest algorithm 5,即信息摘要算法。該算法可以生成定長的數據指紋,被廣泛應用於加密和解密技術,常用於文件和數據的完整性校驗。

 

  • SHA: 全稱爲 Secure Hash Algorithm,即安全散列算法/安全哈希算法。該算法是數字簽名等密碼學應用中的重要工具,被廣泛應用於電子商務等信息安全領域。根據生成的密文的長度而命名的各種具體的算法有:SHA1(160bits)、SHA224(224bits)、SHA256(256bits)、SHA384(384bits)等。

 

  • HMAC: 全稱爲 Hash Message Authentication Code,即散列消息鑑別碼。HMAC是基於密鑰的哈希算法認證協議,主要是利用哈希算法(如MD5, SHA1),以一個密鑰和一個消息作爲輸入,生成一個消息摘要作爲輸出,因此其具體的算法名稱爲HMAC-MD5、HMAC-SHA1等。可見HMAC算法是基於各種哈希算法的,只是它在運算過程中還可以使用一個密鑰來增強安全性。

Python內置模塊簡介

Python早期的相關模塊這裏不再介紹了,我們今天主要說明的是以下幾個模塊:

模塊名

內置模塊

描述

hashlib

Y

主要提供了一些常見的單向加密算法(如MD5,SHA等),每種算法都提供了與其同名的函數實現。

hmac

Y

提供了hmac算法的實現,hamc也是單向加密算法,但是它支持設置一個額外的密鑰(通常被稱爲'salt')來提高安全性

random

Y

該模塊主要用於一些隨機操作,如獲取一個隨機數,從一個可迭代對象中隨機獲取指定個數的元素。

secrets

Y

這是Python 3.6中新增的模塊,用於獲取安全隨機數。

base64

Y

該模塊主要用於二進制數據與可打印ASCII字符之間的轉換操作,它提供了基於Base16, Base32, 和Base64算法以及實際標準Ascii85和Base85的編碼和解碼函數。

pycrypto

N

支持單向加密、對稱加密和公鑰加密以及隨機數操作,這是個第三方模塊,需要額外安裝。

 

本編主要針對內置模塊hashlib和第三方模塊pycrypto展開分析

hashlib模塊:

hashlib模塊包含的函數與屬性:

函數名/屬性名

描述

hashlib.new(name[, data])

這是一個通用的哈希對象構造函數,用於構造指定的哈希算法所對應的哈希對象。其中name參數用於指定哈希算法名稱,如'md5', 'sha1',不區分大小寫;data是一個可選參數,表示初始數據。

hashlib.哈希算法名稱()

這是一個hashlib.new()的替換方式,可以直接通過具體的哈希算法名稱對應的函數來獲取哈希對象,如 hashlib.md5(),hashlib.sha1()等。

hashlib.algorithms_guaranteed

Python 3.2新增的屬性,它的值是一個該模塊在所有平臺都會支持的哈希算法的名稱集合:set(['sha1', 'sha224', 'sha384', 'sha256', 'sha512', 'md5'])

hashlib.algorithms_available

Python 3.2新增的屬性,它的值是是一個當前運行的Python解釋器中可用的哈希算法的名稱集合,algorithms_guaranteed將永遠是它的子集。

hash對象包含的方法與屬性:

函數名/屬性名

描述

hash.update(data)

更新哈希對象所要計算的數據,多次調用爲累加效果,如m.update(a); m.update(b)等價於m.update(a+b)

hash.digest()

返回傳遞給update()函數的所有數據的摘要信息--二進制格式的字符串

hash.hexdigest()

返回傳遞給update()函數的所有數據的摘要信息--十六進制格式的字符串

hash.copy()

返回該哈希對象的一個copy("clone"),這個函數可以用來有效的計算共享一個公共初始子串的數據的摘要信息。

hash.digest_size

hash結果的字節大小,即hash.digest()方法返回結果的字符串長度。這個屬性的值對於一個哈希對象來說是固定的,md5:16,sha1(20), sha224(28)

hash.block_size

hash算法內部塊的字節大小

hash.name

當前hash對象對應的哈希算法的標準名稱--小寫形式,可以直接傳遞給hashlib.new()函數來創建另外一個同類型的哈希對象。

hashlib模塊使用步驟:

1)獲取一個哈希算法對應的哈希對象(比如名稱爲hash): 可以通過 hashlib.new(哈希算法名稱, 初始出入信息)函數,來獲取這個哈希對象,如hashlib.new('MD5', 'Hello'),hashlib.new('SHA1', 'Hello')等;也可以通過hashlib.哈希算法名稱()來獲取這個哈希對象,如hashlib.md5(), hashlib.sha1()等。

2)設置/追加輸入信息: 調用已得到哈希對象的update(輸入信息)方法可以設置或追加輸入信息,多次調用該方法,等價於把每次傳遞的參數憑藉後進行作爲一個參數墊底給update()方法。也就是說,多次調用是累加,而不是覆蓋。

3)獲取輸入信息對應的摘要: 調用已得到的哈希對象的digest()方法或hexdigest()方法即可得到傳遞給update()方法的字符串參數的摘要信息。digest()方法返回的摘要信息是一個二進制格式的字符串,其中可能包含非ASCII字符,包括NUL字節,該字符串長度可以通過哈希對象的digest_size屬性獲取;而hexdigest()方法返回的摘要信息是一個16進制格式的字符串,該字符串中只包含16進制的數字,且長度是digest()返回結果長度的2倍,這可用郵件的安全交互或其它非二進制的環境中。

hashlib模塊使用實例:

我們以MD5算法爲例獲取字符串"Hello, World"的摘要信息(也叫數據指紋)

import hashlib

hash  = hashlib.md5()

hash.update('Hello, ')

hash.update('World!')

ret1 = hash.digest()

print(type(ret1), len(ret1), ret1)

ret2 = hash.hexdigest()

print(type(ret2), len(ret2), ret2)

輸出結果:

(<type 'str'>, 16, 'e\xa8\xe2}\x88y(81\xb6d\xbd\x8b\x7f\n\xd4')

(<type 'str'>, 32, '65a8e27d8879283831b664bd8b7f0ad4')

分析:

  1. digest()方法返回的結果是一個二進制格式的字符串,字符串中的每個元素是一個字節,我們知道1個字節是8bits,MD5算法獲取的數據摘要長度是128bits,因此最後得到的字符串長度是128/8=16;
  2. hexdigest()方法返回的結果是一個16進制格式的字符串,字符串中每個元素是一個16進制數字,我們知道每個16進制數字佔4bits,MD5算法獲取的數據摘要長度是128bits,因此最後得到的字符串長度是128/4=32。

在實際工作中,我們通常都是獲取數據指紋的16進制格式,比如我們在數據庫中存放用戶密碼時,不是明文存放的,而是存放密碼的16進制格式的摘要信息。當用戶發起登錄請求時,我們按照相同的哈希算法獲取用戶發送的密碼的摘要信息,與數據中存放的與該賬號對應的密碼摘要信息做比對,兩者一致則驗證成功。

Pycrypto模塊:

pycrypto的安裝與使用

pycrypto的安裝

使用

pip install pycryptodome

安裝這個庫就可以了。

然後進入這個庫的目錄:Lib\site-packages

找到 crypto 這個庫,更改爲首字母大寫 Crypto 即可

pycrypto的使用方式

由於pycrypto把不同的類別加密算法的實現模塊都放到了Crypto下不同的子包下了,所以我們只需要確定我們所需要使用的加密算法的實現模塊在哪個子包下,然後導入相應的實現模塊就可以使用了。比如我們打算使用MD5算法,就可以通過from Crypto.Hash import MD5來導入MD5這個模塊,然後就可以使用該模塊相應的api了。

pycrypto使用實例1--- SHA256

實例1 使用SHA256算法獲取一段數據的摘要信息

from Crypto.Hash import SHA256

hash = SHA256.new()

hash.update('Hello, World!')

digest = hash.hexdigest()

print(digest)

輸出結果:

dffd6021bb2bd5b0af676290809ec3a53191dd81c7f70a4b28688a362182986f

實例2 使用AES算法加密,解密一段數據

from Crypto.Cipher import AES

 

# 加密與解密所使用的密鑰,長度必須是16的倍數

secret_key = "ThisIs SecretKey"

# 要加密的明文數據,長度必須是16的倍數

plain_data = "Hello, World123!"

# IV參數,長度必須是16的倍數

iv_param = 'This is an IV456'

 

# 數據加密

aes1 = AES.new(secret_key, AES.MODE_CBC, iv_param)

cipher_data = aes1.encrypt(plain_data)

print('cipher data:', cipher_data)

 

# 數據解密

aes2 = AES.new(secret_key, AES.MODE_CBC, 'This is an IV456')

plain_data2 = aes2.decrypt(cipher_data)  # 解密後的明文數據

print('plain text:', plain_data2)

輸出結果:

('cipher data\xef\xbc\x9a', '\xcb\x7fd\x03\x12T,\xbe\x91\xac\x1a\xd5\xaa\xe6P\x9a')

('plain text\xef\xbc\x9a', 'Hello, World123!')

pycrypto使用實例1--- AES

AES簡介

高級加密標準(AES,Advanced Encryption Standard)爲最常見的對稱加密算法(微信小程序加密傳輸就是用這個加密算法的)。對稱加密算法也就是加密和解密用相同的密鑰,具體的加密流程如下圖:

 

下面看下編碼實例:

  1 #!/usr/bin/env python3
  2 
  3 # -*- coding: utf-8 -*-
  4 
  5 # Author: xiaoming
  6 
  7 # @Time :2019/7/3 15:12
  8 
  9 # 這裏使用pycrypto‎demo庫
 10 
 11 # 安裝方法 pip install pycrypto‎demo
 12 
 13  
 14 
 15 from Crypto.Cipher import AES
 16 
 17 from binascii import b2a_hex, a2b_hex
 18 
 19 """
 20 
 21 這裏使用的是第三方庫pycrypto來實現對敏感數據的加解密
 22 
 23 主要用到ES.new(self.key, self.mode, b'0000000000000000'),
 24 
 25 三個參數key是祕鑰,AES.MODE_CBC加密方式,b'0000000000000000'是IV常常用key來代替也可以
 26 
 27 self.key和self.IV必須是16位的倍數, cryptor.encrypt(text)text機密的數據也是16位的倍數
 28 
 29 這裏主要功能實現機密數據的自動補全16位的倍數,進行加解密
 30 
 31 使用過程提示TypeError: Object type <class 'str'> cannot be passed to C code
 32 
 33 解決辦法:經過Debug發現,是因爲傳入參數的參數類型存在問題,需要更換爲 bytearray"""
 34 
 35  
 36 
 37 class PrpCrypt(object):
 38 
 39  
 40 
 41     def __init__(self, key):
 42 
 43         self.key = key.encode('utf-8')
 44 
 45         self.mode = AES.MODE_CBC
 46 
 47  
 48 
 49     # 加密函數,如果text不足16位就用空格補足爲16位,
 50 
 51     # 如果大於16當時不是16的倍數,那就補足爲16的倍數。
 52 
 53     def encrypt(self, text):
 54 
 55         text = text.encode('utf-8')
 56 
 57         cryptor = AES.new(self.key, self.mode, b'0000000000000000')
 58 
 59         # 這裏密鑰key 長度必須爲16(AES-128),
 60 
 61         # 24(AES-192),或者32 (AES-256)Bytes 長度
 62 
 63         # 目前AES-128 足夠目前使用
 64 
 65         length = 16
 66 
 67         count = len(text)
 68 
 69         if count < length:
 70 
 71             add = (length - count)
 72 
 73             # \0 backspace
 74 
 75             # text = text + ('\0' * add)
 76 
 77             text = text + ('\0' * add).encode('utf-8')
 78 
 79         elif count > length:
 80 
 81             add = (length - (count % length))
 82 
 83             # text = text + ('\0' * add)
 84 
 85             text = text + ('\0' * add).encode('utf-8')
 86 
 87         self.ciphertext = cryptor.encrypt(text)
 88 
 89         # 因爲AES加密時候得到的字符串不一定是ascii字符集的,輸出到終端或者保存時候可能存在問題
 90 
 91         # 所以這裏統一把加密後的字符串轉化爲16進制字符串
 92 
 93         return b2a_hex(self.ciphertext)
 94 
 95  
 96 
 97     # 解密後,去掉補足的空格用strip() 去掉
 98 
 99     def decrypt(self, text):
100 
101         cryptor = AES.new(self.key, self.mode, b'0000000000000000')
102 
103         plain_text = cryptor.decrypt(a2b_hex(text))
104 
105         # return plain_text.rstrip('\0')
106 
107         return bytes.decode(plain_text).rstrip('\0')
108 
109  
110 
111  
112 
113 if __name__ == '__main__':
114 
115     pc = PrpCrypt('keyskeyskeyskeys')  # 初始化密鑰
116 
117     e = pc.encrypt("testtesttest")  # 加密
118 
119     d = pc.decrypt(e)  # 解密
120 
121     print("加密:", e)
122 
123     print("解密:", d)
AES加解密使用

 

打印結果是:

"D:\Program Files\Python36\python.exe" D:/PycharmProjects/test01/chapter01/test.py

加密: b'13634ced6377d8837e763fc8b0e7a76a'

解密: testtesttest

總結

上面講了很多內容,現在我們簡單總結下:

 

  • 數據加密方式大體分爲3類:單向加密、對稱加密 和 公鑰加密(非對稱加密)。
  • 這3類加密方式都各自包含不同的加密算法,如單向加密方式中包含MD5、SHA1、SHA256等,這些算法又稱爲“哈希算法”或“散列算法”或“數據摘要算法”
  • Python內置的hashlib和hmac只提供了單向加密的各種算法實現,如果要做對稱加密或者公鑰加密操作需要安裝第三方擴展模塊,常用的是pycrypto模塊。另外,hmac允許在使用哈希算法計算數據摘要時使用一個密鑰。
  • 隨機數操作可以通過三個模塊來做,Python內置的random模塊和secrets模塊(Python 3.6中才可用),還可以通過pycrypto模塊中的Crypto.Random子包中的模塊來完成。
  • base64只適合編碼小段數據,且不能用於數據加密(算法是公開的,且沒有密鑰,所有人都可以解碼)
  • pycrypto是一個加密算法庫,幾乎所有的加密算法都可以在它裏面找到相應的實現模塊。

參考網址:

https://www.cnblogs.com/yyds/p/7072492.html

https://blog.csdn.net/qq_28205153/article/details/55798628

需求定義:

密碼管理系統

需求:

密碼明文顯示不安全,密碼明文傳輸不安全, 密碼複雜記不住

設計統一的平臺管理所有加密後的密碼,指定管理員權限,對訪問批准授權,和併發訪問用戶的策略

詳細代碼設計:

採用的加密算法: 存儲採用pycrypto對稱加密, 傳輸採用sha256單項加密

參考網址:https://www.manageengine.cn/products/passwordmanagerpro/features.html

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章