Skip to content

Commit

Permalink
base64_decode can decode padded or unpadded encodings (#4015)
Browse files Browse the repository at this point in the history
  • Loading branch information
jannotti committed May 22, 2022
1 parent d06c9aa commit 4a922c4
Show file tree
Hide file tree
Showing 2 changed files with 27 additions and 19 deletions.
22 changes: 20 additions & 2 deletions data/transactions/logic/eval.go
Original file line number Diff line number Diff line change
Expand Up @@ -4716,6 +4716,21 @@ func base64Decode(encoded []byte, encoding *base64.Encoding) ([]byte, error) {
return decoded[:n], err
}

// base64padded returns true iff `encoded` has padding chars at the end
func base64padded(encoded []byte) bool {
for i := len(encoded) - 1; i > 0; i-- {
switch encoded[i] {
case '=':
return true
case '\n', '\r':
/* nothing */
default:
return false
}
}
return false
}

func opBase64Decode(cx *EvalContext) error {
last := len(cx.stack) - 1
encodingField := Base64Encoding(cx.program[cx.pc+1])
Expand All @@ -4728,8 +4743,11 @@ func opBase64Decode(cx *EvalContext) error {
if encodingField == StdEncoding {
encoding = base64.StdEncoding
}
encoding = encoding.Strict()
bytes, err := base64Decode(cx.stack[last].Bytes, encoding)
encoded := cx.stack[last].Bytes
if !base64padded(encoded) {
encoding = encoding.WithPadding(base64.NoPadding)
}
bytes, err := base64Decode(encoded, encoding.Strict())
if err != nil {
return err
}
Expand Down
24 changes: 7 additions & 17 deletions data/transactions/logic/eval_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4649,12 +4649,12 @@ By Herman Melville`, "",
{"cGFk=", "StdEncoding", "pad", "input byte 4"},
{"cGFk==", "StdEncoding", "pad", "input byte 4"},
{"cGFk===", "StdEncoding", "pad", "input byte 4"},
// Ensures that even correct padding is illegal if not needed
// Ensures that extra padding, even if 0%4
{"cGFk====", "StdEncoding", "pad", "input byte 4"},

// Test that padding must be present to make len = 0 mod 4.
// Test that padding must be correct or absent
{"bm9wYWQ=", "StdEncoding", "nopad", ""},
{"bm9wYWQ", "StdEncoding", "nopad", "illegal"},
{"bm9wYWQ", "StdEncoding", "nopad", ""},
{"bm9wYWQ==", "StdEncoding", "nopad", "illegal"},

{"YWJjMTIzIT8kKiYoKSctPUB+", "StdEncoding", "abc123!?$*&()'-=@~", ""},
Expand Down Expand Up @@ -4690,15 +4690,15 @@ By Herman Melville`, "",
{"\rS\r\nQ=\n=\r\r\n", "StdEncoding", "I", ""},
{"\rS\r\nQ=\n=\r\r\n", "URLEncoding", "I", ""},

// Padding necessary? - Yes it is! And exactly the expected place and amount.
// If padding is there, it must be correct, but if absent, that's fine.
{"SQ==", "StdEncoding", "I", ""},
{"SQ==", "URLEncoding", "I", ""},
{"S=Q=", "StdEncoding", "", "byte 1"},
{"S=Q=", "URLEncoding", "", "byte 1"},
{"=SQ=", "StdEncoding", "", "byte 0"},
{"=SQ=", "URLEncoding", "", "byte 0"},
{"SQ", "StdEncoding", "", "byte 0"},
{"SQ", "URLEncoding", "", "byte 0"},
{"SQ", "StdEncoding", "I", ""},
{"SQ", "URLEncoding", "I", ""},
{"SQ=", "StdEncoding", "", "byte 3"},
{"SQ=", "URLEncoding", "", "byte 3"},
{"SQ===", "StdEncoding", "", "byte 4"},
Expand All @@ -4721,24 +4721,14 @@ By Herman Melville`, "",
if LogicVersion < fidoVersion {
testProg(t, source, AssemblerMaxVersion, Expect{0, "unknown opcode..."})
} else {
// sanity check - test the helper function first:
encoding := base64.URLEncoding
if tc.alph == "StdEncoding" {
encoding = base64.StdEncoding
}
encoding = encoding.Strict()
decoded, err := base64Decode([]byte(tc.encoded), encoding)
require.NoError(t, err)
require.Equal(t, string(decoded), tc.decoded)

// now check eval:
testAccepts(t, source, fidoVersion)
}
} else {
if LogicVersion < fidoVersion {
testProg(t, source, AssemblerMaxVersion, Expect{0, "unknown opcode..."})
} else {
err := testPanics(t, source, fidoVersion)
require.Error(t, err)
require.Contains(t, err.Error(), tc.error)
}
}
Expand Down

0 comments on commit 4a922c4

Please sign in to comment.