Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Merge pull request #2715 from jruby/strict-base64-encoding
implements strict base64 encoding
  • Loading branch information
mkristian committed Mar 19, 2015
2 parents adeb887 + 13ff7bf commit aabe84c
Show file tree
Hide file tree
Showing 3 changed files with 105 additions and 43 deletions.
139 changes: 97 additions & 42 deletions core/src/main/java/org/jruby/util/Pack.java
Expand Up @@ -1259,61 +1259,116 @@ else if (encode.hasRemaining()) {
int index = 0;
int s = -1;

while (encode.hasRemaining()) {
a = b = c = d = -1;

// obtain a
s = safeGet(encode);
while (((a = b64_xtable[s]) == -1) && encode.hasRemaining()) {
s = safeGet(encode);
if (occurrences == 0){
if (encode.remaining()%4 != 0) {
throw runtime.newArgumentError("invalid base64");
}
if (a == -1) break;

// obtain b
s = safeGet(encode);
while (((b = b64_xtable[s]) == -1) && encode.hasRemaining()) {
while (encode.hasRemaining() && s != '=') {
a = b = c = -1;
d = -2;

// obtain a
s = safeGet(encode);
}
if (b == -1) break;

// obtain c
s = safeGet(encode);
while (((c = b64_xtable[s]) == -1) && encode.hasRemaining()) {
if (s == '=') break;
a = b64_xtable[s];
if (a == -1) throw runtime.newArgumentError("invalid base64");

// obtain b
s = safeGet(encode);
}
if ((s == '=') || c == -1) {
b = b64_xtable[s];
if (b == -1) throw runtime.newArgumentError("invalid base64");

// obtain c
s = safeGet(encode);
c = b64_xtable[s];
if (s == '=') {
encode.position(encode.position() - 1);
if (safeGet(encode) != '=') throw runtime.newArgumentError("invalid base64");
break;
}
break;
}

// obtain d
s = safeGet(encode);
while (((d = b64_xtable[s]) == -1) && encode.hasRemaining()) {
if (s == '=') break;
if (c == -1) throw runtime.newArgumentError("invalid base64");

// obtain d
s = safeGet(encode);
d = b64_xtable[s];
if (s == '=') break;
if (d == -1) throw runtime.newArgumentError("invalid base64");

// calculate based on a, b, c and d
lElem[index++] = (byte)((a << 2 | b >> 4) & 255);
lElem[index++] = (byte)((b << 4 | c >> 2) & 255);
lElem[index++] = (byte)((c << 6 | d) & 255);
}
if ((s == '=') || d == -1) {
if (s == '=') {
encode.position(encode.position() - 1);

if (encode.hasRemaining()) throw runtime.newArgumentError("invalid base64");

if (a != -1 && b != -1) {
if (c == -1 && s == '=') {
if ((b & 15) > 0) throw runtime.newArgumentError("invalid base64");
lElem[index++] = (byte)((a << 2 | b >> 4) & 255);
} else if(c != -1 && s == '=') {
if ((c & 3) > 0) throw runtime.newArgumentError("invalid base64");
lElem[index++] = (byte)((a << 2 | b >> 4) & 255);
lElem[index++] = (byte)((b << 4 | c >> 2) & 255);
}
break;
}

// calculate based on a, b, c and d
lElem[index++] = (byte)((a << 2 | b >> 4) & 255);
lElem[index++] = (byte)((b << 4 | c >> 2) & 255);
lElem[index++] = (byte)((c << 6 | d) & 255);
}
else {

if (a != -1 && b != -1) {
if (c == -1 && s == '=') {
lElem[index++] = (byte)((a << 2 | b >> 4) & 255);
} else if(c != -1 && s == '=') {
while (encode.hasRemaining()) {
a = b = c = d = -1;

// obtain a
s = safeGet(encode);
while (((a = b64_xtable[s]) == -1) && encode.hasRemaining()) {
s = safeGet(encode);
}
if (a == -1) break;

// obtain b
s = safeGet(encode);
while (((b = b64_xtable[s]) == -1) && encode.hasRemaining()) {
s = safeGet(encode);
}
if (b == -1) break;

// obtain c
s = safeGet(encode);
while (((c = b64_xtable[s]) == -1) && encode.hasRemaining()) {
if (s == '=') break;
s = safeGet(encode);
}
if ((s == '=') || c == -1) {
if (s == '=') {
encode.position(encode.position() - 1);
}
break;
}

// obtain d
s = safeGet(encode);
while (((d = b64_xtable[s]) == -1) && encode.hasRemaining()) {
if (s == '=') break;
s = safeGet(encode);
}
if ((s == '=') || d == -1) {
if (s == '=') {
encode.position(encode.position() - 1);
}
break;
}

// calculate based on a, b, c and d
lElem[index++] = (byte)((a << 2 | b >> 4) & 255);
lElem[index++] = (byte)((b << 4 | c >> 2) & 255);
lElem[index++] = (byte)((c << 6 | d) & 255);
}

if (a != -1 && b != -1) {
if (c == -1 && s == '=') {
lElem[index++] = (byte)((a << 2 | b >> 4) & 255);
} else if(c != -1 && s == '=') {
lElem[index++] = (byte)((a << 2 | b >> 4) & 255);
lElem[index++] = (byte)((b << 4 | c >> 2) & 255);
}
}
}
result.append(RubyString.newString(runtime, new ByteList(lElem, 0, index,
Expand Down
1 change: 0 additions & 1 deletion test/externals/ruby1.9/excludes/TestBase64.rb

This file was deleted.

8 changes: 8 additions & 0 deletions test/test_base64_strangeness.rb
Expand Up @@ -9,3 +9,11 @@ def test_base64_strangeness
assert !Class.private_instance_methods.include?('encode64')
end
end

# be strict GH-2551
class TestBase64Strangeness < Test::Unit::TestCase
def test_base64_stictness
require 'base64'
assert_raise(ArgumentError) { Base64.strict_decode64("AA==AAAA") }
end
end if RUBY_VERSION >= '1.9'

0 comments on commit aabe84c

Please sign in to comment.