【问题标题】:Encrypt a string in Python. Restrict the characters used to only alphanumeric在 Python 中加密字符串。将使用的字符限制为仅字母数字
【发布时间】:2012-07-03 05:20:17
【问题描述】:

我想将 10 个字符(仅限字母数字)字符串加密为 16 或 32 个字符的字母数字字符串。

我加密的字符串是一个资产标签。所以它本身不携带任何信息,但我想将所有有效的可能字符串隐藏在更大的可能字符串组中。我希望加密字符串是一个很好的方法。

是否可以使用 Python PyCrypto 库来做到这一点?

Here is an example 我发现关于使用 PyCrypto。

【问题讨论】:

  • 你不想要加密哈希吗?
  • 加密哈希是一种单向函数,它接受可变长度的输入并产生唯一的、固定长度的输出。流行的实现是 SHA 和 MD5。

标签: python encryption hash pycrypto


【解决方案1】:

您最好使用简单的散列(类似于单向加密)。为此,只需使用 md5 函数生成摘要,然后对其进行 base64 或 base16 编码。请注意,base64 字符串可以包含 +、= 或 /。

import md5
import base64

def obfuscate(s):
    return base64.b64encode( md5.new(s).digest())

def obfuscate2(s):
    return base64.b16encode( md5.new(s).digest())

# returns alphanumeric string but strings can also include slash, plus or equal i.e. /+=
print obfuscate('Tag 1')
print obfuscate('Tag 2')
print obfuscate('Tag 3')

# return hex string
print obfuscate2('Tag 1')

正如已经评论的那样,md5 正在迅速失去其安全性,因此如果您希望将来拥有更可靠的东西,请使用下面的 SHA-2 示例。

import hashlib

def obfuscate(s):
    m = hashlib.sha256()
    m.update(s)
    return m.hexdigest()

print obfuscate('Tag 1')
print obfuscate('Tag 2')
print obfuscate('Tag 3')

还有一个功能 - 这次使用 SHA-2 生成大约 96 位* 摘要并截断输出,以便我们可以将其限制为 16 个字母数字字符。这会稍微增加碰撞的可能性,但对于大多数实际用途来说应该足够了。

import hashlib
import base64

def obfuscate(s):
    m = hashlib.sha256()
    m.update(s)
    hash = base64.b64encode(m.digest(), altchars="ZZ")  # make one way base64 encode, to fit characters into alphanum space only
    return hash[:16]    # cut of hash at 16 chars - gives about 96 bits which should 
    # 96 bits means 1 in billion chance of collision if you have 1 billion tags (or much lower chance with fewer tags)
    # http://en.wikipedia.org/wiki/Birthday_attack

print obfuscate('Tag 1')
print obfuscate('Tag 2')
print obfuscate('Tag 3')

*实际的摘要只有 95.2 位,因为我们使用 62 个字符的字母进行编码。

>>> math.log(62**16,2)
95.26714096618998

【讨论】:

  • MD5 被广泛认为是损坏的(参见例如它的维基百科文章,或 Bruce Schneier 的著作)。在这种特殊情况下,这可能并不重要,但通常使用另一个散列函数(如 SHA-2 或 scrypt 密钥派生函数)似乎更好。
  • 一般来说有效点 - 为了帮助我改掉使用 md5 的坏习惯,我现在还包含了 SHA-2 示例。
  • michael 询问加密和 PyCrypto 库,但没有询问哈希
  • Michael 要求隐藏信息 - 并提到加密可能是解决此问题的好方法 - 我提供了替代的有效解决方案来避免加密问题。 :)
  • 查看将字符总数限制为一定数量的示例会很有用。我希望在最多 32 个仅包含字母数字的字符中隐藏 10 个仅包含字母数字的字符资产标签。最好是 16. 哈希字符串进入二维码。
【解决方案2】:

要使字符串更长,您可以尝试以下方法;

  • 先用bzip2压缩
  • 然后使用 base64 编码使其再次可读

像这样:

import bz2
import base64
base64.b64encode(bz2.compress('012345'))

这将产生:

'QlpoOTFBWSZTWeEMDLgAAAAIAH4AIAAhgAwDJy7i7kinChIcIYGXAA=='

由于 bzip2 标头,前 13 个字符将始终相同,因此您应该丢弃它们;

base64.b64encode(bz2.compress('012345'))[14:]

这给出了:

 'EMDLgAAAAIAH4AIAAhgAwDJy7i7kinChIcIYGXAA=='

请注意,这是加密安全的;如果您知道所使用的配方,则倒置是微不足道的:

foo = base64.b64encode(bz2.compress('012345'))
bz2.decompress(base64.b64decode(foo))

给予:

'012345'

【讨论】:

    【解决方案3】:

    我认为 Shake256 符合您的需求:

    你需要安装 pycryptodome。

    https://pycryptodome.readthedocs.io/en/latest/src/hash/shake256.html

    #!/usr/bin/env python
    from Crypto.Hash import SHAKE256
    from binascii import hexlify
    
    
    def encrypt_shake256(s, hash_size):
        shake = SHAKE256.new()
        shake.update(s.encode())
        return hexlify(shake.read(hash_size//2))
    
    
    def main():
        hash = encrypt_shake256("holahola", 16)
        print(hash)
        print(len(hash))
    
    
    if __name__ == '__main__':
        main()
    

    输出:

    b'c126f8fb14fb21d8'
    16
    

    【讨论】:

      【解决方案4】:

      是的,你也可以使用 PyCrypto:

      from Crypto.Hash import SHA256
      
      aHash = SHA256.new("somethingToHash")
      print(aHash.hexdigest()) #will print out the hashed password
      

      Crypto.Hash 模块来自于安装 pycrypto 模块 (sudo pip install pycrypto)。

      这与 hashlib 基本相同,但是 PyCrypto 库带有加密模块。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2013-08-07
        • 1970-01-01
        • 2011-10-02
        • 2018-02-01
        • 1970-01-01
        • 2023-01-18
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多