diff --git a/README.md b/README.md index f3c1b85..6a864f9 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ Maven dependency is available at: rs.in.zivanovic j-password-obfuscator - 1.0.0 + 1.1.0 ## Typical usage @@ -23,8 +23,7 @@ Maven dependency is available at: Say we want to obfuscate our super secret data string "Hello World" using the secret key "key". We'd use the following snippet: - JPasswordObfuscator obfuscator = new JPasswordObfuscator(); - String obfuscated = obfuscator.obfuscate("key".toCharArray(), "Hello World".getBytes(StandardCharsets.UTF_8)); + String obfuscated = new Obfuscated("key".toCharArray(), "Hello World").toString(); System.out.println(obfuscated); output will resemble this: @@ -40,8 +39,7 @@ As with all secret keys, it is recommended to use random, or, at least, not easi When we want to un-obfuscate data: - JPasswordObfuscator obfuscator = new JPasswordObfuscator(); - String original = obfuscator.deObfuscate("key".toCharArray(), "$rizobf$1$l7IwmuwEZnY=$F5K7LeIP0u1cSluV3wBXqQ=="); + String original = new Unobfuscated("key".toCharArray(), "$rizobf$1$l7IwmuwEZnY=$F5K7LeIP0u1cSluV3wBXqQ==").asString(); System.out.println(original); and we get our original super secret data back: diff --git a/jPasswordObfuscator-bin/pom.xml b/jPasswordObfuscator-bin/pom.xml index bae10af..496e224 100644 --- a/jPasswordObfuscator-bin/pom.xml +++ b/jPasswordObfuscator-bin/pom.xml @@ -58,7 +58,13 @@ rs.in.zivanovic j-password-obfuscator - 1.0.0 + 1.1.0-SNAPSHOT + + + junit + junit + 4.10 + test diff --git a/jPasswordObfuscator-bin/src/main/java/rs/in/zivanovic/obfuscator/Main.java b/jPasswordObfuscator-bin/src/main/java/rs/in/zivanovic/obfuscator/Main.java index 97fc6b4..70af81b 100644 --- a/jPasswordObfuscator-bin/src/main/java/rs/in/zivanovic/obfuscator/Main.java +++ b/jPasswordObfuscator-bin/src/main/java/rs/in/zivanovic/obfuscator/Main.java @@ -23,41 +23,31 @@ */ package rs.in.zivanovic.obfuscator; -import com.beust.jcommander.JCommander; -import java.util.HashMap; -import java.util.Map; -import java.util.Map.Entry; +import java.util.concurrent.Callable; /** - * Main entry point. + * Obfuscator command line utility main class. */ public class Main { private Main() { } + /** + * Entry point. + * + * @param args command line arguments + */ public static void main(String[] args) { - JCommander jc = new JCommander(); - Map commands = new HashMap<>(); - Map aliases = new HashMap<>(); - commands.put("o", new ObfuscateCommand()); - aliases.put("o", new String[]{"ob", "obfuscate"}); - commands.put("d", new DeObfuscateCommand()); - aliases.put("d", new String[]{"deob", "deobfuscate"}); - for (Entry e : commands.entrySet()) { - String[] a = aliases.get(e.getKey()); - jc.addCommand(e.getKey(), e.getValue(), a); - } - try { - jc.parse(args); - if (commands.keySet().contains(jc.getParsedCommand())) { - Runnable r = commands.get(jc.getParsedCommand()); - r.run(); + ParsedCommandLine pcl = new ParsedCommandLine(args); + Callable command = pcl.getCommand(); + if (command == null) { + System.out.println(pcl.getHelpText()); } else { - jc.usage(); + System.out.println(command.call()); } - } catch (RuntimeException ex) { + } catch (Exception ex) { System.err.println("ERROR: " + ex.getMessage()); } } diff --git a/jPasswordObfuscator-bin/src/main/java/rs/in/zivanovic/obfuscator/ObfuscateCommand.java b/jPasswordObfuscator-bin/src/main/java/rs/in/zivanovic/obfuscator/ObfuscateCommand.java index b596844..64f76c1 100644 --- a/jPasswordObfuscator-bin/src/main/java/rs/in/zivanovic/obfuscator/ObfuscateCommand.java +++ b/jPasswordObfuscator-bin/src/main/java/rs/in/zivanovic/obfuscator/ObfuscateCommand.java @@ -26,14 +26,14 @@ package rs.in.zivanovic.obfuscator; import com.beust.jcommander.Parameter; import com.beust.jcommander.Parameters; import com.google.common.base.Joiner; -import java.nio.charset.StandardCharsets; import java.util.List; +import java.util.concurrent.Callable; /** * Implementation of the obfuscate command. */ @Parameters(commandDescription = "Obfuscate sensitive data") -public class ObfuscateCommand implements Runnable { +public class ObfuscateCommand implements Callable { @Parameter(names = {"-k", "--key"}, description = "Master key to use for obfuscation", required = true) private String masterKey; @@ -43,14 +43,12 @@ public class ObfuscateCommand implements Runnable { private int version = 1; @Parameter(description = "data to obfuscate", required = true) - private List data; + private List params; @Override - public void run() { - JPasswordObfuscator jpo = new JPasswordObfuscator(); - byte[] dataBytes = Joiner.on(' ').join(data).getBytes(StandardCharsets.UTF_8); - String s = jpo.obfuscate(masterKey.toCharArray(), dataBytes, version); - System.out.println(s); + public String call() { + String data = Joiner.on(' ').join(params); + return new Obfuscated(masterKey.toCharArray(), data, version).toString(); } } diff --git a/jPasswordObfuscator-bin/src/main/java/rs/in/zivanovic/obfuscator/ParsedCommandLine.java b/jPasswordObfuscator-bin/src/main/java/rs/in/zivanovic/obfuscator/ParsedCommandLine.java new file mode 100644 index 0000000..8687db1 --- /dev/null +++ b/jPasswordObfuscator-bin/src/main/java/rs/in/zivanovic/obfuscator/ParsedCommandLine.java @@ -0,0 +1,94 @@ +/* + * 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 com.beust.jcommander.JCommander; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.Callable; + +/** + * Wrapper around command line arguments that performs parsing and returns callable that executes required command. + */ +public class ParsedCommandLine { + + private static final Map> COMMANDS = new HashMap<>(); + private static final Map ALIASES = new HashMap<>(); + private final Callable command; + private final StringBuilder usage = new StringBuilder(); + + static { + COMMANDS.put("o", new ObfuscateCommand()); + ALIASES.put("o", new String[]{"ob", "obfuscate"}); + COMMANDS.put("u", new UnobfuscateCommand()); + ALIASES.put("u", new String[]{"unob", "unobfuscate"}); + } + + /** + * Parse command line arguments and prepare command to execute and usage help text. + * + * @param args command line arguments to parse + */ + public ParsedCommandLine(String[] args) { + JCommander jc = new JCommander(); + addCommands(jc); + jc.usage(usage); + this.command = parse(jc, args); + } + + /** + * Get the command to execute. + * + * @return command to execute + */ + public Callable getCommand() { + return command; + } + + /** + * Get usage help text. + * + * @return usage help text + */ + public String getHelpText() { + return usage.toString(); + } + + private void addCommands(JCommander jc) { + for (Map.Entry> e : COMMANDS.entrySet()) { + String[] a = ALIASES.get(e.getKey()); + jc.addCommand(e.getKey(), e.getValue(), a); + } + } + + private Callable parse(JCommander jc, String[] args) { + Callable ret = null; + jc.parse(args); + if (COMMANDS.keySet().contains(jc.getParsedCommand())) { + ret = COMMANDS.get(jc.getParsedCommand()); + } + return ret; + } + +} diff --git a/jPasswordObfuscator-bin/src/main/java/rs/in/zivanovic/obfuscator/DeObfuscateCommand.java b/jPasswordObfuscator-bin/src/main/java/rs/in/zivanovic/obfuscator/UnobfuscateCommand.java similarity index 68% rename from jPasswordObfuscator-bin/src/main/java/rs/in/zivanovic/obfuscator/DeObfuscateCommand.java rename to jPasswordObfuscator-bin/src/main/java/rs/in/zivanovic/obfuscator/UnobfuscateCommand.java index c66dfe8..1269836 100644 --- a/jPasswordObfuscator-bin/src/main/java/rs/in/zivanovic/obfuscator/DeObfuscateCommand.java +++ b/jPasswordObfuscator-bin/src/main/java/rs/in/zivanovic/obfuscator/UnobfuscateCommand.java @@ -26,27 +26,25 @@ package rs.in.zivanovic.obfuscator; import com.beust.jcommander.Parameter; import com.beust.jcommander.Parameters; import com.google.common.base.Joiner; -import java.nio.charset.StandardCharsets; import java.util.List; +import java.util.concurrent.Callable; /** - * Implementation of the de-obfuscate command. + * Implementation of the un-obfuscate command. */ -@Parameters(commandDescription = "De-obfuscate sensitive data") -public class DeObfuscateCommand implements Runnable { +@Parameters(commandDescription = "Un-obfuscate sensitive data") +public class UnobfuscateCommand implements Callable { - @Parameter(names = {"-k", "--key"}, description = "Master key to use for de-obfuscation", required = true) + @Parameter(names = {"-k", "--key"}, description = "Master key to use for un-obfuscation", required = true) private String masterKey; - @Parameter(description = "obfuscated string to de-obfuscate", required = true) - private List data; + @Parameter(description = "obfuscated string to un-obfuscate", required = true) + private List params; @Override - public void run() { - JPasswordObfuscator jpo = new JPasswordObfuscator(); - String obfuscated = Joiner.on(' ').skipNulls().join(data); - byte[] deObfuscated = jpo.deObfuscate(masterKey.toCharArray(), obfuscated); - System.out.println(new String(deObfuscated, StandardCharsets.UTF_8)); + public String call() { + String obfuscated = Joiner.on(' ').skipNulls().join(params); + return new Unobfuscated(masterKey.toCharArray(), obfuscated).asString(); } } diff --git a/jPasswordObfuscator-bin/src/test/java/rs/in/zivanovic/obfuscator/ObfuscateCommandTest.java b/jPasswordObfuscator-bin/src/test/java/rs/in/zivanovic/obfuscator/ObfuscateCommandTest.java new file mode 100644 index 0000000..4d79d35 --- /dev/null +++ b/jPasswordObfuscator-bin/src/test/java/rs/in/zivanovic/obfuscator/ObfuscateCommandTest.java @@ -0,0 +1,52 @@ +/* + * 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 com.google.common.base.Splitter; +import com.google.common.collect.Iterables; +import java.util.concurrent.Callable; +import static org.hamcrest.CoreMatchers.*; +import static org.junit.Assert.*; +import org.junit.Test; + +/** + * Obfuscator command-line utility unit tests. + */ +public class ObfuscateCommandTest { + + private String run(String args) throws Exception { + Iterable a = Splitter.on(' ').split(args); + ParsedCommandLine pcl = new ParsedCommandLine(Iterables.toArray(a, String.class)); + Callable c = pcl.getCommand(); + return c.call(); + } + + @Test + public void testObfuscateUnobfuscate() throws Exception { + String o = run("o -k test test"); + String d = run("u -k test " + o); + assertThat("test", equalTo(d)); + } + +} diff --git a/jPasswordObfuscator-lib/pom.xml b/jPasswordObfuscator-lib/pom.xml index 0bd44d8..ce563c1 100644 --- a/jPasswordObfuscator-lib/pom.xml +++ b/jPasswordObfuscator-lib/pom.xml @@ -3,7 +3,7 @@ 4.0.0 rs.in.zivanovic j-password-obfuscator - 1.0.1-SNAPSHOT + 1.1.0-SNAPSHOT jar JPasswordObfuscator library @@ -51,7 +51,7 @@ junit junit - 4.10 + 4.12 test @@ -117,7 +117,7 @@ org.apache.maven.plugins maven-gpg-plugin - 1.5 + 1.6 sign-artifacts 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..db61385 --- /dev/null +++ b/jPasswordObfuscator-lib/src/main/java/rs/in/zivanovic/obfuscator/Obfuscated.java @@ -0,0 +1,96 @@ +/* + * 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 + * @param version version of the obfuscation algorithm to use + */ + public Obfuscated(char[] key, String data, int version) { + this(key, data.getBytes(StandardCharsets.UTF_8), version); + } + + /** + * 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/ObfuscatedData.java b/jPasswordObfuscator-lib/src/main/java/rs/in/zivanovic/obfuscator/impl/ObfuscatedData.java index 5e5c34c..b6d023c 100644 --- a/jPasswordObfuscator-lib/src/main/java/rs/in/zivanovic/obfuscator/impl/ObfuscatedData.java +++ b/jPasswordObfuscator-lib/src/main/java/rs/in/zivanovic/obfuscator/impl/ObfuscatedData.java @@ -36,6 +36,13 @@ public class ObfuscatedData { private final byte[] salt; private final byte[] cipherText; + /** + * Build new obfuscated data container. + * + * @param version version of the algorithm used to obfuscate data + * @param salt random salt bytes + * @param cipherText obfuscated data + */ public ObfuscatedData(int version, byte[] salt, byte[] cipherText) { this.version = version; this.salt = Arrays.copyOf(salt, salt.length); @@ -48,6 +55,13 @@ public class ObfuscatedData { Base64.toBase64String(cipherText)); } + /** + * Parse string containing obfuscated data. + * + * @param obfuscatedString obfuscated string to parse + * + * @return parsed data + */ public static ObfuscatedData fromString(String obfuscatedString) { String[] parts = obfuscatedString.split("\\$"); if (parts.length != 5) { 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/ObfuscatorException.java b/jPasswordObfuscator-lib/src/main/java/rs/in/zivanovic/obfuscator/impl/ObfuscatorException.java index 0c9f7f0..1e8c810 100644 --- a/jPasswordObfuscator-lib/src/main/java/rs/in/zivanovic/obfuscator/impl/ObfuscatorException.java +++ b/jPasswordObfuscator-lib/src/main/java/rs/in/zivanovic/obfuscator/impl/ObfuscatorException.java @@ -28,6 +28,11 @@ package rs.in.zivanovic.obfuscator.impl; */ public class ObfuscatorException extends RuntimeException { + /** + * Wrap throwable into obfuscator exception. + * + * @param cause throwable to wrap + */ public ObfuscatorException(Throwable cause) { super(cause); } 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..dda02d4 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 @@ -40,6 +40,15 @@ public class PBEObfuscatorImpl implements Obfuscator { private final int iterations; private final int saltLen; + /** + * Build new PBE-based obfuscator with specified parameters. + * + * @param version version number for this set of parameters + * @param algo encryption algorithm to use + * @param provider crypto provider + * @param iterations number of key derivation rounds + * @param saltLen length of random salt in bytes + */ public PBEObfuscatorImpl(int version, String algo, String provider, int iterations, int saltLen) { this.algo = algo; this.provider = provider; @@ -60,7 +69,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/main/java/rs/in/zivanovic/obfuscator/impl/V1ObfuscatorImpl.java b/jPasswordObfuscator-lib/src/main/java/rs/in/zivanovic/obfuscator/impl/V1ObfuscatorImpl.java index a228111..ce47ffc 100644 --- a/jPasswordObfuscator-lib/src/main/java/rs/in/zivanovic/obfuscator/impl/V1ObfuscatorImpl.java +++ b/jPasswordObfuscator-lib/src/main/java/rs/in/zivanovic/obfuscator/impl/V1ObfuscatorImpl.java @@ -41,6 +41,10 @@ public class V1ObfuscatorImpl extends PBEObfuscatorImpl { private static final int SALT_LEN = 8; private static final int ITERATION_COUNT = 16_000; + /** + * Build new PBE-based obfuscator using PBEWithSHA256And128BitAES-CBC-BC with 8 bytes random salt and 16000 + * iterations. + */ public V1ObfuscatorImpl() { super(VERSION, ALGO, PROVIDER, ITERATION_COUNT, SALT_LEN); } 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..56406c0 --- /dev/null +++ b/jPasswordObfuscator-lib/src/test/java/rs/in/zivanovic/obfuscator/NewApiTest.java @@ -0,0 +1,86 @@ +/* + * 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 + public void testObfuscateUnobfuscateArraysV1() { + String o = new Obfuscated(key, dataBA, 1).toString(); + byte[] unob = new Unobfuscated(key, o).asByteArray(); + assertThat(unob, equalTo(dataBA)); + } + + @Test + public void testObfuscateUnobfuscateStringsV1() { + String o = new Obfuscated(key, dataS, 1).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(); + } + + @Test(expected = IllegalArgumentException.class) + public void testObfuscatedInvalidVersion() { + String o = new Obfuscated(key, dataS, -1).toString(); + } + + @Test(expected = IllegalArgumentException.class) + public void testUnobfuscatedInvalidVersion() { + String o = new Unobfuscated(key, "$rizobf$-1$F6Krv4H91RE=$NjytmuPjmfZbwQjqUWcbDg==").asString(); + } + +}