【问题标题】:encrypt a string to obtain a fixed length加密字符串以获得固定长度
【发布时间】:2014-05-07 14:35:24
【问题描述】:

假设我有以下可能的字符串值:

exp="110"
exp="110-120"
exp="110-120-211"

其实这是从URL获取的GET参数。 exp 可以变得非常大,所以我想让它更短(加密它)。不是因为安全原因,而是因为我不希望它又长又丑。

所以我想加密exp 成为一个固定长度的短字符串,比如说15。有可能吗?像这样的:

encrypt("110")     results in "Ax1234B"
encrypt("110-120") results in "85xHdjX"

我正在使用 python 顺便说一句

编辑

忘了提一下:我还需要一个decrypt 函数才能使用。此外,我更喜欢标准 python 库中的解决方案,而无需安装新包。

【问题讨论】:

  • 不,不可能以可逆的方式将任意大的数据集放入固定长度。也许您需要重新定义允许的内容。不过你当然可以缩短它
  • 我们用来缩短的一种方法是压缩字符串,然后对其进行 base64 编码。这显然不是固定长度,而是非常可逆的。
  • 您尝试传输的数据的域是什么?
  • 如果你想让一些东西更小,并且如果你没有任何安全要求,那么你就是在谈论压缩。如果您想将压缩形式存储在特定字符串中,您正在谈论编码。如果您不介意,我会相应地更改标签。

标签: python django url encoding compression


【解决方案1】:

你的琴弦有多长?如果它们足够长,您可以使用zlib(或标准库中的另一个压缩模块)压缩它们,然后在其上运行 base64。

>>> z = base64.encodestring(zlib.compress("123"))
>>> print z 
eJwzNDIGAAEtAJc=
>>> zlib.decompress(base64.decodestring(z)) 
'123'

这不会缩小你的字符串,除非它们很长(在我的测试中,原始字符串中大约有 36 个字符)。你也没有得到一个固定的长度,但我不相信有任何方法可以实现。

【讨论】:

    【解决方案2】:

    如果要将url转换成固定长度的字符串;您可以使用哈希函数和数据库来检索给定哈希的 url:

    import base64
    import hashlib
    import sqlite3
    
    db = sqlite3.connect('urls.sqlite3')
    db.execute('''CREATE TABLE IF NOT EXISTS urls
                  (hash BLOB PRIMARY KEY, url TEXT)''')
    
    def shorten(url):
        h = sqlite3.Binary(hashlib.sha256(url.encode('ascii')).digest())
        with db:
            db.execute('INSERT OR IGNORE INTO urls VALUES (?, ?)', (h, url))
        return base64.urlsafe_b64encode(h).decode('ascii')
    
    def geturl(shortened_url):
        h = sqlite3.Binary(base64.urlsafe_b64decode(shortened_url.encode('ascii')))
        with db:
            url = db.execute('SELECT url FROM urls WHERE hash=?', (h,)).fetchone()
        if url is None:
            raise KeyError(shortened_url)
        return url[0]
    

    示例

    urls = ["110", "110-120", "110-120-211"]
    width = max(map(len, urls))
    for url in urls:
        slug = shorten(url)
        assert url == geturl(slug)
        print('{url:{width}} -> {slug}'.format(**vars()))
    

    输出

    110         -> m9sq9nmSBKKZxgOZS45ADksf1iXv23QGbMhp_uQsnfM=
    110-120     -> aKGvjidWggSkQ1wBnZoi5f67KlUS1pvoVyhX8Rd04P0=
    110-120-211 -> C8LD7lCh5Tm8XCoWJep9OAfSnMikLU5lgQChe-wfQho=
    

    无论输入 URL 长(或短),输出总是具有相同的长度。

    对于具有良好算法的足够长的散列,对于生成的任何实际数量的 url 散列,冲突的概率(不同的 url 产生相同的散列)非常低。

    【讨论】:

    • 我不介意投反对票,但原因是什么?如何改进答案?
    • 我的猜测是,当发生碰撞时,正如您提到的那样,这不起作用。谁愿意依赖可能不会破坏的东西,但当第一次碰撞实际发生时,解决方案将不起作用?
    • @StephanRyer 我可能低估了实践中的概率有多低。无论如何,很容易检测到冲突并根据特定任务提供解决方法。
    • 概率会增加您要加密的字符串越多,因此在不知道这个数字的情况下 - 实际上不可能说出发生这种情况的总体机会。
    • @StephanRyer 可能的 sha256 哈希数:2**256 相比之下,以秒为单位的宇宙年龄非常小:~10**21。您可以在宇宙存在的每一秒每秒生成数十亿个哈希,并且您只使用所有可能哈希中的一小部分¶鉴于解决方案使用数据库,如果我们检测到非常不可能的碰撞(只需删除代码中的“OR IGNORE” ),我们可以在许多可能的候选者中使用随机的免费哈希值。
    【解决方案3】:

    如果安全性根本不是问题并且您只想混淆和缩小,也许使用base64?它是在 Javascript 和 Python 中实现的,因此您可以轻松地在前端对其进行编码并在后端对其进行解码。

    但是,这不会给你一个固定的长度,除非你故意填充到比实际长度更大的某个长度。

    【讨论】:

    • base64 本身实际上会增长字符串
    • 是的,我在考虑 base64,但随着我的字符串长度增加,base64 也会增加。我认为可能有另一种解决方案..
    • @cmd 嗯,没错;我想可以将字符串(似乎是数字和破折号)表示的数据转换为二进制,然后用 base64 编码,但这似乎很麻烦。
    • @MihaiZamfir 您可以将表示放大到固定限制,但不能将其缩小到固定限制而不会丢失数据。当然,有实际的压缩,但我不知道有多少压缩技术适用于超细的字符串。
    • 对于大多数主要网站来说,URL 中神秘而丑陋的查询字符串是不二之选。参见例如 Youtube、亚马逊、谷歌...
    【解决方案4】:

    不,不可能以可逆的方式将任意大的数据集放入固定长度。您需要更好地定义正在传递的内容。

    例如,如果:

    • 从您的示例来看,它看起来像一个数字列表。
    • 数量相对较少。
    • 不允许重复

    如果这些是真的,您可以将列表作为位打包到一个固定大小的二进制流中,直到最大位数作为最大位数,然后对其进行 base64 编码。这将是固定长度和可逆的。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-09-13
      • 2012-12-15
      相关资源
      最近更新 更多