> ## Documentation Index
> Fetch the complete documentation index at: https://sava.software/llms.txt
> Use this file to discover all available pages before exploring further.

# Key Management Services

> KMS clients for the purpose of isolating ed25519 private key signing.

<Card title="GitHub Repository" icon="github" horizontal={true} href="https://github.com/sava-software/ravina/tree/main/kms" />

## Core

### [Dependencies](https://github.com/sava-software/ravina/blob/main/ravina-kms/core/src/main/java/module-info.java)

* software.sava.json.iterator
* software.sava.core
* software.sava.rpc
* software.sava.ravina\_core

### Service Usage

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

#### Load via Service Provider

Load from service config.

```java theme={null}
// 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.

```java theme={null}
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.

```json theme={null}
{
  "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](https://github.com/sava-software/ravina/blob/main/ravina-kms/core/src/main/java/software/sava/kms/core/signing/MemorySignerFactory.java)

##### Configuration

See [sava core private key parsing](/libraries/core#private-key-parsing) for all supported encodings.

```json theme={null}
{
  "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](https://github.com/sava-software/ravina/blob/main/ravina-kms/core/src/main/java/software/sava/kms/core/signing/MemorySignerFromFilePointerFactory.java)

##### Configuration

```json theme={null}
{
  "filePath": "/path/to/secret.json"
}
```

## HTTP KMS

Host an independent HTTP server that signs data.

### [Dependencies](https://github.com/sava-software/ravina/blob/main/ravina-kms/http/src/main/java/module-info.java)

* java.net.http
* software.sava.json.iterator
* software.sava.core
* software.sava.rpc
* software.sava.ravina\_core
* software.sava.kms\_core

### 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](https://github.com/sava-software/ravina/blob/main/ravina-kms/http/src/main/java/software/sava/kms/http/HttpKMSClientFactory.java)

### User Configuration

```json theme={null}
{
  "endpoint": "https://api.signing.service/",
  "capacity": {
    "minCapacityDuration": "PT8S",
    "maxCapacity": 300,
    "resetDuration": "PT6S"
  }
}
```

## Google KMS

Use [Google Cloud Key Management Service](https://cloud.google.com/kms/docs/) to sign data.

<Info>
  Google's dependency tree exports the same package from multiple jars. This prevents the ability to use this library on the module path.
</Info>

### Dependencies

* software.sava.json.iterator
* software.sava.core
* software.sava.rpc
* software.sava.ravina\_core
* software.sava.kms\_core
* [google.cloud.kms](https://mvnrepository.com/artifact/com.google.cloud/google-cloud-kms)

### Factory Class

[GoogleKMSClientFactory](https://github.com/sava-software/ravina/blob/main/ravina-kms/google/src/main/java/software/sava/kms/google/GoogleKMSClientFactory.java)

### Configuration

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