Skip to content

Commit ddafa8f

Browse files
author
Timothy O'Brien
committed
Fix for Bug 19860: Modified Base64 to remedy non-compliance with RFC 2045. Non-Base64 characters were not being discarded during the decode. RFC 2045 explicitly states that all characters outside of the base64 alphabet are to be ignored. A new function discardNonBase64 is called prior to a decode. Note that isArrayBase64 only discards whitespace before testing the contents of an encoded byte array. Unit tests for Base64 were updated to reflect the changes related to discarding non-Base64 characters.
git-svn-id: https://svn.apache.org/repos/asf/jakarta/commons/proper/codec/trunk@130141 13f79535-47bb-0310-9956-ffa450edef68
1 parent 4f10ae2 commit ddafa8f

2 files changed

Lines changed: 66 additions & 41 deletions

File tree

src/java/org/apache/commons/codec/binary/Base64.java

Lines changed: 33 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/*
2-
* $Header: /home/jerenkrantz/tmp/commons/commons-convert/cvs/home/cvs/jakarta-commons//codec/src/java/org/apache/commons/codec/binary/Base64.java,v 1.2 2003/05/06 20:52:18 ggregory Exp $
3-
* $Revision: 1.2 $
4-
* $Date: 2003/05/06 20:52:18 $
2+
* $Header: /home/jerenkrantz/tmp/commons/commons-convert/cvs/home/cvs/jakarta-commons//codec/src/java/org/apache/commons/codec/binary/Base64.java,v 1.3 2003/05/14 02:40:18 tobrien Exp $
3+
* $Revision: 1.3 $
4+
* $Date: 2003/05/14 02:40:18 $
55
*
66
* ====================================================================
77
*
@@ -196,19 +196,8 @@ public Object decode(Object pObject) throws DecoderException {
196196
}
197197

198198
public byte[] decode(byte[] pArray) throws DecoderException {
199-
200199
byte[] result;
201-
202-
if (!isArrayByteBase64(pArray)) {
203-
throw new DecoderException(
204-
"Parameter supplied to "
205-
+ "Base64 "
206-
+ "decode is not a valid base64 data.");
207-
}
208-
else {
209-
result = decodeBase64((byte[]) pArray);
210-
}
211-
200+
result = decodeBase64((byte[]) pArray);
212201
return (result);
213202
}
214203

@@ -375,9 +364,8 @@ else if (fewerThan24bits == SIXTEENBIT) {
375364
* @return Array containing decoded data.
376365
*/
377366
public static byte[] decodeBase64(byte[] base64Data) {
378-
// RFC 2045 suggests line wrapping at (no more than) 76
379-
// characters -- we may have embedded whitespace.
380-
base64Data = discardWhitespace(base64Data);
367+
// RFC 2045 requires that we discard ALL non-Base64 characters
368+
base64Data = discardNonBase64(base64Data);
381369

382370
// handle the edge case, so we don't have to worry about it later
383371
if (base64Data.length == 0) {
@@ -468,6 +456,33 @@ static byte[] discardWhitespace(byte[] data) {
468456

469457
return packedData;
470458
}
459+
460+
/**
461+
* Discards any characters outside of the base64 alphabet, per
462+
* the requirements on page 25 of RFC 2045 - "Any characters
463+
* outside of the base64 alphabet are to be ignored in base64
464+
* encoded data."
465+
*
466+
* @param data The base-64 encoded data to groom
467+
* @return The data, less non-base64 characters (see RFC 2045).
468+
*/
469+
static byte[] discardNonBase64(byte[] data) {
470+
byte groomedData[] = new byte[data.length];
471+
int bytesCopied = 0;
472+
473+
for (int i = 0; i < data.length; i++) {
474+
if( isBase64(data[i]) ) {
475+
groomedData[bytesCopied++] = data[i];
476+
}
477+
}
478+
479+
byte packedData[] = new byte[bytesCopied];
480+
481+
System.arraycopy(groomedData, 0, packedData, 0, bytesCopied);
482+
483+
return packedData;
484+
}
485+
471486

472487
// Implementation of the Encoder Interface
473488

src/test/org/apache/commons/codec/binary/Base64Test.java

Lines changed: 33 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/*
2-
* $Header: /home/jerenkrantz/tmp/commons/commons-convert/cvs/home/cvs/jakarta-commons//codec/src/test/org/apache/commons/codec/binary/Base64Test.java,v 1.2 2003/05/06 20:45:16 ggregory Exp $
3-
* $Revision: 1.2 $
4-
* $Date: 2003/05/06 20:45:16 $
2+
* $Header: /home/jerenkrantz/tmp/commons/commons-convert/cvs/home/cvs/jakarta-commons//codec/src/test/org/apache/commons/codec/binary/Base64Test.java,v 1.3 2003/05/14 02:40:18 tobrien Exp $
3+
* $Revision: 1.3 $
4+
* $Date: 2003/05/14 02:40:18 $
55
*
66
* ====================================================================
77
*
@@ -67,7 +67,7 @@
6767
import junit.framework.TestCase;
6868

6969
/**
70-
* @version $Revision: 1.2 $ $Date: 2003/05/06 20:45:16 $
70+
* @version $Revision: 1.3 $ $Date: 2003/05/14 02:40:18 $
7171
* @author <a href="mailto:sanders@apache.org">Scott Sanders</a>
7272
* @author <a href="mailto:rwaldhoff@apache.org">Rodney Waldhoff</a>
7373
* @author <a href="mailto:tobrien@apache.org">Tim O'Brien</a>
@@ -313,28 +313,38 @@ public void testKnownDecodings() {
313313
assertEquals("xyzzy!",new String(Base64.decodeBase64("eHl6enkh".getBytes())));
314314
}
315315

316-
public void testNonBase64() throws Exception {
316+
public void testNonBase64Test() throws Exception {
317317

318-
byte[] bArray = { '%' };
318+
byte[] bArray = { '%' };
319319

320-
assertFalse( "Invalid Base64 array was incorrectly validated as " +
321-
"an array of Base64 encoded data",
322-
Base64.isArrayByteBase64( bArray ) );
320+
assertFalse( "Invalid Base64 array was incorrectly validated as " +
321+
"an array of Base64 encoded data",
322+
Base64.isArrayByteBase64( bArray ) );
323323

324-
boolean exceptionThrown = false;
325-
326-
try {
327-
Base64 b64 = new Base64();
328-
b64.decode( bArray );
329-
}
330-
catch( Exception e ) {
331-
exceptionThrown = true;
332-
}
333-
334-
assertTrue( "Exception wasn't thrown when trying to decode " +
335-
"invalid base64 encoded data", exceptionThrown );
336-
337-
}
324+
boolean exceptionThrown = false;
325+
326+
try {
327+
Base64 b64 = new Base64();
328+
byte[] result = b64.decode( bArray );
329+
330+
assertTrue( "The result should be empty as the test encoded content did " +
331+
"not contain any valid base 64 characters", result.length == 0);
332+
}
333+
catch( Exception e ) {
334+
exceptionThrown = true;
335+
}
336+
337+
assertFalse( "Exception was thrown when trying to decode " +
338+
"invalid base64 encoded data - RFC 2045 requires that all " +
339+
"non base64 character be discarded, an exception should not" +
340+
" have been thrown", exceptionThrown );
341+
342+
343+
}
344+
345+
public void testIgnoringNonBase64InDecode() throws Exception {
346+
assertEquals("The quick brown fox jumped over the lazy dogs.",new String(Base64.decodeBase64("VGhlIH@$#$@%F1aWN@#@#@@rIGJyb3duIGZve\n\r\t%#%#%#%CBqd##$#$W1wZWQgb3ZlciB0aGUgbGF6eSBkb2dzLg==".getBytes())));
347+
}
338348

339349
public void testObjectDecodeWithInvalidParameter() throws Exception {
340350
boolean exceptionThrown = false;

0 commit comments

Comments
 (0)