【问题标题】:Is it ok to remove the equal signs from a base64 string?可以从base64字符串中删除等号吗?
【发布时间】:2012-02-19 16:21:34
【问题描述】:

我有一个字符串,我将其编码为 base64 以节省空间。如果我删除最后的等号,这有什么大不了的吗?这会显着降低熵吗?如何确保生成的字符串的长度是固定的?

>>> base64.b64encode(combined.digest(), altchars="AB")
'PeFC3irNFx8fuzwjAzAfEAup9cz6xujsf2gAIH2GdUM='

谢谢。

【问题讨论】:

  • 我有一个字符串,我将其编码为 base64 以节省空间 - Base64 不节省空间,相反。它通常用于在(通常基于 ascii 的)线路协议中表示任意字节序列。
  • 只有我对“我正在编码为 base64 以节省空间的字符串”感到惊讶吗? Base64 比一般字符串更冗长,更常见的用途是将 BINARY 数据作为字符串传输。
  • 另外,请不要像很多人认为的那样认为 Base64 是加密。
  • @MattH 与十六进制相比,它可以节省空间。
  • 你不应该使用AB作为altchars...base64使用A-Za-z0-9来表示6位值0-61,altchars选择用于62和63的值。使用已经分配给值的东西会导致解码错误......例如b64decode(b64encode('\x00','AB'),'AB') 将返回 '\xfb' 而不是 '\x00'。即使您只是在散列,那 正在 丢弃熵,但不会删除填充。

标签: python base64 md5


【解决方案1】:

除非您连接多个 Base64 编码文件或字符串,否则删除等号是安全的,因为它们仅用于填充目的。

【讨论】:

    【解决方案2】:

    我不这么认为。
    https://en.wikipedia.org/wiki/Base64#Output_padding

    这些等号是“有用的”。

    【讨论】:

      【解决方案3】:

      查看您的代码:

      >>> base64.b64encode(combined.digest(), altchars="AB")
      'PeFC3irNFx8fuzwjAzAfEAup9cz6xujsf2gAIH2GdUM='
      

      以base64 编码的字符串是一个名为digest() 的函数的结果。如果您的摘要函数生成固定长度值(例如,如果它正在计算 MD5 或 SHA1 摘要),那么 b64encode 的参数将始终是相同的长度。

      如果上述情况属实, 那么你可以去掉尾随的等号,因为它们的数量总是相同的。如果这样做,只需在解码之前将相同数量的等号附加到字符串即可。

      如果摘要不是固定长度,则修剪等号是不安全的。

      编辑:看起来您可能正在使用 SHA-256 摘要? SHA-256 摘要是 256 位(或 32 字节)。 32 字节是 10 组,每组 3 个,再加上剩下的两个。正如您从Wikipedia section on padding 中看到的那样;这意味着你总是有一个尾随等于。如果是SHA-256,那么剥离就可以了,只要记得在解码前再添加一次即可。

      【讨论】:

      • 你是对的。原始问题中的编码摘要有 44 个字节。所以我们有 256 位,即(10 组 3 字节)+(剩余 2 字节),被编码为 11 组 4 字节。我已经更新了我的评论。谢谢。
      • 似乎 PHP 和 JavaScript 的内置解码函数(base64_decodeatob)不关心填充。有人here 说“在这种情况下启用它的唯一原因可能是增加对没有填充就无法工作的解码器的容忍度。如果你控制两端,那就不用担心了。”想法?
      【解决方案4】:

      除了@Martin Ellis 指出的情况外,弄乱填充字符可能会导致

      TypeError: Incorrect padding
      

      并且在你做的时候会产生一些垃圾。

      正如@MattH 所说,base64 的作用与节省空间相反。

      为了节省空间,您应该应用压缩算法,例如 zlib。

      例如zlib

      import zlib
      
      s = '''large string....'''
      compressed = zlib.compress(s)
      
      compression_ratio = len(s)*1.0/len(compressed)    
      
      # And later...
      out = zlib.decompress(compressed) 
      
      # The above function is also good for relieving stress.
      

      【讨论】:

        【解决方案5】:

        等号可以去掉,只要你知道它们的作用。

        Base64 每编码 3 个字节输出 4 个字符(换句话说,每个字符编码 6 位)。添加了填充字符,因此任何 base64 字符串的长度始终是 4 的倍数,填充字符实际上并不编码任何数据。 (我不能肯定地说为什么会这样做——作为一种错误检查字符串是否被截断的方法,以简化解码,或其他什么?)。

        无论如何,这意味着如果您有x base64 字符(无填充),则将有4-(x%4) 填充字符。 (尽管x%4=1 不会因为 6 和 8 的因式分解而发生)。由于这些不包含实际数据,并且可以恢复,因此当我想节省空间时,我经常将它们剥离,例如以下::

        from base64 import b64encode, b64decode
        
        # encode data
        raw = b'\x00\x01'
        enc = b64encode(raw).rstrip("=")
        
        # func to restore padding
        def repad(data):
             return data + "=" * (-len(data)%4)
        raw = b64decode(repad(enc))
        

        【讨论】:

        • 有更多知识的人,如果不正确,请更正我的C#版本:var pad = (text.Length % 4);如果(垫== 3)垫= 1; for (int i = 0; i
        • 根据@Eli Collins 在这里所说的,您 (@nikib3ro) 所写的 C# 等价物是 var pad = text.Length % 4。您将不需要 if 块,因为 mod 的结果不会变成 1
        【解决方案6】:

        您需要编码为 Base64 的每 3 个字节将转换为 4 个 ASCII 字符,并使用“=”字符填充结果,以便始终有 4 个编码字符的倍数。如果您有 3 个字节的精确倍数,那么您将不会得到等号。 一个备用字节意味着您在最后得到两个“=”字符。 两个备用字节意味着你在最后得到一个“=”字符。 根据您对字符串的解码方式,它可能会将其视为有效字符串,也可能不会。使用您拥有的示例字符串,它不会解码,但我尝试过的一些简单字符串可以解码。

        您可以阅读此页面以更好地了解 base64 字符串和编码/解码。

        http://www.nczonline.net/blog/2009/12/08/computer-science-in-javascript-base64-encoding/

        有免费的在线编码器/解码器可用于检查输出字符串

        【讨论】:

          【解决方案7】:

          那些是填充,删除它们并不会节省太多,因为它们最多有两个,所以如果你想节省空间,看看别处。并且通过对熵的引用,您是否压缩了这些 base64 字符串?如果是这样,即使您删除它们,它们也不会对压缩大小产生太大影响。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2016-11-22
            • 2017-03-19
            • 2019-08-25
            • 1970-01-01
            • 1970-01-01
            • 2020-01-12
            相关资源
            最近更新 更多