GitHub Repository

Core

Dependencies

Service Usage

The KMS library provides SigningService and SigningServiceFactory interfaces to enable decoupled transaction signing.

Load via Service Provider

Load from service config.

// See more configuration examples below.
var jsonConfig = """
    {
      "factoryClass": "software.sava.kms.core.signing.MemorySignerFromFilePointerFactory",
      "config": {
        "filePath": "/path/to/secret.json"
      }
    }
    """;
var ji = JsonIterator.parse(jsonConfig);

// An executor service and backoff is only needed for remote signers.
var executorService = Executors.newVirtualThreadPerTaskExecutor();
var defaultBackoff = Backoff.exponential(1, 16);

var signingServiceConfig = SigningServiceConfig.parseConfig(executorService, defaultBackoff, ji);

var signingService = signingServiceConfig.signingService();

var servicePublicKey = signingService.publicKey().join();

byte[] msg = "Hello World".getBytes();
byte[] sig = signingService.sign(msg).join();
System.out.println(servicePublicKey.verifySignature(msg, sig)); // true

Load from concrete implementation config.

var jsonConfig = """
    {
      "filePath": "/path/to/secret.json"
    }
    """;
var ji = JsonIterator.parse(jsonConfig);

var serviceFactory = new MemorySignerFromFilePointerFactory();
var signingService = serviceFactory.createService(ji);

var servicePublicKey = signingService.publicKey().join();

byte[] sig = signingService.sign("Hello World".getBytes()).join();

Service Configuration

Provide the signing service factory class desired and corresponding configuration. If it is a network related implementation, configure a backoff as well.

{
  "factoryClass": "software.sava.kms.core.signing.MemorySignerFromFilePointerFactory",
  "config": {
    "filePath": "/path/to/secret.json"
  },
  "backoff": {
    "type": "fibonacci",
    "initialRetryDelay": "1S",
    "maxRetryDelay": "21S"
  }
}

Implementations

Local Disk

Local configuration of secret information.

Factory Class

software.sava.kms.core.signing.MemorySignerFactory

Configuration

See sava core private key parsing for all supported encodings.

{
  "pubKey": "<PUB_KEY>",
  "encoding": "base64KeyPair",
  "secret": "<BASE64_ENCODED_PUBLIC_PRIVATE_KEY_PAIR>"
}

File Pointer

Points to a file with the secret contents as shown above.

Factory Class

software.sava.kms.core.signing.MemorySignerFromFilePointerFactory

Configuration
{
  "filePath": "/path/to/secret.json"
}

HTTP KMS

Host an independent HTTP server that signs data.

Dependencies

Endpoints

GET v0/publicKey

Returns a base58 or base64 encoded public key for the service.

  • Response Headers:
    • X-ENCODING: [base58 | base64]

POST v0/sign

Accepts base64 encoded data and returns a corresponding signature.

The server should be able to parse and inspect the data before signing, unless the requesting service can be completely trusted.

  • Request Headers:
    • X-ENCODING: base64

Factory Class

software.sava.kms.http.HttpKMSClientFactory

User Configuration

{
  "endpoint": "https://api.signing.service/",
  "capacity": {
    "minCapacityDuration": "PT8S",
    "maxCapacity": 300,
    "resetDuration": "PT6S"
  }
}

Google KMS

Use Google Cloud Key Management Service to sign data.

Google’s dependency tree exports the same package from multiple jars. This prevents the ability to use this library on the module path.

Dependencies

Factory Class

GoogleKMSClientFactory

Configuration

{
  "project": "google-project-name",
  "location": "global",
  "keyRing": "dev-keyring",
  "cryptoKey": "dev_key",
  "cryptoKeyVersion": "1",
  "capacity": {
    "minCapacityDuration": "PT8S",
    "maxCapacity": 300,
    "resetDuration": "PT6S"
  }
}