我的目标是用python 3.x建立简单的加密系统,所以我在这个周末搜索了网页,获取有关RSA / AES等方面的信息。实际上,看起来有可能加密文本数据以便以合理的安全方式传输的东西。没有偏执狂,我也不是专家,我只是想确保没有钥匙就很难读懂这些东西!
老实说,我对密码学不太了解。经过几个小时的搜索和收集信息和源代码,由于Python 2.7中提供的示例,我的尝试失败了,原因是无效的长度问题或其他转换错误。我在python 3中发现了很少的例子,使用的加密方法似乎并不合适,也不太合适。
我终于能够运行以下代码,接受ISO 8859-1编码字符。我实际上封装了所有的UTF-8编码,以避免语言问题。希望如此..。
我想知道我是否在正确的设计道路上,尤其是如果数据安全是可以接受的,再次我不是在寻找伟大的安全解决方案,只是想保护我自己的个人数据,而不是保护一个军事防御机密洛尔!
请随时转发给我你的意见或建议,特别是那些我可能错过的东西!
非常感谢。
Emmanuel (法国)
注意:下一步,我将尝试将RSA加密的AES密码与文本流一起发送给收件人。由于每个消息的AES密码不同,客户端需要自动翻译它,以便能够对密码消息进行解码。AES密码将在RSA非对称加密中进行传输,并在没有性能崩溃的情况下使用最强大的密钥。其目的是在合理的时间框架内传输简单消息( w/o base64编码)或大量数据。
@+再见。
要执行下面的代码,应该安装PyCrypto (python3.2)
import os, base64, hashlib
from Crypto.Cipher import AES
class Aes(object):
# Crypte / décrypte un texte donné en AES mode CBC. Accepte l'encodage base64.
# Encrypts input text string & decrypts bytes encoded string with or without base64 encoding
# Author: emmanuel.brunet@live.fr - 12/2013
SALT_LENGTH = 64
DERIVATION_ROUNDS=10000
BLOCK_SIZE = 16
KEY_SIZE = 256
MODE = AES.MODE_CBC
def encrypt(self, source, aes_key, outfile=None, base64_encode=False):
'''
Crypte l'entrée source en AES mode CBC avec sortie encodage base64 / fichier facultative
@param str source: text to encode or text file path
@param bytes aes_key: password
@parm str outfile: disk file to write encoded text to. defaults to None
@param bool base64_encode: returns base64 encoded string if True (for emails) or bytes if False
@return bytes ciphertext: the bytes encoded string.
'''
'''
----------------------------
Inputs management
----------------------------
'''
if os.path.exists(source):
fp = open(source, 'rb')
input_text = fp.read()
fp.close()
else:
input_text = bytes(source, 'UTF-8')
if input_text == b'':
print('No data to encrypt')
return
padding_len = 16 - (len(input_text) % 16)
padded_text = str(input_text, 'UTF-8') + chr(padding_len) * padding_len
'''
---------------------------------------------------------
Computes the derived key (derived_key).
---------------------------------------------------------
Elle permet d'utiliser la clé initiale (aes_key) plusieurs
fois, une pour chaque bloc à encrypter.
---------------------------------------------------------
'''
salt = os.urandom(self.SALT_LENGTH)
derived_key = bytes(aes_key, 'UTF-8')
for unused in range(0,self.DERIVATION_ROUNDS):
derived_key = hashlib.sha256(derived_key + salt).digest()
derived_key = derived_key[:self.KEY_SIZE]
'''
----------------
Encrypt
----------------
'''
# The initialization vector should be random
iv = os.urandom(self.BLOCK_SIZE)
cipherSpec = AES.new(derived_key, self.MODE, iv)
cipher_text = cipherSpec.encrypt(padded_text)
cipher_text = cipher_text + iv + salt
'''
-------------------------
Output management
-------------------------
'''
if outfile is None:
'''
Returns cipher in base64 encoding. Useful for email management for instance
'''
if base64_encode:
return(base64.b64encode(cipher_text))
else:
return(cipher_text)
else:
'''
Writes result to disk
'''
fp = open(outfile, 'w')
if base64_encode:
fp.write(base64.b64encode(cipher_text))
else:
fp.write(cipher_text)
fp.close()
print('Cipher text saved in', outfile)
def decrypt(self, source, aes_key, outfile=None, base64_encode=False):
'''
Decrypts encoded string or data file
@param bytes or str source: encrypted bytes string to decode or file path
@param bytes aes_key: password
@parm str outfile: disk file to write encoded text to. defaults to None
@param bool base64_encode: cipher text is given base64 encoded (for mails content for examples)
@returns str secret_text: the decoding text string or None if invalid key given
'''
'''
---------------------------
Input management
---------------------------
'''
if type(source) == str and os.path.exists(source):
fp = open(source, 'rb')
ciphertext = fp.read()
fp.close()
elif type(source) == bytes:
ciphertext = source
else:
print('Invalid data source')
return
if base64_encode:
encoded_text = base64.b64decode(ciphertext)
else:
# decodedCiphertext = ciphertext.decode("hex")
encoded_text = ciphertext
'''
-------------------------
Computes derived key
-------------------------
'''
iv_start = len(encoded_text) - self.BLOCK_SIZE - self.SALT_LENGTH
salt_start = len(encoded_text) - self.SALT_LENGTH
data, iv, salt = encoded_text[:iv_start], encoded_text[iv_start:salt_start], encoded_text[salt_start:]
derived_key = bytes(aes_key, 'utf-8')
for unused in range(0, self.DERIVATION_ROUNDS):
derived_key = hashlib.sha256(derived_key + salt).digest()
derived_key = derived_key[:self.KEY_SIZE]
'''
-------------------------
Decrypt
-------------------------
'''
Cipher = AES.new(derived_key, self.MODE, iv)
padded_text = Cipher.decrypt(data)
padding_length = padded_text[-1]
secret_text = padded_text[:-padding_length]
'''
Si le flux n'est pas décodé (mot de passe invalide), la conversion UTF-8 plante ou au mieux on obtient un texte illisible
'''
try:
secret_text = str(secret_text, 'utf-8')
except:
return
if outfile is None:
return(secret_text)
else:
'''
Writes result to disk
'''
fp = open(outfile, 'w')
fp.write(secret_text)
fp.close()终料
我做了以下修改:
我尝试过多次插入新的代码块..。但不起作用。文本编辑器非常奇怪的行为。
发布于 2013-12-10 13:08:18
发布于 2013-12-10 19:26:57
浮士德已经说了几句有趣的话,但我还有不少其他的话要说。正如“浮士德”已经说过的,你似乎正朝着正确的方向前进。
padding_length = padded_text[-1] (见关于HMAC的部分);AES.block_size而不是16;BaseRNG中的任何内容,但默认情况下使用OSRNG。请注意,我发现RNG类的Python非常难理解,如果您找不到利用库中的类的好方法,请继续使用os.urandom。
发布于 2013-12-11 22:03:45
最后一个源代码版本0.3。希望它能帮到别人。
# -*- coding: utf-8 -*-
from Crypto.Cipher import AES
from Crypto.Hash import HMAC, SHA512
from pbkdf2 import PBKDF2
import os, base64, bz2, binascii
class Aes(object):
'''
Crypte / décrypte un texte donné en AES mode CBC. Accepte l'encodage base64.
Encrypts input text string & decrypts bytes encoded string with or without base64 encoding
PyCrypto and pbkdf2-1.3 packages are mandatory
Author: emmanuel.brunet@live.fr - 12/2013
'''
SALT_LENGTH = 32 # 32 bytes = 256 bits salt
DERIVATION_ROUNDS=7000
KEY_SIZE = 32 # 256 bits key
MODE = AES.MODE_CBC
def encrypt(self, source, aes_key, outfile=None, base64_encode=False):
'''
Crypte l'entrée source en AES mode CBC avec sortie encodage base64 / fichier facultative
@param str source: text to encode or text file path
@param bytes aes_key: password in byte
@parm str outfile: disk file to write encoded text to. defaults to None
@param bool base64_encode: returns base64 encoded string if True (for emails) or bytes if False
@return bytes ciphertext: the bytes encoded string.
'''
'''
----------------------------
Inputs management
----------------------------
'''
if os.path.exists(source):
fp = open(source, 'rb')
input_text = fp.read()
fp.close()
else:
input_text = bytes(source, 'UTF-8')
if input_text == b'':
print('No data to encrypt')
return
'''
# padding_len = AES.block_size - (len(input_text) % AES.block_size)
# padded_text = str(input_text, 'UTF-8') + chr(padding_len) * padding_len
'''
'''
-------------------
Compress
------------------
'''
cmp_text = bz2.compress(input_text)
b64_bin = base64.b64encode(cmp_text)
b64_str = str(b64_bin, 'UTF-8')
padding_len = AES.block_size - (len(b64_str) % AES.block_size)
padded_text = b64_str + chr(padding_len) * padding_len
'''
---------------------------------------------------------
Derived key computing PBKDF2 / specs RSA PKCS#5 V2.0
---------------------------------------------------------
'''
salt = os.urandom(self.SALT_LENGTH)
derived_key = PBKDF2(bytes(aes_key, 'UTF-8'), salt, iterations=self.DERIVATION_ROUNDS, digestmodule=SHA512, macmodule=HMAC).read(self.KEY_SIZE)
'''
----------------
Encrypt
----------------
'''
# le vecteur d'initialisation doit être aléatoire
iv = os.urandom(AES.block_size)
Cipher = AES.new(derived_key, self.MODE, iv)
cipher_text = Cipher.encrypt(padded_text)
cipher_text = cipher_text + iv + salt
# cipher_text = salt + cipher_text
'''
-------------------------
Output management
-------------------------
'''
if outfile is None:
'''
Returns cipher in base64 encoding. Useful for email management for instance
'''
if base64_encode:
return(base64.b64encode(cipher_text))
else:
return(cipher_text)
else:
'''
Writes result to disk
'''
fp = open(outfile, 'w')
if base64_encode:
fp.write(base64.b64encode(cipher_text))
else:
fp.write(cipher_text)
fp.close()
print('Cipher text saved in', outfile)
def decrypt(self, source, aes_key, outfile=None, base64_encode=False):
'''
@param bytes or str source: encrypted bytes string to decode or file path
@param bytes aes_key: password
@parm str outfile: disk file to write encoded text to. defaults to None
@param bool base64_encode: cipher text is given base64 encoded (for mails content for examples)
@returns str secret_text: the decoding text string or None if invalid key given
'''
'''
---------------------------
Input management
---------------------------
'''
if type(source) == str and os.path.exists(source):
fp = open(source, 'rb')
ciphertext = fp.read()
fp.close()
elif type(source) == bytes:
ciphertext = source
else:
print('Invalid data source')
return
if base64_encode:
encoded_text = base64.b64decode(ciphertext)
else:
encoded_text = ciphertext
salt_start = len(encoded_text) - self.SALT_LENGTH
iv_start = len(encoded_text) - AES.block_size - self.SALT_LENGTH
data, iv, salt = encoded_text[:iv_start], encoded_text[iv_start:salt_start], encoded_text[salt_start:]
'''
-------------------------
Derived key computing
-------------------------
'''
# derived_key = PBKDF2(bytes(aes_key, 'UTF-8'), salt).read(self.KEY_SIZE)
derived_key = PBKDF2(bytes(aes_key, 'UTF-8'), salt, iterations=self.DERIVATION_ROUNDS, digestmodule=SHA512, macmodule=HMAC).read(self.KEY_SIZE)
'''
-------------------------
Decrypt
-------------------------
'''
Cipher = AES.new(derived_key, self.MODE, iv)
padded_text = Cipher.decrypt(data)
padding_length = padded_text[-1]
secret_text = padded_text[:-padding_length]
'''
--------------------------
Decompress
--------------------------
'''
cmp_text = base64.b64decode(secret_text)
secret_text = bz2.decompress(cmp_text)
'''
Si le flux n'est pas décodé (mot de passe invalide), la conversion UTF-8 plante ou au mieux on obtient un texte illisible
'''
try:
secret_text = str(secret_text, 'utf-8')
except:
return
if outfile is None:
return(secret_text)
else:
'''
Writes result to disk
'''
fp = open(outfile, 'w')
fp.write(secret_text)
fp.close() https://stackoverflow.com/questions/20494741
复制相似问题