Skip to content

Commit 165d33f

Browse files
committed
[#CODEC-80] Regression: Base64.encode(chunk=true) has bug when input length is multiple of 76.
git-svn-id: https://svn.apache.org/repos/asf/commons/proper/codec/trunk@797284 13f79535-47bb-0310-9956-ffa450edef68
1 parent 3463e5a commit 165d33f

5 files changed

Lines changed: 49 additions & 11 deletions

File tree

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

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -729,7 +729,11 @@ public static byte[] encodeBase64(byte[] binaryData, boolean isChunked, boolean
729729
len += 4 - mod;
730730
}
731731
if (isChunked) {
732-
len += (1 + (len / CHUNK_SIZE)) * CHUNK_SEPARATOR.length;
732+
boolean lenChunksPerfectly = len % CHUNK_SIZE == 0;
733+
len += (len / CHUNK_SIZE) * CHUNK_SEPARATOR.length;
734+
if (!lenChunksPerfectly) {
735+
len += CHUNK_SEPARATOR.length;
736+
}
733737
}
734738
if (len > Integer.MAX_VALUE) {
735739
throw new IllegalArgumentException("Input array too big, output array would be bigger than Integer.MAX_VALUE=" +

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

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -77,12 +77,12 @@ public void testBase64InputStreamByChunk() throws Exception {
7777
testByChunk(encoded, decoded, 76, CRLF);
7878

7979
// OpenSSL interop test.
80-
encoded = StringBytesUtils.getBytesUtf8(Base64TestData.ENCODED);
80+
encoded = StringBytesUtils.getBytesUtf8(Base64TestData.ENCODED_64_CHARS_PER_LINE);
8181
decoded = Base64TestData.DECODED;
8282
testByChunk(encoded, decoded, 64, LF);
8383

8484
// Single Line test.
85-
String singleLine = Base64TestData.ENCODED.replaceAll("\n", "");
85+
String singleLine = Base64TestData.ENCODED_64_CHARS_PER_LINE.replaceAll("\n", "");
8686
encoded = StringBytesUtils.getBytesUtf8(singleLine);
8787
decoded = Base64TestData.DECODED;
8888
testByChunk(encoded, decoded, 0, LF);
@@ -114,12 +114,12 @@ public void testBase64InputStreamByteByByte() throws Exception {
114114
testByteByByte(encoded, decoded, 76, CRLF);
115115

116116
// OpenSSL interop test.
117-
encoded = StringBytesUtils.getBytesUtf8(Base64TestData.ENCODED);
117+
encoded = StringBytesUtils.getBytesUtf8(Base64TestData.ENCODED_64_CHARS_PER_LINE);
118118
decoded = Base64TestData.DECODED;
119119
testByteByByte(encoded, decoded, 64, LF);
120120

121121
// Single Line test.
122-
String singleLine = Base64TestData.ENCODED.replaceAll("\n", "");
122+
String singleLine = Base64TestData.ENCODED_64_CHARS_PER_LINE.replaceAll("\n", "");
123123
encoded = StringBytesUtils.getBytesUtf8(singleLine);
124124
decoded = Base64TestData.DECODED;
125125
testByteByByte(encoded, decoded, 0, LF);

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

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -77,12 +77,12 @@ public void testBase64OutputStreamByChunk() throws Exception {
7777
testByChunk(encoded, decoded, 76, CRLF);
7878

7979
// OpenSSL interop test.
80-
encoded = StringBytesUtils.getBytesUtf8(Base64TestData.ENCODED);
80+
encoded = StringBytesUtils.getBytesUtf8(Base64TestData.ENCODED_64_CHARS_PER_LINE);
8181
decoded = Base64TestData.DECODED;
8282
testByChunk(encoded, decoded, 64, LF);
8383

8484
// Single Line test.
85-
String singleLine = Base64TestData.ENCODED.replaceAll("\n", "");
85+
String singleLine = Base64TestData.ENCODED_64_CHARS_PER_LINE.replaceAll("\n", "");
8686
encoded = StringBytesUtils.getBytesUtf8(singleLine);
8787
decoded = Base64TestData.DECODED;
8888
testByChunk(encoded, decoded, 0, LF);
@@ -114,12 +114,12 @@ public void testBase64OutputStreamByteByByte() throws Exception {
114114
testByteByByte(encoded, decoded, 76, CRLF);
115115

116116
// OpenSSL interop test.
117-
encoded = StringBytesUtils.getBytesUtf8(Base64TestData.ENCODED);
117+
encoded = StringBytesUtils.getBytesUtf8(Base64TestData.ENCODED_64_CHARS_PER_LINE);
118118
decoded = Base64TestData.DECODED;
119119
testByteByByte(encoded, decoded, 64, LF);
120120

121121
// Single Line test.
122-
String singleLine = Base64TestData.ENCODED.replaceAll("\n", "");
122+
String singleLine = Base64TestData.ENCODED_64_CHARS_PER_LINE.replaceAll("\n", "");
123123
encoded = StringBytesUtils.getBytesUtf8(singleLine);
124124
decoded = Base64TestData.DECODED;
125125
testByteByByte(encoded, decoded, 0, LF);

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

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -592,11 +592,11 @@ public void testObjectDecodeWithValidParameter() throws Exception {
592592

593593
public void testObjectEncodeWithInvalidParameter() throws Exception {
594594
Base64 b64 = new Base64();
595-
596595
try {
597596
b64.encode("Yadayadayada");
598597
fail("encode(Object) didn't throw an exception when passed a String object");
599598
} catch (EncoderException e) {
599+
// Expected
600600
}
601601
}
602602

@@ -893,6 +893,20 @@ public void testEmptyBase64() {
893893
assertEquals("empty base64 encode", null, Base64.decodeBase64(null));
894894
}
895895

896+
/**
897+
* Tests Base64.encodeToString() and Base64.decodeFromString() methods.
898+
*
899+
* @throws Exception
900+
*/
901+
public void testChunkedEncodeMultipleOf76() throws Exception {
902+
byte[] expectedEncode = Base64.encodeBase64(Base64TestData.DECODED, true);
903+
// convert to "\n" so we're 100% equal to the old openssl encoding test stored
904+
// in Base64TestData.ENCODED_76_CHARS_PER_LINE:
905+
String actualResult = Base64TestData.ENCODED_76_CHARS_PER_LINE.replaceAll("\n", "\r\n");
906+
byte[] actualEncode = actualResult.getBytes("UTF-8");
907+
assertTrue("chunkedEncodeMultipleOf76", Arrays.equals(expectedEncode, actualEncode));
908+
}
909+
896910
// -------------------------------------------------------- Private Methods
897911

898912
private String toString(byte[] data) {

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

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ public class Base64TestData {
3333

3434
// OpenSSL doesn't include the final \n, but it would be annoying beyond belief
3535
// to further parameterize commons-codec to support this pointless variation.
36-
final static String ENCODED
36+
final static String ENCODED_64_CHARS_PER_LINE
3737
= "9IPNKwUvdLiIAp6ctz12SiQmOGstWyYvSPeevufDhrzaws65voykKjbIj33YWTa9\n"
3838
+ "xA7c/FHypWclrZhQ7onfc3JE93BJ5fT4R9zAEdjbjy1hv4ZYNnET4WJeXMLJ/5p+\n"
3939
+ "qBpTsPpepW8DNVYy1c02/1wyC+kgA6CvRUd9cSr/lt88AEdsTV4GMCn1+EwuAiYd\n"
@@ -57,6 +57,26 @@ public class Base64TestData {
5757
+ "/6YAHZilo8at0OpkkNdNFuhwuGlkBqrZKNUj/gSiYYc06gF/r/z6iWAjpXJRW1qq\n"
5858
+ "3CLZXdZFZ/VrqXeVjtOAu2A=\n";
5959

60+
final static String ENCODED_76_CHARS_PER_LINE
61+
= "9IPNKwUvdLiIAp6ctz12SiQmOGstWyYvSPeevufDhrzaws65voykKjbIj33YWTa9xA7c/FHypWcl\n"
62+
+ "rZhQ7onfc3JE93BJ5fT4R9zAEdjbjy1hv4ZYNnET4WJeXMLJ/5p+qBpTsPpepW8DNVYy1c02/1wy\n"
63+
+ "C+kgA6CvRUd9cSr/lt88AEdsTV4GMCn1+EwuAiYdivxuzn+cLM8q2jewqlI52tP9J7Cs8vqG71s6\n"
64+
+ "+WAELKvm/UovvyaOi+OdMUfjQ0JLiLkHu6p9OwUgvQqiDKzEv/Augo0dTPZzYGEyCP5GVrle3QQd\n"
65+
+ "gciIHnpdd4VUTPGRUbXeKbh++U3fbJIng/sQXM3IYByMZ7xt9HWS1LUcRdQ7Prwn/IlQWxOMeq+K\n"
66+
+ "ZJSoAviWtdserXyHbIEa//hmr4p/j80k0g9q35hq1ayGM9984ALTSaZ8WeyFbZx1CxC/Qoqf92UH\n"
67+
+ "/ylBRnSJNn4sS0oa3uUbNvOnpkB4D9V7Ut9atinCJrw+wiJcMl+9kp251IUxBGA4cUxh0eaxk3OD\n"
68+
+ "WnwI95EktmWOKwCSP0xjWwIMxDjygwAG5R8fk9H9bVi1thMavm4nDc4vaNoSE1RnZNYwbiUVlVPM\n"
69+
+ "9EclvJWTWd6igWeA0MxHAA8iOM5Vnmqp/WGM7UDq59rBIdNQCoeTJaAkEtAuLL5zogOa5e+MzVjv\n"
70+
+ "B5MYQlOlaaTtQrRApXa5Z4VfEanu9UK2fi1T8jJPFC2PmXebxp0bnO+VW+bgyEdIIkIQCaZq1MKW\n"
71+
+ "C3KuiOS9BJ1t7O0A2JKJKvoE4UNulzV2TGCC+KAnmjRqQBqXlJmgjHQAoHNZKOma/uIQOsvfDnqi\n"
72+
+ "cYdDmfyCYuV89HjA1H8tiDJ85VfsrFHdcbPAoNCpi65awJSHfdPO1NDONOK++S7Y0VXUgoYYrBV4\n"
73+
+ "Y7YbC8wg/nqcimr3lm3tRyp+QsgKzdREbfNRk0F5PLyLfsUElepjs1QdV3fEV1LJtiywA3ubVNQJ\n"
74+
+ "RxhbYxa/C/Xy2qxpm6vvdL92l3q1ccev35IcaOiSx7Im+/GxV2lVKdaOvYVGDD1zBRe6Y2CwQb9p\n"
75+
+ "088l3/93qGR5593NCiuPPWcsDWwUShM1EyW0FNX1F8bnzHnYijoyE/jf4s/l9bBd7yJdRWRCyih2\n"
76+
+ "WcypAiOIEkBsH+dCTgalu8sRDoMh4ZIBBdgHfoZUycLqReQFLZZ4Sl4zSmzt5vQxQFhEKb9+ff/4\n"
77+
+ "rb1KAo6wifengxVfIsa2b5ljXzAqXs7JkPvmC6fa7X4ZZndRokaxYlu3cg8OV+uG/6YAHZilo8at\n"
78+
+ "0OpkkNdNFuhwuGlkBqrZKNUj/gSiYYc06gF/r/z6iWAjpXJRW1qq3CLZXdZFZ/VrqXeVjtOAu2A=\n";
79+
6080
final static byte[] DECODED
6181
= {-12, -125, -51, 43, 5, 47, 116, -72, -120, 2, -98, -100, -73, 61, 118, 74, 36, 38, 56, 107, 45, 91, 38,
6282
47, 72, -9, -98, -66, -25, -61, -122, -68, -38, -62, -50, -71, -66, -116, -92, 42, 54, -56, -113, 125,

0 commit comments

Comments
 (0)