From b16158d5e41ec4795331fe291485132fd2fe7c83 Mon Sep 17 00:00:00 2001 From: Marko Zivanovic Date: Wed, 11 Mar 2015 23:30:21 +0100 Subject: [PATCH] Add new API --- .../obfuscator/JPasswordObfuscator.java | 16 ++-- .../in/zivanovic/obfuscator/Obfuscated.java | 85 +++++++++++++++++++ .../in/zivanovic/obfuscator/Unobfuscated.java | 83 ++++++++++++++++++ .../zivanovic/obfuscator/impl/Obfuscator.java | 10 +-- .../obfuscator/impl/PBEObfuscatorImpl.java | 2 +- .../obfuscator/JPasswordObfuscatorTest.java | 36 ++++---- .../in/zivanovic/obfuscator/NewApiTest.java | 62 ++++++++++++++ 7 files changed, 262 insertions(+), 32 deletions(-) create mode 100644 jPasswordObfuscator-lib/src/main/java/rs/in/zivanovic/obfuscator/Obfuscated.java create mode 100644 jPasswordObfuscator-lib/src/main/java/rs/in/zivanovic/obfuscator/Unobfuscated.java create mode 100644 jPasswordObfuscator-lib/src/test/java/rs/in/zivanovic/obfuscator/NewApiTest.java diff --git a/jPasswordObfuscator-lib/src/main/java/rs/in/zivanovic/obfuscator/JPasswordObfuscator.java b/jPasswordObfuscator-lib/src/main/java/rs/in/zivanovic/obfuscator/JPasswordObfuscator.java index 97cd80b..3a38540 100644 --- a/jPasswordObfuscator-lib/src/main/java/rs/in/zivanovic/obfuscator/JPasswordObfuscator.java +++ b/jPasswordObfuscator-lib/src/main/java/rs/in/zivanovic/obfuscator/JPasswordObfuscator.java @@ -29,7 +29,7 @@ import rs.in.zivanovic.obfuscator.impl.Obfuscator; import rs.in.zivanovic.obfuscator.impl.V1ObfuscatorImpl; /** - * Obfuscate and de-obfuscate sensitive data. + * Obfuscate and un-obfuscate sensitive data. * * This method is useful for protecting potentially sensitive data from casual onlookers. It is NOT secure against * attackers with access to source code or live systems. @@ -44,7 +44,7 @@ public final class JPasswordObfuscator { * @param masterKey master key to use for obfuscation * @param data data to obfuscate * - * @return string containing obfuscated data; use {@link #deObfuscate} to get secret data from this string + * @return string containing obfuscated data; use {@link #unObfuscate} to get secret data from this string */ public String obfuscate(char[] masterKey, byte[] data) { return obfuscate(masterKey, data, 1); @@ -57,7 +57,7 @@ public final class JPasswordObfuscator { * @param data data to obfuscate * @param version obfuscation algorithm version to use * - * @return string containing obfuscated data; use {@link #deObfuscate} to get secret data from this string + * @return string containing obfuscated data; use {@link #unObfuscate} to get secret data from this string */ public String obfuscate(char[] masterKey, byte[] data, int version) { Objects.requireNonNull(masterKey); @@ -71,20 +71,20 @@ public final class JPasswordObfuscator { } /** - * De-obfuscate string generated with {@link #obfuscate} method. + * Un-obfuscate string generated with {@link #obfuscate} method. * - * @param masterKey master key to use for de-obfuscation; must match the key used for obfuscation + * @param masterKey master key to use for un-obfuscation; must match the key used for obfuscation * @param obfuscatedString obfuscated string generated using one of {@link #obfuscate} methods * - * @return original, de-obfuscated data + * @return original, un-obfuscated data */ - public byte[] deObfuscate(char[] masterKey, String obfuscatedString) { + public byte[] unObfuscate(char[] masterKey, String obfuscatedString) { Objects.requireNonNull(masterKey); Objects.requireNonNull(obfuscatedString); ObfuscatedData ob = ObfuscatedData.fromString(obfuscatedString); switch (ob.getVersion()) { case 1: - return v1Obfuscator.deObfuscate(masterKey, ob); + return v1Obfuscator.unObfuscate(masterKey, ob); default: throw new IllegalArgumentException("Unsupported version: " + ob.getVersion()); } diff --git a/jPasswordObfuscator-lib/src/main/java/rs/in/zivanovic/obfuscator/Obfuscated.java b/jPasswordObfuscator-lib/src/main/java/rs/in/zivanovic/obfuscator/Obfuscated.java new file mode 100644 index 0000000..e450c4f --- /dev/null +++ b/jPasswordObfuscator-lib/src/main/java/rs/in/zivanovic/obfuscator/Obfuscated.java @@ -0,0 +1,85 @@ +/* + * The MIT License + * + * Copyright 2015 Marko Zivanovic . + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package rs.in.zivanovic.obfuscator; + +import java.nio.charset.StandardCharsets; +import java.util.Objects; +import rs.in.zivanovic.obfuscator.impl.ObfuscatedData; +import rs.in.zivanovic.obfuscator.impl.V1ObfuscatorImpl; + +/** + * Wrapper around sensitive data that performs obfuscation using secret key and generate output string. For the sake of + * security, you should zero your secret key data as soon as possible after constructing Obfuscated object. Objects of + * this class do not retain any sensitive data after being constructed. + */ +public class Obfuscated { + + private final ObfuscatedData obfuscatedData; + + /** + * Build new obfuscation wrapper using latest obfuscation algorithm version. + * + * @param key master key to use for obfuscation + * @param data data to obfuscate + */ + public Obfuscated(char[] key, String data) { + this(key, data.getBytes(StandardCharsets.UTF_8), 1); + } + + /** + * Build new obfuscation wrapper using latest obfuscation algorithm version. + * + * @param key master key to use for obfuscation + * @param data data to obfuscate + */ + public Obfuscated(char[] key, byte[] data) { + this(key, data, 1); + } + + /** + * Build new obfuscation wrapper using specified obfuscation algorithm version. + * + * @param key master key to use for obfuscation + * @param data data to obfuscate + * @param version version of the obfuscation algorithm to use + */ + public Obfuscated(char[] key, byte[] data, int version) { + Objects.requireNonNull(key); + Objects.requireNonNull(data); + Objects.requireNonNull(version); + switch (version) { + case 1: + this.obfuscatedData = new V1ObfuscatorImpl().obfuscate(key, data); + break; + default: + throw new IllegalArgumentException("Unsupported version: " + version); + } + } + + @Override + public String toString() { + return obfuscatedData.toString(); + } + +} diff --git a/jPasswordObfuscator-lib/src/main/java/rs/in/zivanovic/obfuscator/Unobfuscated.java b/jPasswordObfuscator-lib/src/main/java/rs/in/zivanovic/obfuscator/Unobfuscated.java new file mode 100644 index 0000000..248cc05 --- /dev/null +++ b/jPasswordObfuscator-lib/src/main/java/rs/in/zivanovic/obfuscator/Unobfuscated.java @@ -0,0 +1,83 @@ +/* + * The MIT License + * + * Copyright 2015 Marko Zivanovic . + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package rs.in.zivanovic.obfuscator; + +import java.nio.charset.StandardCharsets; +import java.util.Arrays; +import java.util.Objects; +import rs.in.zivanovic.obfuscator.impl.ObfuscatedData; +import rs.in.zivanovic.obfuscator.impl.ObfuscatorException; +import rs.in.zivanovic.obfuscator.impl.V1ObfuscatorImpl; + +/** + * Wrapper around obfuscated data that performs un-obfuscation and generates output in various formats. For the sake of + * security, you should zero your secret key data as soon as possible after constructing Unobfuscated object. Objects of + * this class only retain un-obfuscated data after being constructed. First call to {@link #asByteArray()} or + * {@link #asString()} methods will return copy of and clear the un-obfuscated data; further calls will throw + * {@link ObfuscatorException}. + */ +public class Unobfuscated { + + private byte[] data; + + /** + * Build new wrapper around obfuscated data. + * + * @param key master key to use for un-obfuscation + * @param obfuscatedData obfuscated data to wrap + */ + public Unobfuscated(char[] key, String obfuscatedData) { + ObfuscatedData od = ObfuscatedData.fromString(obfuscatedData); + switch (od.getVersion()) { + case 1: + this.data = new V1ObfuscatorImpl().unObfuscate(key, od); + break; + default: + throw new IllegalArgumentException("Unsupported version: " + od.getVersion()); + } + } + + /** + * Return un-obfuscated data as byte array. + * + * @return un-obfuscated data + */ + public byte[] asByteArray() { + Objects.requireNonNull(data); + byte[] ret = Arrays.copyOf(data, data.length); + Arrays.fill(data, (byte) 0); + data = null; + return ret; + } + + /** + * Return un-obfuscated data as string. + * + * @return un-obfuscated data + */ + public String asString() { + return new String(asByteArray(), StandardCharsets.UTF_8); + } + +} diff --git a/jPasswordObfuscator-lib/src/main/java/rs/in/zivanovic/obfuscator/impl/Obfuscator.java b/jPasswordObfuscator-lib/src/main/java/rs/in/zivanovic/obfuscator/impl/Obfuscator.java index 5663e6f..0ed25a1 100644 --- a/jPasswordObfuscator-lib/src/main/java/rs/in/zivanovic/obfuscator/impl/Obfuscator.java +++ b/jPasswordObfuscator-lib/src/main/java/rs/in/zivanovic/obfuscator/impl/Obfuscator.java @@ -24,7 +24,7 @@ package rs.in.zivanovic.obfuscator.impl; /** - * Obfuscator/de-obfuscator interface. + * Obfuscator/un-obfuscator interface. */ public interface Obfuscator { @@ -39,12 +39,12 @@ public interface Obfuscator { ObfuscatedData obfuscate(char[] masterKey, byte[] data); /** - * De-obfuscate data using supplied master key. + * un-obfuscate data using supplied master key. * - * @param masterKey master key to use for data de-obfuscation; must match master key used for obfuscation - * @param data string obfuscated with {@link #obfuscate} to de-obfuscate + * @param masterKey master key to use for data un-obfuscation; must match master key used for obfuscation + * @param data string obfuscated with {@link #obfuscate} to un-obfuscate * * @return */ - byte[] deObfuscate(char[] masterKey, ObfuscatedData data); + byte[] unObfuscate(char[] masterKey, ObfuscatedData data); } diff --git a/jPasswordObfuscator-lib/src/main/java/rs/in/zivanovic/obfuscator/impl/PBEObfuscatorImpl.java b/jPasswordObfuscator-lib/src/main/java/rs/in/zivanovic/obfuscator/impl/PBEObfuscatorImpl.java index c8b5e5d..724ad25 100644 --- a/jPasswordObfuscator-lib/src/main/java/rs/in/zivanovic/obfuscator/impl/PBEObfuscatorImpl.java +++ b/jPasswordObfuscator-lib/src/main/java/rs/in/zivanovic/obfuscator/impl/PBEObfuscatorImpl.java @@ -60,7 +60,7 @@ public class PBEObfuscatorImpl implements Obfuscator { } @Override - public byte[] deObfuscate(char[] masterKey, ObfuscatedData ob) { + public byte[] unObfuscate(char[] masterKey, ObfuscatedData ob) { try { return crypto(Cipher.DECRYPT_MODE, ob.getCipherText(), masterKey, ob.getSalt()); } catch (GeneralSecurityException ex) { diff --git a/jPasswordObfuscator-lib/src/test/java/rs/in/zivanovic/obfuscator/JPasswordObfuscatorTest.java b/jPasswordObfuscator-lib/src/test/java/rs/in/zivanovic/obfuscator/JPasswordObfuscatorTest.java index d44d973..b0d2224 100644 --- a/jPasswordObfuscator-lib/src/test/java/rs/in/zivanovic/obfuscator/JPasswordObfuscatorTest.java +++ b/jPasswordObfuscator-lib/src/test/java/rs/in/zivanovic/obfuscator/JPasswordObfuscatorTest.java @@ -40,11 +40,11 @@ public class JPasswordObfuscatorTest { private final JPasswordObfuscator engine = new JPasswordObfuscator(); @Test - public void testObfuscateDeObfuscate() { + public void testObfuscateUnObfuscate() { String ob = engine.obfuscate(masterKey, data); System.out.println(ob); - byte[] deob = engine.deObfuscate(masterKey, ob); - assertArrayEquals(data, deob); + byte[] unob = engine.unObfuscate(masterKey, ob); + assertArrayEquals(data, unob); } @Test(expected = IllegalArgumentException.class) @@ -53,10 +53,10 @@ public class JPasswordObfuscatorTest { } @Test(expected = RuntimeException.class) - public void testObfuscateDeObfuscateWrongMasterKey() { + public void testObfuscateUnObfuscateWrongMasterKey() { String ob = engine.obfuscate(masterKey1, data); - byte[] deob = engine.deObfuscate(masterKey2, ob); - assertThat(data, not(equalTo(deob))); + byte[] unob = engine.unObfuscate(masterKey2, ob); + assertThat(data, not(equalTo(unob))); } @Test @@ -83,33 +83,33 @@ public class JPasswordObfuscatorTest { } @Test(expected = NullPointerException.class) - public void testDeobfuscateNullData() { - engine.deObfuscate(masterKey, null); + public void testUnobfuscateNullData() { + engine.unObfuscate(masterKey, null); } @Test(expected = RuntimeException.class) - public void testDeobfuscateGarbageData() { - engine.deObfuscate(masterKey, "23499999puchn-p23948hfrn-[8f2333331xd"); + public void testUnobfuscateGarbageData() { + engine.unObfuscate(masterKey, "23499999puchn-p23948hfrn-[8f2333331xd"); } @Test(expected = IllegalArgumentException.class) - public void testDeobfuscateInvalidSignature() { - engine.deObfuscate(masterKey, "$INV$1$v1hACmQULBk=$ggRxqVe1fUMvUnzpLA6CoQ=="); + public void testUnobfuscateInvalidSignature() { + engine.unObfuscate(masterKey, "$INV$1$v1hACmQULBk=$ggRxqVe1fUMvUnzpLA6CoQ=="); } @Test(expected = IllegalArgumentException.class) - public void testDeobfuscateTruncated() { - engine.deObfuscate(masterKey, "$rizobf$1$v1hACmQULBk=$"); + public void testUnobfuscateTruncated() { + engine.unObfuscate(masterKey, "$rizobf$1$v1hACmQULBk=$"); } @Test(expected = RuntimeException.class) - public void testDeobfuscateInvalidData() { - engine.deObfuscate(masterKey, "$rizobf$1$v1hACmQULBk=$ggRxqVe1fUMvUnzpLA6Coq"); + public void testUnobfuscateInvalidData() { + engine.unObfuscate(masterKey, "$rizobf$1$v1hACmQULBk=$ggRxqVe1fUMvUnzpLA6Coq"); } @Test(expected = IllegalArgumentException.class) - public void testDeobfuscateInvalidVersion() { - engine.deObfuscate(masterKey, "$rizobf$211$v1hACmQULBk=$ggRxqVe1fUMvUnzpLA6Coq"); + public void testUnobfuscateInvalidVersion() { + engine.unObfuscate(masterKey, "$rizobf$211$v1hACmQULBk=$ggRxqVe1fUMvUnzpLA6Coq"); } } diff --git a/jPasswordObfuscator-lib/src/test/java/rs/in/zivanovic/obfuscator/NewApiTest.java b/jPasswordObfuscator-lib/src/test/java/rs/in/zivanovic/obfuscator/NewApiTest.java new file mode 100644 index 0000000..43acece --- /dev/null +++ b/jPasswordObfuscator-lib/src/test/java/rs/in/zivanovic/obfuscator/NewApiTest.java @@ -0,0 +1,62 @@ +/* + * The MIT License + * + * Copyright 2015 Marko Zivanovic . + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package rs.in.zivanovic.obfuscator; + +import java.nio.charset.StandardCharsets; +import static org.hamcrest.CoreMatchers.*; +import static org.junit.Assert.*; +import org.junit.Test; + +/** + * New API ({@link Obfuscated} and {@link Unobfuscated}) tests. + */ +public class NewApiTest { + + private static final char[] key = "key".toCharArray(); + private static final String dataS = "data"; + private static final byte[] dataBA = dataS.getBytes(StandardCharsets.UTF_8); + + @Test + public void testObfuscateUnobfuscateArrays() { + String o = new Obfuscated(key, dataBA).toString(); + byte[] unob = new Unobfuscated(key, o).asByteArray(); + assertThat(unob, equalTo(dataBA)); + } + + @Test + public void testObfuscateUnobfuscateStrings() { + String o = new Obfuscated(key, dataS).toString(); + String unob = new Unobfuscated(key, o).asString(); + assertThat(unob, equalTo(dataS)); + } + + @Test(expected = NullPointerException.class) + public void testUnobfuscationClearsData() { + String o = new Obfuscated(key, dataBA).toString(); + Unobfuscated unob = new Unobfuscated(key, o); + unob.asByteArray(); + unob.asByteArray(); + } + +}