Base64编码与Ascii85编码的区别

18

我在工作中的项目使用Jackson JSON序列化器将一堆Java对象转换成字符串,以便将它们发送到REST服务。

其中一些对象包含敏感数据,因此我编写了自定义的序列化器来将这些对象序列化为JSON字符串,然后用AES进行gzip压缩和加密;

这将字符串转换为字节数组,所以我使用Apache commons codec中的Base64编码器将字节数组转换为字符串。 REST接口背后的自定义反序列化器将反转此过程:

base64解码 -> 解密 -> 解压缩 -> 使用默认Jackson反序列化器反序列化。

Base64编码会增加输出大小(序列化中的gzip步骤旨在帮助减轻此增加),因此我查阅谷歌以查看是否有更有效的替代方法,导致我找到了这个以前的stackoverflow线程,其中提出了Ascii85编码作为更有效的替代方法 -

Base64会将输出大小增加33%,而Ascii85会将输出大小增加25%。

我找到了一些Java Ascii85实现,例如Apache pdfbox,但我有点犹豫使用该编码 - 这似乎几乎没有人使用或实现它,这可能只意味着Base64具有更大的惯性,或者可能意味着Ascii85存在某些问题。

有人对此有更多了解吗?是否存在Ascii85的任何问题,这意味着我应该改用Base64?


2
为什么不直接通过HTTPS调用REST服务,而要在消息的某些部分使用自制加密? - Samuel Rossille
我们在REST调用中使用HTTPS,加密数据的原因是因为大多数消息也花费了时间在Amazon Web Services简单队列服务队列中,该队列仅接受字符串。有权访问队列的人员与具有加密密钥访问权限的人员不同。 - Zim-Zam O'Pootertoot
3个回答

19

Base64是更加普遍的方式。在大多数情况下,大小上的差异并不是那么显著,如果您在HTTP层级上添加(这将压缩base64),而不是在负载内部进行添加,您可能会发现差异完全消失。

Ascii85有什么问题,这意味着我应该使用Base64?

我强烈建议使用base64,因为它非常广泛。这几乎是用文本表示二进制数据的规范方式(除非您想使用十六进制,当然)。


5
更为常见并不代表更好。如果数据大小的开销较小,则也许应该使用它。1 Gb中8%的数据传输节省可以得到85 MB的流量节省。但这当然取决于需要传输多少数据。软件需求确实会发生变化,数据量也会发生变化,但文件格式之后的更改可能会带来很大的痛苦。但我怀疑这些编码不用于大数据传输。 - TarmoPikaro
2
@TarmoPikaro:更常见意味着“在你可能需要的每个平台上都更有可能被正确实现”,如果你正在传输大量数据,最好想办法避免执行文本编码 - 既节省带宽又节省 CPU 编码/解码时间。 - Jon Skeet
通常,实现始于具有参考实现,因此如果我们有一个工作解决方案,很可能会被克隆到更多。我简要查看了维基页面 - ascii 85和mime 64都没有在视觉上给出任何优势。但是,使用一种编码或另一种编码有多容易使用 - 例如,在Windows中,有CryptBinaryToString内置函数,可以立即生成mime64。 - TarmoPikaro
我已经恢复了编辑,不再使用代码字体来表示非代码项。这通常会使阅读变得更加困难。 - Jon Skeet

9

ASCII85是一种很好的编码方式,可以节省额外的空间。但如果直接通过HTTP发送,它会输出许多需要转义的字符。Base64编码有一个变体,可以在HTTP中发送而不需要任何转义。

这里有一个javascript ASCII85编码器,以防有人需要尝试:

// By Steve Hanov. Released to the public domain.
function encodeAscii85(input) {
  var output = "<~";
  var chr1, chr2, chr3, chr4, chr, enc1, enc2, enc3, enc4, enc5;
  var i = 0;

  while (i < input.length) {
    // Access past the end of the string is intentional.
    chr1 = input.charCodeAt(i++);
    chr2 = input.charCodeAt(i++);
    chr3 = input.charCodeAt(i++);
    chr4 = input.charCodeAt(i++);

    chr = ((chr1 << 24) | (chr2 << 16) | (chr3 << 8) | chr4) >>> 0;

    enc1 = (chr / (85 * 85 * 85 * 85) | 0) % 85 + 33;
    enc2 = (chr / (85 * 85 * 85) | 0) % 85 + 33;
    enc3 = (chr / (85 * 85) | 0 ) % 85 + 33;
    enc4 = (chr / 85 | 0) % 85 + 33;
    enc5 = chr % 85 + 33;

    output += String.fromCharCode(enc1) +
      String.fromCharCode(enc2);
    if (!isNaN(chr2)) {
      output += String.fromCharCode(enc3);
      if (!isNaN(chr3)) {
        output += String.fromCharCode(enc4);
        if (!isNaN(chr4)) {
          output += String.fromCharCode(enc5);
        }
      }
    }
  }

  output += "~>";

  return output;
}
<input onKeyUp="result.innerHTML = encodeAscii85(this.value)" placeholder="write text here" type="text">
<p id="result"></p>


我从未编写过解码器,因为我的应用程序不需要它。 - Steve Hanov
我认为您错过了一个前导的<~。如果没有它,我就无法解码该字符串。我错了吗?另外,我修改了您的答案并添加了一段代码片段;) - Qwerty
具有讽刺意味的是,当我尝试编码"Can we have decode too? :)"时,它就崩溃了。它在Can we ha处开始变得奇怪。编辑:在该框架中运行时有些奇怪,但编码器函数本身正常工作。 - enorl76
你不需要回到更低效的1950年代向后兼容的6位编码。使用Z85(https://www.johndcook.com/blog/2019/03/05/base85-encoding/),你也可以做到HTTP友好。常见语言的开源Base-Z85编解码器易于找到。 - Jan

3

这是一个匹配的ASCII85(也称为Base85)解码器,在JavaScript中(为用户Qwerty):

function decode_ascii85(a) {
  var c, d, e, f, g, h = String, l = "length", w = 255, x = "charCodeAt", y = "slice", z = "replace";
  for ("<~" === a[y](0, 2) && "~>" === a[y](-2), a = a[y](2, -2)[z](/\s/g, "")[z]("z", "!!!!!"), 
  c = "uuuuu"[y](a[l] % 5 || 5), a += c, e = [], f = 0, g = a[l]; g > f; f += 5) d = 52200625 * (a[x](f) - 33) + 614125 * (a[x](f + 1) - 33) + 7225 * (a[x](f + 2) - 33) + 85 * (a[x](f + 3) - 33) + (a[x](f + 4) - 33), 
  e.push(w & d >> 24, w & d >> 16, w & d >> 8, w & d);
  return function(a, b) {
    for (var c = b; c > 0; c--) a.pop();
  }(e, c[l]), h.fromCharCode.apply(h, e);
}
<input onKeyUp="result.innerHTML = decode_ascii85(this.value)" placeholder="insert encoded string here" type="text">
<p id="result"></p>
example: <xmp><~<+oue+DGm>@3BW*D/a<&+EV19F<L~></xmp>


1
这并没有回答问题。 - james.garriss
@james.garriss 这样可以让OP在他的上下文或实现中进行“并排”测试,从而回答问题(“Base64编码与Ascii85编码”或“是否存在任何Ascii85问题,这意味着我应该改用Base64?”)。 --- 提出的唯一其他问题,“有人知道更多关于这个主题吗?”,属于“过于宽泛”的类别。 --- 换句话说,我认为这是完全有效的答案。虽然实际的解释会是更好的答案。 - CosmicGiant

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接