add char[] constructors to SevenZFile
Project: http://git-wip-us.apache.org/repos/asf/commons-compress/repo Commit: http://git-wip-us.apache.org/repos/asf/commons-compress/commit/237e1721 Tree: http://git-wip-us.apache.org/repos/asf/commons-compress/tree/237e1721 Diff: http://git-wip-us.apache.org/repos/asf/commons-compress/diff/237e1721 Branch: refs/heads/COMPRESS-452 Commit: 237e1721221d158f6800e868cbefc83f02385029 Parents: 3eeb22c Author: Stefan Bodewig <bode...@apache.org> Authored: Mon May 7 08:08:45 2018 +0200 Committer: Stefan Bodewig <bode...@apache.org> Committed: Mon May 7 16:25:46 2018 +0200 ---------------------------------------------------------------------- .../compress/archivers/sevenz/SevenZFile.java | 77 +++++++++++++++++++- .../archivers/sevenz/SevenZFileTest.java | 22 +++++- .../archivers/sevenz/SevenZOutputFileTest.java | 2 +- 3 files changed, 96 insertions(+), 5 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/commons-compress/blob/237e1721/src/main/java/org/apache/commons/compress/archivers/sevenz/SevenZFile.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/apache/commons/compress/archivers/sevenz/SevenZFile.java b/src/main/java/org/apache/commons/compress/archivers/sevenz/SevenZFile.java index 6690847..902174c 100644 --- a/src/main/java/org/apache/commons/compress/archivers/sevenz/SevenZFile.java +++ b/src/main/java/org/apache/commons/compress/archivers/sevenz/SevenZFile.java @@ -27,7 +27,10 @@ import java.io.IOException; import java.io.InputStream; import java.nio.ByteBuffer; import java.nio.ByteOrder; +import java.nio.CharBuffer; import java.nio.channels.SeekableByteChannel; +import java.nio.charset.StandardCharsets; +import java.nio.charset.CharsetEncoder; import java.nio.file.Files; import java.nio.file.StandardOpenOption; import java.util.ArrayList; @@ -97,10 +100,24 @@ public class SevenZFile implements Closeable { * Reads a file as 7z archive * * @param filename the file to read + * @param password optional password if the archive is encrypted + * @throws IOException if reading the archive fails + * @since 1.17 + */ + public SevenZFile(final File filename, final char[] password) throws IOException { + this(Files.newByteChannel(filename.toPath(), EnumSet.of(StandardOpenOption.READ)), + filename.getAbsolutePath(), utf16Decode(password), true); + } + + /** + * Reads a file as 7z archive + * + * @param filename the file to read * @param password optional password if the archive is encrypted - * the byte array is supposed to be the UTF16-LE encoded * representation of the password. * @throws IOException if reading the archive fails + * @deprecated use the char[]-arg version for the password instead */ public SevenZFile(final File filename, final byte[] password) throws IOException { this(Files.newByteChannel(filename.toPath(), EnumSet.of(StandardOpenOption.READ)), @@ -119,7 +136,46 @@ public class SevenZFile implements Closeable { * @since 1.13 */ public SevenZFile(final SeekableByteChannel channel) throws IOException { - this(channel, "unknown archive", null); + this(channel, "unknown archive", (char[]) null); + } + + /** + * Reads a SeekableByteChannel as 7z archive + * + * <p>{@link + * org.apache.commons.compress.utils.SeekableInMemoryByteChannel} + * allows you to read from an in-memory archive.</p> + * + * @param channel the channel to read + * @param password optional password if the archive is encrypted - + * the byte array is supposed to be the UTF16-LE encoded + * representation of the password. + * @throws IOException if reading the archive fails + * @since 1.17 + */ + public SevenZFile(final SeekableByteChannel channel, + final char[] password) throws IOException { + this(channel, "unknown archive", utf16Decode(password)); + } + + /** + * Reads a SeekableByteChannel as 7z archive + * + * <p>{@link + * org.apache.commons.compress.utils.SeekableInMemoryByteChannel} + * allows you to read from an in-memory archive.</p> + * + * @param channel the channel to read + * @param filename name of the archive - only used for error reporting + * @param password optional password if the archive is encrypted - + * the byte array is supposed to be the UTF16-LE encoded + * representation of the password. + * @throws IOException if reading the archive fails + * @since 1.17 + */ + public SevenZFile(final SeekableByteChannel channel, String filename, + final char[] password) throws IOException { + this(channel, filename, utf16Decode(password), false); } /** @@ -135,6 +191,7 @@ public class SevenZFile implements Closeable { * representation of the password. * @throws IOException if reading the archive fails * @since 1.13 + * @deprecated use the char[]-arg version for the password instead */ public SevenZFile(final SeekableByteChannel channel, final byte[] password) throws IOException { @@ -155,6 +212,7 @@ public class SevenZFile implements Closeable { * representation of the password. * @throws IOException if reading the archive fails * @since 1.13 + * @deprecated use the char[]-arg version for the password instead */ public SevenZFile(final SeekableByteChannel channel, String filename, final byte[] password) throws IOException { @@ -188,7 +246,7 @@ public class SevenZFile implements Closeable { * @throws IOException if reading the archive fails */ public SevenZFile(final File filename) throws IOException { - this(filename, null); + this(filename, (char[]) null); } /** @@ -1122,4 +1180,19 @@ public class SevenZFile implements Closeable { public String toString() { return archive.toString(); } + + private static final CharsetEncoder PASSWORD_ENCODER = StandardCharsets.UTF_16LE.newEncoder(); + + private static byte[] utf16Decode(char[] chars) throws IOException { + if (chars == null) { + return null; + } + ByteBuffer encoded = PASSWORD_ENCODER.encode(CharBuffer.wrap(chars)); + if (encoded.hasArray()) { + return encoded.array(); + } + byte[] e = new byte[encoded.remaining()]; + encoded.get(e); + return e; + } } http://git-wip-us.apache.org/repos/asf/commons-compress/blob/237e1721/src/test/java/org/apache/commons/compress/archivers/sevenz/SevenZFileTest.java ---------------------------------------------------------------------- diff --git a/src/test/java/org/apache/commons/compress/archivers/sevenz/SevenZFileTest.java b/src/test/java/org/apache/commons/compress/archivers/sevenz/SevenZFileTest.java index 954cd09..6ad7224 100644 --- a/src/test/java/org/apache/commons/compress/archivers/sevenz/SevenZFileTest.java +++ b/src/test/java/org/apache/commons/compress/archivers/sevenz/SevenZFileTest.java @@ -144,8 +144,16 @@ public class SevenZFileTest extends AbstractTestCase { } } + @Test + public void test7zDecryptUnarchiveUsingCharArrayPassword() throws Exception { + if (isStrongCryptoAvailable()) { + test7zUnarchive(getFile("bla.encrypted.7z"), SevenZMethod.LZMA, // stack LZMA + AES + "foo".toCharArray()); + } + } + private void test7zUnarchive(final File f, final SevenZMethod m) throws Exception { - test7zUnarchive(f, m, null); + test7zUnarchive(f, m, (char[]) null); } @Test @@ -288,6 +296,17 @@ public class SevenZFileTest extends AbstractTestCase { private void test7zUnarchive(final File f, final SevenZMethod m, final byte[] password) throws Exception { try (SevenZFile sevenZFile = new SevenZFile(f, password)) { + test7zUnarchive(sevenZFile, m); + } + } + + private void test7zUnarchive(final File f, final SevenZMethod m, final char[] password) throws Exception { + try (SevenZFile sevenZFile = new SevenZFile(f, password)) { + test7zUnarchive(sevenZFile, m); + } + } + + private void test7zUnarchive(SevenZFile sevenZFile, final SevenZMethod m) throws Exception { SevenZArchiveEntry entry = sevenZFile.getNextEntry(); assertEquals("test1.xml", entry.getName()); assertEquals(m, entry.getContentMethods().iterator().next().getMethod()); @@ -303,7 +322,6 @@ public class SevenZFileTest extends AbstractTestCase { } assertEquals(TEST2_CONTENT, new String(contents, "UTF-8")); assertNull(sevenZFile.getNextEntry()); - } } private void checkHelloWorld(final String filename) throws Exception { http://git-wip-us.apache.org/repos/asf/commons-compress/blob/237e1721/src/test/java/org/apache/commons/compress/archivers/sevenz/SevenZOutputFileTest.java ---------------------------------------------------------------------- diff --git a/src/test/java/org/apache/commons/compress/archivers/sevenz/SevenZOutputFileTest.java b/src/test/java/org/apache/commons/compress/archivers/sevenz/SevenZOutputFileTest.java index 058c9e3..092e520 100644 --- a/src/test/java/org/apache/commons/compress/archivers/sevenz/SevenZOutputFileTest.java +++ b/src/test/java/org/apache/commons/compress/archivers/sevenz/SevenZOutputFileTest.java @@ -502,7 +502,7 @@ public class SevenZOutputFileTest extends AbstractTestCase { } try (SevenZFile archive = new SevenZFile(new SeekableInMemoryByteChannel(output.array()), "in memory", - null)) { + (char[]) null)) { assertEquals(Boolean.TRUE, verifyFile(archive, 0, methods)); } }