@Override
    public int invoke(ToolInvocation invocation) {
        try {
            var arguments    = invocation.arguments();
            var leftoverArgs = arguments.getArgs();
            if (leftoverArgs.length != 1) {
                throw new IllegalArgumentException("Expected exactly 1 file argument to decrypt");
            }
            var inputArg    = leftoverArgs[0];
            var maybeKeyId  = Optional.ofNullable(arguments.getOptionValue(EXPECTED_KEY_ID_OPTION));
            var outputArg   = CliUtils.optionOrThrow(arguments, OUTPUT_FILE_OPTION);
            var tokenString = CliUtils.optionOrThrow(arguments, TOKEN_OPTION);
            var sealedSharedKey = SealedSharedKey.fromTokenString(tokenString.strip());
            ToolUtils.verifyExpectedKeyId(sealedSharedKey, maybeKeyId);

            var secret = arguments.hasOption(RESEAL_REQUEST)
                    ? secretFromInteractiveResealing(invocation, inputArg, outputArg, sealedSharedKey)
                    : secretFromPrivateKey(invocation, inputArg, outputArg, sealedSharedKey);

            var cipher     = secret.makeDecryptionCipher();
            boolean unZstd = arguments.hasOption(ZSTD_DECOMPRESS_OPTION);

            try (var inStream  = CliUtils.inputStreamFromFileOrStream(inputArg, invocation.stdIn());
                 var outStream = CliUtils.outputStreamToFileOrStream(outputArg, invocation.stdOut())) {
                CipherUtils.streamDecrypt(inStream, outStream, cipher, unZstd);
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        return 0;
    }
Tooling for decrypting a file using a private key that corresponds to the public key used
to originally encrypt the file.

Uses the opaque token abstraction from {@link SharedKeyGenerator}.

@author vekterli
vespaclient-java/src/main/java/com/yahoo/vespa/security/tool/crypto/DecryptTool.java