NAV Navbar
Rust Go Python Scala C# C++ Node.js Java

Introduction

This document describes Crypto service's gRPC API (and potential other future interfaces).

gRPC is a remote procedure call system developed at Google in 2015. The RPC requests are transported over HTTP2 and can be encoded in various ways, including protocol buffers.

Example features supported by a compliant gRPC implementation:

Cryptographic API

The cryptographic API provides access to cryptographic capabilities and security by using Hardware Security Modules (HSM) to process requests.

The current API named subtle is intended for people familiar with cryptographic primitives and best practices. An easier-to-use API is in the works.

Backends

The term backend is used to refer to our implementations of cryptographic providers. These are used behind the scenes to process the requests made to the API.

The cryptographic API does not depend on a specific backend implementation to be able to offer most of its features. Since backends can use various types of harware (or software) to provide their functionalities, some API features will only work with a handful of backends, whereas some other features will work with most backends.

Production use-cases should always use backends that are based on hardware. Software backends exist to facilitate development and integration testing.

The list of currently supported backends is the following:

Please note that this choice is sometimes ignored. For instance, if you generate a secret key using a specific hardware backend, then only that backend will be able to use that key for cryptographic operations. In those cases, the backend is selected automatically depending on the context.

Some operations support explicit selection of a backend, if multiple ones are configured. You can select which backend to force by setting the value of the x-arcaos-crypto-backend gRPC header to the required backend's name.

Algorithms

These strings have similar sementic with TLS Cipher Strings

The API supports various algorithms described with strings. Strings can represent an algorithm with its length parameter, if the algorithm has a parameter, like SHA with 512 bits, or a combination of algorithms like ECDSA with SHA in 256 bits mode, i.e. "ECDSA_SHA_256".

Here are few other examples:

These strings are used to construct requests to cryptographic backends in operation like key generation and key operation.

Usage examples

API usage will be showcased using client-side examples in various programming languages. These are intended to help developers by introducing them to the API through small snippets of code.

Most of the time, there will be multiple ways to interact with a gRPC API within the ecosystem of a given language. The libraries and frameworks selected in the examples do not imply that they are the only ones that can be used. You may prefer to use something else depending on your use case.

Last but not least, the examples may not compile as is. They are meant to be used as guidelines, and most of them probably require some setup in order to work. Since gRPC is a popular and well documented RPC system, this document does not aim to explain how to do this setup.

Connecting to the API

use crypto::derive_wallet_master_key_request;
use crypto::derive_wallet_public_key_one_shot_request;
use crypto::derive_wallet_and_sign_one_shot_request;

use crypto::*;
use service::subtle_crypto_client::SubtleCryptoClient;

use anyhow::Result;
use std::{env, str};
use tokio::time::{sleep, Duration};
use tonic::metadata::MetadataValue;
use tonic::transport::Channel;
use tonic::Request;

#[tokio::main]
async fn main() -> Result<()> {
    // Open connection to the service with GRPC and creates a client
    let host = format!("https://{}", env::var("HOST")?);
    let channel = Channel::from_shared(host)?.connect().await?;

    let token = MetadataValue::from_str("Bearer 00000000-0000-0000-0000-000000000000")?;
    let mut client = SubtleCryptoClient::with_interceptor(channel, move |mut req: Request<()>| {
        req.metadata_mut().insert("authorization", token.clone());
        Ok(req)
    });

    // Do something with the client

    Ok(())
}
package main

import (
	"context"
	"fmt"
	"os"
	"time"

	"arcaos/api/crypto"
	"arcaos/api/service"

	"google.golang.org/grpc"
	"google.golang.org/grpc/metadata"
)

func main() {
	// Open connection to the service with GRPC
	conn, err := grpc.Dial(os.Getenv("HOST"), grpc.WithInsecure())
	if err != nil {
		panic(err)
	}
	defer conn.Close()

	// Create a client from the crypto service
	ctx := metadata.AppendToOutgoingContext(
		context.Background(),
		"Authorization",
		"Bearer 00000000-0000-0000-0000-000000000000",
	)
	client := service.NewSubtleCryptoClient(conn)

	// Do something with the service

}
import os
import sys
import time

import grpc

from service import crypto_pb2
from service import crypto_pb2_grpc

from crypto import *

metadata = [('authorization', 'Bearer 00000000-0000-0000-0000-000000000000')]


def run():
    with grpc.insecure_channel(os.environ['HOST']) as channel:
        stub = crypto_pb2_grpc.SubtleCryptoStub(channel)

        # Do something with the client

package sample

import arcaos.api.service._
import arcaos.api.crypto._

import akka.{Done, NotUsed}
import akka.actor.ActorSystem
import akka.grpc.GrpcClientSettings
import akka.grpc.SSLContextUtils
import akka.stream.ActorMaterializer
import akka.stream.scaladsl.Source
import scala.concurrent.Future
import scala.concurrent.duration._
import scala.util.{Failure, Success}
import io.grpc.Metadata
import io.grpc.CallCredentials
import io.grpc.CallCredentials.{RequestInfo, MetadataApplier}
import io.grpc.Status

import com.google.protobuf.ByteString

object Sample {
  def main(args: Array[String]): Unit = {
    implicit val sys = ActorSystem("CryptoClient")
    implicit val mat = ActorMaterializer()
    implicit val ec = sys.dispatcher

    val cred: CallCredentials = new CallCredentials() {
      override def thisUsesUnstableApi(): Unit = {}

      override def applyRequestMetadata(
          requestInfo: RequestInfo,
          appExecutor: java.util.concurrent.Executor,
          applier: MetadataApplier
      ) = {
        appExecutor.execute(new Runnable() {
          override def run() = {
            try {
              val headers: Metadata = new Metadata()
              val authorizationKey: Metadata.Key[String] =
                Metadata.Key
                  .of("Authorization", Metadata.ASCII_STRING_MARSHALLER)
              headers
                .put(
                  authorizationKey,
                  "Bearer 00000000-0000-0000-0000-000000000000"
                )
              applier.apply(headers)
            } catch {
              case ex: Throwable =>
                applier.fail(Status.UNAUTHENTICATED.withCause(ex))
            }
          }
        });
      }
    }

    val host = System.getenv("HOST").split(":")

    // Connects to broker with a config file on src/main/resources/application.conf :
    /*
    akka.grpc.client {
      "sample.Sample" {
        host = arcaos-api
        port = 8023
        use-tls = false
      }
    }
     */
    val client = SubtleCryptoClient(
      GrpcClientSettings.fromConfig("sample.Sample").withCallCredentials(cred)
    )

    // Using a for comprehension to gather all upcoming API calls.
    val statusAll = for {

      // Do something with the client

    // End of for comprehension
    } yield ()
  }
}
using System;
using System.Diagnostics;
using System.IO;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
using Grpc.Core;
using Service;
using Crypto;
using Google.Protobuf;
using System.Collections.Generic;

namespace crypto_grpc_csharp {
class Program {

  public static string Bytes2Hex(ByteString ba) {
    return "0x" + BitConverter.ToString(ba.ToByteArray()).Replace("-", "");
  }

  static void Main(string[] args) {
    // Follow the configuration:
    // https://docs.microsoft.com/en-us/aspnet/core/tutorials/grpc/grpc-start?view=aspnetcore-3.1&tabs=visual-studio-code
    // And add in .csproj:
    // <Protobuf Include="api/**/*.proto" ProtoRoot="./api/"
    // GrpcServices="Client" /> For the following to work you need to use
    // Grpc.Core package instead of Grpc.Net.Client
    var channel = new Channel(Environment.GetEnvironmentVariable("HOST"),
                              ChannelCredentials.Insecure);
    var client = new SubtleCrypto.SubtleCryptoClient(channel);

    var metadata = new Metadata();
    metadata.Add("Authorization",
                 "Bearer 00000000-0000-0000-0000-000000000000");

    // Do something with the client
    }
  }
}
#include <chrono>
#include <fstream>
#include <iomanip>
#include <iostream>
#include <memory>
#include <sstream>
#include <stdlib.h>
#include <string>
#include <thread>
#include <vector>

#include <grpcpp/grpcpp.h>

#include "crypto/hash.pb.h"
#include "crypto/rand.pb.h"
#include "service/crypto.grpc.pb.h"

using grpc::Channel;
using grpc::ClientContext;
using grpc::Status;

const std::string HEADER = "authorization";
const std::string TOKEN = "Bearer 00000000-0000-0000-0000-000000000000";

class SubtleCryptoClient {
public:
  SubtleCryptoClient(std::shared_ptr<Channel> channel)
      : stub_(service::SubtleCrypto::NewStub(channel)) {}
private:
  std::unique_ptr<service::SubtleCrypto::Stub> stub_;
};

void print_bytes(const std::string &msg, const std::string &data) {
  std::cout << msg;
  std::cout << std::hex;

  for (const char &c : data) {
    std::cout << std::setw(2) << std::setfill('0') << (0xFF & c);
  }

  std::cout << std::endl;
}

int main(int argc, char **argv) {
  // Instantiate the client. It requires a channel, out of which the actual RPCs
  // are created. This channel models a connection to an endpoint specified by
  // the argument "--target=" which is the only expected argument.
  // We indicate that the channel isn't authenticated (use of
  // InsecureChannelCredentials()).
  std::string target_str;
  std::string arg_str("--target");

  if (argc > 1) {
    std::string arg_val = argv[1];
    size_t start_pos = arg_val.find(arg_str);
    if (start_pos != std::string::npos) {
      start_pos += arg_str.size();
      if (arg_val[start_pos] == '=') {
        target_str = arg_val.substr(start_pos + 1);
      } else {
        std::cout << "The only correct argument syntax is --target="
                  << std::endl;
        return 0;
      }
    } else {
      std::cout << "The only acceptable argument is --target=" << std::endl;
      return 0;
    }
  } else {
    target_str = "arcaos-api:8023";
  }

  auto channel =
      grpc::CreateChannel(target_str, grpc::InsecureChannelCredentials());

  SubtleCryptoClient subtle_crypto(channel);
  return 0;
}
  const path = require('path')
  const PROTO_PATH = path.join(__dirname, '/api/service/crypto.proto')
  const grpc = require('@grpc/grpc-js')
  const protoLoader = require('@grpc/proto-loader')

  const options = {
    keepCase: true,
    longs: String,
    enums: String,
    defaults: true,
    oneofs: true,
    includeDirs: [path.join(__dirname, '/api/')]
  }

  const packageDefinition = protoLoader.loadSync(PROTO_PATH, options)
  const packageObject = grpc.loadPackageDefinition(packageDefinition)

  sleep()

  const service = packageObject.service
  const client = new service.SubtleCrypto(process.env.HOST, grpc.credentials.createInsecure())

  // metadata will have to be passed as the second argument to any client method
  const metadata = new grpc.Metadata()
  metadata.add('Authorization', 'Bearer 00000000-0000-0000-0000-000000000000')

  // Do something with the client

package api.grpc.cysec.systems;
import arcaos.api.crypto.Encrypt.*;
import arcaos.api.crypto.Generate.*;
import arcaos.api.crypto.Hash.*;
import arcaos.api.crypto.Public.*;
import arcaos.api.crypto.Rand.*;
import arcaos.api.crypto.Sign.*;
import arcaos.api.crypto.Wallet.*;
import arcaos.api.service.SubtleCryptoGrpc;
import com.google.protobuf.ByteString;
import io.grpc.ManagedChannel;
import io.grpc.ManagedChannelBuilder;
import io.grpc.Metadata;
import io.grpc.netty.NettyChannelBuilder;
import io.grpc.stub.MetadataUtils;
import java.io.File;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

public class App {
  static final Metadata.Key<String> AUTHORIZATION_KEY =
      Metadata.Key.of("authorization", Metadata.ASCII_STRING_MARSHALLER);

  public static void main(String[] args) {
    ManagedChannel channel =
        NettyChannelBuilder.forTarget(System.getenv("HOST"))
            .usePlaintext()
            .build();

    SubtleCryptoGrpc.SubtleCryptoBlockingStub client =
        SubtleCryptoGrpc.newBlockingStub(channel);

    Metadata headers = new Metadata();
    headers.put(AUTHORIZATION_KEY,
                "Bearer 00000000-0000-0000-0000-000000000000");
    client = MetadataUtils.attachHeaders(client, headers);

    // Do something with the client

  }
}

In order to execute operations on the cryptographic service, a client using a gRPC framework depending on the language must be initialized. The gateway's IP address could change depending on the configuration, however the port number is 8023.

All requests are authenticated with the Authorization header and the value Bearer <token>.

On a physical appliance, you can generate a token with the command arcaos-ctl:

arcaos-ctl token create --client-id "Client" --comment "Comment for this token"

Once the client is initialized, it exposes all RPCs of the defined services, allowing operations with hardware backends, or software backends in testing environment.

The default backend is managed in the platform configuration, you can pin a specific backend with x-arcaos-crypto-backend but should refrain to do so if not required.

Hashing data

    // Hash of a message using sha256
    let response = client
        .hash(HashRequest {
            data: b"I want to hash this message".to_vec(),
            algorithm: "SHA_256".to_string(),
        })
        .await?;

    println!("Hash: {:?}", response.into_inner().digest);
	// Hash of a message using sha256
	msg := "I want to hash this message"

	rsp, err := client.Hash(ctx, &crypto.HashRequest{
		Algorithm: "SHA_256",
		Data:      []byte(msg),
	})

	// Check err for errors

	fmt.Printf("Hash: %x\n", rsp.Digest)
    msg = 'I want to hash this message'
    try:
        req = hash_pb2.HashRequest(algorithm='SHA_256', data=msg.encode())
        res = stub.Hash(request=req, metadata=metadata)
        print('Hash:', res.digest.hex())
    except Exception as err:
        print('There was an error hashing the message:', err)
      // Hash of a message using sha256
      val msg: String = "I want to hash this message"
      rspHash <-
        client
          .hash(
            HashRequest(
              ByteString.copyFromUtf8(msg),
              "SHA_256"
            )
          )
      _ = println("Hash: " + rspHash
                               .digest
                               .toByteArray()
                               .map("%02x" format _)
                               .mkString
                  )
    // Hashing payload
    var msg = "I want to hash this message";

    var replyHash =
        client.Hash(new HashRequest { Data = ByteString.CopyFromUtf8(msg),
                                      Algorithm = "SHA_256" },
                    metadata);

    Console.WriteLine("Hash: " + Bytes2Hex(replyHash.Digest));
  // Inside the public part of class SubtleCryptoClient
  std::string Hash(const std::string &data, const std::string &algorithm) {
    crypto::HashRequest request;
    request.set_data(data);
    request.set_algorithm(algorithm);

    crypto::HashResponse response;
    ClientContext context;
    context.AddMetadata(HEADER, TOKEN);

    Status status = stub_->Hash(&context, request, &response);

    if (status.ok()) {
      return response.digest();
    } else {
      std::cout << status.error_code() << ": " << status.error_message()
                << std::endl;
      exit(EXIT_FAILURE);
    }
  }

  // Inside of main
  // Hash of a message using sha256
  std::string hash_msg("I want to hash this message");
  std::string hash_response = subtle_crypto.Hash(hash_msg, "SHA_256");
  print_bytes("Hash: ", hash_response);
    // Hash of a message using sha256
    client.Hash(
      {
        data: Buffer.from('Message to digest', 'utf8'),
        algorithm: 'SHA_256'
      },
      metadata,
      (err, res) => {
        console.log(err || `Hash: ${res.digest.toString('hex')}`)
    }
  )
    // Hash of a message using sha256
    HashRequest reqHash =
        HashRequest.newBuilder()
            .setAlgorithm("SHA_256")
            .setData(ByteString.copyFromUtf8("I want to hash this message"))
            .build();

    HashResponse respHash = client.hash(reqHash);

    System.out.println("Hash: " + respHash.getDigest());

The hashing interface supports hashing blocks of bytes. The full data must be provided in the request, limiting the quantity of data that can be hashed at the moment.

HashRequest is used to ask the backend to hash a byte array of data with the given algorithm string identifier. See section about algorithms to understand how to construct such strings.

A streaming interface with initialize, update, and finalize is in the works.

In the given example bytes corresponding to the string "I want to hash this message" are hashed with SHA_256.

The response contains a digest field with the result of the hashing operation.

Generating randomness

    // Get 32 bytes of pseudo randomness (library)
    let response = client
        .get_entropy(GetEntropyRequest {
            source: "PRNG".to_string(),
            length: 32,
        })
        .await?;

    println!("Entropy: {:?}", response.into_inner().entropy);
	// Get 32 bytes of pseudo randomness (library)
	rsp, err := client.GetEntropy(ctx, &crypto.GetEntropyRequest{
		Source: "PRNG",
		Length: 32,
	})

	// Check err for errors

	fmt.Printf("Entropy: %x\n", rsp.Entropy)
    # Get 32 bytes of pseudo randomness (library)
    try:
        req = rand_pb2.GetEntropyRequest(source='PRNG', length=32)
        res = stub.GetEntropy(request=req, metadata=metadata)
        print('Entropy:', res.entropy.hex())
    except Exception as err:
        print('There was an error getting the entropy:', err)
      // Get 32 bytes of pseudo randomness (library)
      rspEntropy <-
        client
          .getEntropy(
            GetEntropyRequest(
              32,
              "PRNG"
            )
          )
      _ = println("Entropy: " + rspEntropy
                                  .entropy
                                  .toByteArray()
                                  .map("%02x" format _)
                                  .mkString
                  )
    // Get 32 bytes of pseudo randomness (library)
    var replyEntropy = client.GetEntropy(
        new GetEntropyRequest { Length = 32, Source = "PRNG" }, metadata);

    Console.WriteLine("Entropy: " + Bytes2Hex(replyEntropy.Entropy));
  // Inside the public part of class SubtleCryptoClient
  std::string GetEntropy(const std::string &source, const int length) {
    crypto::GetEntropyRequest request;
    request.set_source(source);
    request.set_length(length);

    crypto::GetEntropyResponse response;
    ClientContext context;
    context.AddMetadata(HEADER, TOKEN);

    Status status = stub_->GetEntropy(&context, request, &response);

    if (status.ok()) {
      return response.entropy();
    } else {
      std::cout << status.error_code() << ": " << status.error_message()
                << std::endl;
      exit(EXIT_FAILURE);
    }
  }

  // Inside of main
  // Get 32 bytes of pseudo randomness (library)
  std::string rand_response = subtle_crypto.GetEntropy("PRNG", 32);
  print_bytes("Entropy: ", rand_response);
    // Get 32 bytes of pseudo randomness (library)
    client.GetEntropy(
      {
        length: 32,
        source: 'PRNG'
      },
      metadata,
      (err, res) => {
        console.log(err || `Entropy: ${res.entropy.toString('hex')}`)
    }
  )
    // Get 32 bytes of pseudo randomness (library)
    GetEntropyRequest reqEntropy =
        GetEntropyRequest.newBuilder().setSource("PRNG").setLength(32).build();

    GetEntropyResponse respEntropy = client.getEntropy(reqEntropy);

    System.out.println("Entropy: " + respEntropy.getEntropy());

Random bytes, or random numbers, can be retreived from three different sources:

Depending on the configured cryptographic backends, the TRNG and QRNG options might not be available.

In the given example 32 bytes of entropy are retreived from a pseudo random number generator. The response contains an entropy field with the random bytes.

During development, and for some use cases during production, PRNG is enough for entropy needs.

Generating keys

    // Generate a key on elliptic curve SECP256K1, this key will be able to sign
    // according to ECDSA algorithm using SHA256 or SHA512 digest
    let response = client
        .generate_key(GenerateKeyRequest {
            algorithm: "EC_SECP256K1".to_string(),
            whitelist: vec!["ECDSA_SHA_256".to_string(), "ECDSA_SHA_512".to_string()],
            delete_after: String::new(),
        })
        .await?;

    let key_id_ec = response.into_inner().key_id;

    println!("EC Key id: {:?}", key_id_ec);

    // Generate a key for AES encryption and decryption
    // For examples we need AES_GCM and CBC
    let response = client
        .generate_key(GenerateKeyRequest {
            algorithm: "CIPHER_256".to_string(),
            whitelist: vec!["AES_CBC_PKCS7".to_string(), "AES_GCM".to_string()],
            delete_after: String::new(),
        })
        .await?;

    let key_id_aes = response.into_inner().key_id;

    println!("AES Key id: {:?}", key_id_aes);

    // Generate a key for RSA encryption and decryption
    let response = client
        .generate_key(GenerateKeyRequest {
            algorithm: "RSA_2048".to_string(),
            whitelist: vec!["RSAES_OAEP".to_string()],
            delete_after: String::new(),
        })
        .await?;

    let key_id_rsa = response.into_inner().key_id;

    println!("RSA Key id: {:?}", key_id_rsa);
	// Generate a key on elliptic curve SECP256K1, this key will be able to sign
	// according to ECDSA algorithm using a SHA256 digest.
	rspEc, err := client.GenerateKey(ctx, &crypto.GenerateKeyRequest{
		Algorithm: "EC_SECP256K1",
		Whitelist: []string{"ECDSA_SHA_256"},
	})

	// Check err for errors

	keyIdEc := rspEc.KeyId
	fmt.Printf("EC Key id: %s\n", keyIdEc)

	// Generate a key for AES encryption and decryption
	// For the examples we'll use same key for CBC and GCM
	rspAes, err := client.GenerateKey(ctx, &crypto.GenerateKeyRequest{
		Algorithm: "CIPHER_256",
		Whitelist: []string{"AES_CBC_PKCS7", "AES_GCM"},
	})

	// Check err for errors

	keyIdAes := rspAes.KeyId
	fmt.Printf("AES Key id: %s\n", keyIdAes)

	// Generate a key for RSA encryption and decryption
	rspRsa, err := client.GenerateKey(ctx, &crypto.GenerateKeyRequest{
		Algorithm: "RSA_2048",
		Whitelist: []string{"RSAES_OAEP"},
	})

	// Check err for errors

	keyIdRsa := rspRsa.KeyId
	fmt.Printf("RSA Key id: %s\n", keyIdRsa)

    try:
        # Generate a key on elliptic curve SECP256K1, this key will be able to sign
        # according to ECDSA algorithm using a SHA256 digest.
        req = generate_pb2.GenerateKeyRequest(algorithm='EC_SECP256K1',
                                              whitelist=['ECDSA_SHA_256'])
        res = stub.GenerateKey(request=req, metadata=metadata)
        key_id_ec = res.key_id
        print('EC Key id:', key_id_ec)

        # Generate a key for AES encryption and decryption
        # For examples we need AES_GCM and CBC
        req = generate_pb2.GenerateKeyRequest(
            algorithm='CIPHER_256', whitelist=['AES_CBC_PKCS7', 'AES_GCM'])
        res = stub.GenerateKey(request=req, metadata=metadata)
        key_id_aes = res.key_id
        print('AES Key id:', key_id_aes)

        # Generate a key for RSA encryption and decryption
        req = generate_pb2.GenerateKeyRequest(algorithm='RSA_2048',
                                              whitelist=['RSAES_OAEP'])
        res = stub.GenerateKey(request=req, metadata=metadata)
        key_id_rsa = res.key_id
        print('RSA Key id:', key_id_rsa)

    except Exception as err:
        print('There was an error generating the key:', err)
      // Generate a key on elliptic curve SECP256K1, this key will be able to sign
      // according to ECDSA algorithm using a SHA256 digest.
      rspGenEc <-
        client
          .generateKey(
            GenerateKeyRequest(
              "EC_SECP256K1",
              Seq("ECDSA_SHA_256")
            )
          )
      _ = println("EC Key id: " + rspGenEc.keyId)

      // Generate a key for AES encryption and decryption
      rspGenAes <-
        client
          .generateKey(
            GenerateKeyRequest(
              "CIPHER_256",
              Seq("AES_CBC_PKCS7", "AES_GCM")
            )
          )
      _ = println("AES Key id: " + rspGenAes.keyId)

      // Generate a key for RSA encryption and decryption
      rspGenRsa <- client
        .generateKey(
          GenerateKeyRequest(
            "RSA_2048",
            Seq("RSAES_OAEP")
          )
        )
      _ = println("RSA Key id: " + rspGenRsa.keyId)
    // Generate a key on elliptic curve SECP256K1, this key will be able to sign
    // according to ECDSA algorithm using a SHA256 digest.
    var reqGenEc = new GenerateKeyRequest { Algorithm = "EC_SECP256K1",
                                            Whitelist = { "ECDSA_SHA_256" } };

    var keyIdEc = client.GenerateKey(reqGenEc, metadata).KeyId;

    Console.WriteLine("EC Key ID: " + keyIdEc);

    // Generate a key for AES encryption and decryption
    // For the examples we'll use same key for CBC and GCM
    var reqGenAes =
        new GenerateKeyRequest { Algorithm = "CIPHER_256",
                                 Whitelist = { "AES_CBC_PKCS7", "AES_GCM" } };

    var keyIdAes = client.GenerateKey(reqGenAes, metadata).KeyId;

    Console.WriteLine("AES Key ID: " + keyIdAes);

    // Generate a key for RSA encryption and decryption
    var reqGenRsa = new GenerateKeyRequest { Algorithm = "RSA_2048",
                                             Whitelist = { "RSAES_OAEP" } };

    var keyIdRsa = client.GenerateKey(reqGenRsa, metadata).KeyId;

    Console.WriteLine("RSA Key ID: " + keyIdRsa);
  // Inside the public part of class SubtleCryptoClient
  std::string GenerateKey(const std::string &algorithm,
                          const std::vector<std::string> &whitelist) {
    crypto::GenerateKeyRequest request;
    request.set_algorithm(algorithm);
    *request.mutable_whitelist() = {whitelist.begin(), whitelist.end()};

    crypto::GenerateKeyResponse response;
    ClientContext context;
    context.AddMetadata(HEADER, TOKEN);

    Status status = stub_->GenerateKey(&context, request, &response);

    if (status.ok()) {
      return response.key_id();
    } else {
      std::cout << status.error_code() << ": " << status.error_message()
                << std::endl;
      exit(EXIT_FAILURE);
    }
  }

  // Inside of main
  std::vector<std::string> whitelist_ec;
  whitelist_ec.push_back("ECDSA_SHA_256");
  std::string key_id_ec =
      subtle_crypto.GenerateKey("EC_SECP256K1", whitelist_ec);
  std::cout << "EC Key id: " << key_id_ec << std::endl;

  std::vector<std::string> whitelist_aes;
  whitelist_aes.push_back("AES_CBC_PKCS7");
  whitelist_aes.push_back("AES_GCM");
  std::string key_id_aes =
      subtle_crypto.GenerateKey("CIPHER_256", whitelist_aes);
  std::cout << "AES Key id: " << key_id_aes << std::endl;

  std::vector<std::string> whitelist_rsa;
  whitelist_rsa.push_back("RSAES_OAEP");
  std::string key_id_rsa = subtle_crypto.GenerateKey("RSA_2048", whitelist_rsa);
  std::cout << "RSA Key id: " << key_id_rsa << std::endl;
    // Generate a key on elliptic curve SECP256K1, this key will be able to sign
    // according to ECDSA algorithm using a SHA256 digest.
    client.GenerateKey(
      {
        algorithm: 'EC_SECP256K1',
        whitelist: [
          'ECDSA_SHA_256'
        ]
      },
      metadata,
      (err, res) => {
        const keyIdEc = res.key_id
        console.log(err || `EC Key ID ${keyIdEc}`)
    }
  )
    // Generate a key for RSA encryption and decryption
    client.GenerateKey(
      {
        algorithm: 'CIPHER_256',
        whitelist: [
          'AES_CBC_PKCS7',
          'AES_GCM'
        ]
      },
      metadata,
      (err, res) => {
        const keyIdAes = res.key_id
        console.log(err || `AES Key ID ${keyIdAes}`)
    }
  )
    // Generate a key on elliptic curve SECP256K1, this key will be able to sign
    // according to ECDSA algorithm using a SHA256 digest.
    GenerateKeyRequest reqGenEc = GenerateKeyRequest.newBuilder()
                                        .setAlgorithm("EC_SECP256K1")
                                        .addWhitelist("ECDSA_SHA_256")
                                        .build();

    GenerateKeyResponse respGenEc = client.generateKey(reqGenEc);

    System.out.println("EC Key ID: " + respGenEc.getKeyId());

    // Generate a key for AES encryption and decryption
    GenerateKeyRequest reqGenAes = GenerateKeyRequest.newBuilder()
                                        .setAlgorithm("CIPHER_256")
                                        .addWhitelist("AES_CBC_PKCS7")
                                        .addWhitelist("AES_GCM")
                                        .build();

    GenerateKeyResponse respGenAes = client.generateKey(reqGenAes);

    System.out.println("AES Key ID: " + respGenAes.getKeyId());

    // Generate a key for RSA encryption and decryption
    GenerateKeyRequest reqGenRsa = GenerateKeyRequest.newBuilder()
                                        .setAlgorithm("RSA_2048")
                                        .addWhitelist("RSAES_OAEP")
                                        .build();

    GenerateKeyResponse respGenRsa = client.generateKey(reqGenRsa);

    System.out.println("RSA Key ID: " + respGenRsa.getKeyId());

    // Generate a wrapped key for EC
    GenerateWrappedKeyRequest reqGenWrapEc = GenerateWrappedKeyRequest.newBuilder()
                                        .setAlgorithm("EC_SECP256K1")
                                        .build();

    GenerateWrappedKeyResponse respGenWrapEc = client.generateWrappedKey(reqGenWrapEc);

    System.out.println("EC Wrapped Key: " + respGenWrapEc.getWrappedSecret());
    System.out.println("EC Public Key: " + respGenWrapEc.getPublic());

    // Generate a key for AES encryption and decryption
    GenerateWrappedKeyRequest reqGenWrapAes = GenerateWrappedKeyRequest.newBuilder()
                                        .setAlgorithm("CIPHER_256")
                                        .build();

    GenerateWrappedKeyResponse respGenWrapAes = client.generateWrappedKey(reqGenWrapAes);

    System.out.println("AES Wrapped Key: " + respGenWrapAes.getWrappedSecret());
    //Public field always exists, but is empty for symmetric key generation algorithms
    if (respGenWrapAes.getPublic().size() != 0) {
        throw new IllegalStateException("Public field is not empty !");
    }


    // Sign a message using the previously generated key
    SignRequest reqSign =
        SignRequest.newBuilder()
            .setData(ByteString.copyFromUtf8("Message to sign"))
            .setAlgorithm("ECDSA_SHA_256")
            .setKeyId(respGenEc.getKeyId())
            .build();

    SignResponse respSign = client.sign(reqSign);

    System.out.println("Signature: " + respSign.getSignature());

    // Sign a message using the previously generated wrapped key
    SignWithWrappedRequest reqSignWithWrapped =
    SignWithWrappedRequest.newBuilder()
            .setData(ByteString.copyFromUtf8("Message to sign"))
            .setAlgorithm("ECDSA_SHA_256")
            .setWrappedKey(respGenWrapEc.getWrappedSecret())
            .build();

    SignResponse respSignWithWrapped = client.signWithWrapped(reqSignWithWrapped);

    System.out.println("Signature With Wrapped: " + respSignWithWrapped.getSignature());

    // Get the public key linked to the key id previously generated
    GetPublicComponentRequest reqPub = GetPublicComponentRequest.newBuilder()
                                           .setKeyId(respGenEc.getKeyId())
                                           .build();

    GetPublicComponentResponse respPub = client.getPublicComponent(reqPub);

    System.out.println("Public Key: " + respPub.getPublic());

    // Verify the signature of the message
    VerifySignatureRequest reqVerify =
        VerifySignatureRequest.newBuilder()
            .setKey(respPub.getPublic())
            .setAlgorithm("ECDSA_SHA_256")
            .setSignature(respSign.getSignature())
            .setData(ByteString.copyFromUtf8("Message to sign"))
            .build();

    VerifySignatureResponse respVerify = client.verifySignature(reqVerify);

    System.out.println("Signature is valid: " + respVerify.getValid());

    // Verify the signature with wrapped
    VerifySignatureRequest reqVerifyWithWrapped =
        VerifySignatureRequest.newBuilder()
            .setKey(respGenWrapEc.getPublic())
            .setAlgorithm("ECDSA_SHA_256")
            .setSignature(respSignWithWrapped.getSignature())
            .setData(ByteString.copyFromUtf8("Message to sign"))
            .build();

    VerifySignatureResponse respVerifyWithWrapped = client.verifySignature(reqVerifyWithWrapped);

    System.out.println("Signature from wrapped key is valid: " + respVerifyWithWrapped.getValid());

    // Encrypt some payload with AES
    EncryptRequest reqEncrypt =
        EncryptRequest.newBuilder()
            .setKeyId(respGenAes.getKeyId())
            .setAlgorithm("AES_CBC_PKCS7")
            .setPlaintext(ByteString.copyFromUtf8("Message to encrypt"))
            .setIv(ByteString.EMPTY)
            .build();

    EncryptResponse respEncrypt = client.encrypt(reqEncrypt);

    System.out.println("Cipher Text: " + respEncrypt.getCiphertext());
    System.out.println("IV: " + respEncrypt.getIv());

    // Decrypt the payload with AES
    DecryptRequest reqDecrypt = DecryptRequest.newBuilder()
                                    .setKeyId(respGenAes.getKeyId())
                                    .setAlgorithm("AES_CBC_PKCS7")
                                    .setCiphertext(respEncrypt.getCiphertext())
                                    .setIv(respEncrypt.getIv())
                                    .build();

    DecryptResponse respDecrypt = client.decrypt(reqDecrypt);

    System.out.println("Plain Text: " +
                       respDecrypt.getPlaintext().toStringUtf8());

    // Encrypt some payload with AES-GCM
    EncryptAeadRequest reqEncryptAead =
        EncryptAeadRequest.newBuilder()
            .setKeyId(respGenAes.getKeyId())
            .setAlgorithm("AES_GCM")
            .setPlaintext(
                ByteString.copyFromUtf8("Message to encrypt and authenticate"))
            .setAad(
                ByteString.copyFromUtf8("And this will be authenticated only"))
            .setIv(ByteString.EMPTY)
            .build();

    EncryptAeadResponse respEncryptAead = client.encryptAead(reqEncryptAead);

    System.out.println("Cipher Text: " + respEncryptAead.getCiphertext());
    System.out.println("IV: " + respEncryptAead.getIv());
    System.out.println("Tag: " + respEncryptAead.getAuthenticationTag());

    // Decrypt the payload with AES_GCM
    DecryptAeadRequest reqDecryptAead =
        DecryptAeadRequest.newBuilder()
            .setKeyId(respGenAes.getKeyId())
            .setAlgorithm("AES_GCM")
            .setCiphertext(respEncryptAead.getCiphertext())
            .setAad(
                ByteString.copyFromUtf8("And this will be authenticated only"))
            .setAuthenticationTag(respEncryptAead.getAuthenticationTag())
            .setIv(respEncryptAead.getIv())
            .build();

    DecryptAeadResponse respDecryptAead = client.decryptAead(reqDecryptAead);

    System.out.println("Plain Text: " +
                       respDecryptAead.getPlaintext().toStringUtf8());

    /*
    // Encrypt some payload with RSA
    EncryptRequest reqEncrypt = EncryptRequest.newBuilder()
        .setKeyId(respGenRsa.getKeyId())
        .setAlgorithm("RSAES_OAEP")
        .setPlaintext(ByteString.copyFromUtf8("Message to encrypt"))
        .build();

    EncryptResponse respEncrypt = client.publicEncrypt(reqEncrypt);

    System.out.println("Cipher Text: " + respEncrypt.getCiphertext());
    */

    /*
    // Decrypt the payload with RSA
    DecryptRequest reqDecrypt = DecryptRequest.newBuilder()
        .setKeyId(respGenRsa.getKeyId())
        .setAlgorithm("RSAES_OAEP")
        .setCiphertext(respEncrypt.getCiphertext())
        .build();

    DecryptResponse respDecrypt = client.decrypt(reqDecrypt);

    System.out.println("Plain Text: " + respDecrypt.getPlaintext());
    */

    GenerateWalletSeedRequest reqSeed =
        GenerateWalletSeedRequest.newBuilder().setLength(32).build();

    GenerateWalletSeedResponse respSeed = client.generateWalletSeed(reqSeed);

    DeriveWalletMasterKeyRequest reqMaster =
        DeriveWalletMasterKeyRequest.newBuilder()
            .setAlgorithm("BIP32")
            .addWhitelist("ECDSA_SHA_512")
            .setWrapped(respSeed.getWrappedSeed())
            .build();

    /*
    It is possible to use a plaintext seed

    GetEntropyRequest reqEntropyWallet =
    GetEntropyRequest.newBuilder().setSource("PRNG").setLength(64).build();

    GetEntropyResponse respEntropyWallet = client.getEntropy(reqEntropyWallet);

    ...
    .setPlaintext(respEntropyWallet.getEntropy())
    ...
    */

    DeriveWalletMasterKeyResponse respMaster =
        client.deriveWalletMasterKey(reqMaster);
    System.out.println("Master key id : " + respMaster.getKeyId());

    DeriveWalletPrivateKeyRequest reqPrivate =
        DeriveWalletPrivateKeyRequest.newBuilder()
            .setKeyId(respMaster.getKeyId())
            .addWhitelist("ECDSA_SHA_512")
            .addPath(2)
            .addPath(4)
            .addPath(1)
            .build();

    DeriveWalletPrivateKeyResponse respPrivate =
        client.deriveWalletPrivateKey(reqPrivate);
    System.out.println("Private key id : " + respPrivate.getKeyId());

    SignRequest reqSignWallet =
        SignRequest.newBuilder()
            .setData(ByteString.copyFromUtf8("Message to sign"))
            .setAlgorithm("ECDSA_SHA_512")
            .setKeyId(respPrivate.getKeyId())
            .build();

    SignResponse respSignWallet = client.sign(reqSignWallet);

    System.out.println("Signature: " + respSignWallet.getSignature());

    GetWalletPublicComponentsRequest reqPubWallet =
        GetWalletPublicComponentsRequest.newBuilder()
            .setKeyId(respMaster.getKeyId())
            .build();

    GetWalletPublicComponentsResponse respPubWallet =
        client.getWalletPublicComponents(reqPubWallet);
    System.out.println("Master Public key : " + respPubWallet.getPublic());
    System.out.println("Master Chaincode : " + respPubWallet.getChainCode());
    System.out.println("Master Fingerprint : " +
                       respPubWallet.getParentFingerprint());
    System.out.println("Master Index key : " + respPubWallet.getIndex());
    System.out.println("Depth of master key : " + respPubWallet.getDepth());

    DeriveWalletPublicKeyRequest reqPublicKeyWallet =
        DeriveWalletPublicKeyRequest.newBuilder()
            .setAlgorithm("BIP32")
            .setPublicKey(respPubWallet.getPublic())
            .setChainCode(respPubWallet.getChainCode())
            .addPath(2)
            .addPath(4)
            .addPath(1)
            .build();

    DeriveWalletPublicKeyResponse respPublicKeyWallet =
        client.deriveWalletPublicKey(reqPublicKeyWallet);
    System.out.println("Public key : " + respPublicKeyWallet.getPublicKey());
    System.out.println("Chaincode key : " + respPublicKeyWallet.getChainCode());

    VerifySignatureRequest reqVerifyWallet =
        VerifySignatureRequest.newBuilder()
            .setKey(respPublicKeyWallet.getPublicKey())
            .setAlgorithm("ECDSA_SHA_512")
            .setSignature(respSignWallet.getSignature())
            .setData(ByteString.copyFromUtf8("Message to sign"))
            .build();

    VerifySignatureResponse respVerifyWallet =
        client.verifySignature(reqVerifyWallet);

    System.out.println("Signature is valid: " + respVerifyWallet.getValid());

    GenerateWalletSeedRequest reqSeedOneShot =
        GenerateWalletSeedRequest.newBuilder().setLength(32).build();

    GenerateWalletSeedResponse respSeedOneShot = client.generateWalletSeed(reqSeedOneShot);

    DeriveWalletPublicKeyOneShotRequest reqPublicKeyOneShot =
    DeriveWalletPublicKeyOneShotRequest.newBuilder()
            .setAlgorithm("BIP32")
            .setWrapped(respSeedOneShot.getWrappedSeed())
            .addPath(4)
            .addPath(8)
            .addPath(2)
            .build();

    DeriveWalletPublicKeyOneShotResponse respPublicKeyOneShot =
        client.deriveWalletPublicKeyOneShot(reqPublicKeyOneShot);
    System.out.println("Public key is : " + respPublicKeyOneShot.getPublicKey());
    System.out.println("Chain code is : " + respPublicKeyOneShot.getChainCode());

    DeriveWalletAndSignOneShotRequest reqSignOneShot =
    DeriveWalletAndSignOneShotRequest.newBuilder()
            .setAlgorithm("BIP32")
            .setWrapped(respSeedOneShot.getWrappedSeed())
            .addPath(4)
            .addPath(8)
            .addPath(2)
            .setSignatureAlgorithm("ECDSA_SHA_512")
            .setData(ByteString.copyFromUtf8("Message to sign"))
            .build();

    DeriveWalletAndSignOneShotResponse respSignOneShot =
        client.deriveWalletAndSignOneShot(reqSignOneShot);
    System.out.println("Signature is : " + respSignOneShot.getSignature());

    VerifySignatureRequest reqVerifyOneShot =
    VerifySignatureRequest.newBuilder()
        .setKey(respPublicKeyOneShot.getPublicKey())
        .setAlgorithm("ECDSA_SHA_512")
        .setSignature(respSignOneShot.getSignature())
        .setData(ByteString.copyFromUtf8("Message to sign"))
        .build();

    VerifySignatureResponse respVerifyOneShot =
        client.verifySignature(reqVerifyOneShot);

    System.out.println("Signature is valid: " + respVerifyOneShot.getValid());

    System.exit(0);
  }
}

Key generation is one of the most important operations in the cryptographic API. To understand the key management in ARCA we have to understand how keys are generated.

When a request for a key generation is sent, that request is processed by one specific backend, that backend is chosen either by the default configuration, or by pinning with the x-arcaos-crypto-backend header. The generated key is tagged by the processing backend, thus that key can by used only by the tagged backend.

During key generation, in addition to the tagged backend, a whitelist of algorithms is passed to limit usage of that key only to whitelisted contexts. E.g. this key generated with RSA with a 4096 bits modulus size can only be used to do RSA signatures and not encryption.

In the given example a key for the elliptic curve secp256k1 that can only performed ECDSA signatures with SHA in 256 bits mode is generated.

The response returns a key_id. Those key ids serves as handles and MUST be stored by the application for future usage of the generated key.

Generating wrapped keys

    // Generate a wrapped key on elliptic curve SECP256K1
    let response = client
        .generate_wrapped_key(GenerateWrappedKeyRequest {
            algorithm: "EC_SECP256K1".to_string(),
        })
        .await?;

    let generated_keys = response.into_inner();
    let wrapped_key_ec = generated_keys.wrapped_secret;
    let wrapped_key_ec_pub = generated_keys.public;

    println!("Wrapped EC Key: {:?}", wrapped_key_ec);
    println!("Wrapped EC Public Key: {:?}", wrapped_key_ec_pub);

    // Generate a wrapped key for AES encryption and decryption
    let response = client
        .generate_wrapped_key(GenerateWrappedKeyRequest {
            algorithm: "CIPHER_256".to_string(),
        })
        .await?;

    let generated_keys = response.into_inner();
    let wrapped_key_aes = generated_keys.wrapped_secret;
    // Public field always exists, but is empty for symmetric key generation algorithms
    assert!(generated_keys.public.is_empty());

    println!("Wrapped AES Key: {:?}", wrapped_key_aes);

    // Generate a wrapped key for RSA encryption and decryption
    let response = client
        .generate_wrapped_key(GenerateWrappedKeyRequest {
            algorithm: "RSA_2048".to_string(),
        })
        .await?;

    let generated_keys = response.into_inner();
    let wrapped_key_rsa = generated_keys.wrapped_secret;
    let wrapped_key_rsa_pub = generated_keys.public;

    println!("Wrapped RSA Key: {:?}", wrapped_key_rsa);
    println!("Wrapped ERSAC Public Key: {:?}", wrapped_key_rsa_pub);
	// Generate a key on elliptic curve SECP256K1, this key will be able to sign
	// according to ECDSA algorithm using a SHA256 digest.
	rspEc, errEc := client.GenerateWrappedKey(ctx, &crypto.GenerateWrappedKeyRequest{
		Algorithm: "EC_SECP256K1",
	})

	// Check err for errors

	fmt.Printf("EC Wrapped Key: %x\n", rspEc.WrappedSecret)
	fmt.Printf("EC Public Key: %x\n", rspEc.Public)


	// Generate a key for AES encryption and decryption
	// For the examples we'll use same key for CBC and GCM
	rspAes, errAes := client.GenerateWrappedKey(ctx, &crypto.GenerateWrappedKeyRequest{
		Algorithm: "CIPHER_256",
	})

	// Check err for errors

	fmt.Printf("AES Wrapped Key: %x\n", rspAes.WrappedSecret)
	// Public field always exists, but is empty for symmetric key generation algorithms
	if len(rspAes.Public) != 0 {
		panic("Public key is not empty")
	}

    try:
        # Generate a key on elliptic curve SECP256K1
        req = generate_pb2.GenerateWrappedKeyRequest(algorithm='EC_SECP256K1')
        res = stub.GenerateWrappedKey(request=req, metadata=metadata)
        wrapped_key_ec     = res.wrapped_secret
        wrapped_key_ec_pub = res.public
        print('Wrapped EC Key: ', wrapped_key_ec);
        print('Wrapped EC Public Key: ', wrapped_key_ec_pub);

        # Generate a key for AES encryption and decryption
        req = generate_pb2.GenerateWrappedKeyRequest(algorithm='CIPHER_256')
        res = stub.GenerateWrappedKey(request=req, metadata=metadata)
        wrapped_key_aes = res.wrapped_secret
        print('Wrapped AES Key:', wrapped_key_aes)
        # Public field always exists, but is empty for symmetric key generation algorithms
        assert not res.public

        # Generate a key for RSA encryption and decryption
        req = generate_pb2.GenerateWrappedKeyRequest(algorithm='RSA_2048')
        res = stub.GenerateWrappedKey(request=req, metadata=metadata)
        wrapped_key_rsa     = res.wrapped_secret
        wrapped_key_rsa_pub = res.public
        print('Wrapped RSA Key: ', wrapped_key_rsa);
        print('Wrapped RSA Public Key: ', wrapped_key_rsa_pub);

    except Exception as err:
        print('There was an error generating the wrapped key:', err)
      rspGenWrappedEc <- client.generateWrappedKey(GenerateWrappedKeyRequest("EC_SECP256K1"))
      _ = println("Wrapped EC Key: " + rspGenWrappedEc.wrappedSecret)
      _ = println("Wrapped EC Public Key: " + rspGenWrappedEc.public)

      rspGenWrappedAes <- client.generateWrappedKey(GenerateWrappedKeyRequest("CIPHER_256"))
      _ = println("Wrapped AES Key: " + rspGenWrappedAes.wrappedSecret)
      // Public part always exist, but is empty for symmetric key generation algorithms
      _ = println("Wrapped AES Public Key: " + rspGenWrappedAes.public)
    // Generate a wrapped key on elliptic curve SECP256K1
    var reqGenWrappedEc =
        new GenerateWrappedKeyRequest { Algorithm = "EC_SECP256K1" };
    var respGenWrappedEc = client.GenerateWrappedKey(reqGenWrappedEc, metadata);

    Console.WriteLine("Wrappd EC Key: " +
                      Bytes2Hex(respGenWrappedEc.WrappedSecret));
    Console.WriteLine("Wrapped EC Public Key: " +
                      Bytes2Hex(respGenWrappedEc.Public));

    // Generate a key for AES encryption and decryption
    // For the examples we'll use same key for CBC and GCM
    var reqGenWrappedAes =
        new GenerateWrappedKeyRequest { Algorithm = "CIPHER_256" };
    var respGenWrappedAes =
        client.GenerateWrappedKey(reqGenWrappedAes, metadata);

    Console.WriteLine("Wrappd AES Key: " +
                      Bytes2Hex(respGenWrappedAes.WrappedSecret));
    Console.WriteLine("Wrapped AES Public Key: " +
                      Bytes2Hex(respGenWrappedAes.Public));

    // Public part always exist, but is empty for symmetric key generation
    // algorithms
    Debug.Assert(respGenWrappedAes.Public.Length == 0);
  // Inside the public part of class SubtleCryptoClient
  crypto::GenerateWrappedKeyResponse GenerateWrappedKey(const std::string &algorithm) {
    crypto::GenerateWrappedKeyRequest request;
    request.set_algorithm(algorithm);

    crypto::GenerateWrappedKeyResponse response;
    ClientContext context;
    context.AddMetadata(HEADER, TOKEN);

    Status status = stub_->GenerateWrappedKey(&context, request, &response);

    if (status.ok()) {
      return response;
    } else {
      std::cout << status.error_code() << ": " << status.error_message()
                << std::endl;
      exit(EXIT_FAILURE);
    }
  }

  // Inside of main
  crypto::GenerateWrappedKeyResponse wrapped_key_ec =
      subtle_crypto.GenerateWrappedKey("EC_SECP256K1");
  print_bytes("Wrapped Key: ", wrapped_key_ec.wrapped_secret());
  print_bytes("Public Key: ", wrapped_key_ec.public_());

  crypto::GenerateWrappedKeyResponse wrapped_key_aes =
      subtle_crypto.GenerateWrappedKey("CIPHER_256");
  print_bytes("Wrapped Key: ", wrapped_key_aes.wrapped_secret());
  // Public field always exists, but is empty for symmetric key generation algorithms
  assert(wrapped_key_aes.public_().size() == 0);
    // Generate a key on elliptic curve SECP256K1, this key will be able to sign
    // according to ECDSA algorithm using a SHA256 digest.
    client.GenerateWrappedKey(
      {
        algorithm: 'EC_SECP256K1'
      },
      metadata,
      (err, res) => {
        const wrappedKeyEc = res.wrapped_secret
        const wrappedKeyEcPub = res.public
        console.log(err || `Wrapped EC Key ${wrappedKeyEc.toString('hex')}`)
        console.log(err || `Wrapped EC Public Key ${wrappedKeyEcPub.toString('hex')}`)
    }
  )
    // Generate a key for RSA encryption and decryption
    client.GenerateWrappedKey(
      {
        algorithm: 'CIPHER_256'
      },
      metadata,
      (err, res) => {
        const wrappedKeyAes = res.wrapped_secret
        console.log(res.public)
        assert(res.public.length === 0,
          'Public field always exists, but is empty for symmetric key generation algorithms')
        console.log(err || `Wrapped Aes Key ${wrappedKeyAes.toString('hex')}`)
    }
  )
    // Generate a wrapped key for EC
    GenerateWrappedKeyRequest reqGenWrapEc = GenerateWrappedKeyRequest.newBuilder()
                                        .setAlgorithm("EC_SECP256K1")
                                        .build();

    GenerateWrappedKeyResponse respGenWrapEc = client.generateWrappedKey(reqGenWrapEc);

    System.out.println("EC Wrapped Key: " + respGenWrapEc.getWrappedSecret());
    System.out.println("EC Public Key: " + respGenWrapEc.getPublic());

    // Generate a key for AES encryption and decryption
    GenerateWrappedKeyRequest reqGenWrapAes = GenerateWrappedKeyRequest.newBuilder()
                                        .setAlgorithm("CIPHER_256")
                                        .build();

    GenerateWrappedKeyResponse respGenWrapAes = client.generateWrappedKey(reqGenWrapAes);

    System.out.println("AES Wrapped Key: " + respGenWrapAes.getWrappedSecret());
    //Public field always exists, but is empty for symmetric key generation algorithms
    if (respGenWrapAes.getPublic().size() != 0) {
        throw new IllegalStateException("Public field is not empty !");
    }

This section decribe how to generate a wrapped key that can be used on specific call suffixed with WithWrapped.

When a request for a wrapped key generation is sent, that request is processed by one specific backend, that backend is chosen either by the default configuration, or by pinning with the x-arcaos-crypto-backend header.

This call differs from traditional key generation in that the generated key is never stored by the crypto service. The storage and management of the key is entirely up to the user. It is important to know that these keys do not contain any metadata that limits their use on the various operations offered by the crypto service. This private key is protected by the chosen backend. In the case of the software backend, the generated key are not protected, this backend is not recommended for production environment.

The response returns a wrapped_secret key and an optional public key. The public key is empty for symmetric algorithms.

Signing messages

    // Sign a message using the previously generated key
    let response = client
        .sign(SignRequest {
            data: b"I want to sign this message using my SECP256K1 key".to_vec(),
            key_id: key_id_ec.clone(),
            algorithm: "ECDSA_SHA_512".to_string(), // If not supported by the key, error out
        })
        .await?;

    let signature = response.into_inner().signature;

    println!("Signature: {:?}", signature);
    // Sign a message using the previously exported wrapped key
    let response = client
        .sign_with_wrapped(SignWithWrappedRequest {
            data: b"I want to sign this message using my SECP256K1 key".to_vec(),
            wrapped_key: wrapped_key_ec.clone(),
            algorithm: "ECDSA_SHA_512".to_string(), // If not supported by the key, error out
        })
        .await?;

    let signature_with_wrapped = response.into_inner().signature;

    println!("Signature with wrapped: {:?}", signature_with_wrapped);
	// Sign a message using the previously generated key
	msg := "I want to sign this message using my SECP256K1 key"
	rsp, err := client.Sign(ctx, &crypto.SignRequest{
		Algorithm: "ECDSA_SHA_256", // If not supported by the key, error out
		KeyId:     keyIdEc,
		Data:      []byte(msg),
	})

	// Check err for errors

	signature := rsp.Signature
	fmt.Printf("Signature: %x\n", signature)
	// Sign a message using the previously generated key
	msg := "I want to sign this message using my SECP256K1 wrapped key"
	rsp, err := client.SignWithWrapped(ctx, &crypto.SignWithWrappedRequest{
		Algorithm:  "ECDSA_SHA_256", // If not supported by the key, error out
		WrappedKey: wrappedKey,
		Data:       []byte(msg),
	})

	// Check err for errors

	signature := rsp.Signature
	fmt.Printf("Signature From Wrapped Key: %x\n", signature)
    # Sign a message using the previously generated key
    msg = 'I want to sign this message using my SECP256K1 key'
    try:
        req = sign_pb2.SignRequest(algorithm='ECDSA_SHA_256',
                                   key_id=key_id_ec,
                                   data=msg.encode())
        res = stub.Sign(request=req, metadata=metadata)
        signature = res.signature
        print('Signature:', signature.hex())
    except Exception as err:
        print('There was an error signing the message:', err)
    # Sign a message using the previously generated key
    try:
        req = sign_pb2.SignWithWrappedRequest(algorithm='ECDSA_SHA_256',
                                              wrapped_key=wrapped_key_ec,
                                              data=msg.encode())
        res = stub.SignWithWrapped(request=req, metadata=metadata)
        signature_with_wrapped = res.signature
        print('Signature:', signature.hex())
    except Exception as err:
        print('There was an error signing the message with wrapped key:', err)
      // Sign a message using the previously generated key
      val msg: String = "I want to sign this message using my SECP256K1 key"
      rspSign <-
        client
          .sign(
            SignRequest(
              ByteString.copyFromUtf8(msg),
              rspGenEc.keyId,
              "ECDSA_SHA_256"
            )
          )
      _ = println(
        "Signature: " + rspSign.signature
          .toByteArray()
          .map("%02x" format _)
          .mkString
      )
      val msg: String = "I want to sign this message using my wrapped SECP256K1 key"
      rspSignWithWrapped <-
        client
          .signWithWrapped(
            SignWithWrappedRequest(
              ByteString.copyFromUtf8(msg),
              rspGenWrappedEc.wrappedSecret,
              "ECDSA_SHA_256"
            )
          )
      _ = println(
        "Signature: " + rspSign.signature
          .toByteArray()
          .map("%02x" format _)
          .mkString
      )
    var msgToSign = "I want to sign this message using my SECP256K1 key";

    var replySign =
        client.Sign(new SignRequest { Algorithm = "ECDSA_SHA_256",
                                      Data = ByteString.CopyFromUtf8(msgToSign),
                                      KeyId = keyIdEc },
                    metadata);

    Console.WriteLine("Signature: " + Bytes2Hex(replySign.Signature));
    var msgToSignWithWrapped =
        "I want to sign this message using my wrapped SECP256K1 key";

    var replySignWithWrapped = client.SignWithWrapped(
        new SignWithWrappedRequest {
          Algorithm = "ECDSA_SHA_256",
          Data = ByteString.CopyFromUtf8(msgToSignWithWrapped),
          WrappedKey = respGenWrappedEc.WrappedSecret
        },
        metadata);

    Console.WriteLine("Signature: " +
                      Bytes2Hex(replySignWithWrapped.Signature));
  // Inside the public part of class SubtleCryptoClient
  std::string Sign(const std::string &algorithm, const std::string &key_id,
                   const std::string &data) {
    crypto::SignRequest request;
    request.set_algorithm(algorithm);
    request.set_key_id(key_id);
    request.set_data(data);

    crypto::SignResponse response;
    ClientContext context;
    context.AddMetadata(HEADER, TOKEN);

    Status status = stub_->Sign(&context, request, &response);

    if (status.ok()) {
      return response.signature();
    } else {
      std::cout << status.error_code() << ": " << status.error_message()
                << std::endl;
      exit(EXIT_FAILURE);
    }
  }

  // Inside of main
  // Sign a message using the previously generated key
  std::string sign_msg("I want to sign this message using my SECP256K1 key");
  std::string signature =
      subtle_crypto.Sign("ECDSA_SHA_256", key_id_ec, sign_msg);
  print_bytes("Signature: ", signature);
  // Inside the public part of class SubtleCryptoClient
  std::string SignWithWrapped(const std::string &algorithm, const std::string &wrapped_key,
                   const std::string &data) {
    crypto::SignWithWrappedRequest request;
    request.set_algorithm(algorithm);
    request.set_wrapped_key(wrapped_key);
    request.set_data(data);

    crypto::SignResponse response;
    ClientContext context;
    context.AddMetadata(HEADER, TOKEN);

    Status status = stub_->SignWithWrapped(&context, request, &response);

    if (status.ok()) {
      return response.signature();
    } else {
      std::cout << status.error_code() << ": " << status.error_message()
                << std::endl;
      exit(EXIT_FAILURE);
    }
  }

  // Inside of main
  // Sign a message using the previously generated wrapped key
  std::string sign_with_wrapped_msg("I want to sign this message using my SECP256K1 wrapped key");
  std::string signature_from_wrapped =
      subtle_crypto.SignWithWrapped("ECDSA_SHA_256", wrapped_key_ec.wrapped_secret(), sign_with_wrapped_msg);
  print_bytes("Signature from wrapped key: ", signature_from_wrapped);
    // Sign a message using the previously generated key
    client.Sign(
      {
        algorithm: 'ECDSA_SHA_256',
        data: Buffer.from('Message to sign', 'utf8'),
        key_id: keyIdEc
      },
      metadata,
      (err, resSign) => {
        console.log(err || `Signature: ${resSign.signature.toString('hex')}`)
    }
  )
    // Sign a message using the previously generated wrapped key
    client.SignWithWrapped(
      {
        algorithm: 'ECDSA_SHA_256',
        data: Buffer.from('Message to sign', 'utf8'),
        wrapped_key: wrappedKeyEc
      },
      metadata,
      (err, resSign) => {
        console.log(err || `Signature with wrapped: ${resSign.signature.toString('hex')}`)
    }
  )
    // Sign a message using the previously generated key
    SignRequest reqSign =
        SignRequest.newBuilder()
            .setData(ByteString.copyFromUtf8("Message to sign"))
            .setAlgorithm("ECDSA_SHA_256")
            .setKeyId(respGenEc.getKeyId())
            .build();

    SignResponse respSign = client.sign(reqSign);

    System.out.println("Signature: " + respSign.getSignature());
    // Sign a message using the previously generated wrapped key
    SignWithWrappedRequest reqSignWithWrapped =
    SignWithWrappedRequest.newBuilder()
            .setData(ByteString.copyFromUtf8("Message to sign"))
            .setAlgorithm("ECDSA_SHA_256")
            .setWrappedKey(respGenWrapEc.getWrappedSecret())
            .build();

    SignResponse respSignWithWrapped = client.signWithWrapped(reqSignWithWrapped);

    System.out.println("Signature With Wrapped: " + respSignWithWrapped.getSignature());

After generating a wrapped key or a key with signing capabilities one can perform signatures with a given algorithm on provided data.

If the key represented by the key_id does not exists, meaning this id does not exists or the key has not been generated by the currently pinned backend, or the key doesn't whitelist the selected algorithm an error is returned. If all conditions are fulfilled a signature is returned.

In the response the signature field contains the full signature. The format depends on the selected algorithm and will be documented here soon.

Interface for signing hashes directly, or streaming large messages may be provided in the future.

Getting public components

    // Get the public key linked to the key id previously generated
    let response = client
        .get_public_component(GetPublicComponentRequest {
            key_id: key_id_ec.clone(),
        })
        .await?;

    let public_key = response.into_inner().public;

    println!("Public Key: {:?}", public_key);
	// Get the public key linked to the key id previously generated
	rsp, err := client.GetPublicComponent(ctx, &crypto.GetPublicComponentRequest{
		KeyId: keyIdEc,
	})

	// Check err for errors

	publicKey := rsp.Public
	fmt.Printf("Public Key: %x\n", publicKey)
    # Get the public key linked to the key id previously generated
    try:
        req = public_pb2.GetPublicComponentRequest(key_id=key_id_ec)
        res = stub.GetPublicComponent(request=req, metadata=metadata)
        public_key = res.public
        print('Public Key: ', public_key.hex())
    except Exception as err:
        print('There was an error getting the public key:', err)
      // Get the public key linked to the key id previously generated
      rspPubkey <- client.getPublicComponent(
        GetPublicComponentRequest(rspGenEc.keyId)
      )
      _ = println(
        "Public Key: " + rspPubkey.public
          .toByteArray()
          .map("%02x" format _)
          .mkString
      )
    var publicKey =
        client
            .GetPublicComponent(
                new GetPublicComponentRequest { KeyId = keyIdEc }, metadata)
            .Public;

    Console.WriteLine("Public Key: " + Bytes2Hex(publicKey));
  // Inside the public part of class SubtleCryptoClient
  std::string GetPublicComponent(const std::string &key_id) {
    crypto::GetPublicComponentRequest request;
    request.set_key_id(key_id);

    crypto::GetPublicComponentResponse response;
    ClientContext context;
    context.AddMetadata(HEADER, TOKEN);

    Status status = stub_->GetPublicComponent(&context, request, &response);

    if (status.ok()) {
      return response.public_();
    } else {
      std::cout << status.error_code() << ": " << status.error_message()
                << std::endl;
      exit(EXIT_FAILURE);
    }
  }

  // Inside of main
  // Get the public key linked to the key id previously generated
  std::string public_key = subtle_crypto.GetPublicComponent(key_id_ec);
  print_bytes("Public Key: ", public_key);
    // Get the public key linked to the key id previously generated
    client.GetPublicComponent(
      {
        key_id: keyIdEc
      },
      metadata,
      (err, resPub) => {
        console.log(err || `Public key: ${resPub.public.toString('hex')}`)
    }
  )
    // Get the public key linked to the key id previously generated
    GetPublicComponentRequest reqPub = GetPublicComponentRequest.newBuilder()
                                           .setKeyId(respGenEc.getKeyId())
                                           .build();

    GetPublicComponentResponse respPub = client.getPublicComponent(reqPub);

    System.out.println("Public Key: " + respPub.getPublic());

In the case of asymmetric key generation (elliptic curves, RSA), the public part of a key pair can be retreived using the key_id handle.

If GetPublicComponent is called on a key_id referencing a symmetric key, like AES or ChaCha, an error is returned.

Verifying signatures

    // Verify the signature of the message
    let response = client
        .verify_signature(VerifySignatureRequest {
            data: b"I want to sign this message using my SECP256K1 key".to_vec(),
            signature,
            key: public_key,
            algorithm: "ECDSA_SHA_512".to_string(),
        })
        .await?;

    println!("Signature is valid: {:?}", response.into_inner().valid);

    // Verify the signature of the message made out of wrapped EC key
    let response = client
        .verify_signature(VerifySignatureRequest {
            data: b"I want to sign this message using my SECP256K1 key".to_vec(),
            signature: signature_with_wrapped,
            key: wrapped_key_ec_pub,
            algorithm: "ECDSA_SHA_512".to_string(),
        })
        .await?;

    println!("Signature with wrapped is valid: {:?}", response.into_inner().valid);
	// Verify the signature of the message
	rsp, err := client.VerifySignature(ctx, &crypto.VerifySignatureRequest{
		Algorithm: "ECDSA_SHA_256",
		Key:       publicKey,
		Signature: signature,
		Data:      []byte(msg),
	})

	// Check err for errors

	valid := rsp.Valid
	fmt.Printf("Signature is valid: %t\n", valid)
    try:
        # Verify the signature of the message
        req = sign_pb2.VerifySignatureRequest(
            algorithm='ECDSA_SHA_256',
            key=public_key,
            signature=signature,
            data=msg.encode(),
        )
        res = stub.VerifySignature(request=req, metadata=metadata)
        print('Signature is valid:', res.valid)

        # Verify the signature of the message made out of wrapped EC key
        req = sign_pb2.VerifySignatureRequest(
            algorithm='ECDSA_SHA_256',
            key=wrapped_key_ec_pub,
            signature=signature_with_wrapped,
            data=msg.encode(),
        )
        res = stub.VerifySignature(request=req, metadata=metadata)
        print('Signature with wrapped is valid:', res.valid)
    except Exception as err:
        print('There was an error verifying the signature:', err)
      // Verify the signature of the message
      rspVerify <- client.verifySignature(
        VerifySignatureRequest(
          ByteString.copyFromUtf8(msg),
          rspSign.signature,
          rspPubkey.public,
          "ECDSA_SHA_256"
        )
      )
      _ = println(
        "Signature is valid: " + rspVerify.valid
      )
    var replyVerify = client.VerifySignature(
        new VerifySignatureRequest { Key = publicKey,
                                     Algorithm = "ECDSA_SHA_256",
                                     Signature = replySign.Signature,
                                     Data =
                                         ByteString.CopyFromUtf8(msgToSign) },
        metadata);

    Console.WriteLine("Signature is valid: " + replyVerify.Valid);
  // Inside the public part of class SubtleCryptoClient
  bool VerifySignature(const std::string &algorithm,
                       const std::string &public_key,
                       const std::string &signature, const std::string &data) {
    crypto::VerifySignatureRequest request;
    request.set_algorithm(algorithm);
    request.set_key(public_key);
    request.set_signature(signature);
    request.set_data(data);

    crypto::VerifySignatureResponse response;
    ClientContext context;
    context.AddMetadata(HEADER, TOKEN);

    Status status = stub_->VerifySignature(&context, request, &response);

    if (status.ok()) {
      return response.valid();
    } else {
      std::cout << status.error_code() << ": " << status.error_message()
                << std::endl;
      exit(EXIT_FAILURE);
    }
  }

  // Inside of main
  // Verify the signature of the message
  bool valid = subtle_crypto.VerifySignature("ECDSA_SHA_256", public_key,
                                             signature, sign_msg);
  std::cout << "Signature is valid: " << valid << std::endl;

  bool valid_from_wrapped = subtle_crypto.VerifySignature("ECDSA_SHA_256", wrapped_key_ec.public_(),
                                             signature_from_wrapped, sign_with_wrapped_msg);
  std::cout << "Signature from wrapped key is valid: " << valid_from_wrapped << std::endl;
    // Verify the signature of the message
    client.VerifySignature(
      {
        key: resPub.public,
        algorithm: 'ECDSA_SHA_256',
        signature: resSign.signature,
        data: Buffer.from('Message to sign', 'utf8')
      },
      metadata,
      (err, resVerify) => {
        console.log(err || `Signature is valid: ${resVerify.valid}`)
    }
  )
    // Verify the signature of the message made out of wrapped EC key
    client.VerifySignature(
      {
        key: wrappedKeyEcPub,
        algorithm: 'ECDSA_SHA_256',
        signature: resSignWithWrapped.signature,
        data: Buffer.from('Message to sign', 'utf8')
      },
      metadata,
      (err, resVerify) => {
        console.log(err || `Signature with wrapped is valid: ${resVerify.valid}`)
    }
  )
    // Verify the signature of the message
    VerifySignatureRequest reqVerify =
        VerifySignatureRequest.newBuilder()
            .setKey(respPub.getPublic())
            .setAlgorithm("ECDSA_SHA_256")
            .setSignature(respSign.getSignature())
            .setData(ByteString.copyFromUtf8("Message to sign"))
            .build();

    VerifySignatureResponse respVerify = client.verifySignature(reqVerify);

    System.out.println("Signature is valid: " + respVerify.getValid());

    // Verify the signature with wrapped
    VerifySignatureRequest reqVerifyWithWrapped =
        VerifySignatureRequest.newBuilder()
            .setKey(respGenWrapEc.getPublic())
            .setAlgorithm("ECDSA_SHA_256")
            .setSignature(respSignWithWrapped.getSignature())
            .setData(ByteString.copyFromUtf8("Message to sign"))
            .build();

    VerifySignatureResponse respVerifyWithWrapped = client.verifySignature(reqVerifyWithWrapped);

    System.out.println("Signature from wrapped key is valid: " + respVerifyWithWrapped.getValid());

Signature verification is performed given a public key (not a key_id) and a signature. This allows verifying signatures for keys that have not been generated on the platform.

In the given example a signature is checked for the given public key passed in parameter and the string "I want to sign this message using my SECP256K1 key" using ECDSA.

In response a valid field is returned to indicate if the signature passed the validation check.

Encrypting plaintexts

    // Encrypt some payload with AES
    let response = client
        .encrypt(EncryptRequest {
            plaintext: b"I want to encrypt this message using my AES 256 bits key".to_vec(),
            key_id: key_id_aes.clone(),
            algorithm: "AES_CBC_PKCS7".to_string(),
            iv: b"".to_vec(),
        })
        .await?;

    let encrypt_response = response.into_inner();

    println!("Ciper Text: {:?}", &encrypt_response.ciphertext);
    println!("IV: {:?}", &encrypt_response.iv);
    // Encrypt some payload with AES-GCM
    let response = client
        .encrypt_aead(EncryptAeadRequest {
            plaintext: b"I want to encrypt and authenticate this message using my AES 256 bits key"
                .to_vec(),
            aad: b"And this to be authenticated".to_vec(),
            key_id: key_id_aes.clone(),
            algorithm: "AES_GCM".to_string(),
            iv: b"".to_vec(),
        })
        .await?;

    let encrypt_aead_response = response.into_inner();

    println!("Ciper Text: {:?}", &encrypt_aead_response.ciphertext);
    println!("IV: {:?}", &encrypt_aead_response.iv);
    println!("Tag: {:?}", &encrypt_aead_response.authentication_tag);
	// Encrypt some payload with AES
	msg := "I want to encrypt this message using my AES key"
	rsp, err := client.Encrypt(ctx, &crypto.EncryptRequest{
		Plaintext: []byte(msg),
		KeyId:     keyId,
		Algorithm: "AES_CBC_PKCS7",
		Iv:        []byte(""),
	})

	// Check err for errors

	cipherText := rsp.Ciphertext
	fmt.Printf("Cipher Text: %x\n", cipherText)
	iv := rsp.Iv
	fmt.Printf("IV: %x\n", iv)
	// Encrypt some payload with AES
	msg := "I want to encrypt this message using my AES key"
	authMsg := "This data will just be authenticated"
	rsp, err := client.EncryptAead(ctx, &crypto.EncryptAeadRequest{
		Plaintext: []byte(msg),
		KeyId:     keyId,
		Algorithm: "AES_GCM",
		Aad:       []byte(authMsg),
		Iv:        []byte(""),
	})

	// Check err for errors

	cipherText := rsp.Ciphertext
	fmt.Printf("Cipher Text: %x\n", cipherText)
	iv := rsp.Iv
	fmt.Printf("IV: %x\n", iv)
	authTag := rsp.AuthenticationTag
	fmt.Printf("Auth Tag: %x\n", authTag)
    # Encrypt some payload with AES
    msg = 'I want to encrypt this message using my AES key'
    iv = ''
    try:
        req = encrypt_pb2.EncryptRequest(plaintext=msg.encode(),
                                         key_id=key_id_aes,
                                         algorithm='AES_CBC_PKCS7',
                                         iv=iv.encode())
        res = stub.Encrypt(request=req, metadata=metadata)
        encrypt_resp = res
        print('Cipher Text:', encrypt_resp.ciphertext.hex())
        print('IV:', encrypt_resp.iv.hex())
    except Exception as err:
        print('There was an error encrypting the message:', err)
    # Encrypt some payload with AES
    msg = 'I want to encrypt and authenticate this message using my AES key'
    msg_auth = 'And this just to be authenticated'
    iv = ''
    try:
        req = encrypt_pb2.EncryptAeadRequest(plaintext=msg.encode(),
                                             aad=msg_auth.encode(),
                                             key_id=key_id_aes,
                                             algorithm='AES_GCM',
                                             iv=iv.encode())
        res = stub.EncryptAead(request=req, metadata=metadata)
        encrypt_resp_gcm = res
        print('Cipher Text:', encrypt_resp_gcm.ciphertext.hex())
        print('IV:', encrypt_resp_gcm.iv.hex())
        print('Auth tag:', encrypt_resp_gcm.authentication_tag.hex())
    except Exception as err:
        print('There was an error encrypting the message:', err)
      // Encrypt some payload with AES
      val msg: String = "I want to encrypt this message using my AES 256 key"
      rspEnc <- client.encrypt(
        EncryptRequest(
          ByteString.copyFromUtf8(msg),
          rspGenAes.keyId,
          "AES_CBC_PKCS7",
          ByteString.EMPTY
        )
      )
      _ = println(
        "Cipher Text: " + rspEnc.ciphertext
          .toByteArray()
          .map("%02x" format _)
          .mkString
      )
      _ = println(
        "IV: " + rspEnc.iv
          .toByteArray()
          .map("%02x" format _)
          .mkString
      )
      // Encrypt some payload with AES-GCM
      val msgGcm: String =
        "I want to encrypt and authenticate this message using my AES 256 key"
      val msg_auth: String = "And this to be authenticated"
      rspEncGcm <- client.encryptAead(
        EncryptAeadRequest(
          ByteString.copyFromUtf8(msgGcm),
          rspGenAes.keyId,
          "AES_GCM",
          ByteString.EMPTY,
          ByteString.copyFromUtf8(msg_auth)
        )
      )
      _ = println(
        "Cipher Text: " + rspEncGcm.ciphertext
          .toByteArray()
          .map("%02x" format _)
          .mkString
      )
      _ = println(
        "IV: " + rspEncGcm.iv
          .toByteArray()
          .map("%02x" format _)
          .mkString
      )

      _ = println(
        "Tag: " + rspEncGcm.authenticationTag
          .toByteArray()
          .map("%02x" format _)
          .mkString
      )
    var msgAes = "I want to encrypt this message using my AES key";
    var replyEncrypt = client.Encrypt(
        new EncryptRequest { Algorithm = "AES_CBC_PKCS7", KeyId = keyIdAes,
                             Plaintext = ByteString.CopyFromUtf8(msgAes),
                             Iv = ByteString.Empty },
        metadata);

    Console.WriteLine("Cipher Text: " + Bytes2Hex(replyEncrypt.Ciphertext));
    Console.WriteLine("IV: " + Bytes2Hex(replyEncrypt.Iv));
    var msgAesGcm =
        "I want to encrypt and authenticate this message using my AES key";
    var authenticatedData = "This message will be authenticated";
    var replyEncryptGcm = client.EncryptAead(
        new EncryptAeadRequest { Algorithm = "AES_GCM", KeyId = keyIdAes,
                                 Plaintext = ByteString.CopyFromUtf8(msgAesGcm),
                                 Aad =
                                     ByteString.CopyFromUtf8(authenticatedData),
                                 Iv = ByteString.Empty },
        metadata);

    Console.WriteLine("Cipher Text: " + Bytes2Hex(replyEncryptGcm.Ciphertext));
    Console.WriteLine("IV: " + Bytes2Hex(replyEncryptGcm.Iv));
    Console.WriteLine("Authentication Tag: " +
                      Bytes2Hex(replyEncryptGcm.AuthenticationTag));
  // Inside the public part of class SubtleCryptoClient
  crypto::EncryptResponse Encrypt(const std::string &algorithm,
                                  const std::string &key_id,
                                  const std::string &data,
                                  const std::string &iv) {
    crypto::EncryptRequest request;
    request.set_algorithm(algorithm);
    request.set_key_id(key_id);
    request.set_plaintext(data);
    // Can be empty
    request.set_iv(iv);

    crypto::EncryptResponse response;
    ClientContext context;
    context.AddMetadata(HEADER, TOKEN);

    Status status = stub_->Encrypt(&context, request, &response);

    if (status.ok()) {
      return response;
    } else {
      std::cout << status.error_code() << ": " << status.error_message()
                << std::endl;
      exit(EXIT_FAILURE);
    }
  }

  // Inside of main
  // Encrypt some payload with AES
  std::string encrypt_msg("I want to encrypt this message using my AES key");
  // The last parameter is the IV and can be empty to be generated by the
  // backend
  crypto::EncryptResponse encrypt_response =
      subtle_crypto.Encrypt("AES_CBC_PKCS7", key_id_aes, encrypt_msg, "");
  print_bytes("Cipher Text: : ", encrypt_response.ciphertext());
  print_bytes("IV used: : ", encrypt_response.iv());
  // Inside the public part of class SubtleCryptoClient
  crypto::EncryptAeadResponse EncryptAead(const std::string &algorithm,
                                          const std::string &key_id,
                                          const std::string &data,
                                          const std::string &authenticated_data,
                                          const std::string &iv) {
    crypto::EncryptAeadRequest request;
    request.set_algorithm(algorithm);
    request.set_key_id(key_id);
    request.set_plaintext(data);
    request.set_aad(authenticated_data);
    // Can be empty
    request.set_iv(iv);

    crypto::EncryptAeadResponse response;
    ClientContext context;
    context.AddMetadata(HEADER, TOKEN);

    Status status = stub_->EncryptAead(&context, request, &response);

    if (status.ok()) {
      return response;
    } else {
      std::cout << status.error_code() << ": " << status.error_message()
                << std::endl;
      exit(EXIT_FAILURE);
    }
  }

  // Inside of main
  // Encrypt some payload with AES-GCM
  std::string auth_encrypted_msg(
      "I want to encrypt this message using my AES key");
  std::string auth_msg("And this will just be authentified !");

  // The last parameter is the IV and can be empty to be generated by the
  // backend
  crypto::EncryptAeadResponse encrypted_auth_response =
      subtle_crypto.EncryptAead("AES_GCM", key_id_aes, auth_encrypted_msg,
                                auth_msg, "");
  print_bytes("Cipher Text: : ", encrypted_auth_response.ciphertext());
  print_bytes("IV used: : ", encrypted_auth_response.iv());
  print_bytes("Auth TAG: : ", encrypted_auth_response.authentication_tag());
    client.Encrypt(
      {
        algorithm: 'AES_CBC_PKCS7',
        key_id: keyIdAes,
        plaintext: Buffer.from('I want to encrypt this message using my AES key', 'utf8'),
        iv: Buffer.from('', 'utf8')
      },
      metadata,
      (err, resEncrypt) => {
        console.log(err || `Cipher Text: ${resEncrypt.ciphertext.toString('hex')}`)
        console.log(err || `IV: ${resEncrypt.iv.toString('hex')}`)
    }
  )
    client.EncryptAead(
      {
        algorithm: 'AES_GCM',
        key_id: keyIdAes,
        plaintext: Buffer.from('I want to encrypt and authenticate this message using my AES key', 'utf8'),
        aad: Buffer.from('And this to be authenticated', 'utf-8'),
        iv: Buffer.from('', 'utf8')
      },
      metadata,
      (err, resEncrypt) => {
        console.log(err || `Cipher Text: ${resEncrypt.ciphertext.toString('hex')}`)
        console.log(err || `IV: ${resEncrypt.iv.toString('hex')}`)
        console.log(err || `Tag: ${resEncrypt.authentication_tag.toString('hex')}`)
    }
  )
    // Encrypt some payload with AES
    EncryptRequest reqEncrypt =
        EncryptRequest.newBuilder()
            .setKeyId(respGenAes.getKeyId())
            .setAlgorithm("AES_CBC_PKCS7")
            .setPlaintext(ByteString.copyFromUtf8("Message to encrypt"))
            .setIv(ByteString.EMPTY)
            .build();

    EncryptResponse respEncrypt = client.encrypt(reqEncrypt);

    System.out.println("Cipher Text: " + respEncrypt.getCiphertext());
    System.out.println("IV: " + respEncrypt.getIv());
    // Encrypt some payload with AES-GCM
    EncryptAeadRequest reqEncryptAead =
        EncryptAeadRequest.newBuilder()
            .setKeyId(respGenAes.getKeyId())
            .setAlgorithm("AES_GCM")
            .setPlaintext(
                ByteString.copyFromUtf8("Message to encrypt and authenticate"))
            .setAad(
                ByteString.copyFromUtf8("And this will be authenticated only"))
            .setIv(ByteString.EMPTY)
            .build();

    EncryptAeadResponse respEncryptAead = client.encryptAead(reqEncryptAead);

    System.out.println("Cipher Text: " + respEncryptAead.getCiphertext());
    System.out.println("IV: " + respEncryptAead.getIv());
    System.out.println("Tag: " + respEncryptAead.getAuthenticationTag());

Data encryption is done on a provided plaintext with a key_id and an algorithm. The algorithm contains the type of the cipher and, in most cases, a padding scheme or block cipher mode.

There are multiple RPC calls for encryption. For instance, symmetric encryption algorithms are used through the Encrypt RPC and public encryption algorithms (such as RSA) use the PublicEncrypt RPC.

Authenticated encryption algorithms use their own RPC call (EncryptAead) and some hybrid schemes such as ECIES also have their own call to avoid overloading messages for simple encryption operations.

Decrypting ciphertexts

    let response = client
        .decrypt(DecryptRequest {
            ciphertext: encrypt_response.ciphertext,
            key_id: key_id_aes.clone(),
            iv: encrypt_response.iv,
            algorithm: "AES_CBC_PKCS7".to_string(),
        })
        .await?;

    println!(
        "Plain Text: {:?}",
        str::from_utf8(&response.into_inner().plaintext[..]).unwrap()
    );
    // Decrypt some payload with AES-GCM
    let response = client
        .decrypt_aead(DecryptAeadRequest {
            ciphertext: encrypt_aead_response.ciphertext,
            aad: b"And this to be authenticated".to_vec(),
            authentication_tag: encrypt_aead_response.authentication_tag,
            key_id: key_id_aes.clone(),
            iv: encrypt_aead_response.iv,
            algorithm: "AES_GCM".to_string(),
        })
        .await?;

    println!(
        "Plain Text: {:?}",
        str::from_utf8(&response.into_inner().plaintext[..]).unwrap()
    );
	// Decrypt the payload with AES
	rsp, err := client.Decrypt(ctx, &crypto.DecryptRequest{
		Ciphertext: cipherText,
		KeyId:      keyId,
		Algorithm:  "AES_CBC_PKCS7",
		Iv:         iv,
	})

	// Check err for errors

	plainText := rsp.Plaintext
	fmt.Printf("Plain Text: %s\n", plainText)
	// Decrypt the payload with AES
	rsp, err := client.DecryptAead(ctx, &crypto.DecryptAeadRequest{
		Ciphertext:        cipherText,
		Aad:               []byte(authMsg),
		AuthenticationTag: authTag,
		KeyId:             keyId,
		Algorithm:         "AES_GCM",
		Iv:                iv,
	})

	// Check err for errors

	plainText := rsp.Plaintext
	fmt.Printf("Plain Text: %s\n", plainText)
    # Decrypt the payload with AES
    try:
        req = encrypt_pb2.DecryptRequest(ciphertext=encrypt_resp.ciphertext,
                                         key_id=key_id_aes,
                                         algorithm='AES_CBC_PKCS7',
                                         iv=encrypt_resp.iv)
        res = stub.Decrypt(request=req, metadata=metadata)
        print('Plain Text:', res.plaintext)
    except Exception as err:
        print('There was an error decrypting the message:', err)
    msg_auth = 'And this just to be authenticated'
    # Decrypt the payload with AES_GCM
    try:
        req = encrypt_pb2.DecryptAeadRequest(
            ciphertext=encrypt_resp_gcm.ciphertext,
            aad=msg_auth.encode(),
            authentication_tag=encrypt_resp_gcm.authentication_tag,
            key_id=key_id_aes,
            algorithm='AES_GCM',
            iv=encrypt_resp_gcm.iv)
        res = stub.DecryptAead(request=req, metadata=metadata)
        print('Plain Text:', res.plaintext)
    except Exception as err:
        print('There was an error decrypting the message:', err)
      rspDec <- client.decrypt(
        DecryptRequest(
          rspEnc.ciphertext,
          rspGenAes.keyId,
          "AES_CBC_PKCS7",
          rspEnc.iv
        )
      )
      _ = println(
        "Clear Text: " + rspDec.plaintext.toStringUtf8()
      )
      rspDecGcm <- client.decryptAead(
        DecryptAeadRequest(
          rspEncGcm.ciphertext,
          rspGenAes.keyId,
          "AES_GCM",
          rspEncGcm.iv,
          rspEncGcm.authenticationTag,
          ByteString.copyFromUtf8(msg_auth)
        )
      )
      _ = println(
        "Clear Text: " + rspDecGcm.plaintext.toStringUtf8()
      )
    var replyDecrypt = client.Decrypt(
        new DecryptRequest { Algorithm = "AES_CBC_PKCS7", KeyId = keyIdAes,
                             Ciphertext = replyEncrypt.Ciphertext,
                             Iv = replyEncrypt.Iv },
        metadata);

    Console.WriteLine("Clear Text: " + replyDecrypt.Plaintext.ToStringUtf8());
    var replyDecryptGcm = client.DecryptAead(
        new DecryptAeadRequest { Algorithm = "AES_GCM", KeyId = keyIdAes,
                                 Ciphertext = replyEncryptGcm.Ciphertext,
                                 AuthenticationTag =
                                     replyEncryptGcm.AuthenticationTag,
                                 Aad =
                                     ByteString.CopyFromUtf8(authenticatedData),
                                 Iv = replyEncryptGcm.Iv },
        metadata);

    Console.WriteLine("Clear Text: " +
                      replyDecryptGcm.Plaintext.ToStringUtf8());
  // Inside the public part of class SubtleCryptoClient
  std::string Decrypt(const std::string &algorithm, const std::string &key_id,
                      const std::string &ciphertext, const std::string &iv) {
    crypto::DecryptRequest request;
    request.set_algorithm(algorithm);
    request.set_key_id(key_id);
    request.set_ciphertext(ciphertext);
    request.set_iv(iv);

    crypto::DecryptResponse response;
    ClientContext context;
    context.AddMetadata(HEADER, TOKEN);

    Status status = stub_->Decrypt(&context, request, &response);

    if (status.ok()) {
      return response.plaintext();
    } else {
      std::cout << status.error_code() << ": " << status.error_message()
                << std::endl;
      exit(EXIT_FAILURE);
    }
  }

  // Inside of main
  // Decrypt the payload with AES
  std::string plaintext = subtle_crypto.Decrypt("AES_CBC_PKCS7", key_id_aes,
                                                encrypt_response.ciphertext(),
                                                encrypt_response.iv());
  std::cout << "Plain Text: : " << plaintext << std::endl;
  // Inside the public part of class SubtleCryptoClient
  std::string
  DecryptAead(const std::string &algorithm, const std::string &key_id,
              const std::string &ciphertext, const std::string &auth_tag,
              const std::string &authenticated_data, const std::string &iv) {
    crypto::DecryptAeadRequest request;
    request.set_algorithm(algorithm);
    request.set_key_id(key_id);
    request.set_ciphertext(ciphertext);
    request.set_iv(iv);
    request.set_aad(authenticated_data);
    request.set_authentication_tag(auth_tag);

    crypto::DecryptAeadResponse response;
    ClientContext context;
    context.AddMetadata(HEADER, TOKEN);

    Status status = stub_->DecryptAead(&context, request, &response);

    if (status.ok()) {
      return response.plaintext();
    } else {
      std::cout << status.error_code() << ": " << status.error_message()
                << std::endl;
      exit(EXIT_FAILURE);
    }
  }

  // Inside of main
  // Decrypt the payload with AES
  std::string plaintext_auth = subtle_crypto.DecryptAead(
      "AES_GCM", key_id_aes, encrypted_auth_response.ciphertext(),
      encrypted_auth_response.authentication_tag(), auth_msg,
      encrypted_auth_response.iv());
  std::cout << "Plain Text: : " << plaintext_auth << std::endl;
    // Decrypt the payload with AES
    client.Decrypt(
      {
        algorithm: 'AES_CBC_PKCS7',
        key_id: keyIdAes,
        ciphertext: resEncrypt.ciphertext,
        iv: resEncrypt.iv
      },
      metadata,
      (err, resDecrypt) => {
        console.log(err || `Plain text: ${resDecrypt.plaintext}`)
    }
  )
    // Decrypt the payload with AES-GCM
    client.DecryptAead(
      {
        algorithm: 'AES_GCM',
        key_id: keyIdAes,
        ciphertext: resEncrypt.ciphertext,
        aad: Buffer.from('And this to be authenticated', 'utf-8'),
        authentication_tag: resEncrypt.authentication_tag,
        iv: resEncrypt.iv
      },
      metadata,
      (err, resDecrypt) => {
        console.log(err || `Plain text: ${resDecrypt.plaintext}`)
    }
  )
    // Decrypt the payload with AES
    DecryptRequest reqDecrypt = DecryptRequest.newBuilder()
                                    .setKeyId(respGenAes.getKeyId())
                                    .setAlgorithm("AES_CBC_PKCS7")
                                    .setCiphertext(respEncrypt.getCiphertext())
                                    .setIv(respEncrypt.getIv())
                                    .build();

    DecryptResponse respDecrypt = client.decrypt(reqDecrypt);

    System.out.println("Plain Text: " +
                       respDecrypt.getPlaintext().toStringUtf8());
    // Decrypt the payload with AES_GCM
    DecryptAeadRequest reqDecryptAead =
        DecryptAeadRequest.newBuilder()
            .setKeyId(respGenAes.getKeyId())
            .setAlgorithm("AES_GCM")
            .setCiphertext(respEncryptAead.getCiphertext())
            .setAad(
                ByteString.copyFromUtf8("And this will be authenticated only"))
            .setAuthenticationTag(respEncryptAead.getAuthenticationTag())
            .setIv(respEncryptAead.getIv())
            .build();

    DecryptAeadResponse respDecryptAead = client.decryptAead(reqDecryptAead);

    System.out.println("Plain Text: " +
                       respDecryptAead.getPlaintext().toStringUtf8());

Data decryption is done on a provided ciphertext with a key_id and an algorithm. Like in the encryption, the algorithm contains the type of cipher and, in most cases, a padding scheme or block cipher mode.

In response the plaintext is returned if the decryption succeeded.

Wallet key derivation

    let response = client
        .generate_wallet_seed(GenerateWalletSeedRequest { length: 32 })
        .await?;

    let res_seed = response.into_inner();

    let response = client
        .derive_wallet_master_key(DeriveWalletMasterKeyRequest {
            algorithm: "BIP32".to_string(),
            whitelist: vec!["ECDSA_SHA_512".to_string()],
            seed: Some(derive_wallet_master_key_request::Seed::Wrapped(res_seed.wrapped_seed)),
        })
        .await?;

    // It is also possible to use a plaintext seed
    //
    // let response = client
    //     .get_entropy(GetEntropyRequest {
    //         length: 64,
    //         source: "PRNG".to_string(),
    //     })
    //     .await?;
    //
    // let res_seed = response.into_inner();
    //
    // ...
    // seed: Some(Seed::Plaintext(res_seed.entropy)),
    // ...

    let res_master = response.into_inner();

    println!("Master key id: {:?}", &res_master.key_id);
    let response = client
        .get_wallet_public_components(GetWalletPublicComponentsRequest {
            key_id: res_master.key_id.clone(),
        })
        .await?;

    let res_public_master = response.into_inner();
    println!("Master Public key {:?}", &res_public_master.public);
    println!("Master Chaincode : {:?}", &res_public_master.chain_code);
    println!(
        "Master Fingerprint : {:?}",
        &res_public_master.parent_fingerprint
    );
    println!("Master Index key : {:?}", &res_public_master.index);
    println!("Depth of master key : {:?}", &res_public_master.depth);
    let response = client
        .derive_wallet_private_key(DeriveWalletPrivateKeyRequest {
            key_id: res_master.key_id.clone(),
            whitelist: vec!["ECDSA_SHA_512".to_string()],
            path: vec![2, 4, 1],
        })
        .await?;

    let res_private = response.into_inner();
    println!("Private key id: {:?}", &res_private.key_id);

    let response = client
        .sign(SignRequest {
            data: b"I want to sign this with wallet private key".to_vec(),
            key_id: res_private.key_id.clone(),
            algorithm: "ECDSA_SHA_512".to_string(),
        })
        .await?;
    let res_sign_wallet = response.into_inner();
    println!("Signature : {:?}", &res_sign_wallet.signature);
    let response = client
        .derive_wallet_public_key(DeriveWalletPublicKeyRequest {
            algorithm: "BIP32".to_string(),
            chain_code: res_public_master.chain_code,
            public_key: res_public_master.public,
            path: vec![2, 4, 1],
        })
        .await?;
    let res_public_wallet = response.into_inner();
    println!("Public key {:?}", &res_public_wallet.public_key);
    println!("Chaincode : {:?}", &res_public_wallet.chain_code);

    let response = client
        .verify_signature(VerifySignatureRequest {
            data: b"I want to sign this with wallet private key".to_vec(),
            signature: res_sign_wallet.signature,
            key: res_public_wallet.public_key,
            algorithm: "ECDSA_SHA_512".to_string(),
        })
        .await?;

    println!("Signature is valid: {:?}", response.into_inner().valid);
    let response = client
    .generate_wallet_seed(GenerateWalletSeedRequest { length: 32 })
    .await?;

    let res_seed = response.into_inner();

    let response = client
    .derive_wallet_public_key_one_shot(DeriveWalletPublicKeyOneShotRequest {
        algorithm: "BIP32".to_string(),
        seed: Some(derive_wallet_public_key_one_shot_request::Seed::Wrapped(res_seed.wrapped_seed.clone())),
        path: vec![4, 8, 2],
    })
    .await?;
    let res_public_oneshot_wallet = response.into_inner();
    println!("Public key {:?}", &res_public_oneshot_wallet.public_key);
    println!("Chaincode : {:?}", &res_public_oneshot_wallet.chain_code);
    let response = client
    .derive_wallet_and_sign_one_shot(DeriveWalletAndSignOneShotRequest {
        algorithm: "BIP32".to_string(),
        seed: Some(derive_wallet_and_sign_one_shot_request::Seed::Wrapped(res_seed.wrapped_seed)),
        path: vec![4, 8, 2],
        data: b"I want to sign this with `one shot calls`".to_vec(),
        signature_algorithm: "ECDSA_SHA_512".to_string(),
    })
    .await?;
    let res_sign_oneshot_wallet = response.into_inner();

    let response = client
        .verify_signature(VerifySignatureRequest {
            data: b"I want to sign this with `one shot calls`".to_vec(),
            signature: res_sign_oneshot_wallet.signature,
            key: res_public_oneshot_wallet.public_key,
            algorithm: "ECDSA_SHA_512".to_string(),
        })
        .await?;

    println!("Signature is valid: {:?}", response.into_inner().valid);
	rsp, err := client.GenerateWalletSeed(ctx, &crypto.GenerateWalletSeedRequest{
		Length: 32,
	})

	// Check for errors

	rspMaster, errMaster := client.DeriveWalletMasterKey(ctx, &crypto.DeriveWalletMasterKeyRequest{
		Algorithm: "BIP32",
		Whitelist: []string{"ECDSA_SHA_512"},
		Seed: &crypto.DeriveWalletMasterKeyRequest_Wrapped{
			Wrapped: rsp.WrappedSeed,
		},
	})

	// It is also possible to use a plaintext seed
	//
	// rsp, err := client.GetEntropy(ctx, &crypto.GetEntropyRequest{
	// 	Source: "PRNG",
	// 	Length: 64,
	// })
	//
	// ...
	// Seed: &crypto.DeriveWalletMasterKeyRequest_Wrapped{
	//     Plaintext: rsp.Entropy,
	// },
	// ...

	// Check for errors

	masterKey := rspMaster.KeyId
	fmt.Printf("Master Key: %s\n", masterKey)
	rsp, err := client.GetWalletPublicComponents(ctx, &crypto.GetWalletPublicComponentsRequest{
		KeyId: keyIdWalletMaster,
	})

	publicKey := rsp.Public
	fmt.Printf("Master Public key: %x\n", publicKey)
	chainCode := rsp.ChainCode
	fmt.Printf("Master ChainCode: %x\n", chainCode)
	fingerprint := rsp.ParentFingerprint
	fmt.Printf("Master Fingerprint: %x\n", fingerprint)
	index := rsp.Index
	fmt.Printf("Index : %x\n", index)
	depth := rsp.Depth
	fmt.Printf("Depth: %x\n", depth)
	rsp, err := client.DeriveWalletPrivateKey(ctx, &crypto.DeriveWalletPrivateKeyRequest{
		KeyId:     keyIdWalletMaster,
		Whitelist: []string{"ECDSA_SHA_512"},
		Path:      []uint32{2, 4, 1},
	})

	// Check for errors

	privateKey := rsp.KeyId
	fmt.Printf("Private KeyId: %s\n", privateKey)
	msg := "I want to sign this"
	rspSign, errSign := client.Sign(ctx, &crypto.SignRequest{
		Data:      []byte(msg),
		Algorithm: "ECDSA_SHA_512",
		KeyId:     privateKey,
	})

	// Check for errors

	signature := rspSign.Signature
	fmt.Printf("Signature: %x\n", signature)
	rsp, err := client.DeriveWalletPublicKey(ctx, &crypto.DeriveWalletPublicKeyRequest{
		Algorithm: "BIP32",
		PublicKey: pubKey,
		ChainCode: chainCode,
		Path:      []uint32{2, 4, 1},
	})

	// Check for errors

	publicKey := rsp.PublicKey
	fmt.Printf("Public key m/2/4/1 : %x\n", publicKey)
	chainCodeRecv := rsp.ChainCode
	fmt.Printf("ChainCode m/2/4/1: %x\n", chainCodeRecv)

	rspSign, errSign := client.VerifySignature(ctx, &crypto.VerifySignatureRequest{
		Algorithm: "ECDSA_SHA_512",
		Key:       publicKey,
		Signature: signature,
		Data:      []byte(msg),
	})

	// Check err for errors

	valid := rspSign.Valid
	fmt.Printf("Signature is valid: %t\n", valid)

	rspPublicKey, errMaster := client.DeriveWalletPublicKeyOneShot(ctx, &crypto.DeriveWalletPublicKeyOneShotRequest{
		Algorithm: "BIP32",
		Seed: &crypto.DeriveWalletPublicKeyOneShotRequest_Wrapped{
			Wrapped: seed,
		},
		Path: []uint32{4, 8, 2},
	})

	// Check for errors

	publicKey := rspPublicKey.PublicKey
	chainCode := rspPublicKey.ChainCode
	fmt.Printf("Public Key: %x\n", publicKey)
	fmt.Printf("Chain Code: %x\n", chainCode)
	msg := "I want to sign this message using my SECP256K1 key"
	rspSign, errSign := client.DeriveWalletAndSignOneShot(ctx, &crypto.DeriveWalletAndSignOneShotRequest{
		Algorithm: "BIP32",
		Seed: &crypto.DeriveWalletAndSignOneShotRequest_Wrapped{
			Wrapped: seed,
		},
		Path:               []uint32{4, 8, 2},
		SignatureAlgorithm: "ECDSA_SHA_512",
		Data:               []byte(msg),
	})

	// Check for errors

	signature := rspSign.Signature
	fmt.Printf("Signature: %x\n", signature)

	//Public key from WalletDerivePublicKeyOneShot
	rspVerify, errVerify := client.VerifySignature(ctx, &crypto.VerifySignatureRequest{
		Algorithm: "ECDSA_SHA_512",
		Key:       publicKey,
		Signature: signature,
		Data:      []byte(msg),
	})

	// Check for errors

	valid := rspVerify.Valid
	fmt.Printf("Signature is valid: %t\n", valid)
    try:
        reqSeed = wallet_pb2.GenerateWalletSeedRequest(length=32)
        resSeed = stub.GenerateWalletSeed(request=reqSeed, metadata=metadata)
    except Exception as err:
        print('There was error getting entropy : ', err)
    try:
        reqMaster = wallet_pb2.DeriveWalletMasterKeyRequest(
            algorithm='BIP32',
            whitelist=['ECDSA_SHA_512'],
            wrapped=resSeed.wrapped_seed)

        # It is also possible to use a plaintext seed
        #
        # reqSeed = rand_pb2.GetEntropyRequest(length=64, source='PRNG')
        # resSeed = stub.GetEntropy(request=reqSeed, metadata=metadata)
        #
        # ...
        # plaintext = resSeed.entropy,
        # ...

        resMaster = stub.DeriveWalletMasterKey(request=reqMaster,
                                               metadata=metadata)
        print('Master key id : ', resMaster.key_id)
    except Exception as err:
        print('Error deriving master wallet key : ', err)
    try:
        reqMasterPublic = wallet_pb2.GetWalletPublicComponentsRequest(
            key_id=resMaster.key_id)
        resMasterPublic = stub.GetWalletPublicComponents(
            request=reqMasterPublic, metadata=metadata)
    except Exception as err:
        print('Error trying to get the public components of master :', err)

    print('Master Public key', resMasterPublic.public.hex())
    print('Master Chaincode :', resMasterPublic.chain_code.hex())
    print('Master Fingerprint :', resMasterPublic.parent_fingerprint.hex())
    print('Master Index key :', resMasterPublic.index)
    print('Depth of master key :', resMasterPublic.depth)
    try:
        reqPrivate = wallet_pb2.DeriveWalletPrivateKeyRequest(
            key_id=resMaster.key_id,
            whitelist=['ECDSA_SHA_512'],
            path=[2, 4, 1])
        resPrivate = stub.DeriveWalletPrivateKey(request=reqPrivate,
                                                 metadata=metadata)
        print('Private key id : ', resPrivate.key_id)
    except Exception as err:
        print('Error trying to derive private key : ', err)

    msgWallet = 'I want to sign this message using my wallet private key'
    try:
        reqSignWallet = sign_pb2.SignRequest(algorithm='ECDSA_SHA_512',
                                             key_id=resPrivate.key_id,
                                             data=msgWallet.encode())
        resSignWallet = stub.Sign(request=reqSignWallet, metadata=metadata)
        signatureWallet = resSignWallet.signature
        print('Signature using the wallet private key :', signature.hex())
    except Exception as err:
        print('There was an error signing the message:', err)
    try:
        reqPublicKey = wallet_pb2.DeriveWalletPublicKeyRequest(
            algorithm='BIP32',
            chain_code=resMasterPublic.chain_code,
            path=[2, 4, 1],
            public_key=resMasterPublic.public,
        )
        resPublicKey = stub.DeriveWalletPublicKey(request=reqPublicKey,
                                                  metadata=metadata)
    except Exception as err:
        print('Error deriving public key wallet:', err)
    print('Public key : ', resPublicKey.public_key.hex())
    print('Chaincode ', resPublicKey.chain_code.hex())
    try:
        req = sign_pb2.VerifySignatureRequest(
            algorithm='ECDSA_SHA_512',
            key=resPublicKey.public_key,
            signature=signatureWallet,
            data=msgWallet.encode(),
        )
        res = stub.VerifySignature(request=req, metadata=metadata)
        print('Signature is valid:', res.valid)
    except Exception as err:
        print('There was an error verifying the signature:', err)
    try:
        reqSeed = wallet_pb2.GenerateWalletSeedRequest(length=32)
        seedOneShot = stub.GenerateWalletSeed(request=reqSeed, metadata=metadata)
    except Exception as err:
        print('There was error getting entropy : ', err)
    try:
        reqPublicKeyOneShot = wallet_pb2.DeriveWalletPublicKeyOneShotRequest(
            algorithm='BIP32',
            wrapped=seedOneShot.wrapped_seed,
            path=[4, 8, 2])

        resPublicKeyOneShot = stub.DeriveWalletPublicKeyOneShot(request=reqPublicKeyOneShot,
                                               metadata=metadata)
        print('Public key is : ', resPublicKeyOneShot.public_key.hex())
        print('Chain code is : ', resPublicKeyOneShot.chain_code.hex())
    except Exception as err:
        print('Error deriving wallet public key OneShot : ', err)
    try:
        reqSignOneShot = wallet_pb2.DeriveWalletAndSignOneShotRequest(
            algorithm='BIP32',
            wrapped=seedOneShot.wrapped_seed,
            path=[4, 8, 2],
            signature_algorithm='ECDSA_SHA_512',
            data=msgWallet.encode())

        resSignOneShot = stub.DeriveWalletAndSignOneShot(request=reqSignOneShot,
                                               metadata=metadata)
        print('Signature is : ', resSignOneShot.signature.hex())
    except Exception as err:
        print('Error deriving wallet and sign OneShot : ', err)
        sys.exit(1)
    try:
        req = sign_pb2.VerifySignatureRequest(
            algorithm='ECDSA_SHA_512',
            key=resPublicKeyOneShot.public_key,
            signature=resSignOneShot.signature,
            data=msgWallet.encode(),
        )
        res = stub.VerifySignature(request=req, metadata=metadata)
        print('Signature is valid:', res.valid)
    except Exception as err:
        print('There was an error verifying the signature:', err)
      rspSeed <- client.generateWalletSeed(GenerateWalletSeedRequest(32))

      rspMasterWallet <- client.deriveWalletMasterKey(
        DeriveWalletMasterKeyRequest(
          "BIP32",
          Seq("ECDSA_SHA_512"),
          DeriveWalletMasterKeyRequest.Seed.Wrapped(rspSeed.wrappedSeed)
        )
      )
      _ = println("Master Key Id : " + rspMasterWallet.keyId)

      // It is possible to use a plaintext seed
      //
      // rspEntropy <- client.getEntropy(GetEntropyRequest(64, "PRNG"))
      //
      // ...
      // DeriveWalletMasterKeyRequest(
      //   "BIP32",
      //   Seq("ECDSA_SHA_512"),
      //   DeriveWalletMasterKeyRequest.Seed.Plaintext(rspEntropy.entropy)
      // )
      // ...

      rspWalletPublic <- client.getWalletPublicComponents(
        GetWalletPublicComponentsRequest(rspMasterWallet.keyId)
      )
      _ = println(
        "Master Public key : " + rspWalletPublic.public
          .toByteArray()
          .map("%02x" format _)
          .mkString
      )
      _ = println(
        "Master Chaincode : " + rspWalletPublic.chainCode
          .toByteArray()
          .map("%02x" format _)
          .mkString
      )
      _ = println(
        "Master Fingerprint : " + rspWalletPublic.parentFingerprint
          .toByteArray()
          .map("%02x" format _)
          .mkString
      )
      _ = println("Master Index key : " + rspWalletPublic.index)
      _ = println("Depth of master key : " + rspWalletPublic.depth)
      rspPrivateKey <- client.deriveWalletPrivateKey(
        DeriveWalletPrivateKeyRequest(
          Seq("ECDSA_SHA_512"),
          rspMasterWallet.keyId,
          Seq(2, 4, 1)
        )
      )
      _ = println("Private Key Id : " + rspPrivateKey.keyId)
      val msgSignWallet = "This message will be signed with wallet private key"
      rspSignWallet <- client.sign(
        SignRequest(
          ByteString.copyFromUtf8(msgSignWallet),
          rspPrivateKey.keyId,
          "ECDSA_SHA_512"
        )
      )
      _ = println(
        "Signature : " + rspSignWallet.signature
          .toByteArray()
          .map("%02x" format _)
          .mkString
      )
      rspPublicKey <- client.deriveWalletPublicKey(
        DeriveWalletPublicKeyRequest(
          "BIP32",
          rspWalletPublic.public,
          rspWalletPublic.chainCode,
          Seq(2, 4, 1)
        )
      )
      _ = println("Public key :" +
          rspPublicKey.publicKey
          .toByteArray()
          .map("%02x" format _)
          .mkString)
      _ = println("Chaincode : " +
          rspPublicKey.chainCode
          .toByteArray()
          .map("%02x" format _)
          .mkString)

      rspVerifySignWallet <- client.verifySignature(
        VerifySignatureRequest(
          ByteString.copyFromUtf8(msgSignWallet),
          rspSignWallet.signature,
          rspPublicKey.publicKey,
          "ECDSA_SHA_512"
        )
      )
      _ = println("Signature is valid : " + rspVerifySignWallet.valid)
      rspSeedOneShot <- client.generateWalletSeed(GenerateWalletSeedRequest(32))

      rspPublicKeyOneShot <- client.deriveWalletPublicKeyOneShot(
        DeriveWalletPublicKeyOneShotRequest(
          "BIP32",
          DeriveWalletPublicKeyOneShotRequest.Seed.Wrapped(rspSeedOneShot.wrappedSeed),
          Seq(4, 8, 2)
        )
      )
      _ = println("Public key is : " +
          rspPublicKeyOneShot.publicKey
          .toByteArray()
          .map("%02x" format _)
          .mkString)
      _ = println("Chain code is : " +
          rspPublicKeyOneShot.chainCode
          .toByteArray()
          .map("%02x" format _)
          .mkString)
      rspSignOneShot <- client.deriveWalletAndSignOneShot(
        DeriveWalletAndSignOneShotRequest(
          "BIP32",
          DeriveWalletAndSignOneShotRequest.Seed.Wrapped(rspSeedOneShot.wrappedSeed),
          Seq(4, 8, 2),
          ByteString.copyFromUtf8(msgSignWallet),
          "ECDSA_SHA_512"
        )
      )
      _ = println("Signature is : " +
          rspSignOneShot.signature
          .toByteArray()
          .map("%02x" format _)
          .mkString)

      rspVerifySignOneShot <- client.verifySignature(
        VerifySignatureRequest(
          ByteString.copyFromUtf8(msgSignWallet),
          rspSignOneShot.signature,
          rspPublicKeyOneShot.publicKey,
          "ECDSA_SHA_512"
        )
      )
      _ = println("Signature is valid : " + rspVerifySignOneShot.valid)
    var wrapped_seed = client.GenerateWalletSeed(
        new GenerateWalletSeedRequest {
          Length = 32,
        },
        metadata);

    var wallet_master = client.DeriveWalletMasterKey(
        new DeriveWalletMasterKeyRequest {
          Algorithm = "BIP32",
          Whitelist = { "ECDSA_SHA_512" },
          Wrapped = wrapped_seed.WrappedSeed,
        },
        metadata);

    // It is also possible to use a plaintext seed
    //
    // var wallet_seed = client.GetEntropy(
    //     new GetEntropyRequest { Source = "PRNG", Length = 64 }, metadata);
    //
    // ...
    // Plaintext = wallet_seed.Entropy
    // ...

    Console.WriteLine("Wallet Master Key: " + wallet_master.KeyId);
    // We can pull the public key of master in order to generate key pair for
    // m/2/4/1
    var master_public_components = client.GetWalletPublicComponents(
        new GetWalletPublicComponentsRequest { KeyId = wallet_master.KeyId },
        metadata);

    Console.WriteLine("Master Public key: " +
                      Bytes2Hex(master_public_components.Public));
    Console.WriteLine("Master Chaincode: " +
                      Bytes2Hex(master_public_components.ChainCode));
    Console.WriteLine("Master Fingerprint: " +
                      Bytes2Hex(master_public_components.ParentFingerprint));
    Console.WriteLine("Master Index key: " + master_public_components.Index);
    Console.WriteLine("Depth of master key: " + master_public_components.Depth);
    // ANCHOR_END get_public_wallet

    var wallet_public_first = client.DeriveWalletPublicKey(
        new DeriveWalletPublicKeyRequest {
          Algorithm = "BIP32", PublicKey = master_public_components.Public,
          ChainCode = master_public_components.ChainCode, Path = { 2, 4, 1 }
        },
        metadata);

    // Reusing the same path to generate public key of the freshly generated
    // private key
    Console.WriteLine("Public key of m/2/4/1: " +
                      Bytes2Hex(wallet_public_first.PublicKey));
    Console.WriteLine("Chaincode of public key of m/2/4/1: " +
                      Bytes2Hex(wallet_public_first.ChainCode));

    var testSignature = client.VerifySignature(
        new VerifySignatureRequest {
          Algorithm = "ECDSA_SHA_512", Key = wallet_public_first.PublicKey,
          Signature = signature_wallet.Signature,
          Data = ByteString.CopyFromUtf8(wallet_message)
        },
        metadata);
    Console.WriteLine("Signature is valid: " + testSignature);

    var wrapped_oneshot_seed = client.GenerateWalletSeed(
        new GenerateWalletSeedRequest {
          Length = 32,
        },
        metadata);

    var wallet_public_oneshot = client.DeriveWalletPublicKeyOneShot(
        new DeriveWalletPublicKeyOneShotRequest {
          Algorithm = "BIP32", Wrapped = wrapped_oneshot_seed.WrappedSeed,
          Path = { 4, 8, 2 }
        },
        metadata);

    Console.WriteLine("Public key is : " +
                      Bytes2Hex(wallet_public_oneshot.PublicKey));
    Console.WriteLine("Chain code is : " +
                      Bytes2Hex(wallet_public_oneshot.ChainCode));

    var wallet_sign_oneshot = client.DeriveWalletAndSignOneShot(
        new DeriveWalletAndSignOneShotRequest {
          Algorithm = "BIP32", Wrapped = wrapped_oneshot_seed.WrappedSeed,
          Path = { 4, 8, 2 }, SignatureAlgorithm = "ECDSA_SHA_512",
          Data = ByteString.CopyFromUtf8(wallet_message)
        },
        metadata);

    Console.WriteLine("Signature is : " +
                      Bytes2Hex(wallet_sign_oneshot.Signature));

    var testOneShotSignature = client.VerifySignature(
        new VerifySignatureRequest {
          Algorithm = "ECDSA_SHA_512", Key = wallet_public_oneshot.PublicKey,
          Signature = wallet_sign_oneshot.Signature,
          Data = ByteString.CopyFromUtf8(wallet_message)
        },
        metadata);
    Console.WriteLine("Signature is valid: " + testOneShotSignature);
  }
}
}
    var wallet_private_first = client.DeriveWalletPrivateKey(
        new DeriveWalletPrivateKeyRequest { Whitelist = { "ECDSA_SHA_512" },
                                            KeyId = wallet_master.KeyId,
                                            Path = { 2, 4, 1 } },
        metadata);

    Console.WriteLine("wallet m/2/4/1 Private Key: " +
                      wallet_private_first.KeyId);
    // We can use this key ID with the given signatures algorithm
    var wallet_message = "I want to sign this message !";

    var signature_wallet = client.Sign(
        new SignRequest { Data = ByteString.CopyFromUtf8(wallet_message),
                          KeyId = wallet_private_first.KeyId,
                          Algorithm = "ECDSA_SHA_512" },
        metadata);

    Console.WriteLine("Signed message with derived private key: " +
                      signature_wallet.Signature.ToStringUtf8());
    var wallet_public_first = client.DeriveWalletPublicKey(
        new DeriveWalletPublicKeyRequest {
          Algorithm = "BIP32", PublicKey = master_public_components.Public,
          ChainCode = master_public_components.ChainCode, Path = { 2, 4, 1 }
        },
        metadata);

    // Reusing the same path to generate public key of the freshly generated
    // private key
    Console.WriteLine("Public key of m/2/4/1: " +
                      Bytes2Hex(wallet_public_first.PublicKey));
    Console.WriteLine("Chaincode of public key of m/2/4/1: " +
                      Bytes2Hex(wallet_public_first.ChainCode));

    var testSignature = client.VerifySignature(
        new VerifySignatureRequest {
          Algorithm = "ECDSA_SHA_512", Key = wallet_public_first.PublicKey,
          Signature = signature_wallet.Signature,
          Data = ByteString.CopyFromUtf8(wallet_message)
        },
        metadata);
    Console.WriteLine("Signature is valid: " + testSignature);
    var wrapped_oneshot_seed = client.GenerateWalletSeed(
        new GenerateWalletSeedRequest {
          Length = 32,
        },
        metadata);

    var wallet_public_oneshot = client.DeriveWalletPublicKeyOneShot(
        new DeriveWalletPublicKeyOneShotRequest {
          Algorithm = "BIP32", Wrapped = wrapped_oneshot_seed.WrappedSeed,
          Path = { 4, 8, 2 }
        },
        metadata);

    Console.WriteLine("Public key is : " +
                      Bytes2Hex(wallet_public_oneshot.PublicKey));
    Console.WriteLine("Chain code is : " +
                      Bytes2Hex(wallet_public_oneshot.ChainCode));
    var wallet_sign_oneshot = client.DeriveWalletAndSignOneShot(
        new DeriveWalletAndSignOneShotRequest {
          Algorithm = "BIP32", Wrapped = wrapped_oneshot_seed.WrappedSeed,
          Path = { 4, 8, 2 }, SignatureAlgorithm = "ECDSA_SHA_512",
          Data = ByteString.CopyFromUtf8(wallet_message)
        },
        metadata);

    Console.WriteLine("Signature is : " +
                      Bytes2Hex(wallet_sign_oneshot.Signature));

    var testOneShotSignature = client.VerifySignature(
        new VerifySignatureRequest {
          Algorithm = "ECDSA_SHA_512", Key = wallet_public_oneshot.PublicKey,
          Signature = wallet_sign_oneshot.Signature,
          Data = ByteString.CopyFromUtf8(wallet_message)
        },
        metadata);
    Console.WriteLine("Signature is valid: " + testOneShotSignature);
  std::vector<std::string> whitelist_wallet;
  whitelist_wallet.push_back("ECDSA_SHA_512");
  // Usually use BIP-0039 to seed, here seede randomly for the example
  std::string wallet_master =
      subtle_crypto.DeriveWalletMasterKey("BIP32", whitelist_wallet);

  std::cout << "Wallet Master Key : " << wallet_master << std::endl;
  // We can pull the public key of master in order to generate key pair for
  // m/2/4/1
  crypto::GetWalletPublicComponentsResponse master_public_components =
      subtle_crypto.GetWalletPublicComponents(wallet_master);

  print_bytes("Master Public key : ", master_public_components.public_());
  print_bytes("Master Chaincode : ", master_public_components.chain_code());
  print_bytes("Master Fingerprint : ",
              master_public_components.parent_fingerprint());
  std::cout << "Master Index key : " << master_public_components.index()
            << std::endl;
  std::cout << "Depth of master key : " << master_public_components.depth()
            << std::endl;
  // ANCHOR_END get_public_wallet

  std::vector<std::uint32_t> path_first_public;
  // In this example we don't use hardened keys to derive private and public and
  // show how the API works The path will be m/2/4/1, if you want an hardened
  // key you need to have the MSB to 1 (so 0H is 2147483648)
  path_first_public.push_back(2);
  path_first_public.push_back(4);
  path_first_public.push_back(1);
  // Reusing the same path to generate public key of the freshly generated
  // private key
  crypto::DeriveWalletPublicKeyResponse wallet_public_first =
      subtle_crypto.DeriveWalletPublicKey(
          "BIP32", master_public_components.public_(),
          master_public_components.chain_code(), path_first_public);
  print_bytes("Public key of m/2/4/1 : ", wallet_public_first.public_key());
  print_bytes("Chaincode of public key of m/2/4/1 : ",
              wallet_public_first.chain_code());
  bool testSignature = subtle_crypto.VerifySignature(
      "ECDSA_SHA_512", wallet_public_first.public_key(), signature_wallet,
      wallet_message);
  std::cout << "Signature is valid: " << testSignature << std::endl;

  std::string wallet_wrapped_seed = subtle_crypto.GenerateWalletSeed();

  std::vector<std::uint32_t> path_oneshot;
  // In this example we don't use hardened keys to derive private and public and
  // show how the API works The path will be m/4/8/2, if you want an hardened
  // key you need to have the MSB to 1 (so 0H is 2147483648)
  path_oneshot.push_back(4);
  path_oneshot.push_back(8);
  path_oneshot.push_back(2);

  crypto::DeriveWalletPublicKeyOneShotResponse wallet_public_oneshot =
      subtle_crypto.DeriveWalletPublicKeyOneShot(
          "BIP32", wallet_wrapped_seed, path_oneshot);
  print_bytes("Public key of m/4/8/2 : ", wallet_public_oneshot.public_key());
  print_bytes("Chaincode of public key of m/4/8/2 : ",
              wallet_public_oneshot.chain_code());

  std::string wallet_oneshot_message = "I want to sign this message !";

  crypto::DeriveWalletAndSignOneShotResponse wallet_sign_oneshot =
      subtle_crypto.DeriveWalletAndSignOneShot(
          "BIP32", wallet_wrapped_seed, path_oneshot, "ECDSA_SHA_512", wallet_oneshot_message);

  print_bytes("Signature of key m/4/8/2 : ", wallet_sign_oneshot.signature());

  bool testOneShotSignature = subtle_crypto.VerifySignature(
      "ECDSA_SHA_512", wallet_public_oneshot.public_key(), wallet_sign_oneshot.signature(),
      wallet_oneshot_message);
  std::cout << "Signature is valid: " << testOneShotSignature << std::endl;

  return 0;
}
  std::vector<std::uint32_t> path_first_key;
  // In this example we don't use hardened keys to derive private and public
  // keys and show how the API works The path will be m/2/4/1, if you want an
  // hardened key you need to have the MSB to 1 (so 0H is 2147483648)
  path_first_key.push_back(2);
  path_first_key.push_back(4);
  path_first_key.push_back(1);

  std::string wallet_private_first = subtle_crypto.DeriveWalletPrivateKey(
      wallet_master, whitelist_wallet, path_first_key);

  std::cout << "wallet m/2/4/1 Private Key : " << wallet_private_first
            << std::endl;
  // We can use this key ID with the given signatures algorithm
  std::string wallet_message = "I want to sign this message !";
  std::string signature_wallet =
      subtle_crypto.Sign("ECDSA_SHA_512", wallet_private_first, wallet_message);
  print_bytes("Signed message with derived private key : ", signature_wallet);
  std::vector<std::uint32_t> path_first_public;
  // In this example we don't use hardened keys to derive private and public and
  // show how the API works The path will be m/2/4/1, if you want an hardened
  // key you need to have the MSB to 1 (so 0H is 2147483648)
  path_first_public.push_back(2);
  path_first_public.push_back(4);
  path_first_public.push_back(1);
  // Reusing the same path to generate public key of the freshly generated
  // private key
  crypto::DeriveWalletPublicKeyResponse wallet_public_first =
      subtle_crypto.DeriveWalletPublicKey(
          "BIP32", master_public_components.public_(),
          master_public_components.chain_code(), path_first_public);
  print_bytes("Public key of m/2/4/1 : ", wallet_public_first.public_key());
  print_bytes("Chaincode of public key of m/2/4/1 : ",
              wallet_public_first.chain_code());
  bool testSignature = subtle_crypto.VerifySignature(
      "ECDSA_SHA_512", wallet_public_first.public_key(), signature_wallet,
      wallet_message);
  std::cout << "Signature is valid: " << testSignature << std::endl;
  std::string wallet_wrapped_seed = subtle_crypto.GenerateWalletSeed();

  std::vector<std::uint32_t> path_oneshot;
  // In this example we don't use hardened keys to derive private and public and
  // show how the API works The path will be m/4/8/2, if you want an hardened
  // key you need to have the MSB to 1 (so 0H is 2147483648)
  path_oneshot.push_back(4);
  path_oneshot.push_back(8);
  path_oneshot.push_back(2);

  crypto::DeriveWalletPublicKeyOneShotResponse wallet_public_oneshot =
      subtle_crypto.DeriveWalletPublicKeyOneShot(
          "BIP32", wallet_wrapped_seed, path_oneshot);
  print_bytes("Public key of m/4/8/2 : ", wallet_public_oneshot.public_key());
  print_bytes("Chaincode of public key of m/4/8/2 : ",
              wallet_public_oneshot.chain_code());
  std::string wallet_oneshot_message = "I want to sign this message !";

  crypto::DeriveWalletAndSignOneShotResponse wallet_sign_oneshot =
      subtle_crypto.DeriveWalletAndSignOneShot(
          "BIP32", wallet_wrapped_seed, path_oneshot, "ECDSA_SHA_512", wallet_oneshot_message);

  print_bytes("Signature of key m/4/8/2 : ", wallet_sign_oneshot.signature());

  bool testOneShotSignature = subtle_crypto.VerifySignature(
      "ECDSA_SHA_512", wallet_public_oneshot.public_key(), wallet_sign_oneshot.signature(),
      wallet_oneshot_message);
  std::cout << "Signature is valid: " << testOneShotSignature << std::endl;

    }
  )
    client.getWalletPublicComponents(
      {
        key_id: resWalletMaster.key_id
      },
      metadata,
      (err, resPublicWallet) => {
        console.log(err || `Master Public key : ${resPublicWallet.public.toString('hex')}`)
        console.log(err || `Master Chaincode : ${resPublicWallet.chain_code.toString('hex')}`)
        console.log(err || `Master Fingerprint : ${resPublicWallet.parent_fingerprint}`)
        console.log(err || `Master Index key : ${resPublicWallet.index}`)
        console.log(err || `Depth of master key : ${resPublicWallet.depth}`)
    }
  )
    client.deriveWalletPrivateKey(
      {
        key_id: resWalletMaster.key_id,
        whitelist: ['ECDSA_SHA_512'],
        path: [2, 4, 1]
      },
      metadata,
      (err, resPrivate) => {
        console.log(err || `Private KeyId: ${resPrivate.key_id}`)
    }
  )

    // Sign a message using the previously generated key
    client.Sign(
      {
        algorithm: 'ECDSA_SHA_512',
        data: Buffer.from('Message to sign', 'utf8'),
        key_id: resPrivate.key_id
      },
      metadata,
      (err, resSignWallet) => {
        console.log(err || `Signature: ${resSignWallet.signature.toString('hex')}`)
    }
  )
    client.deriveWalletPublicKey(
      {
        algorithm: 'BIP32',
        chain_code: resPublicWallet.chain_code,
        path: [2, 4, 1],
        public_key: resPublicWallet.public
      },
      metadata,
      (err, resPublicKey) => {
        console.log(err || `Public KeyId: ${resPublicKey.public_key.toString('hex')}`)
        console.log(err || `Chaincode: ${resPublicKey.chain_code.toString('hex')}`)
    }
  )

    // Verify the signature of the message
    client.VerifySignature(
      {
        key: resPublicKey.public_key,
        algorithm: 'ECDSA_SHA_512',
        signature: resSignWallet.signature,
        data: Buffer.from('Message to sign', 'utf8')
      },
      metadata,
      (err, resVerify) => {
        console.log(err || `Signature is valid: ${resVerify.valid}`)
    }
  )
    client.deriveWalletPublicKeyOneShot(
      {
        algorithm: 'BIP32',
        wrapped: resSeed.wrapped_seed,
        path: [4, 8, 2]
      },
      metadata,
      (err, resPublicKey) => {
        console.log(err || `Public KeyId: ${resPublicKey.public_key.toString('hex')}`)
        console.log(err || `Chaincode: ${resPublicKey.chain_code.toString('hex')}`)
    }
  )
    client.deriveWalletAndSignOneShot(
      {
        algorithm: 'BIP32',
        wrapped: resSeed.wrapped_seed,
        path: [4, 8, 2],
        signature_algorithm: 'ECDSA_SHA_512',
        data: Buffer.from('Message to sign', 'utf8')
      },
      metadata,
      (err, resSign) => {
        console.log(err || `Signature: ${resSign.signature.toString('hex')}`)
    }
  )

    // Verify the signature of the message
    client.VerifySignature(
      {
        key: resPublicKey.public_key,
        algorithm: 'ECDSA_SHA_512',
        signature: resSign.signature,
        data: Buffer.from('Message to sign', 'utf8')
      },
      metadata,
      (err, resVerify) => {
        console.log(err || `Signature is valid: ${resVerify.valid}`)
    }
  )
    GenerateWalletSeedRequest reqSeed =
        GenerateWalletSeedRequest.newBuilder().setLength(32).build();

    GenerateWalletSeedResponse respSeed = client.generateWalletSeed(reqSeed);

    DeriveWalletMasterKeyRequest reqMaster =
        DeriveWalletMasterKeyRequest.newBuilder()
            .setAlgorithm("BIP32")
            .addWhitelist("ECDSA_SHA_512")
            .setWrapped(respSeed.getWrappedSeed())
            .build();

    /*
    It is possible to use a plaintext seed

    GetEntropyRequest reqEntropyWallet =
    GetEntropyRequest.newBuilder().setSource("PRNG").setLength(64).build();

    GetEntropyResponse respEntropyWallet = client.getEntropy(reqEntropyWallet);

    ...
    .setPlaintext(respEntropyWallet.getEntropy())
    ...
    */

    DeriveWalletMasterKeyResponse respMaster =
        client.deriveWalletMasterKey(reqMaster);
    System.out.println("Master key id : " + respMaster.getKeyId());
    GetWalletPublicComponentsRequest reqPubWallet =
        GetWalletPublicComponentsRequest.newBuilder()
            .setKeyId(respMaster.getKeyId())
            .build();

    GetWalletPublicComponentsResponse respPubWallet =
        client.getWalletPublicComponents(reqPubWallet);
    System.out.println("Master Public key : " + respPubWallet.getPublic());
    System.out.println("Master Chaincode : " + respPubWallet.getChainCode());
    System.out.println("Master Fingerprint : " +
                       respPubWallet.getParentFingerprint());
    System.out.println("Master Index key : " + respPubWallet.getIndex());
    System.out.println("Depth of master key : " + respPubWallet.getDepth());
    DeriveWalletPrivateKeyRequest reqPrivate =
        DeriveWalletPrivateKeyRequest.newBuilder()
            .setKeyId(respMaster.getKeyId())
            .addWhitelist("ECDSA_SHA_512")
            .addPath(2)
            .addPath(4)
            .addPath(1)
            .build();

    DeriveWalletPrivateKeyResponse respPrivate =
        client.deriveWalletPrivateKey(reqPrivate);
    System.out.println("Private key id : " + respPrivate.getKeyId());

    SignRequest reqSignWallet =
        SignRequest.newBuilder()
            .setData(ByteString.copyFromUtf8("Message to sign"))
            .setAlgorithm("ECDSA_SHA_512")
            .setKeyId(respPrivate.getKeyId())
            .build();

    SignResponse respSignWallet = client.sign(reqSignWallet);

    System.out.println("Signature: " + respSignWallet.getSignature());
    DeriveWalletPublicKeyRequest reqPublicKeyWallet =
        DeriveWalletPublicKeyRequest.newBuilder()
            .setAlgorithm("BIP32")
            .setPublicKey(respPubWallet.getPublic())
            .setChainCode(respPubWallet.getChainCode())
            .addPath(2)
            .addPath(4)
            .addPath(1)
            .build();

    DeriveWalletPublicKeyResponse respPublicKeyWallet =
        client.deriveWalletPublicKey(reqPublicKeyWallet);
    System.out.println("Public key : " + respPublicKeyWallet.getPublicKey());
    System.out.println("Chaincode key : " + respPublicKeyWallet.getChainCode());

    VerifySignatureRequest reqVerifyWallet =
        VerifySignatureRequest.newBuilder()
            .setKey(respPublicKeyWallet.getPublicKey())
            .setAlgorithm("ECDSA_SHA_512")
            .setSignature(respSignWallet.getSignature())
            .setData(ByteString.copyFromUtf8("Message to sign"))
            .build();

    VerifySignatureResponse respVerifyWallet =
        client.verifySignature(reqVerifyWallet);

    System.out.println("Signature is valid: " + respVerifyWallet.getValid());
    GenerateWalletSeedRequest reqSeedOneShot =
        GenerateWalletSeedRequest.newBuilder().setLength(32).build();

    GenerateWalletSeedResponse respSeedOneShot = client.generateWalletSeed(reqSeedOneShot);

    DeriveWalletPublicKeyOneShotRequest reqPublicKeyOneShot =
    DeriveWalletPublicKeyOneShotRequest.newBuilder()
            .setAlgorithm("BIP32")
            .setWrapped(respSeedOneShot.getWrappedSeed())
            .addPath(4)
            .addPath(8)
            .addPath(2)
            .build();

    DeriveWalletPublicKeyOneShotResponse respPublicKeyOneShot =
        client.deriveWalletPublicKeyOneShot(reqPublicKeyOneShot);
    System.out.println("Public key is : " + respPublicKeyOneShot.getPublicKey());
    System.out.println("Chain code is : " + respPublicKeyOneShot.getChainCode());
    DeriveWalletAndSignOneShotRequest reqSignOneShot =
    DeriveWalletAndSignOneShotRequest.newBuilder()
            .setAlgorithm("BIP32")
            .setWrapped(respSeedOneShot.getWrappedSeed())
            .addPath(4)
            .addPath(8)
            .addPath(2)
            .setSignatureAlgorithm("ECDSA_SHA_512")
            .setData(ByteString.copyFromUtf8("Message to sign"))
            .build();

    DeriveWalletAndSignOneShotResponse respSignOneShot =
        client.deriveWalletAndSignOneShot(reqSignOneShot);
    System.out.println("Signature is : " + respSignOneShot.getSignature());

    VerifySignatureRequest reqVerifyOneShot =
    VerifySignatureRequest.newBuilder()
        .setKey(respPublicKeyOneShot.getPublicKey())
        .setAlgorithm("ECDSA_SHA_512")
        .setSignature(respSignOneShot.getSignature())
        .setData(ByteString.copyFromUtf8("Message to sign"))
        .build();

    VerifySignatureResponse respVerifyOneShot =
        client.verifySignature(reqVerifyOneShot);

    System.out.println("Signature is valid: " + respVerifyOneShot.getValid());

The cryptographic API supports blockchain wallet key derivation using algorithms such as SLIP-010 and BIP-032. A set of RPCs is provided to allow:

The attached code examples use all of these functionalities.

The last two calls are a bit special in the way they work. They are suffixed with "OneShot" because it does not keep any intermediate steps. This means that it performs a master key generation, then a private key derivation on each call. These steps are not returned to the caller and are not stored by the crypto service. For signature verification, you need to retrieve the public key with the DeriveWalletPublicKeyOneShot command.

Features

Here are feature matrices you can use to check if a given algorithm is supported by the cryptographic API, and through which backend.

Key generation

software-opensslhardware-dekaton
EC_SECP256K1yesyes
EC_SECP256R1yesyes
EC_SECP384R1yesyes
EC_SECP521R1yesyes
RSA_{2048,4096}yesyes
CIPHER_{128,256}yesyes
ECIES_{curve}soonsoon

Hashing

software-opensslhardware-dekaton
SHA_{256,384,512}yesyes

Signatures

software-opensslhardware-dekaton
ECDSA_{hash}yesyes
RSASSA_NONE_{hash}yesyes
RSASSA_PSS_{hash}yesyes

Asymmetric encryption

software-opensslhardware-dekaton
RSAES_OAEPsoonsoon

Symmetric encryption

software-opensslhardware-dekaton
AES_CBCyesyes
CHACHA_20soonsoon

Wallet key derivation

software-opensslhardware-dekaton
BIP-032yesyes
SLIP-010yesyes

ECIES

software-opensslhardware-dekaton
ECIES_{cipher}_{mac}_{kdf}soonsoon

Random

software-opensslhardware-dekaton
PRNGyesno
TRNGnoyes
QRNGnono

Protocol Buffers

What are protocol buffers?

Protocol buffers are Google's language-neutral, platform-neutral, extensible mechanism for serializing structured data – think XML, but smaller, faster, and simpler. You define how you want your data to be structured once, then you can use special generated source code to easily write and read your structured data to and from a variety of data streams and using a variety of languages.

If you want to learn more about protocol buffers, checkout Google's documentation.

How do I start?

crypto/encrypt.proto

DecryptAeadRequest

Request to decrypt and authenticate data using an internal key

FieldTypeLabelDescription
ciphertextbytesData to decrypt
key_idstringKey id of the key used to decrypt the data
algorithmstringAlgorithm used to decrypt the data
ivbytesInitialization Vector. Must be empty if the algorithm don't use one
authentication_tagbytesAuthentication tag
aadbytesAdditional associated data

DecryptAeadResponse

Response with the decrypted and authenticated data

FieldTypeLabelDescription
plaintextbytesDecrypted data

DecryptEciesRequest

Request to decrypt data using an internal private key for ECIES

FieldTypeLabelDescription
algorithmstringAlgorithm specification used in encrypt
key_idstringKey id of the private key
ciphertextbytesEncrypted data
authentication_tagbytesTag of the ciphertext
ephemeral_public_keybytesEphemeral public key

DecryptEciesResponse

Response with the decrypted data

FieldTypeLabelDescription
plaintextbytesDecrypted data

DecryptRequest

Request to decrypt data using an internal key

FieldTypeLabelDescription
ciphertextbytesData to decrypt
key_idstringKey id of the key used to decrypt the data
algorithmstringAlgorithm used to decrypt the data
ivbytesInitialization Vector. Must be empty if the algorithm don't use one

DecryptResponse

Response with the decrypted data

FieldTypeLabelDescription
plaintextbytesDecrypted data

EasyDecryptRequest

Request to decrypt data using an internal key

FieldTypeLabelDescription
ciphertextbytesData to decrypt
key_idstringKey id of the key used to decrypt the data

EasyEncryptRequest

Request to encrypt data using an internal key

FieldTypeLabelDescription
plaintextbytesData to encrypt
key_idstringKey id of the key used to encrypt the data

EasyEncryptResponse

Response with the encrypted data

FieldTypeLabelDescription
ciphertextbytesEncrypted data

EncryptAeadRequest

Request to encrypt data using an internal key

FieldTypeLabelDescription
plaintextbytesData to encrypt
key_idstringKey id of the key used to encrypt the data
algorithmstringAlgorithm used to encrypt the data
ivbytesInitialization Vector. A random one in generated if none is provided. Must be empty if the algorithm don't use one
aadbytesAdditional associated data

EncryptAeadResponse

Response with the encrypted data and authentication tag

FieldTypeLabelDescription
ciphertextbytesEncrypted data
ivbytesInitialization Vector. Empty if the algorithm don't use one.
authentication_tagbytesAuthentication tag

EncryptEciesRequest

Request to encrypt data using an public key for ECIES

FieldTypeLabelDescription
algorithmstringAlgorithm specification for deriving and encrypting in ECIES
public_keybytesPublic key of destination
plaintextbytesData to encrypt

EncryptEciesResponse

Response with the encrypted data

FieldTypeLabelDescription
ciphertextbytesEncrypted data
authentication_tagbytesTag of the ciphertext
ephemeral_public_keybytesEphemeral public key

EncryptRequest

Request to encrypt data using an internal key

FieldTypeLabelDescription
plaintextbytesData to encrypt
key_idstringKey id of the key used to encrypt the data
algorithmstringAlgorithm used to encrypt the data
ivbytesInitialization Vector. A random one in generated if none is provided. Must be empty if the algorithm don't use one

EncryptResponse

Response with the encrypted data

FieldTypeLabelDescription
ciphertextbytesEncrypted data
ivbytesInitialization Vector. Empty if the algorithm don't use one.

PublicDecryptRequest

Request to decrypt data using an internal key

FieldTypeLabelDescription
ciphertextbytesData to decrypt
key_idstringKey id of the key used to decrypt the data
algorithmstringAlgorithm used to decrypt the data

PublicDecryptResponse

Response with the decrypted data

FieldTypeLabelDescription
plaintextbytesDecrypted data

PublicEncryptRequest

Request to encrypt data using a public key

FieldTypeLabelDescription
plaintextbytesData to encrypt
public_keybytesPublic key used to encrypt the data
algorithmstringAlgorithm used to encrypt the data

PublicEncryptResponse

Response with the encrypted data

FieldTypeLabelDescription
ciphertextbytesEncrypted data

crypto/generate.proto

EasyGenerateEncryptionKeyRequest

Request to generate cryptographic material for encryption operations

FieldTypeLabelDescription
delete_afterstringDuration after which the key will be automatically deleted

EasyGenerateEncryptionKeyResponse

Response with the id of the generated material

FieldTypeLabelDescription
key_idstringId of the generated key

EasyGenerateSignatureKeyRequest

Request to generate cryptographic material for signature operations

FieldTypeLabelDescription
delete_afterstringDuration after which the key will be automatically deleted

EasyGenerateSignatureKeyResponse

Response with the id of the generated material

FieldTypeLabelDescription
privatestringId of the generated key
publicbytesEncoded public key generated

GenerateKeyRequest

Request to generate cryptographic material

FieldTypeLabelDescription
algorithmstringAlgorithm used to generate the key
whiteliststringrepeatedWhitelist of algorithms this key will be able to use
delete_afterstringDuration after which the key will be automatically deleted

GenerateKeyResponse

Response with the id of the generated material

FieldTypeLabelDescription
key_idstringId of the generated key

GenerateWrappedKeyRequest

Request to generate wrapped cryptographic material

FieldTypeLabelDescription
algorithmstringAlgorithm used to generate the key

GenerateWrappedKeyResponse

Request to generate wrapped cryptographic material

FieldTypeLabelDescription
wrapped_secretbytesWrapped secret key generated
publicbytesEncoded public key generated for asym algorithm

RevokeKeyRequest

Request to revoke cryptographic material

FieldTypeLabelDescription
key_idstringId of the generated key

RevokeKeyResponse

Response to revoke request

crypto/hash.proto

HashRequest

Request to hash data

FieldTypeLabelDescription
databytesData to hash
algorithmstringAlgorithm used to hash the data

HashResponse

Response with the digest

FieldTypeLabelDescription
digestbytesHashed data

crypto/key_exchange.proto

DeriveEcdhRequest

Request to derive secret with ECDH algorithm

FieldTypeLabelDescription
key_idstringsecret key id
public_keybytesPublic key from the opposite side

DeriveEcdhResponse

Response to derive secret with ECDH algorithm

FieldTypeLabelDescription
shared_secretbytesShared secret

DeriveEcdhWithWrappedRequest

Request to derive secret with ECDH algorithm with a wrapped secret

FieldTypeLabelDescription
wrapped_secretbytessecret wrapped key
public_keybytesPublic key from the opposite side

crypto/mac.proto

AuthenticateMessageRequest

Request to authenticate data using an internal key

FieldTypeLabelDescription
plaintextbytesData to authenticate
key_idstringKey used to authenticate the data
algorithmstringAlgorithm used to hash the data

AuthenticateMessageResponse

Response with the encrypted data

FieldTypeLabelDescription
tagbytesEncrypted data

AuthenticateMessageWithWrappedRequest

Request to authenticate data using an internal key

FieldTypeLabelDescription
plaintextbytesData to authenticate
wrapped_keybytesWrapped key used to authenticate the data
algorithmstringAlgorithm used to hash the data

VerifyTagRequest

Request to verify authenticated data using an internal key

FieldTypeLabelDescription
plaintextbytesData to authenticate
key_idstringKey used to authenticate the data
algorithmstringMac algorithm used to authenticate the data
tagbytesTag to verify

VerifyTagResponse

Response with the success status

FieldTypeLabelDescription
successboolSuccess status of the verification

VerifyTagWithWrappedRequest

Request to verify authenticated data using an internal key

FieldTypeLabelDescription
plaintextbytesData to authenticate
wrapped_keybytesWrapped key used to authenticate the data
algorithmstringMac algorithm used to authenticate the data
tagbytesTag to verify

crypto/public.proto

GetPublicComponentRequest

Request to get the public component of an internal key

FieldTypeLabelDescription
key_idstringKey id of the public key to fetch

GetPublicComponentResponse

Response with the public data

FieldTypeLabelDescription
publicbytesPublic key data

crypto/rand.proto

GetEntropyRequest

Request random bytes in a buffer of given length

FieldTypeLabelDescription
lengthuint32Entropy buffer length in bytes
sourcestringSource of the entropy

GetEntropyResponse

Response with the requested entropy in a buffer

FieldTypeLabelDescription
entropybytesEntropy buffer

crypto/sign.proto

EasySignRequest

Request to sign data using an internal key

FieldTypeLabelDescription
databytesData to sign
key_idstringKey id of the key used to sign the data

EasyVerifySignatureRequest

Request to verify data with a public key

FieldTypeLabelDescription
databytesData to verify
signaturebytesSignature of the data
keybytesPublic key used to verify the data

SignRequest

Request to sign data using an internal key

FieldTypeLabelDescription
databytesData to sign
key_idstringKey id of the key used to sign the data
algorithmstringAlgorithm used to sign the data

SignResponse

Response with the requested signature

FieldTypeLabelDescription
signaturebytesSignature of the data

SignWithWrappedRequest

Request to sign data using a wrapped key

FieldTypeLabelDescription
databytesData to sign
wrapped_keybytesWrapped key used to sign the data
algorithmstringAlgorithm used to sign the data

VerifySignatureRequest

Request to verify data with a public key

FieldTypeLabelDescription
databytesData to verify
signaturebytesSignature of the data
keybytesPublic key used to verify the data
algorithmstringAlgorithm used to verify the data

VerifySignatureResponse

Response with the validity of the signature

FieldTypeLabelDescription
validboolValidity of the signature

crypto/wallet.proto

DeriveWalletAndSignOneShotRequest

One-shot requests that derive and use child_key from seed&path directly

FieldTypeLabelDescription
algorithmstringAlgorithm used to derive the master key
plaintextbytesPlaintext seed used to derive the master key
wrappedbytesWrapped seed used to derive the master key
pathuint32repeatedPath of the child
databytesData to sign
signature_algorithmstringAlgorithm used to sign the data

DeriveWalletAndSignOneShotResponse

FieldTypeLabelDescription
signaturebytesSignature of the data

DeriveWalletMasterKeyRequest

FieldTypeLabelDescription
algorithmstringAlgorithm used to derive the master key
whiteliststringrepeatedWhitelist of algorithms this key will be able to use
plaintextbytesPlaintext seed used to derive the master key
wrappedbytesWrapped seed used to derive the master key

DeriveWalletMasterKeyResponse

FieldTypeLabelDescription
key_idstringId of the derived key. The key include the chain code

DeriveWalletPrivateKeyRequest

FieldTypeLabelDescription
whiteliststringrepeatedWhitelist of algorithms the child key will be able to use. Must be a subset of the parent key whitelist
key_idstringId of the parent key
pathuint32repeatedPath of the child

DeriveWalletPrivateKeyResponse

FieldTypeLabelDescription
key_idstringId of the derived child key. The key include the chain code

DeriveWalletPublicKeyOneShotRequest

FieldTypeLabelDescription
algorithmstringAlgorithm used to derive the master key
plaintextbytesPlaintext seed used to derive the master key
wrappedbytesWrapped seed used to derive the master key
pathuint32repeatedPath of the child

DeriveWalletPublicKeyOneShotResponse

FieldTypeLabelDescription
public_keybytesPublic key of the child
chain_codebytesChain code of the child

DeriveWalletPublicKeyRequest

FieldTypeLabelDescription
algorithmstringAlgorithm used to derive the child key
public_keybytesPublic key of the parent
chain_codebytesChain code of the parent
pathuint32repeatedPath of the child

DeriveWalletPublicKeyResponse

FieldTypeLabelDescription
public_keybytesPublic key of the child
chain_codebytesChain code of the child

GenerateWalletSeedRequest

FieldTypeLabelDescription
lengthuint32Length of the seed to generate in bytes [16, 64]

GenerateWalletSeedResponse

FieldTypeLabelDescription
wrapped_seedbytesWrapped seed bytes

GetWalletPublicComponentsRequest

Request to get the public components of a wallet extended public key

FieldTypeLabelDescription
key_idstringKey id of the public key to fetch

GetWalletPublicComponentsResponse

FieldTypeLabelDescription
publicbytesPublic key data
chain_codebytesChain code data
parent_fingerprintbytesFingerprint of the parent public key, 0x00000000 for a master key
indexuint32Index used to derive this key, 0 for a master key
depthuint32Depth of the key in the tree

service/crypto.proto

RPC services declaration

Service providing high-level cryptographic capabilities

Method NameRequest TypeResponse TypeDescription
SignEasySignRequestSignResponseSign messages and verify signatures
VerifyEasyVerifySignatureRequestVerifySignatureResponse
EncryptEasyEncryptRequestEasyEncryptResponseEasy symmetric encryption and decryption with authentication
DecryptEasyDecryptRequestDecryptResponse
GenerateEncryptionKeyEasyGenerateEncryptionKeyRequestEasyGenerateEncryptionKeyResponseGenerate symmetric key material
GenerateSignatureKeyEasyGenerateSignatureKeyRequestEasyGenerateSignatureKeyResponseGenerate asym key material

Service providing low-level cryptographic capabilities

Method NameRequest TypeResponse TypeDescription
GetEntropyGetEntropyRequestGetEntropyResponseGet random bytes
HashHashRequestHashResponseHash data
AuthenticateMessageAuthenticateMessageRequestAuthenticateMessageResponseMessage Authentication
VerifyTagVerifyTagRequestVerifyTagResponse
AuthenticateMessageWithWrappedAuthenticateMessageWithWrappedRequestAuthenticateMessageResponse
VerifyTagWithWrappedVerifyTagWithWrappedRequestVerifyTagResponse
GenerateKeyGenerateKeyRequestGenerateKeyResponseGenerate key material
GenerateWrappedKeyGenerateWrappedKeyRequestGenerateWrappedKeyResponseGenerate key material
RevokeKeyRevokeKeyRequestRevokeKeyResponseRevoke key material
GetPublicComponentGetPublicComponentRequestGetPublicComponentResponseGet the public component of some key material
SignSignRequestSignResponseSign messages and verify signatures
SignWithWrappedSignWithWrappedRequestSignResponse
VerifySignatureVerifySignatureRequestVerifySignatureResponse
EncryptEncryptRequestEncryptResponseSymmetric encryption and decryption without authentication
DecryptDecryptRequestDecryptResponse
EncryptAeadEncryptAeadRequestEncryptAeadResponseSymmetric encryption and decryption with authentication and additional
associated data
DecryptAeadDecryptAeadRequestDecryptAeadResponse
EncryptEciesEncryptEciesRequestEncryptEciesResponseEncryption using : Elliptic Curve Integrated Encryption Scheme (ECIES)
DecryptEciesDecryptEciesRequestDecryptEciesResponse
PublicEncryptPublicEncryptRequestPublicEncryptResponsePublic encryption and decryption without authentication
PublicDecryptPublicDecryptRequestPublicDecryptResponse
GenerateWalletSeedGenerateWalletSeedRequestGenerateWalletSeedResponseWallet key derivation
DeriveWalletMasterKeyDeriveWalletMasterKeyRequestDeriveWalletMasterKeyResponse
DeriveWalletPrivateKeyDeriveWalletPrivateKeyRequestDeriveWalletPrivateKeyResponse
DeriveWalletPublicKeyDeriveWalletPublicKeyRequestDeriveWalletPublicKeyResponse
DeriveWalletAndSignOneShotDeriveWalletAndSignOneShotRequestDeriveWalletAndSignOneShotResponse
DeriveWalletPublicKeyOneShotDeriveWalletPublicKeyOneShotRequestDeriveWalletPublicKeyOneShotResponse
GetWalletPublicComponentsGetWalletPublicComponentsRequestGetWalletPublicComponentsResponse
DeriveEcdhWithWrappedDeriveEcdhWithWrappedRequestDeriveEcdhResponseElliptic Curve Diffie-Hellman
DeriveEcdhDeriveEcdhRequestDeriveEcdhResponse