Encoding Decoding + and / has unexpected results in Jest
trajano opened this issue · 2 comments
trajano commented
it('base64 migration test 5', () => {
const decoded = base64.decode("da+//Z==");
expect(decoded).toHaveLength(4);
expect(base64.encode(decoded, true)).toBe("da-__Z"); // this fails
expect(base64.encode(decoded, false)).toBe("da+//Z=="); // this fails
})
Just to make sure it's not because of encoding I tested with this as well
it('base64 migration test 5', () => {
const specimen = "+s/s/Z==";
const decoded = base64.toUint8Array(specimen);
expect(decoded).toHaveLength(4);
expect(base64.fromUint8Array(decoded, false)).toBe(specimen); // fails here.
expect(base64.fromUint8Array(decoded, true)).toBe("-s_s_Z");
})
dankogai commented
No. They do not supposed to round-trip because the given base64-encode strings are somewhat malformed.
decode_encode.pl
#!/usr/bin/env perl
use strict;
use warnings;
use MIME::Base64;
print encode_base64(decode_base64(shift)), "\n";
$ ./decode_encode.pl da+//Z==
da+//Q==
decode_encode.py
#!/usr/bin/env python
import sys
import base64
print(base64.b64encode(base64.b64decode(sys.argv[1])))
$ ./decode_encode.py da+//Z==
b'da+//Q=='
decode_encode.rb
#!/usr/bin/env ruby
require 'base64'
puts Base64.encode64(Base64.decode64(ARGV.shift))
./decode_encode.rb da+//Z==
da+//Q==
The trick is the last character can be anything between Q
and f
. da+//R==
, da+//S==
… and of course, da+//Z==
(and da+//f==
). The trick is that the lower 4 bits are truncated in this case. Q
represents 0b010000
and only upper 2 bits matter. Virtually all encoders including this module choose Q
but as I said [Q-Za-f]
are accidentally acceptable.
trajano commented
Thanks for the explanation