diff options
author | Tor Brede Vekterli <vekterli@yahooinc.com> | 2022-11-08 17:06:15 +0100 |
---|---|---|
committer | Tor Brede Vekterli <vekterli@yahooinc.com> | 2022-11-08 17:12:54 +0100 |
commit | 29993d7fa6af8edbc51dcd903a1e27d3f62b4e82 (patch) | |
tree | 19e211cf4be60d056dd4834b532e5027df279260 /vespaclient-java/src/main/java/com/yahoo | |
parent | f268379cb63e70cefaea18999767244a7d8bfc7f (diff) |
Add a simple base conversion tool
Currently supports converting from and to any combination of
base {16, 58, 62, 64}. Input is read from STDIN and is intentionally
limited in length due to the algorithmic complexity of base
conversions that are not a power of two. Converted value is
written to STDOUT.
Diffstat (limited to 'vespaclient-java/src/main/java/com/yahoo')
-rw-r--r-- | vespaclient-java/src/main/java/com/yahoo/vespa/security/tool/Main.java | 4 | ||||
-rw-r--r-- | vespaclient-java/src/main/java/com/yahoo/vespa/security/tool/crypto/ConvertBaseTool.java | 98 |
2 files changed, 101 insertions, 1 deletions
diff --git a/vespaclient-java/src/main/java/com/yahoo/vespa/security/tool/Main.java b/vespaclient-java/src/main/java/com/yahoo/vespa/security/tool/Main.java index 11bd8815d77..0498154aa91 100644 --- a/vespaclient-java/src/main/java/com/yahoo/vespa/security/tool/Main.java +++ b/vespaclient-java/src/main/java/com/yahoo/vespa/security/tool/Main.java @@ -1,6 +1,7 @@ // Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. package com.yahoo.vespa.security.tool; +import com.yahoo.vespa.security.tool.crypto.ConvertBaseTool; import com.yahoo.vespa.security.tool.crypto.DecryptTool; import com.yahoo.vespa.security.tool.crypto.EncryptTool; import com.yahoo.vespa.security.tool.crypto.KeygenTool; @@ -45,7 +46,8 @@ public class Main { } private static final List<Tool> TOOLS = List.of( - new KeygenTool(), new EncryptTool(), new DecryptTool(), new TokenInfoTool()); + new KeygenTool(), new EncryptTool(), new DecryptTool(), new TokenInfoTool(), + new ConvertBaseTool()); private static Optional<Tool> toolFromCliArgs(String[] args) { if (args.length == 0) { diff --git a/vespaclient-java/src/main/java/com/yahoo/vespa/security/tool/crypto/ConvertBaseTool.java b/vespaclient-java/src/main/java/com/yahoo/vespa/security/tool/crypto/ConvertBaseTool.java new file mode 100644 index 00000000000..120fc8a6f98 --- /dev/null +++ b/vespaclient-java/src/main/java/com/yahoo/vespa/security/tool/crypto/ConvertBaseTool.java @@ -0,0 +1,98 @@ +// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.vespa.security.tool.crypto; + +import com.yahoo.security.Base58; +import com.yahoo.security.Base62; +import com.yahoo.vespa.security.tool.CliUtils; +import com.yahoo.vespa.security.tool.Tool; +import com.yahoo.vespa.security.tool.ToolDescription; +import com.yahoo.vespa.security.tool.ToolInvocation; +import org.apache.commons.cli.Option; + +import java.io.IOException; +import java.io.UncheckedIOException; +import java.util.Base64; +import java.util.List; + +import static com.yahoo.security.ArrayUtils.fromUtf8Bytes; +import static com.yahoo.security.ArrayUtils.hex; +import static com.yahoo.security.ArrayUtils.unhex; + +/** + * Simple tool to convert between different Base N encodings, for a fixed set of N. + * + * @author vekterli + */ +public class ConvertBaseTool implements Tool { + + private static final int MAX_IN_BYTES = 1024; + + static final String FROM_OPTION = "from"; + static final String TO_OPTION = "to"; + + private static final List<Option> OPTIONS = List.of( + Option.builder("f") + .longOpt(FROM_OPTION) + .hasArg(true) + .required(false) + .desc("From base. Supported values: 16, 58, 62, 64") + .build(), + Option.builder("t") + .longOpt(TO_OPTION) + .hasArg(true) + .required(false) + .desc("To base. Supported values: 16, 58, 62, 64") + .build()); + + @Override + public String name() { + return "convert-base"; + } + + @Override + public ToolDescription description() { + return new ToolDescription( + "--from <base N> --to <base M>", + ("Reads up to %d bytes of STDIN interpreted as a base N string (ignoring " + + "whitespace) and writes to STDOUT as a base M string. Note that base 64 is " + + "expected to be in (and is output as) the URL-safe alphabet (padding optional " + + "for input, no padding for output).").formatted(MAX_IN_BYTES), + "Note: this is a BETA tool version; its interface may be changed at any time.", + OPTIONS); + } + + @Override + public int invoke(ToolInvocation invocation) { + try { + var arguments = invocation.arguments(); + var fromBase = Integer.parseInt(CliUtils.optionOrThrow(arguments, FROM_OPTION)); + var toBase = Integer.parseInt(CliUtils.optionOrThrow(arguments, TO_OPTION)); + // We cap the input length since non-base(16|64) transforms are O(n^2) and we don't want + // to risk melting someone's CPU by them piping something large into the process by accident. + byte[] inBytes = invocation.stdIn().readAllBytes(); + if (inBytes.length > MAX_IN_BYTES) { + throw new IllegalArgumentException("Input size is too large (%d), max is %d" + .formatted(inBytes.length, MAX_IN_BYTES)); + } + var inString = fromUtf8Bytes(inBytes).strip(); // We ignore whitespace to avoid trailing \n issues + byte[] decoded = switch (fromBase) { + case 16 -> unhex(inString); + case 58 -> Base58.codec().decode(inString); + case 62 -> Base62.codec().decode(inString); + case 64 -> Base64.getUrlDecoder().decode(inString); + default -> throw new IllegalArgumentException("Unsupported from-base: %d".formatted(fromBase)); + }; + String encoded = switch (toBase) { + case 16 -> hex(decoded); + case 58 -> Base58.codec().encode(decoded); + case 62 -> Base62.codec().encode(decoded); + case 64 -> Base64.getUrlEncoder().withoutPadding().encodeToString(decoded); + default -> throw new IllegalArgumentException("Unsupported to-base: %d".formatted(toBase)); + }; + invocation.stdOut().println(encoded); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + return 0; + } +} |