This is an automated email from the ASF dual-hosted git repository.

aherbert pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/commons-codec.git


The following commit(s) were added to refs/heads/master by this push:
     new a6b2f13  CODEC-289: Add strict decoding to BaseNCodecInput/OutputStream
a6b2f13 is described below

commit a6b2f1329beec2cd9abb86dc2ea80300e9ccb77b
Author: Alex Herbert <aherb...@apache.org>
AuthorDate: Wed May 6 22:48:12 2020 +0100

    CODEC-289: Add strict decoding to BaseNCodecInput/OutputStream
---
 src/changes/changes.xml                            |  1 +
 .../codec/binary/BaseNCodecInputStream.java        | 34 ++++++++++++++++++++++
 .../codec/binary/BaseNCodecOutputStream.java       | 34 ++++++++++++++++++++++
 .../codec/binary/Base32InputStreamTest.java        | 28 ++++++++++++++++++
 .../codec/binary/Base32OutputStreamTest.java       | 33 +++++++++++++++++++++
 .../apache/commons/codec/binary/Base32Test.java    |  6 +++-
 .../codec/binary/Base64InputStreamTest.java        | 28 ++++++++++++++++++
 .../codec/binary/Base64OutputStreamTest.java       | 33 +++++++++++++++++++++
 .../apache/commons/codec/binary/Base64Test.java    |  6 +++-
 9 files changed, 201 insertions(+), 2 deletions(-)

diff --git a/src/changes/changes.xml b/src/changes/changes.xml
index f5996a3..5fc223b 100644
--- a/src/changes/changes.xml
+++ b/src/changes/changes.xml
@@ -45,6 +45,7 @@ The <action> type attribute can be add,update,fix,remove.
     <release version="1.15" date="YYYY-MM-DD" description="Feature and fix 
release.">
       <action issue="CODEC-264" dev="aherbert" due-to="Andy Seaborne" 
type="fix">MurmurHash3: Ensure hash128 maintains the sign extension 
bug.</action>
       <action issue="CODEC-280" dev="aherbert" 
type="update">Base32/Base64/BCodec: Added strict decoding property to control 
handling of trailing bits. Default lenient mode discards them without error. 
Strict mode raise an exception.</action>
+      <action issue="CODEC-289" dev="aherbert" type="update">Base32/Base64 
Input/OutputStream: Added strict decoding property to control handling of 
trailing bits. Default lenient mode discards them without error. Strict mode 
raise an exception.</action>
     </release>
 
     <release version="1.14" date="2019-12-30" description="Feature and fix 
release.">
diff --git 
a/src/main/java/org/apache/commons/codec/binary/BaseNCodecInputStream.java 
b/src/main/java/org/apache/commons/codec/binary/BaseNCodecInputStream.java
index 58f21fe..c183c43 100644
--- a/src/main/java/org/apache/commons/codec/binary/BaseNCodecInputStream.java
+++ b/src/main/java/org/apache/commons/codec/binary/BaseNCodecInputStream.java
@@ -48,6 +48,40 @@ public class BaseNCodecInputStream extends FilterInputStream 
{
     }
 
     /**
+     * Sets the decoding behavior when the input bytes contain leftover 
trailing bits that
+     * cannot be created by a valid encoding. This setting is transferred to 
the instance
+     * of {@link BaseNCodec} used to perform decoding.
+     *
+     * <p>The default is false for lenient encoding. Decoding will compose 
trailing bits
+     * into 8-bit bytes and discard the remainder.
+     *
+     * <p>Set to true to enable strict decoding. Decoding will raise an
+     * {@link IllegalArgumentException} if trailing bits are not part of a 
valid encoding.
+     *
+     * @param strictDecoding Set to true to enable strict decoding; otherwise 
use lenient decoding.
+     * @see BaseNCodec#setStrictDecoding(boolean)
+     * @since 1.15
+     */
+    public void setStrictDecoding(boolean strictDecoding) {
+        baseNCodec.setStrictDecoding(strictDecoding);
+    }
+
+    /**
+     * Returns true if decoding behavior is strict. Decoding will raise an
+     * {@link IllegalArgumentException} if trailing bits are not part of a 
valid encoding.
+     *
+     * <p>The default is false for lenient encoding. Decoding will compose 
trailing bits
+     * into 8-bit bytes and discard the remainder.
+     *
+     * @return true if using strict decoding
+     * @see #setStrictDecoding(boolean)
+     * @since 1.15
+     */
+    public boolean isStrictDecoding() {
+        return baseNCodec.isStrictDecoding();
+    }
+
+    /**
      * {@inheritDoc}
      *
      * @return {@code 0} if the {@link InputStream} has reached {@code EOF},
diff --git 
a/src/main/java/org/apache/commons/codec/binary/BaseNCodecOutputStream.java 
b/src/main/java/org/apache/commons/codec/binary/BaseNCodecOutputStream.java
index e6580d9..71b2a13 100644
--- a/src/main/java/org/apache/commons/codec/binary/BaseNCodecOutputStream.java
+++ b/src/main/java/org/apache/commons/codec/binary/BaseNCodecOutputStream.java
@@ -61,6 +61,40 @@ public class BaseNCodecOutputStream extends 
FilterOutputStream {
     }
 
     /**
+     * Sets the decoding behavior when the input bytes contain leftover 
trailing bits that
+     * cannot be created by a valid encoding. This setting is transferred to 
the instance
+     * of {@link BaseNCodec} used to perform decoding.
+     *
+     * <p>The default is false for lenient encoding. Decoding will compose 
trailing bits
+     * into 8-bit bytes and discard the remainder.
+     *
+     * <p>Set to true to enable strict decoding. Decoding will raise an
+     * {@link IllegalArgumentException} if trailing bits are not part of a 
valid encoding.
+     *
+     * @param strictDecoding Set to true to enable strict decoding; otherwise 
use lenient decoding.
+     * @see BaseNCodec#setStrictDecoding(boolean)
+     * @since 1.15
+     */
+    public void setStrictDecoding(boolean strictDecoding) {
+        baseNCodec.setStrictDecoding(strictDecoding);
+    }
+
+    /**
+     * Returns true if decoding behavior is strict. Decoding will raise an
+     * {@link IllegalArgumentException} if trailing bits are not part of a 
valid encoding.
+     *
+     * <p>The default is false for lenient encoding. Decoding will compose 
trailing bits
+     * into 8-bit bytes and discard the remainder.
+     *
+     * @return true if using strict decoding
+     * @see #setStrictDecoding(boolean)
+     * @since 1.15
+     */
+    public boolean isStrictDecoding() {
+        return baseNCodec.isStrictDecoding();
+    }
+
+    /**
      * Writes the specified {@code byte} to this output stream.
      *
      * @param i
diff --git 
a/src/test/java/org/apache/commons/codec/binary/Base32InputStreamTest.java 
b/src/test/java/org/apache/commons/codec/binary/Base32InputStreamTest.java
index e033741..85bcbb3 100644
--- a/src/test/java/org/apache/commons/codec/binary/Base32InputStreamTest.java
+++ b/src/test/java/org/apache/commons/codec/binary/Base32InputStreamTest.java
@@ -557,4 +557,32 @@ public class Base32InputStreamTest {
             b32stream.skip(-10);
         }
     }
+
+    /**
+     * Test strict decoding.
+     *
+     * @throws Exception
+     *             for some failure scenarios.
+     */
+    @Test
+    public void testStrictDecoding() throws Exception {
+        for (final String s : Base32Test.BASE32_IMPOSSIBLE_CASES) {
+            final byte[] encoded = StringUtils.getBytesUtf8(s);
+            Base32InputStream in = new Base32InputStream(new 
ByteArrayInputStream(encoded), false);
+            // Default is lenient decoding; it should not throw
+            assertFalse(in.isStrictDecoding());
+            Base32TestData.streamToBytes(in);
+
+            // Strict decoding should throw
+            in = new Base32InputStream(new ByteArrayInputStream(encoded), 
false);
+            in.setStrictDecoding(true);
+            assertTrue(in.isStrictDecoding());
+            try {
+                Base32TestData.streamToBytes(in);
+                fail();
+            } catch (final IllegalArgumentException ex) {
+                // expected
+            }
+        }
+    }
 }
diff --git 
a/src/test/java/org/apache/commons/codec/binary/Base32OutputStreamTest.java 
b/src/test/java/org/apache/commons/codec/binary/Base32OutputStreamTest.java
index 4486289..2cb09e0 100644
--- a/src/test/java/org/apache/commons/codec/binary/Base32OutputStreamTest.java
+++ b/src/test/java/org/apache/commons/codec/binary/Base32OutputStreamTest.java
@@ -17,6 +17,7 @@
 
 package org.apache.commons.codec.binary;
 
+import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
@@ -333,4 +334,36 @@ public class Base32OutputStreamTest {
         }
     }
 
+    /**
+     * Test strict decoding.
+     *
+     * @throws Exception
+     *             for some failure scenarios.
+     */
+    @Test
+    public void testStrictDecoding() throws Exception {
+        for (final String s : Base32Test.BASE32_IMPOSSIBLE_CASES) {
+            final byte[] encoded = StringUtils.getBytesUtf8(s);
+            ByteArrayOutputStream bout = new ByteArrayOutputStream();
+            Base32OutputStream out = new Base32OutputStream(bout, false);
+            // Default is lenient decoding; it should not throw
+            assertFalse(out.isStrictDecoding());
+            out.write(encoded);
+            out.close();
+            assertTrue(bout.size() > 0);
+
+            // Strict decoding should throw
+            bout = new ByteArrayOutputStream();
+            out = new Base32OutputStream(bout, false);
+            out.setStrictDecoding(true);
+            assertTrue(out.isStrictDecoding());
+            try {
+                out.write(encoded);
+                out.close();
+                fail();
+            } catch (final IllegalArgumentException ex) {
+                // expected
+            }
+        }
+    }
 }
diff --git a/src/test/java/org/apache/commons/codec/binary/Base32Test.java 
b/src/test/java/org/apache/commons/codec/binary/Base32Test.java
index 51d528e..7033e91 100644
--- a/src/test/java/org/apache/commons/codec/binary/Base32Test.java
+++ b/src/test/java/org/apache/commons/codec/binary/Base32Test.java
@@ -48,7 +48,11 @@ public class Base32Test {
         {"foobar" ,"MZXW6YTBOI======"},
     };
 
-    private static final String[] BASE32_IMPOSSIBLE_CASES = {
+    /**
+     * Example test cases with valid characters but impossible combinations of
+     * trailing characters (i.e. cannot be created during encoding).
+     */
+    static final String[] BASE32_IMPOSSIBLE_CASES = {
         "MC======",
         "MZXE====",
         "MZXWB===",
diff --git 
a/src/test/java/org/apache/commons/codec/binary/Base64InputStreamTest.java 
b/src/test/java/org/apache/commons/codec/binary/Base64InputStreamTest.java
index 60dd122..2b1f5cf 100644
--- a/src/test/java/org/apache/commons/codec/binary/Base64InputStreamTest.java
+++ b/src/test/java/org/apache/commons/codec/binary/Base64InputStreamTest.java
@@ -570,4 +570,32 @@ public class Base64InputStreamTest {
             b64stream.skip(-10);
         }
     }
+
+    /**
+     * Test strict decoding.
+     *
+     * @throws Exception
+     *             for some failure scenarios.
+     */
+    @Test
+    public void testStrictDecoding() throws Exception {
+        for (final String s : Base64Test.BASE64_IMPOSSIBLE_CASES) {
+            final byte[] encoded = StringUtils.getBytesUtf8(s);
+            Base64InputStream in = new Base64InputStream(new 
ByteArrayInputStream(encoded), false);
+            // Default is lenient decoding; it should not throw
+            assertFalse(in.isStrictDecoding());
+            Base64TestData.streamToBytes(in);
+
+            // Strict decoding should throw
+            in = new Base64InputStream(new ByteArrayInputStream(encoded), 
false);
+            in.setStrictDecoding(true);
+            assertTrue(in.isStrictDecoding());
+            try {
+                Base64TestData.streamToBytes(in);
+                fail();
+            } catch (final IllegalArgumentException ex) {
+                // expected
+            }
+        }
+    }
 }
diff --git 
a/src/test/java/org/apache/commons/codec/binary/Base64OutputStreamTest.java 
b/src/test/java/org/apache/commons/codec/binary/Base64OutputStreamTest.java
index 25ff22f..b644363 100644
--- a/src/test/java/org/apache/commons/codec/binary/Base64OutputStreamTest.java
+++ b/src/test/java/org/apache/commons/codec/binary/Base64OutputStreamTest.java
@@ -18,6 +18,7 @@
 package org.apache.commons.codec.binary;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
@@ -341,4 +342,36 @@ public class Base64OutputStreamTest {
         }
     }
 
+    /**
+     * Test strict decoding.
+     *
+     * @throws Exception
+     *             for some failure scenarios.
+     */
+    @Test
+    public void testStrictDecoding() throws Exception {
+        for (final String s : Base64Test.BASE64_IMPOSSIBLE_CASES) {
+            final byte[] encoded = StringUtils.getBytesUtf8(s);
+            ByteArrayOutputStream bout = new ByteArrayOutputStream();
+            Base64OutputStream out = new Base64OutputStream(bout, false);
+            // Default is lenient decoding; it should not throw
+            assertFalse(out.isStrictDecoding());
+            out.write(encoded);
+            out.close();
+            assertTrue(bout.size() > 0);
+
+            // Strict decoding should throw
+            bout = new ByteArrayOutputStream();
+            out = new Base64OutputStream(bout, false);
+            out.setStrictDecoding(true);
+            assertTrue(out.isStrictDecoding());
+            try {
+                out.write(encoded);
+                out.close();
+                fail();
+            } catch (final IllegalArgumentException ex) {
+                // expected
+            }
+        }
+    }
 }
diff --git a/src/test/java/org/apache/commons/codec/binary/Base64Test.java 
b/src/test/java/org/apache/commons/codec/binary/Base64Test.java
index dcccef6..8d79f59 100644
--- a/src/test/java/org/apache/commons/codec/binary/Base64Test.java
+++ b/src/test/java/org/apache/commons/codec/binary/Base64Test.java
@@ -45,7 +45,11 @@ public class Base64Test {
 
     private static final Charset CHARSET_UTF8 = StandardCharsets.UTF_8;
 
-    private static final String[] BASE64_IMPOSSIBLE_CASES = {
+    /**
+     * Example test cases with valid characters but impossible combinations of
+     * trailing characters (i.e. cannot be created during encoding).
+     */
+    static final String[] BASE64_IMPOSSIBLE_CASES = {
         "ZE==",
         "ZmC=",
         "Zm9vYE==",

Reply via email to