根据密码编码字符串的简单方法?

时间:2010-03-22 06:23:04

标签: python encryption passwords

Python是否有使用密码编码/解码字符串的内置简单方法?

这样的事情:

>>> encode('John Doe', password = 'mypass')
'sjkl28cn2sx0'
>>> decode('sjkl28cn2sx0', password = 'mypass')
'John Doe'

因此字符串“John Doe”被加密为'sjkl28cn2sx0'。要获取原始字符串,我将使用密钥'mypass'“解锁”该字符串,这是我的源代码中的密码。我希望这是我用密码加密/解密Word文档的方式。

我想将这些加密字符串用作URL参数。我的目标是混淆,而不是强大的安全性;没有任何关键任务被编码。我意识到我可以使用数据库表来存储密钥和值,但我试图做到极简主义。

20 个答案:

答案 0 :(得分:63)

当你明确表示你想要默默无闻而不是安全时,我们会避免因你建议的弱点而谴责你:)

所以,使用PyCrypto:

from Crypto.Cipher import AES
import base64

msg_text = 'test some plain text here'.rjust(32)
secret_key = '1234567890123456' # create new & store somewhere safe

cipher = AES.new(secret_key,AES.MODE_ECB) # never use ECB in strong systems obviously
encoded = base64.b64encode(cipher.encrypt(msg_text))
# ...
decoded = cipher.decrypt(base64.b64decode(encoded))
print decoded.strip()

如果某人掌握了您的数据库和代码库,他们将能够解码加密数据。保持您的secret_key安全!

答案 1 :(得分:59)

假设您正在寻找简单的混淆,这会模糊来自非常偶然观察者的事情,并且您不打算使用第三方库。我推荐像Vigenere密码这样的东西。它是最简单的古代密码之一。

Vigenère cipher

实施起来既快捷又容易。类似的东西:

import base64

def encode(key, string):
    encoded_chars = []
    for i in xrange(len(string)):
        key_c = key[i % len(key)]
        encoded_c = chr(ord(string[i]) + ord(key_c) % 256)
        encoded_chars.append(encoded_c)
    encoded_string = "".join(encoded_chars)
    return base64.urlsafe_b64encode(encoded_string)

解码几乎相同,除非你减去密钥。

如果您编码的字符串很短,并且/或者很难猜测所使用的密码的长度,则更难打破。

如果你正在寻找加密的东西,PyCrypto可能是你最好的选择,虽然之前的答案忽略了一些细节:PyCrypto中的ECB模式要求你的信息长度为16个字符的倍数。所以,你必须垫。此外,如果要将它们用作URL参数,请使用base64.urlsafe_b64_encode(),而不是标准参数。这将使用URL安全字符替换base64字母表中的一些字符(顾名思义)。

但是,在使用它之前,您应该绝对确定这个非常薄层混淆是否满足您的需求。我链接的维基百科文章提供了破解密码的详细说明,因此任何具有适度决心的人都可以轻易破解密码。

答案 2 :(得分:46)

@ smehmood的Vigenere密码答案中提到的“encoded_c”应为“key_c”。

以下是编码/解码功能。

import base64
def encode(key, clear):
    enc = []
    for i in range(len(clear)):
        key_c = key[i % len(key)]
        enc_c = chr((ord(clear[i]) + ord(key_c)) % 256)
        enc.append(enc_c)
    return base64.urlsafe_b64encode("".join(enc))

def decode(key, enc):
    dec = []
    enc = base64.urlsafe_b64decode(enc)
    for i in range(len(enc)):
        key_c = key[i % len(key)]
        dec_c = chr((256 + ord(enc[i]) - ord(key_c)) % 256)
        dec.append(dec_c)
    return "".join(dec)

答案 3 :(得分:44)

这是@qneill answer中函数的Python 3版本:

import base64
def encode(key, clear):
    enc = []
    for i in range(len(clear)):
        key_c = key[i % len(key)]
        enc_c = chr((ord(clear[i]) + ord(key_c)) % 256)
        enc.append(enc_c)
    return base64.urlsafe_b64encode("".join(enc).encode()).decode()

def decode(key, enc):
    dec = []
    enc = base64.urlsafe_b64decode(enc).decode()
    for i in range(len(enc)):
        key_c = key[i % len(key)]
        dec_c = chr((256 + ord(enc[i]) - ord(key_c)) % 256)
        dec.append(dec_c)
    return "".join(dec)

需要额外的编码/解码,因为Python 3将字符串/字节数组拆分为两个不同的概念,并更新了它们的API以反映这一点。

答案 4 :(得分:24)

免责声明:如评论中所述,不应使用 来保护实际应用中的数据。

What's wrong with XOR encryption?

https://crypto.stackexchange.com/questions/56281/breaking-a-xor-cipher-of-known-key-length

https://github.com/hellman/xortool


正如前面提到的,PyCrypto库包含一套密码。如果您不想自己动手,可以使用XOR“密码”进行肮脏的工作:

from Crypto.Cipher import XOR
import base64

def encrypt(key, plaintext):
  cipher = XOR.new(key)
  return base64.b64encode(cipher.encrypt(plaintext))

def decrypt(key, ciphertext):
  cipher = XOR.new(key)
  return cipher.decrypt(base64.b64decode(ciphertext))

密码的工作方式如下,无需填充明文:

>>> encrypt('notsosecretkey', 'Attack at dawn!')
'LxsAEgwYRQIGRRAKEhdP'

>>> decrypt('notsosecretkey', encrypt('notsosecretkey', 'Attack at dawn!'))
'Attack at dawn!'

感谢https://stackoverflow.com/a/2490376/241294的base64编码/解码函数(我是一个python新手)。

答案 5 :(得分:21)

Python没有内置的加密方案,没有。您还应该认真对待加密数据存储;一个开发人员理解为不安全的琐碎加密方案和一个玩具方案很可能会被经验不足的开发人员误认为是安全方案。如果加密,请正确加密。

但是,您无需做很多工作即可实施适当的加密方案。首先,不要重新发明密码轮,请使用受信任的密码库为您处理。对于Python 3,该受信任的库为cryptography

我还建议加密和解密适用于个字节;首先将文本消息编码为字节; stringvalue.encode()编码为UTF8,可以使用bytesvalue.decode()轻松地再次还原。

最后但并非最不重要的一点是,在加密和解密时,我们谈论的是密钥,而不是密码。密钥不应该让人记忆深刻,它是您存储在一个秘密位置但可以机读的东西,而密码通常可以被人类可读和记住。您可以 稍加小心就可以从密码中获取密钥。

但是对于在群集中运行的Web应用程序或进程却没有人为保持运行,您需要使用密钥。密码仅在最终用户需要访问特定信息时使用。即使那样,您通常也可以使用密码保护应用程序安全,然后使用可能是用户帐户附带的密钥交换加密信息。

对称密钥加密

Fernet – 强烈建议使用AES CBC + HMAC

cryptography库包含Fernet recipe,这是使用加密技术的最佳实践方法。 Fernet是an open standard,  可以使用多种编程语言进行现成的实现,并且为您提供AES CBC加密以及版本信息,时间戳和HMAC签名,以防止篡改消息。

Fernet使加密和解密消息 非常容易,并确保您的安全。这是用秘密加密数据的理想方法。

我建议您使用Fernet.generate_key()生成安全密钥。您也可以使用密码(下一节),但是完整的32字节秘密密钥(用于加密的16个字节,再加上16个字节用于签名)将比您想到的大多数密码更安全。

Fernet生成的密钥是一个bytes对象,该对象具有URL和文件安全的base64字符,因此可打印:

from cryptography.fernet import Fernet

key = Fernet.generate_key()  # store in a secure location
print("Key:", key.decode())

要加密或解密消息,请使用给定的密钥创建一个Fernet()实例,然后调用Fernet.encrypt()Fernet.decrypt(),要加密的纯文本消息和加密的令牌均为{{ 1}}个对象。

bytesencrypt()函数如下所示:

decrypt()

演示:

from cryptography.fernet import Fernet

def encrypt(message: bytes, key: bytes) -> bytes:
    return Fernet(key).encrypt(message)

def decrypt(token: bytes, key: bytes) -> bytes:
    return Fernet(key).decrypt(token)

带有密码的Fernet –从密码派生的密钥,在一定程度上削弱了安全性

use a strong key derivation method允许您使用密码而不是密钥。然后,您必须在消息中包含salt和HMAC迭代计数,因此,如果不先分离salt,count和Fernet令牌,则加密值不再与Fernet兼容:

>>> key = Fernet.generate_key()
>>> print(key.decode())
GZWKEhHGNopxRdOHS4H4IyKhLQ8lwnyU7vRLrM3sebY=
>>> message = 'John Doe'
>>> encrypt(message.encode(), key)
'gAAAAABciT3pFbbSihD_HZBZ8kqfAj94UhknamBuirZWKivWOukgKQ03qE2mcuvpuwCSuZ-X_Xkud0uWQLZ5e-aOwLC0Ccnepg=='
>>> token = _
>>> decrypt(token, key).decode()
'John Doe'

演示:

import secrets
from base64 import urlsafe_b64encode as b64e, urlsafe_b64decode as b64d

from cryptography.fernet import Fernet
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC

backend = default_backend()
iterations = 100_000

def _derive_key(password: bytes, salt: bytes, iterations: int = iterations) -> bytes:
    """Derive a secret key from a given password and salt"""
    kdf = PBKDF2HMAC(
        algorithm=hashes.SHA256(), length=32, salt=salt,
        iterations=iterations, backend=backend)
    return b64e(kdf.derive(password))

def password_encrypt(message: bytes, password: str, iterations: int = iterations) -> bytes:
    salt = secrets.token_bytes(16)
    key = _derive_key(password.encode(), salt, iterations)
    return b64e(
        b'%b%b%b' % (
            salt,
            iterations.to_bytes(4, 'big'),
            b64d(Fernet(key).encrypt(message)),
        )
    )

def password_decrypt(token: bytes, password: str) -> bytes:
    decoded = b64d(token)
    salt, iter, token = decoded[:16], decoded[16:20], b64e(decoded[20:])
    iterations = int.from_bytes(iter, 'big')
    key = _derive_key(password.encode(), salt, iterations)
    return Fernet(key).decrypt(token)

在输出中包含salt可以使用随机salt值,这又可以确保无论密码重用或消息重复如何,加密输出都可以保证是完全随机的。包含迭代计数可确保您可以适应CPU性能随时间的增长,而不会失去解密较旧消息的能力。

一个单独的密码 可以和Fernet 32​​字节随机密钥一样安全,只要您从相似大小的池中生成适当的随机密码即可。 32个字节为您提供256 ^ 32个键,因此,如果您使用74个字符的字母(26个大写,26个小写,10个数字和12个可能的符号),则密码至少应为>>> message = 'John Doe' >>> password = 'mypass' >>> password_encrypt(message.encode(), password) b'9Ljs-w8IRM3XT1NDBbSBuQABhqCAAAAAAFyJdhiCPXms2vQHO7o81xZJn5r8_PAtro8Qpw48kdKrq4vt-551BCUbcErb_GyYRz8SVsu8hxTXvvKOn9QdewRGDfwx' >>> token = _ >>> password_decrypt(token, password).decode() 'John Doe' == 42长字符。但是,well-selected larger number of HMAC iterations可以在一定程度上缓解熵的缺乏,因为这会使攻击者蛮横地闯入变得更加昂贵。

仅知道选择一个较短但仍相当安全的密码不会破坏该方案,它只是减少了暴力攻击者必须搜索的可能值的数量;确保选择一个strong enough password for your security requirements

替代项

遮盖

另一种选择是不加密。 Vignere说,不要试图只使用低安全性的密码,也不要尝试在家中使用这种密码。这些方法没有安全性,但是可能会给经验不足的开发人员提供将来维护代码的任务,使他们产生安全性的幻想,这比根本没有安全性还差。

如果您所需要的只是晦涩难懂,只需对数据进行base64处理;对于URL安全要求,可以使用base64.urlsafe_b64encode() function。在这里不要使用密码,只需编码即可。最多添加一些压缩(如math.ceil(math.log(256 ** 32, 74))):

zlib

这会将import zlib from base64 import urlsafe_b64encode as b64e, urlsafe_b64decode as b64d def obscure(data: bytes) -> bytes: return b64e(zlib.compress(data, 9)) def unobscure(obscured: bytes) -> bytes: return zlib.decompress(b64d(obscured)) 变成b'Hello world!'

仅完整性

如果您所需要的只是一种确保将数据发送到不受信任的客户端并收到后又可以信任的未更改的方法,那么您想要对数据进行签名,可以将hmac library与SHA1结合使用(仍为considered secure for HMAC signing)或更好:

b'eNrzSM3JyVcozy_KSVEEAB0JBF4='

使用它来对数据签名,然后将签名与数据附加在一起并将其发送给客户端。当您收到数据时,请分割数据并签名并进行验证。我已将默认算法设置为SHA256,因此您需要一个32字节的密钥:

import hmac
import hashlib

def sign(data: bytes, key: bytes, algorithm=hashlib.sha256) -> bytes:
    assert len(key) >= algorithm().digest_size, (
        "Key must be at least as long as the digest size of the "
        "hashing algorithm"
    )
    return hmac.new(key, data, algorithm).digest()

def verify(signature: bytes, data: bytes, key: bytes, algorithm=hashlib.sha256) -> bytes:
    expected = sign(data, key, algorithm)
    return hmac.compare_digest(expected, signature)

您可能想看看itsdangerous library,它将所有这些与各种格式的序列化和反序列化打包在一起。

使用AES-GCM加密提供加密和完整性

Fernet建立在具有HMAC签名的AEC-CBC上,以确保加密数据的完整性;恶意攻击者无法输入您的系统废话数据,以使您的服务在输入错误的情况下仍无法正常运行,因为密文已签名。

Galois / Counter mode block cipher产生密文和一个 tag 以达到相同的目的,因此可以用于相同的目的。不利的一面是,与Fernet不同,没有一种易于使用的“一刀切”的配方可以在其他平台上重复使用。 AES-GCM也不使用填充,因此此加密密文与输入消息的长度匹配(而Fernet / AES-CBC将消息加密为固定长度的块,从而使消息长度有些模糊)。

AES256-GCM将通常的32字节密钥作为密钥:

key = secrets.token_bytes(32)

然后使用

key = secrets.token_bytes(32)

我提供了一个时间戳,以支持Fernet支持的相同的生存时间用例。

此页面上的其他方法,使用Python 3

AES CFB-类似于CBC,但无需填充

这是All Іѕ Vаиітy遵循的方法,尽管有误。这是import binascii, time from base64 import urlsafe_b64encode as b64e, urlsafe_b64decode as b64d from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes from cryptography.hazmat.backends import default_backend from cryptography.exceptions import InvalidTag backend = default_backend() def aes_gcm_encrypt(message: bytes, key: bytes) -> bytes: current_time = int(time.time()).to_bytes(8, 'big') algorithm = algorithms.AES(key) iv = secrets.token_bytes(algorithm.block_size // 8) cipher = Cipher(algorithm, modes.GCM(iv), backend=backend) encryptor = cipher.encryptor() encryptor.authenticate_additional_data(current_time) ciphertext = encryptor.update(message) + encryptor.finalize() return b64e(current_time + iv + ciphertext + encryptor.tag) def aes_gcm_decrypt(token: bytes, key: bytes, ttl=None) -> bytes: algorithm = algorithms.AES(key) try: data = b64d(token) except (TypeError, binascii.Error): raise InvalidToken timestamp, iv, tag = data[:8], data[8:algorithm.block_size // 8 + 8], data[-16:] if ttl is not None: current_time = int(time.time()) time_encrypted, = int.from_bytes(data[:8], 'big') if time_encrypted + ttl < current_time or current_time + 60 < time_encrypted: # too old or created well before our current time + 1 h to account for clock skew raise InvalidToken cipher = Cipher(algorithm, modes.GCM(iv, tag), backend=backend) decryptor = cipher.decryptor() decryptor.authenticate_additional_data(timestamp) ciphertext = data[8 + len(iv):-16] return decryptor.update(ciphertext) + decryptor.finalize() 版本,但请注意,我在密文中包含IV ,不应将其存储为全局变量(重用IV会削弱密钥的安全性,并将其存储作为模块全局,意味着它将在下一次Python调用时重新生成,从而使所有密文无法解密):

cryptography

这缺少HMAC签名的附加保护,并且没有时间戳;您必须自己添加这些人。

以上内容还说明了错误地组合基本密码构造块有多么容易;凡是对IV值的不正确处理都可能导致数据泄露或由于IV丢失而导致所有加密消息不可读。使用Fernet可以保护您免受此类错误的影响。

AES ECB – 不安全

如果您以前实现了AES ECB encryption,并且仍需要在Python 3中支持,则也可以使用import secrets from base64 import urlsafe_b64encode as b64e, urlsafe_b64decode as b64d from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes from cryptography.hazmat.backends import default_backend backend = default_backend() def aes_cfb_encrypt(message, key): algorithm = algorithms.AES(key) iv = secrets.token_bytes(algorithm.block_size // 8) cipher = Cipher(algorithm, modes.CFB(iv), backend=backend) encryptor = cipher.encryptor() ciphertext = encryptor.update(message) + encryptor.finalize() return b64e(iv + ciphertext) def aes_cfb_decrypt(ciphertext, key): iv_ciphertext = b64d(ciphertext) algorithm = algorithms.AES(key) size = algorithm.block_size // 8 iv, encrypted = iv_ciphertext[:size], iv_ciphertext[size:] cipher = Cipher(algorithm, modes.CFB(iv), backend=backend) decryptor = cipher.decryptor() return decryptor.update(encrypted) + decryptor.finalize() 来实现。 同样的警告,ECB为not secure enough for real-life applications 。重新实现针对Python 3的答案,添加自动填充功能:

cryptography

同样,它缺少HMAC签名,因此您无论如何都不应使用ECB。以上只是为了说明from base64 import urlsafe_b64encode as b64e, urlsafe_b64decode as b64d from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes from cryptography.hazmat.primitives import padding from cryptography.hazmat.backends import default_backend backend = default_backend() def aes_ecb_encrypt(message, key): cipher = Cipher(algorithms.AES(key), modes.ECB(), backend=backend) encryptor = cipher.encryptor() padder = padding.PKCS7(cipher.algorithm.block_size).padder() padded = padder.update(msg_text.encode()) + padder.finalize() return b64e(encryptor.update(padded) + encryptor.finalize()) def aes_ecb_decrypt(ciphertext, key): cipher = Cipher(algorithms.AES(key), modes.ECB(), backend=backend) decryptor = cipher.decryptor() unpadder = padding.PKCS7(cipher.algorithm.block_size).unpadder() padded = decryptor.update(b64d(ciphertext)) + decryptor.finalize() return unpadder.update(padded) + unpadder.finalize() 可以处理常见的密码构造块,甚至您实际上不应该使用的那些。

答案 6 :(得分:10)

这是使用AES(PyCrypto)和base64实现URL安全加密和解密。

import base64
from Crypto import Random
from Crypto.Cipher import AES

AKEY = 'mysixteenbytekey' # AES key must be either 16, 24, or 32 bytes long

iv = Random.new().read(AES.block_size)


def encode(message):
    obj = AES.new(AKEY, AES.MODE_CFB, iv)
    return base64.urlsafe_b64encode(obj.encrypt(message))


def decode(cipher):
    obj2 = AES.new(AKEY, AES.MODE_CFB, iv)
    return obj2.decrypt(base64.urlsafe_b64decode(cipher))

如果你遇到像https://bugs.python.org/issue4329这样的问题(TypeError:字符映射必须返回整数,None或unicode)         解码时使用str(cipher)如下

return obj2.decrypt(base64.urlsafe_b64decode(str(cipher)))

In [13]: encode("Hello World")
Out[13]: b'67jjg-8_RyaJ-28='

In [14]: %timeit encode("Hello World")
100000 loops, best of 3: 13.9 µs per loop

In [15]: decode(b'67jjg-8_RyaJ-28=')
Out[15]: b'Hello World'

In [16]: %timeit decode(b'67jjg-8_RyaJ-28=')
100000 loops, best of 3: 15.2 µs per loop

答案 7 :(得分:8)

在python3中使用编码/解码函数(从qneill的答案中调整得非常少):

def encode(key, clear):
    enc = []
    for i in range(len(clear)):
        key_c = key[i % len(key)]
        enc_c = (ord(clear[i]) + ord(key_c)) % 256
        enc.append(enc_c)
    return base64.urlsafe_b64encode(bytes(enc))

def decode(key, enc):
    dec = []
    enc = base64.urlsafe_b64decode(enc)
    for i in range(len(enc)):
        key_c = key[i % len(key)]
        dec_c = chr((256 + enc[i] - ord(key_c)) % 256)
        dec.append(dec_c)
    return "".join(dec)

答案 8 :(得分:5)

感谢您的一些好消息。没有什么可以添加的原创,但这里是使用一些有用的Python工具对qneill的答案的一些渐进式重写。我希望你同意他们简化并澄清代码。

import base64


def qneill_encode(key, clear):
    enc = []
    for i in range(len(clear)):
        key_c = key[i % len(key)]
        enc_c = chr((ord(clear[i]) + ord(key_c)) % 256)
        enc.append(enc_c)
    return base64.urlsafe_b64encode("".join(enc))


def qneill_decode(key, enc):
    dec = []
    enc = base64.urlsafe_b64decode(enc)
    for i in range(len(enc)):
        key_c = key[i % len(key)]
        dec_c = chr((256 + ord(enc[i]) - ord(key_c)) % 256)
        dec.append(dec_c)
    return "".join(dec)
  

enumerate() - 将列表中的项目与其索引

配对      

遍历字符串中的字符

def encode_enumerate(key, clear):
    enc = []
    for i, ch in enumerate(clear):
        key_c = key[i % len(key)]
        enc_c = chr((ord(ch) + ord(key_c)) % 256)
        enc.append(enc_c)
    return base64.urlsafe_b64encode("".join(enc))


def decode_enumerate(key, enc):
    dec = []
    enc = base64.urlsafe_b64decode(enc)
    for i, ch in enumerate(enc):
        key_c = key[i % len(key)]
        dec_c = chr((256 + ord(ch) - ord(key_c)) % 256)
        dec.append(dec_c)
    return "".join(dec)
  

使用列表推导构建列表

def encode_comprehension(key, clear):
    enc = [chr((ord(clear_char) + ord(key[i % len(key)])) % 256)
                for i, clear_char in enumerate(clear)]
    return base64.urlsafe_b64encode("".join(enc))


def decode_comprehension(key, enc):
    enc = base64.urlsafe_b64decode(enc)
    dec = [chr((256 + ord(ch) - ord(key[i % len(key)])) % 256)
           for i, ch in enumerate(enc)]
    return "".join(dec)
  

通常在Python中根本不需要列表索引。完全使用zip和循环消除循环索引变量:

from itertools import cycle


def encode_zip_cycle(key, clear):
    enc = [chr((ord(clear_char) + ord(key_char)) % 256)
                for clear_char, key_char in zip(clear, cycle(key))]
    return base64.urlsafe_b64encode("".join(enc))


def decode_zip_cycle(key, enc):
    enc = base64.urlsafe_b64decode(enc)
    dec = [chr((256 + ord(enc_char) - ord(key_char)) % 256)
                for enc_char, key_char in zip(enc, cycle(key))]
    return "".join(dec)
  

和一些测试...

msg = 'The quick brown fox jumps over the lazy dog.'
key = 'jMG6JV3QdtRh3EhCHWUi'
print('cleartext: {0}'.format(msg))
print('ciphertext: {0}'.format(encode_zip_cycle(key, msg)))

encoders = [qneill_encode, encode_enumerate, encode_comprehension, encode_zip_cycle]
decoders = [qneill_decode, decode_enumerate, decode_comprehension, decode_zip_cycle]

# round-trip check for each pair of implementations
matched_pairs = zip(encoders, decoders)
assert all([decode(key, encode(key, msg)) == msg for encode, decode in matched_pairs])
print('Round-trips for encoder-decoder pairs: all tests passed')

# round-trip applying each kind of decode to each kind of encode to prove equivalent
from itertools import product
all_combinations = product(encoders, decoders)
assert all(decode(key, encode(key, msg)) == msg for encode, decode in all_combinations)
print('Each encoder and decoder can be swapped with any other: all tests passed')

>>> python crypt.py
cleartext: The quick brown fox jumps over the lazy dog.
ciphertext: vrWsVrvLnLTPlLTaorzWY67GzYnUwrSmvXaix8nmctybqoivqdHOic68rmQ=
Round-trips for encoder-decoder pairs: all tests passed
Each encoder and decoder can be swapped with any other: all tests passed

答案 9 :(得分:4)

如果您想要安全,可以使用加密声音的Fernet。如果你不想单独存储它,你可以使用静态“盐” - 你只会丢失字典和彩虹攻击预防。我之所以选择它是因为我可以选择长或短的密码,这对于AES来说并不那么容易。

from cryptography.fernet import Fernet
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC
import base64

#set password
password = "mysecretpassword"
#set message
message = "secretmessage"

kdf = PBKDF2HMAC(algorithm=hashes.SHA256(), length=32, salt="staticsalt", iterations=100000, backend=default_backend())
key = base64.urlsafe_b64encode(kdf.derive(password))
f = Fernet(key)

#encrypt
encrypted = f.encrypt(message)
print encrypted

#decrypt
decrypted = f.decrypt(encrypted)
print decrypted

如果这太复杂了,有人建议使用simplecrypt

from simplecrypt import encrypt, decrypt
ciphertext = encrypt('password', plaintext)
plaintext = decrypt('password', ciphertext)

答案 10 :(得分:3)

注意:我在使用Windows + Python 3.6以及涉及pycrypto(在Windows上无法pip install pycrypto)或pycryptodome(此处与{{1}一起回答)的所有答案时遇到问题}失败,因为此from Crypto.Cipher import XOR分支不支持XOR;使用pycrypto的解决方案也因... AES而失败。另外,库simple-crypt具有TypeError: Object type <class 'str'> cannot be passed to C code作为依赖项,因此不是一种选择。


这是使用软件包pycrypto的解决方案,您可以像往常一样使用cryptography安装:

pip install cryptography

用法:

import base64
from cryptography.fernet import Fernet
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC

def encrypt(plaintext, password):
    f = Fernet(base64.urlsafe_b64encode(PBKDF2HMAC(algorithm=hashes.SHA256(), length=32, salt=b'abcd', iterations=1000, backend=default_backend()).derive(password.encode())))
    return f.encrypt(plaintext.encode()).decode()

def decrypt(ciphertext, password):
    f = Fernet(base64.urlsafe_b64encode(PBKDF2HMAC(algorithm=hashes.SHA256(), length=32, salt=b'abcd', iterations=1000, backend=default_backend()).derive(password.encode())))
    return f.decrypt(ciphertext.encode()).decode()

注意:

  • 您可以适应自己的盐,迭代次数等。

  • 与@HCLivess的答案相距不远,但此处的目标是要拥有随时可用的>>> encrypt('John Doe', password='mypass') 'gAAAAABciC64VNUoeLVoPKut7HxlPcsqJZTFf99EMYTmnR9jFkZBNMxklIDc5WZ6k3TxfcFSDO-4PRZUsOvywtGLSFwOzToO_g==' >>> decrypt('gAAAAABciC64VNUoeLVoPKut7HxlPcsqJZTFf99EMYTmnR9jFkZBNMxklIDc5WZ6k3TxfcFSDO-4PRZUsOvywtGLSFwOzToO_g==', password='mypass') 'John Doe' encrypt函数

  • 来源:https://cryptography.io/en/latest/fernet/#using-passwords-with-fernet

答案 11 :(得分:2)

这样可行,但密码长度应该是8。这很简单,需要pyDes

from pyDes import *

def encode(data,password):
    k = des(password, CBC, "\0\0\0\0\0\0\0\0", pad=None, padmode=PAD_PKCS5)
    d = k.encrypt(data)
    return d

def decode(data,password):
    k = des(password, CBC, "\0\0\0\0\0\0\0\0", pad=None, padmode=PAD_PKCS5)
    d = k.decrypt(data)
    return d

x = encode('John Doe', 'mypass12')
y = decode(x,'mypass12')

print x
print y

输出:

³.\Þ\åS¾+æÅ`;Ê
John Doe

答案 12 :(得分:2)

@qneill代码的另一个实现,包括原始消息的CRC校验和,如果检查失败则抛出异常:

import hashlib
import struct
import zlib

def vigenere_encode(text, key):
    text = '{}{}'.format(text, struct.pack('i', zlib.crc32(text)))

    enc = []
    for i in range(len(text)):
        key_c = key[i % len(key)]
        enc_c = chr((ord(text[i]) + ord(key_c)) % 256)
        enc.append(enc_c)

    return base64.urlsafe_b64encode("".join(enc))


def vigenere_decode(encoded_text, key):
    dec = []
    encoded_text = base64.urlsafe_b64decode(encoded_text)
    for i in range(len(encoded_text)):
        key_c = key[i % len(key)]
        dec_c = chr((256 + ord(encoded_text[i]) - ord(key_c)) % 256)
        dec.append(dec_c)

    dec = "".join(dec)
    checksum = dec[-4:]
    dec = dec[:-4]

    assert zlib.crc32(dec) == struct.unpack('i', checksum)[0], 'Decode Checksum Error'

    return dec

答案 13 :(得分:2)

您可以使用AES通过密码加密字符串。虽然,你会想要选择一个足够强大的密码,所以人们不能轻易猜出它是什么(对不起,我无法帮助它。我是一个想要的安全威胁)。

AES具有良好的密钥大小,但它也很容易与PyCrypto一起使用。

答案 14 :(得分:2)

cryptocode 提供了一种使用密码对字符串进行编码和解码的简单方法。 安装方法如下:

pip install cryptocode

加密消息(示例代码):

import cryptocode

encoded = cryptocode.encrypt("mystring","mypassword")
## And then to decode it:
decoded = cryptocode.decrypt(encoded, "mypassword")

文档可以在 here

答案 15 :(得分:1)

外部库提供密钥加密算法。

例如,Cypher module in PyCrypto提供了许多加密算法的选择:

  • Crypto.Cipher.AES
  • Crypto.Cipher.ARC2
  • Crypto.Cipher.ARC4
  • Crypto.Cipher.Blowfish
  • Crypto.Cipher.CAST
  • Crypto.Cipher.DES
  • Crypto.Cipher.DES3
  • Crypto.Cipher.IDEA
  • Crypto.Cipher.RC5
  • Crypto.Cipher.XOR

MeTooCryptoOpenSSLPython包装器,提供(以及其他功能)全功能通用加密库。包括对称密码(如AES)。

答案 16 :(得分:1)

无论谁来这里(和赏金猎人)似乎都在寻找没有太多设置的单线,其他答案没有提供。所以我提出了base64。

现在,请记住,这仅是基本的混淆,并且 **无法保证安全** ,但是这里有一些内容:

from base64 import urlsafe_b64encode, urlsafe_b64decode

def encode(data, key):
    return urlsafe_b64encode(bytes(key+data, 'utf-8'))

def decode(enc, key):
    return urlsafe_b64decode(enc)[len(key):].decode('utf-8')

print(encode('hi', 'there')) # b'dGhlcmVoaQ=='
print(decode(encode('hi', 'there'), 'there')) # 'hi'

一些注意事项:

  • 您将希望自己处理更多/更少的字节到字符串编码/解码,具体取决于您的I / O。查看bytes()bytes::decode()
  • base64可以通过所使用的字符类型轻松识别,并且通常以=字符结尾。当我们在网站上看到它们时,像我这样的人绝对会在javascript控制台中解码它们。就像btoa(string)(js)
  • 一样简单
  • 顺序是键+数据,如b64所示,末尾出现的字符取决于开头的字符(由于字节偏移。Wikipedia有一些很好的解释)。在这种情况下,对于使用该键编码的所有内容,编码字符串的开头都将相同。加号的是,数据将更加混乱。否则,无论密钥如何,每个人的数据部分都将完全相同。

现在,如果您想要的甚至不需要任何类型的密钥,而只是需要一些混淆,您可以再次使用base64,而无需任何类型的密钥:

from base64 import urlsafe_b64encode, urlsafe_b64decode

def encode(data):
    return urlsafe_b64encode(bytes(data, 'utf-8'))

def decode(enc):
    return urlsafe_b64decode(enc).decode()

print(encode('hi')) # b'aGk='
print(decode(encode('hi'))) # 'hi'

答案 17 :(得分:0)

如果您想要安全加密:

对于python 2,你应该使用keyczar http://www.keyczar.org/

对于python 3,直到keyczar可用,我写了simple-crypt http://pypi.python.org/pypi/simple-crypt

这两个都将使用密钥强化,这使得它们比这里的大多数其他答案更安全。因为它们非常容易使用,所以即使安全性不是很严重,也可能想要使用它们......

答案 18 :(得分:0)

因此,由于关键任务没有被编码,因此您只想对混淆进行加密。

让我呈现 caeser的密码

enter image description here

Caesar的密码或Caesar移位是最简单和最广为人知的加密技术之一。这是一种替换密码,其中明文中的每个字母都由一个字母固定下来,位于字母表下方一定数量的位置。例如,左移3时,D将被A替换,E将变为B,依此类推。

示例代码供您参考:

def encrypt(text,s): 
        result = "" 

        # traverse text 
        for i in range(len(text)): 
            char = text[i] 

            # Encrypt uppercase characters 
            if (char.isupper()): 
                result += chr((ord(char) + s-65) % 26 + 65) 

            # Encrypt lowercase characters 
            else: 
                result += chr((ord(char) + s - 97) % 26 + 97) 

        return result 

    def decrypt(text,s): 
        result = "" 

        # traverse text 
        for i in range(len(text)): 
            char = text[i] 

            # Encrypt uppercase characters 
            if (char.isupper()): 
                result += chr((ord(char) - s-65) % 26 + 65) 

            # Encrypt lowercase characters 
            else: 
                result += chr((ord(char) - s - 97) % 26 + 97) 

        return result 

    #check the above function 
    text = "ATTACKATONCE"
    s = 4
    print("Text  : " + text) 
    print("Shift : " + str(s)) 
    print("Cipher: " + encrypt(text,s))
    print("Original text: " + decrypt(encrypt(text,s),s))

优点:它可以满足您的要求,并且很简单,并且编码为'y'。

缺点:可以通过简单的暴力算法来破解(几乎不可能有人尝试通过所有额外结果)。

答案 19 :(得分:0)

再添加一个带有解码和编码的代码以供参考

import base64

def encode(key, string):
    encoded_chars = []
    for i in range(len(string)):
        key_c = key[i % len(key)]
        encoded_c = chr(ord(string[i]) + ord(key_c) % 128)
        encoded_chars.append(encoded_c)
    encoded_string = "".join(encoded_chars)
    arr2 = bytes(encoded_string, 'utf-8')
    return base64.urlsafe_b64encode(arr2)

def decode(key, string):
    encoded_chars = []
    string = base64.urlsafe_b64decode(string)
    string = string.decode('utf-8')
    for i in range(len(string)):
        key_c = key[i % len(key)]
        encoded_c = chr(ord(string[i]) - ord(key_c) % 128)
        encoded_chars.append(encoded_c)
    encoded_string = "".join(encoded_chars)
    return encoded_string

def main():
    answer = str(input("EorD"))
    if(answer in ['E']):
        #ENCODE
        file = open("D:\enc.txt")
        line = file.read().replace("\n", " NEWLINEHERE ")
        file.close()
        text = encode("4114458",line)
        fnew = open("D:\\new.txt","w+")
        fnew.write(text.decode('utf-8'))
        fnew.close()
    else:
        #DECODE
        file = open("D:\\new.txt",'r+')
        eline = file.read().replace("NEWLINEHERE","\n")
        file.close()
        print(eline)
        eline = eline.encode('utf-8')
        dtext=decode("4114458",eline)
        print(dtext)
        fnew = open("D:\\newde.txt","w+")
        fnew.write(dtext)
        fnew.close

if __name__ == '__main__':
    main()