diff --git a/.vscode/launch.json b/.vscode/launch.json
new file mode 100644
index 0000000000000000000000000000000000000000..9359b9a52f7c3795fa85b0c580bac209bca120c5
--- /dev/null
+++ b/.vscode/launch.json
@@ -0,0 +1,16 @@
+{
+    // Verwendet IntelliSense zum Ermitteln möglicher Attribute.
+    // Zeigen Sie auf vorhandene Attribute, um die zugehörigen Beschreibungen anzuzeigen.
+    // Weitere Informationen finden Sie unter https://go.microsoft.com/fwlink/?linkid=830387
+    "version": "0.2.0",
+    "configurations": [
+        {
+            "name": "Launch file",
+            "type": "go",
+            "request": "launch",
+            "mode": "debug",
+            "program": "${workspaceFolder}",
+            "args": ["-selftesting", "false"], 
+        },
+    ]
+}
\ No newline at end of file
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000000000000000000000000000000000000..d85ead5dea46d1fded413e41f0f793921cfd6d22
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,29 @@
+BSD 3-Clause License
+
+Copyright (c) 2023, da/net Research Group
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+   list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright notice,
+   this list of conditions and the following disclaimer in the documentation
+   and/or other materials provided with the distribution.
+
+3. Neither the name of the copyright holder nor the names of its
+   contributors may be used to endorse or promote products derived from
+   this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/README.md b/README.md
index a37c72472d3c450beeda8327c8c31dface106215..befcadae335152a55030d68ba6834714bb8fb808 100644
--- a/README.md
+++ b/README.md
@@ -4,6 +4,16 @@ This is a prototypically Key Management System (KMS) for Quantum Key Distributio
 
 It uses, by now, an emulation of a quantum link to exchange random numbers between neighboring quantum network elements.
 
+**Note well** _This is not intended to be used in production environments, neither in networks that can be reached by everybody, nor in other uncontrolled settings._
+
+# Acknowledgements
+
+This prototypically Key Management System (KMS) has been developed in the [DemoQuanDT](https://www.forschung-it-sicherheit-kommunikationssysteme.de/projekte/demoquandt) project ("Quantenschlüsselaustausch im deutschen Telekommunikationsnetz für höhere IT-Sicherheit", engl. quantum key exchange in the german telecommunications network for higher IT security). 
+
+The DemoQuanDT project is funded by the german ministry of education and research ([BMBF](https://www.bmbf.de)). 
+
+<img src="./figures/BMBF_gefoerdert_2017_en.jpg" alt= "Logo of the BMBF" width="20%">
+
 ## Implementation of the Quantum Layer
 
 ### Pseudo Random Number Generator (PRNG) based Emulation
@@ -28,6 +38,48 @@ First, rand is used to generate the amount of random numbers `numRands`and then
 
 A quantum layer link peer is the communication partner on a point-to-point link. One has to generate a new peer in the quantum layer in order to communicate with the peer. 
 
+# Interfaces to the proto-kms
+
+## Interface to the Quantum Layer
+
+This interface is solely a go API within the proto-kms. 
+
+## Inter-KMS Communication
+
+This interface is required for the communication between the peering KMS in order to coordinate their actions for key selection and key forwardwing path configuration. This is in *interkmsproto*.
+
+## ETSI-Interfaces 
+
+There are basically two ETSI interfaces, i.e., 
+ - ETSI QKD GS 14 for retrieval of keys by an external entity from the kms
+ - ETSI QKD GS 15 for the configuration of the key forwarding process and peers of the kms
+
+ However, at this point of this, both interfaces are lumped together in one gRPC interface *kmsetsiproto*.
+
+### Encryption Key Retrieval Interface
+
+### SDN Controller (ETSI GS QKD 15)
+
+
+# Interactions (AKA Flowcharts)
+
+```mermaid 
+sequenceDiagram
+QKDNC->>KMS1: ETSIGetQuantumInterfaces()
+loop 
+    KMS1->>KMS1: range es.handlingEkms.QuantumElements
+end
+KMS1-->>QKDNC: List QuantumInterfaces
+QKDNC->>KMS1: ETSIAddKMSPeer(KMS2)
+KMS1-->>QKDNC: KMSPeer added
+KMS1->>KMS2: InterComCapabilities()
+KMS2->>KMS1: InterComCapabilitiesReply
+QKDNC->>KMS1: AddSession() NOTIMPLYET
+KMS1->>KMS2: InterComKeyTransportSessionHandling()
+KMS2->>KMS1: InterComKeyTransportSessionHandlingReply
+KMS1-->>QKDNC: SessionReply NOTIMPLYET
+
+```
 
 
 
diff --git a/api/buf.gen.yaml b/api/buf.gen.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..72950582b034612d2feccdb2fc95cea8f49694de
--- /dev/null
+++ b/api/buf.gen.yaml
@@ -0,0 +1,14 @@
+version: v1
+managed:
+  enabled: true
+  go_package_prefix:
+    default: code.fbi.h-da.de/demoquandt/proto-kms/gen/proto/go
+plugins:
+  - plugin: buf.build/grpc/go
+    out: gen/proto/go
+    opt:
+      - paths=source_relative
+  - plugin: buf.build/protocolbuffers/go
+    out: gen/proto/go
+    opt:
+      - paths=source_relative
diff --git a/api/buf.work.yaml b/api/buf.work.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..a35f7482c73f003e017f657f018b274dfafe5b22
--- /dev/null
+++ b/api/buf.work.yaml
@@ -0,0 +1,4 @@
+version: v1
+directories:
+    - kmsetsi
+    - kmsintercom
diff --git a/api/gen/proto/go/kmsetsi/kmsetsiproto.pb.go b/api/gen/proto/go/kmsetsi/kmsetsiproto.pb.go
new file mode 100644
index 0000000000000000000000000000000000000000..f859f18b5db223fd1a89169290cb840d05770439
--- /dev/null
+++ b/api/gen/proto/go/kmsetsi/kmsetsiproto.pb.go
@@ -0,0 +1,924 @@
+// Code generated by protoc-gen-go. DO NOT EDIT.
+// versions:
+// 	protoc-gen-go v1.31.0
+// 	protoc        (unknown)
+// source: kmsetsi/kmsetsiproto.proto
+
+package kmsetsi
+
+import (
+	protoreflect "google.golang.org/protobuf/reflect/protoreflect"
+	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
+	reflect "reflect"
+	sync "sync"
+)
+
+const (
+	// Verify that this generated code is sufficiently up-to-date.
+	_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
+	// Verify that runtime/protoimpl is sufficiently up-to-date.
+	_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
+)
+
+// The request message containing the user's name.
+type ETSICapabilitiesRequest struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	MyKmsName string `protobuf:"bytes,1,opt,name=myKmsName,proto3" json:"myKmsName,omitempty"`
+}
+
+func (x *ETSICapabilitiesRequest) Reset() {
+	*x = ETSICapabilitiesRequest{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_kmsetsi_kmsetsiproto_proto_msgTypes[0]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *ETSICapabilitiesRequest) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ETSICapabilitiesRequest) ProtoMessage() {}
+
+func (x *ETSICapabilitiesRequest) ProtoReflect() protoreflect.Message {
+	mi := &file_kmsetsi_kmsetsiproto_proto_msgTypes[0]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use ETSICapabilitiesRequest.ProtoReflect.Descriptor instead.
+func (*ETSICapabilitiesRequest) Descriptor() ([]byte, []int) {
+	return file_kmsetsi_kmsetsiproto_proto_rawDescGZIP(), []int{0}
+}
+
+func (x *ETSICapabilitiesRequest) GetMyKmsName() string {
+	if x != nil {
+		return x.MyKmsName
+	}
+	return ""
+}
+
+// The response message containing the greetings
+type ETSICapabilitiesReply struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	PeerKmsName string `protobuf:"bytes,1,opt,name=peerKmsName,proto3" json:"peerKmsName,omitempty"`
+}
+
+func (x *ETSICapabilitiesReply) Reset() {
+	*x = ETSICapabilitiesReply{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_kmsetsi_kmsetsiproto_proto_msgTypes[1]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *ETSICapabilitiesReply) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ETSICapabilitiesReply) ProtoMessage() {}
+
+func (x *ETSICapabilitiesReply) ProtoReflect() protoreflect.Message {
+	mi := &file_kmsetsi_kmsetsiproto_proto_msgTypes[1]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use ETSICapabilitiesReply.ProtoReflect.Descriptor instead.
+func (*ETSICapabilitiesReply) Descriptor() ([]byte, []int) {
+	return file_kmsetsi_kmsetsiproto_proto_rawDescGZIP(), []int{1}
+}
+
+func (x *ETSICapabilitiesReply) GetPeerKmsName() string {
+	if x != nil {
+		return x.PeerKmsName
+	}
+	return ""
+}
+
+type ETSIKMSQuantumInterfaceListRequest struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+}
+
+func (x *ETSIKMSQuantumInterfaceListRequest) Reset() {
+	*x = ETSIKMSQuantumInterfaceListRequest{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_kmsetsi_kmsetsiproto_proto_msgTypes[2]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *ETSIKMSQuantumInterfaceListRequest) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ETSIKMSQuantumInterfaceListRequest) ProtoMessage() {}
+
+func (x *ETSIKMSQuantumInterfaceListRequest) ProtoReflect() protoreflect.Message {
+	mi := &file_kmsetsi_kmsetsiproto_proto_msgTypes[2]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use ETSIKMSQuantumInterfaceListRequest.ProtoReflect.Descriptor instead.
+func (*ETSIKMSQuantumInterfaceListRequest) Descriptor() ([]byte, []int) {
+	return file_kmsetsi_kmsetsiproto_proto_rawDescGZIP(), []int{2}
+}
+
+// NB for myself: this be used to link QLE mit KMS-Session!
+type QuantumElementInfo struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	QleID   uint64 `protobuf:"varint,1,opt,name=qleID,proto3" json:"qleID,omitempty"`
+	UdpAddr string `protobuf:"bytes,2,opt,name=udpAddr,proto3" json:"udpAddr,omitempty"`
+}
+
+func (x *QuantumElementInfo) Reset() {
+	*x = QuantumElementInfo{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_kmsetsi_kmsetsiproto_proto_msgTypes[3]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *QuantumElementInfo) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*QuantumElementInfo) ProtoMessage() {}
+
+func (x *QuantumElementInfo) ProtoReflect() protoreflect.Message {
+	mi := &file_kmsetsi_kmsetsiproto_proto_msgTypes[3]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use QuantumElementInfo.ProtoReflect.Descriptor instead.
+func (*QuantumElementInfo) Descriptor() ([]byte, []int) {
+	return file_kmsetsi_kmsetsiproto_proto_rawDescGZIP(), []int{3}
+}
+
+func (x *QuantumElementInfo) GetQleID() uint64 {
+	if x != nil {
+		return x.QleID
+	}
+	return 0
+}
+
+func (x *QuantumElementInfo) GetUdpAddr() string {
+	if x != nil {
+		return x.UdpAddr
+	}
+	return ""
+}
+
+type ETSIKMSQuantumInterfaceListReply struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	QlElementInfo []*QuantumElementInfo `protobuf:"bytes,1,rep,name=qlElementInfo,proto3" json:"qlElementInfo,omitempty"`
+}
+
+func (x *ETSIKMSQuantumInterfaceListReply) Reset() {
+	*x = ETSIKMSQuantumInterfaceListReply{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_kmsetsi_kmsetsiproto_proto_msgTypes[4]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *ETSIKMSQuantumInterfaceListReply) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ETSIKMSQuantumInterfaceListReply) ProtoMessage() {}
+
+func (x *ETSIKMSQuantumInterfaceListReply) ProtoReflect() protoreflect.Message {
+	mi := &file_kmsetsi_kmsetsiproto_proto_msgTypes[4]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use ETSIKMSQuantumInterfaceListReply.ProtoReflect.Descriptor instead.
+func (*ETSIKMSQuantumInterfaceListReply) Descriptor() ([]byte, []int) {
+	return file_kmsetsi_kmsetsiproto_proto_rawDescGZIP(), []int{4}
+}
+
+func (x *ETSIKMSQuantumInterfaceListReply) GetQlElementInfo() []*QuantumElementInfo {
+	if x != nil {
+		return x.QlElementInfo
+	}
+	return nil
+}
+
+type ETSIKMSPeerRequest struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	KmsPeerSocket string `protobuf:"bytes,1,opt,name=kmsPeerSocket,proto3" json:"kmsPeerSocket,omitempty"`
+	KmsLocalQLEId uint32 `protobuf:"varint,2,opt,name=kmsLocalQLEId,proto3" json:"kmsLocalQLEId,omitempty"`
+}
+
+func (x *ETSIKMSPeerRequest) Reset() {
+	*x = ETSIKMSPeerRequest{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_kmsetsi_kmsetsiproto_proto_msgTypes[5]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *ETSIKMSPeerRequest) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ETSIKMSPeerRequest) ProtoMessage() {}
+
+func (x *ETSIKMSPeerRequest) ProtoReflect() protoreflect.Message {
+	mi := &file_kmsetsi_kmsetsiproto_proto_msgTypes[5]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use ETSIKMSPeerRequest.ProtoReflect.Descriptor instead.
+func (*ETSIKMSPeerRequest) Descriptor() ([]byte, []int) {
+	return file_kmsetsi_kmsetsiproto_proto_rawDescGZIP(), []int{5}
+}
+
+func (x *ETSIKMSPeerRequest) GetKmsPeerSocket() string {
+	if x != nil {
+		return x.KmsPeerSocket
+	}
+	return ""
+}
+
+func (x *ETSIKMSPeerRequest) GetKmsLocalQLEId() uint32 {
+	if x != nil {
+		return x.KmsLocalQLEId
+	}
+	return 0
+}
+
+type ETSIKMSPeerReply struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	KmsPeerName string `protobuf:"bytes,1,opt,name=kmsPeerName,proto3" json:"kmsPeerName,omitempty"`
+}
+
+func (x *ETSIKMSPeerReply) Reset() {
+	*x = ETSIKMSPeerReply{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_kmsetsi_kmsetsiproto_proto_msgTypes[6]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *ETSIKMSPeerReply) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ETSIKMSPeerReply) ProtoMessage() {}
+
+func (x *ETSIKMSPeerReply) ProtoReflect() protoreflect.Message {
+	mi := &file_kmsetsi_kmsetsiproto_proto_msgTypes[6]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use ETSIKMSPeerReply.ProtoReflect.Descriptor instead.
+func (*ETSIKMSPeerReply) Descriptor() ([]byte, []int) {
+	return file_kmsetsi_kmsetsiproto_proto_rawDescGZIP(), []int{6}
+}
+
+func (x *ETSIKMSPeerReply) GetKmsPeerName() string {
+	if x != nil {
+		return x.KmsPeerName
+	}
+	return ""
+}
+
+type ETSIKMSPeerListRequest struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+}
+
+func (x *ETSIKMSPeerListRequest) Reset() {
+	*x = ETSIKMSPeerListRequest{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_kmsetsi_kmsetsiproto_proto_msgTypes[7]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *ETSIKMSPeerListRequest) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ETSIKMSPeerListRequest) ProtoMessage() {}
+
+func (x *ETSIKMSPeerListRequest) ProtoReflect() protoreflect.Message {
+	mi := &file_kmsetsi_kmsetsiproto_proto_msgTypes[7]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use ETSIKMSPeerListRequest.ProtoReflect.Descriptor instead.
+func (*ETSIKMSPeerListRequest) Descriptor() ([]byte, []int) {
+	return file_kmsetsi_kmsetsiproto_proto_rawDescGZIP(), []int{7}
+}
+
+type ETSIKMSPeer struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	PeerName   string `protobuf:"bytes,1,opt,name=peerName,proto3" json:"peerName,omitempty"`
+	PeerStatus string `protobuf:"bytes,2,opt,name=peerStatus,proto3" json:"peerStatus,omitempty"`
+}
+
+func (x *ETSIKMSPeer) Reset() {
+	*x = ETSIKMSPeer{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_kmsetsi_kmsetsiproto_proto_msgTypes[8]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *ETSIKMSPeer) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ETSIKMSPeer) ProtoMessage() {}
+
+func (x *ETSIKMSPeer) ProtoReflect() protoreflect.Message {
+	mi := &file_kmsetsi_kmsetsiproto_proto_msgTypes[8]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use ETSIKMSPeer.ProtoReflect.Descriptor instead.
+func (*ETSIKMSPeer) Descriptor() ([]byte, []int) {
+	return file_kmsetsi_kmsetsiproto_proto_rawDescGZIP(), []int{8}
+}
+
+func (x *ETSIKMSPeer) GetPeerName() string {
+	if x != nil {
+		return x.PeerName
+	}
+	return ""
+}
+
+func (x *ETSIKMSPeer) GetPeerStatus() string {
+	if x != nil {
+		return x.PeerStatus
+	}
+	return ""
+}
+
+type ETSIKMSPeerListReply struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	Peer []*ETSIKMSPeer `protobuf:"bytes,1,rep,name=peer,proto3" json:"peer,omitempty"`
+}
+
+func (x *ETSIKMSPeerListReply) Reset() {
+	*x = ETSIKMSPeerListReply{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_kmsetsi_kmsetsiproto_proto_msgTypes[9]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *ETSIKMSPeerListReply) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ETSIKMSPeerListReply) ProtoMessage() {}
+
+func (x *ETSIKMSPeerListReply) ProtoReflect() protoreflect.Message {
+	mi := &file_kmsetsi_kmsetsiproto_proto_msgTypes[9]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use ETSIKMSPeerListReply.ProtoReflect.Descriptor instead.
+func (*ETSIKMSPeerListReply) Descriptor() ([]byte, []int) {
+	return file_kmsetsi_kmsetsiproto_proto_rawDescGZIP(), []int{9}
+}
+
+func (x *ETSIKMSPeerListReply) GetPeer() []*ETSIKMSPeer {
+	if x != nil {
+		return x.Peer
+	}
+	return nil
+}
+
+type ETSIGetEncryptKeys256BitRequest struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	Amount int64 `protobuf:"varint,1,opt,name=amount,proto3" json:"amount,omitempty"`
+}
+
+func (x *ETSIGetEncryptKeys256BitRequest) Reset() {
+	*x = ETSIGetEncryptKeys256BitRequest{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_kmsetsi_kmsetsiproto_proto_msgTypes[10]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *ETSIGetEncryptKeys256BitRequest) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ETSIGetEncryptKeys256BitRequest) ProtoMessage() {}
+
+func (x *ETSIGetEncryptKeys256BitRequest) ProtoReflect() protoreflect.Message {
+	mi := &file_kmsetsi_kmsetsiproto_proto_msgTypes[10]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use ETSIGetEncryptKeys256BitRequest.ProtoReflect.Descriptor instead.
+func (*ETSIGetEncryptKeys256BitRequest) Descriptor() ([]byte, []int) {
+	return file_kmsetsi_kmsetsiproto_proto_rawDescGZIP(), []int{10}
+}
+
+func (x *ETSIGetEncryptKeys256BitRequest) GetAmount() int64 {
+	if x != nil {
+		return x.Amount
+	}
+	return 0
+}
+
+type ETSIGetEncryptKeys256BitReply struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	KeyID string `protobuf:"bytes,1,opt,name=keyID,proto3" json:"keyID,omitempty"`
+	Key   []byte `protobuf:"bytes,2,opt,name=key,proto3" json:"key,omitempty"`
+}
+
+func (x *ETSIGetEncryptKeys256BitReply) Reset() {
+	*x = ETSIGetEncryptKeys256BitReply{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_kmsetsi_kmsetsiproto_proto_msgTypes[11]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *ETSIGetEncryptKeys256BitReply) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ETSIGetEncryptKeys256BitReply) ProtoMessage() {}
+
+func (x *ETSIGetEncryptKeys256BitReply) ProtoReflect() protoreflect.Message {
+	mi := &file_kmsetsi_kmsetsiproto_proto_msgTypes[11]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use ETSIGetEncryptKeys256BitReply.ProtoReflect.Descriptor instead.
+func (*ETSIGetEncryptKeys256BitReply) Descriptor() ([]byte, []int) {
+	return file_kmsetsi_kmsetsiproto_proto_rawDescGZIP(), []int{11}
+}
+
+func (x *ETSIGetEncryptKeys256BitReply) GetKeyID() string {
+	if x != nil {
+		return x.KeyID
+	}
+	return ""
+}
+
+func (x *ETSIGetEncryptKeys256BitReply) GetKey() []byte {
+	if x != nil {
+		return x.Key
+	}
+	return nil
+}
+
+var File_kmsetsi_kmsetsiproto_proto protoreflect.FileDescriptor
+
+var file_kmsetsi_kmsetsiproto_proto_rawDesc = []byte{
+	0x0a, 0x1a, 0x6b, 0x6d, 0x73, 0x65, 0x74, 0x73, 0x69, 0x2f, 0x6b, 0x6d, 0x73, 0x65, 0x74, 0x73,
+	0x69, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x07, 0x6b, 0x6d,
+	0x73, 0x65, 0x74, 0x73, 0x69, 0x22, 0x37, 0x0a, 0x17, 0x45, 0x54, 0x53, 0x49, 0x43, 0x61, 0x70,
+	0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x69, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
+	0x12, 0x1c, 0x0a, 0x09, 0x6d, 0x79, 0x4b, 0x6d, 0x73, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20,
+	0x01, 0x28, 0x09, 0x52, 0x09, 0x6d, 0x79, 0x4b, 0x6d, 0x73, 0x4e, 0x61, 0x6d, 0x65, 0x22, 0x39,
+	0x0a, 0x15, 0x45, 0x54, 0x53, 0x49, 0x43, 0x61, 0x70, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x69,
+	0x65, 0x73, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x20, 0x0a, 0x0b, 0x70, 0x65, 0x65, 0x72, 0x4b,
+	0x6d, 0x73, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x70, 0x65,
+	0x65, 0x72, 0x4b, 0x6d, 0x73, 0x4e, 0x61, 0x6d, 0x65, 0x22, 0x24, 0x0a, 0x22, 0x45, 0x54, 0x53,
+	0x49, 0x4b, 0x4d, 0x53, 0x51, 0x75, 0x61, 0x6e, 0x74, 0x75, 0x6d, 0x49, 0x6e, 0x74, 0x65, 0x72,
+	0x66, 0x61, 0x63, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22,
+	0x44, 0x0a, 0x12, 0x51, 0x75, 0x61, 0x6e, 0x74, 0x75, 0x6d, 0x45, 0x6c, 0x65, 0x6d, 0x65, 0x6e,
+	0x74, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x14, 0x0a, 0x05, 0x71, 0x6c, 0x65, 0x49, 0x44, 0x18, 0x01,
+	0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x71, 0x6c, 0x65, 0x49, 0x44, 0x12, 0x18, 0x0a, 0x07, 0x75,
+	0x64, 0x70, 0x41, 0x64, 0x64, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x75, 0x64,
+	0x70, 0x41, 0x64, 0x64, 0x72, 0x22, 0x65, 0x0a, 0x20, 0x45, 0x54, 0x53, 0x49, 0x4b, 0x4d, 0x53,
+	0x51, 0x75, 0x61, 0x6e, 0x74, 0x75, 0x6d, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65,
+	0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x41, 0x0a, 0x0d, 0x71, 0x6c, 0x45,
+	0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b,
+	0x32, 0x1b, 0x2e, 0x6b, 0x6d, 0x73, 0x65, 0x74, 0x73, 0x69, 0x2e, 0x51, 0x75, 0x61, 0x6e, 0x74,
+	0x75, 0x6d, 0x45, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x0d, 0x71,
+	0x6c, 0x45, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x22, 0x60, 0x0a, 0x12,
+	0x45, 0x54, 0x53, 0x49, 0x4b, 0x4d, 0x53, 0x50, 0x65, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65,
+	0x73, 0x74, 0x12, 0x24, 0x0a, 0x0d, 0x6b, 0x6d, 0x73, 0x50, 0x65, 0x65, 0x72, 0x53, 0x6f, 0x63,
+	0x6b, 0x65, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x6b, 0x6d, 0x73, 0x50, 0x65,
+	0x65, 0x72, 0x53, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x12, 0x24, 0x0a, 0x0d, 0x6b, 0x6d, 0x73, 0x4c,
+	0x6f, 0x63, 0x61, 0x6c, 0x51, 0x4c, 0x45, 0x49, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52,
+	0x0d, 0x6b, 0x6d, 0x73, 0x4c, 0x6f, 0x63, 0x61, 0x6c, 0x51, 0x4c, 0x45, 0x49, 0x64, 0x22, 0x34,
+	0x0a, 0x10, 0x45, 0x54, 0x53, 0x49, 0x4b, 0x4d, 0x53, 0x50, 0x65, 0x65, 0x72, 0x52, 0x65, 0x70,
+	0x6c, 0x79, 0x12, 0x20, 0x0a, 0x0b, 0x6b, 0x6d, 0x73, 0x50, 0x65, 0x65, 0x72, 0x4e, 0x61, 0x6d,
+	0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x6b, 0x6d, 0x73, 0x50, 0x65, 0x65, 0x72,
+	0x4e, 0x61, 0x6d, 0x65, 0x22, 0x18, 0x0a, 0x16, 0x45, 0x54, 0x53, 0x49, 0x4b, 0x4d, 0x53, 0x50,
+	0x65, 0x65, 0x72, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x49,
+	0x0a, 0x0b, 0x45, 0x54, 0x53, 0x49, 0x4b, 0x4d, 0x53, 0x50, 0x65, 0x65, 0x72, 0x12, 0x1a, 0x0a,
+	0x08, 0x70, 0x65, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52,
+	0x08, 0x70, 0x65, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x70, 0x65, 0x65,
+	0x72, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x70,
+	0x65, 0x65, 0x72, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0x40, 0x0a, 0x14, 0x45, 0x54, 0x53,
+	0x49, 0x4b, 0x4d, 0x53, 0x50, 0x65, 0x65, 0x72, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x70, 0x6c,
+	0x79, 0x12, 0x28, 0x0a, 0x04, 0x70, 0x65, 0x65, 0x72, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32,
+	0x14, 0x2e, 0x6b, 0x6d, 0x73, 0x65, 0x74, 0x73, 0x69, 0x2e, 0x45, 0x54, 0x53, 0x49, 0x4b, 0x4d,
+	0x53, 0x50, 0x65, 0x65, 0x72, 0x52, 0x04, 0x70, 0x65, 0x65, 0x72, 0x22, 0x39, 0x0a, 0x1f, 0x45,
+	0x54, 0x53, 0x49, 0x47, 0x65, 0x74, 0x45, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x4b, 0x65, 0x79,
+	0x73, 0x32, 0x35, 0x36, 0x42, 0x69, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x16,
+	0x0a, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x06,
+	0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x22, 0x47, 0x0a, 0x1d, 0x45, 0x54, 0x53, 0x49, 0x47, 0x65,
+	0x74, 0x45, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x4b, 0x65, 0x79, 0x73, 0x32, 0x35, 0x36, 0x42,
+	0x69, 0x74, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x6b, 0x65, 0x79, 0x49, 0x44,
+	0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x6b, 0x65, 0x79, 0x49, 0x44, 0x12, 0x10, 0x0a,
+	0x03, 0x6b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x32,
+	0xb7, 0x04, 0x0a, 0x07, 0x4b, 0x6d, 0x73, 0x45, 0x54, 0x53, 0x49, 0x12, 0x56, 0x0a, 0x10, 0x45,
+	0x54, 0x53, 0x49, 0x43, 0x61, 0x70, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x69, 0x65, 0x73, 0x12,
+	0x20, 0x2e, 0x6b, 0x6d, 0x73, 0x65, 0x74, 0x73, 0x69, 0x2e, 0x45, 0x54, 0x53, 0x49, 0x43, 0x61,
+	0x70, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x69, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
+	0x74, 0x1a, 0x1e, 0x2e, 0x6b, 0x6d, 0x73, 0x65, 0x74, 0x73, 0x69, 0x2e, 0x45, 0x54, 0x53, 0x49,
+	0x43, 0x61, 0x70, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x69, 0x65, 0x73, 0x52, 0x65, 0x70, 0x6c,
+	0x79, 0x22, 0x00, 0x12, 0x74, 0x0a, 0x18, 0x45, 0x54, 0x53, 0x49, 0x47, 0x65, 0x74, 0x51, 0x75,
+	0x61, 0x6e, 0x74, 0x75, 0x6d, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x73, 0x12,
+	0x2b, 0x2e, 0x6b, 0x6d, 0x73, 0x65, 0x74, 0x73, 0x69, 0x2e, 0x45, 0x54, 0x53, 0x49, 0x4b, 0x4d,
+	0x53, 0x51, 0x75, 0x61, 0x6e, 0x74, 0x75, 0x6d, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63,
+	0x65, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x29, 0x2e, 0x6b,
+	0x6d, 0x73, 0x65, 0x74, 0x73, 0x69, 0x2e, 0x45, 0x54, 0x53, 0x49, 0x4b, 0x4d, 0x53, 0x51, 0x75,
+	0x61, 0x6e, 0x74, 0x75, 0x6d, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x4c, 0x69,
+	0x73, 0x74, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x00, 0x12, 0x4a, 0x0a, 0x0e, 0x45, 0x54, 0x53,
+	0x49, 0x41, 0x64, 0x64, 0x4b, 0x4d, 0x53, 0x50, 0x65, 0x65, 0x72, 0x12, 0x1b, 0x2e, 0x6b, 0x6d,
+	0x73, 0x65, 0x74, 0x73, 0x69, 0x2e, 0x45, 0x54, 0x53, 0x49, 0x4b, 0x4d, 0x53, 0x50, 0x65, 0x65,
+	0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x19, 0x2e, 0x6b, 0x6d, 0x73, 0x65, 0x74,
+	0x73, 0x69, 0x2e, 0x45, 0x54, 0x53, 0x49, 0x4b, 0x4d, 0x53, 0x50, 0x65, 0x65, 0x72, 0x52, 0x65,
+	0x70, 0x6c, 0x79, 0x22, 0x00, 0x12, 0x4d, 0x0a, 0x11, 0x45, 0x54, 0x53, 0x49, 0x52, 0x65, 0x6d,
+	0x6f, 0x76, 0x65, 0x4b, 0x4d, 0x53, 0x50, 0x65, 0x65, 0x72, 0x12, 0x1b, 0x2e, 0x6b, 0x6d, 0x73,
+	0x65, 0x74, 0x73, 0x69, 0x2e, 0x45, 0x54, 0x53, 0x49, 0x4b, 0x4d, 0x53, 0x50, 0x65, 0x65, 0x72,
+	0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x19, 0x2e, 0x6b, 0x6d, 0x73, 0x65, 0x74, 0x73,
+	0x69, 0x2e, 0x45, 0x54, 0x53, 0x49, 0x4b, 0x4d, 0x53, 0x50, 0x65, 0x65, 0x72, 0x52, 0x65, 0x70,
+	0x6c, 0x79, 0x22, 0x00, 0x12, 0x53, 0x0a, 0x0f, 0x45, 0x54, 0x53, 0x49, 0x47, 0x65, 0x74, 0x50,
+	0x65, 0x65, 0x72, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x1f, 0x2e, 0x6b, 0x6d, 0x73, 0x65, 0x74, 0x73,
+	0x69, 0x2e, 0x45, 0x54, 0x53, 0x49, 0x4b, 0x4d, 0x53, 0x50, 0x65, 0x65, 0x72, 0x4c, 0x69, 0x73,
+	0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x6b, 0x6d, 0x73, 0x65, 0x74,
+	0x73, 0x69, 0x2e, 0x45, 0x54, 0x53, 0x49, 0x4b, 0x4d, 0x53, 0x50, 0x65, 0x65, 0x72, 0x4c, 0x69,
+	0x73, 0x74, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x00, 0x12, 0x6e, 0x0a, 0x18, 0x45, 0x54, 0x53,
+	0x49, 0x47, 0x65, 0x74, 0x45, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x4b, 0x65, 0x79, 0x73, 0x32,
+	0x35, 0x36, 0x42, 0x69, 0x74, 0x12, 0x28, 0x2e, 0x6b, 0x6d, 0x73, 0x65, 0x74, 0x73, 0x69, 0x2e,
+	0x45, 0x54, 0x53, 0x49, 0x47, 0x65, 0x74, 0x45, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x4b, 0x65,
+	0x79, 0x73, 0x32, 0x35, 0x36, 0x42, 0x69, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a,
+	0x26, 0x2e, 0x6b, 0x6d, 0x73, 0x65, 0x74, 0x73, 0x69, 0x2e, 0x45, 0x54, 0x53, 0x49, 0x47, 0x65,
+	0x74, 0x45, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x4b, 0x65, 0x79, 0x73, 0x32, 0x35, 0x36, 0x42,
+	0x69, 0x74, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x00, 0x42, 0x98, 0x01, 0x0a, 0x0b, 0x63, 0x6f,
+	0x6d, 0x2e, 0x6b, 0x6d, 0x73, 0x65, 0x74, 0x73, 0x69, 0x42, 0x11, 0x4b, 0x6d, 0x73, 0x65, 0x74,
+	0x73, 0x69, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x3a,
+	0x63, 0x6f, 0x64, 0x65, 0x2e, 0x66, 0x62, 0x69, 0x2e, 0x68, 0x2d, 0x64, 0x61, 0x2e, 0x64, 0x65,
+	0x2f, 0x64, 0x65, 0x6d, 0x6f, 0x71, 0x75, 0x61, 0x6e, 0x64, 0x74, 0x2f, 0x70, 0x72, 0x6f, 0x74,
+	0x6f, 0x2d, 0x6b, 0x6d, 0x73, 0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f,
+	0x67, 0x6f, 0x2f, 0x6b, 0x6d, 0x73, 0x65, 0x74, 0x73, 0x69, 0xa2, 0x02, 0x03, 0x4b, 0x58, 0x58,
+	0xaa, 0x02, 0x07, 0x4b, 0x6d, 0x73, 0x65, 0x74, 0x73, 0x69, 0xca, 0x02, 0x07, 0x4b, 0x6d, 0x73,
+	0x65, 0x74, 0x73, 0x69, 0xe2, 0x02, 0x13, 0x4b, 0x6d, 0x73, 0x65, 0x74, 0x73, 0x69, 0x5c, 0x47,
+	0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x07, 0x4b, 0x6d, 0x73,
+	0x65, 0x74, 0x73, 0x69, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
+}
+
+var (
+	file_kmsetsi_kmsetsiproto_proto_rawDescOnce sync.Once
+	file_kmsetsi_kmsetsiproto_proto_rawDescData = file_kmsetsi_kmsetsiproto_proto_rawDesc
+)
+
+func file_kmsetsi_kmsetsiproto_proto_rawDescGZIP() []byte {
+	file_kmsetsi_kmsetsiproto_proto_rawDescOnce.Do(func() {
+		file_kmsetsi_kmsetsiproto_proto_rawDescData = protoimpl.X.CompressGZIP(file_kmsetsi_kmsetsiproto_proto_rawDescData)
+	})
+	return file_kmsetsi_kmsetsiproto_proto_rawDescData
+}
+
+var file_kmsetsi_kmsetsiproto_proto_msgTypes = make([]protoimpl.MessageInfo, 12)
+var file_kmsetsi_kmsetsiproto_proto_goTypes = []interface{}{
+	(*ETSICapabilitiesRequest)(nil),            // 0: kmsetsi.ETSICapabilitiesRequest
+	(*ETSICapabilitiesReply)(nil),              // 1: kmsetsi.ETSICapabilitiesReply
+	(*ETSIKMSQuantumInterfaceListRequest)(nil), // 2: kmsetsi.ETSIKMSQuantumInterfaceListRequest
+	(*QuantumElementInfo)(nil),                 // 3: kmsetsi.QuantumElementInfo
+	(*ETSIKMSQuantumInterfaceListReply)(nil),   // 4: kmsetsi.ETSIKMSQuantumInterfaceListReply
+	(*ETSIKMSPeerRequest)(nil),                 // 5: kmsetsi.ETSIKMSPeerRequest
+	(*ETSIKMSPeerReply)(nil),                   // 6: kmsetsi.ETSIKMSPeerReply
+	(*ETSIKMSPeerListRequest)(nil),             // 7: kmsetsi.ETSIKMSPeerListRequest
+	(*ETSIKMSPeer)(nil),                        // 8: kmsetsi.ETSIKMSPeer
+	(*ETSIKMSPeerListReply)(nil),               // 9: kmsetsi.ETSIKMSPeerListReply
+	(*ETSIGetEncryptKeys256BitRequest)(nil),    // 10: kmsetsi.ETSIGetEncryptKeys256BitRequest
+	(*ETSIGetEncryptKeys256BitReply)(nil),      // 11: kmsetsi.ETSIGetEncryptKeys256BitReply
+}
+var file_kmsetsi_kmsetsiproto_proto_depIdxs = []int32{
+	3,  // 0: kmsetsi.ETSIKMSQuantumInterfaceListReply.qlElementInfo:type_name -> kmsetsi.QuantumElementInfo
+	8,  // 1: kmsetsi.ETSIKMSPeerListReply.peer:type_name -> kmsetsi.ETSIKMSPeer
+	0,  // 2: kmsetsi.KmsETSI.ETSICapabilities:input_type -> kmsetsi.ETSICapabilitiesRequest
+	2,  // 3: kmsetsi.KmsETSI.ETSIGetQuantumInterfaces:input_type -> kmsetsi.ETSIKMSQuantumInterfaceListRequest
+	5,  // 4: kmsetsi.KmsETSI.ETSIAddKMSPeer:input_type -> kmsetsi.ETSIKMSPeerRequest
+	5,  // 5: kmsetsi.KmsETSI.ETSIRemoveKMSPeer:input_type -> kmsetsi.ETSIKMSPeerRequest
+	7,  // 6: kmsetsi.KmsETSI.ETSIGetPeerList:input_type -> kmsetsi.ETSIKMSPeerListRequest
+	10, // 7: kmsetsi.KmsETSI.ETSIGetEncryptKeys256Bit:input_type -> kmsetsi.ETSIGetEncryptKeys256BitRequest
+	1,  // 8: kmsetsi.KmsETSI.ETSICapabilities:output_type -> kmsetsi.ETSICapabilitiesReply
+	4,  // 9: kmsetsi.KmsETSI.ETSIGetQuantumInterfaces:output_type -> kmsetsi.ETSIKMSQuantumInterfaceListReply
+	6,  // 10: kmsetsi.KmsETSI.ETSIAddKMSPeer:output_type -> kmsetsi.ETSIKMSPeerReply
+	6,  // 11: kmsetsi.KmsETSI.ETSIRemoveKMSPeer:output_type -> kmsetsi.ETSIKMSPeerReply
+	9,  // 12: kmsetsi.KmsETSI.ETSIGetPeerList:output_type -> kmsetsi.ETSIKMSPeerListReply
+	11, // 13: kmsetsi.KmsETSI.ETSIGetEncryptKeys256Bit:output_type -> kmsetsi.ETSIGetEncryptKeys256BitReply
+	8,  // [8:14] is the sub-list for method output_type
+	2,  // [2:8] is the sub-list for method input_type
+	2,  // [2:2] is the sub-list for extension type_name
+	2,  // [2:2] is the sub-list for extension extendee
+	0,  // [0:2] is the sub-list for field type_name
+}
+
+func init() { file_kmsetsi_kmsetsiproto_proto_init() }
+func file_kmsetsi_kmsetsiproto_proto_init() {
+	if File_kmsetsi_kmsetsiproto_proto != nil {
+		return
+	}
+	if !protoimpl.UnsafeEnabled {
+		file_kmsetsi_kmsetsiproto_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*ETSICapabilitiesRequest); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_kmsetsi_kmsetsiproto_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*ETSICapabilitiesReply); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_kmsetsi_kmsetsiproto_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*ETSIKMSQuantumInterfaceListRequest); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_kmsetsi_kmsetsiproto_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*QuantumElementInfo); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_kmsetsi_kmsetsiproto_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*ETSIKMSQuantumInterfaceListReply); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_kmsetsi_kmsetsiproto_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*ETSIKMSPeerRequest); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_kmsetsi_kmsetsiproto_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*ETSIKMSPeerReply); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_kmsetsi_kmsetsiproto_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*ETSIKMSPeerListRequest); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_kmsetsi_kmsetsiproto_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*ETSIKMSPeer); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_kmsetsi_kmsetsiproto_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*ETSIKMSPeerListReply); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_kmsetsi_kmsetsiproto_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*ETSIGetEncryptKeys256BitRequest); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_kmsetsi_kmsetsiproto_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*ETSIGetEncryptKeys256BitReply); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+	}
+	type x struct{}
+	out := protoimpl.TypeBuilder{
+		File: protoimpl.DescBuilder{
+			GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
+			RawDescriptor: file_kmsetsi_kmsetsiproto_proto_rawDesc,
+			NumEnums:      0,
+			NumMessages:   12,
+			NumExtensions: 0,
+			NumServices:   1,
+		},
+		GoTypes:           file_kmsetsi_kmsetsiproto_proto_goTypes,
+		DependencyIndexes: file_kmsetsi_kmsetsiproto_proto_depIdxs,
+		MessageInfos:      file_kmsetsi_kmsetsiproto_proto_msgTypes,
+	}.Build()
+	File_kmsetsi_kmsetsiproto_proto = out.File
+	file_kmsetsi_kmsetsiproto_proto_rawDesc = nil
+	file_kmsetsi_kmsetsiproto_proto_goTypes = nil
+	file_kmsetsi_kmsetsiproto_proto_depIdxs = nil
+}
diff --git a/api/gen/proto/go/kmsetsi/kmsetsiproto_grpc.pb.go b/api/gen/proto/go/kmsetsi/kmsetsiproto_grpc.pb.go
new file mode 100644
index 0000000000000000000000000000000000000000..20e30c30fb5c949365073f3e2d9fd31d607830eb
--- /dev/null
+++ b/api/gen/proto/go/kmsetsi/kmsetsiproto_grpc.pb.go
@@ -0,0 +1,296 @@
+// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
+// versions:
+// - protoc-gen-go-grpc v1.3.0
+// - protoc             (unknown)
+// source: kmsetsi/kmsetsiproto.proto
+
+package kmsetsi
+
+import (
+	context "context"
+	grpc "google.golang.org/grpc"
+	codes "google.golang.org/grpc/codes"
+	status "google.golang.org/grpc/status"
+)
+
+// This is a compile-time assertion to ensure that this generated file
+// is compatible with the grpc package it is being compiled against.
+// Requires gRPC-Go v1.32.0 or later.
+const _ = grpc.SupportPackageIsVersion7
+
+const (
+	KmsETSI_ETSICapabilities_FullMethodName         = "/kmsetsi.KmsETSI/ETSICapabilities"
+	KmsETSI_ETSIGetQuantumInterfaces_FullMethodName = "/kmsetsi.KmsETSI/ETSIGetQuantumInterfaces"
+	KmsETSI_ETSIAddKMSPeer_FullMethodName           = "/kmsetsi.KmsETSI/ETSIAddKMSPeer"
+	KmsETSI_ETSIRemoveKMSPeer_FullMethodName        = "/kmsetsi.KmsETSI/ETSIRemoveKMSPeer"
+	KmsETSI_ETSIGetPeerList_FullMethodName          = "/kmsetsi.KmsETSI/ETSIGetPeerList"
+	KmsETSI_ETSIGetEncryptKeys256Bit_FullMethodName = "/kmsetsi.KmsETSI/ETSIGetEncryptKeys256Bit"
+)
+
+// KmsETSIClient is the client API for KmsETSI service.
+//
+// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
+type KmsETSIClient interface {
+	// Sends a greeting
+	ETSICapabilities(ctx context.Context, in *ETSICapabilitiesRequest, opts ...grpc.CallOption) (*ETSICapabilitiesReply, error)
+	ETSIGetQuantumInterfaces(ctx context.Context, in *ETSIKMSQuantumInterfaceListRequest, opts ...grpc.CallOption) (*ETSIKMSQuantumInterfaceListReply, error)
+	ETSIAddKMSPeer(ctx context.Context, in *ETSIKMSPeerRequest, opts ...grpc.CallOption) (*ETSIKMSPeerReply, error)
+	ETSIRemoveKMSPeer(ctx context.Context, in *ETSIKMSPeerRequest, opts ...grpc.CallOption) (*ETSIKMSPeerReply, error)
+	ETSIGetPeerList(ctx context.Context, in *ETSIKMSPeerListRequest, opts ...grpc.CallOption) (*ETSIKMSPeerListReply, error)
+	ETSIGetEncryptKeys256Bit(ctx context.Context, in *ETSIGetEncryptKeys256BitRequest, opts ...grpc.CallOption) (*ETSIGetEncryptKeys256BitReply, error)
+}
+
+type kmsETSIClient struct {
+	cc grpc.ClientConnInterface
+}
+
+func NewKmsETSIClient(cc grpc.ClientConnInterface) KmsETSIClient {
+	return &kmsETSIClient{cc}
+}
+
+func (c *kmsETSIClient) ETSICapabilities(ctx context.Context, in *ETSICapabilitiesRequest, opts ...grpc.CallOption) (*ETSICapabilitiesReply, error) {
+	out := new(ETSICapabilitiesReply)
+	err := c.cc.Invoke(ctx, KmsETSI_ETSICapabilities_FullMethodName, in, out, opts...)
+	if err != nil {
+		return nil, err
+	}
+	return out, nil
+}
+
+func (c *kmsETSIClient) ETSIGetQuantumInterfaces(ctx context.Context, in *ETSIKMSQuantumInterfaceListRequest, opts ...grpc.CallOption) (*ETSIKMSQuantumInterfaceListReply, error) {
+	out := new(ETSIKMSQuantumInterfaceListReply)
+	err := c.cc.Invoke(ctx, KmsETSI_ETSIGetQuantumInterfaces_FullMethodName, in, out, opts...)
+	if err != nil {
+		return nil, err
+	}
+	return out, nil
+}
+
+func (c *kmsETSIClient) ETSIAddKMSPeer(ctx context.Context, in *ETSIKMSPeerRequest, opts ...grpc.CallOption) (*ETSIKMSPeerReply, error) {
+	out := new(ETSIKMSPeerReply)
+	err := c.cc.Invoke(ctx, KmsETSI_ETSIAddKMSPeer_FullMethodName, in, out, opts...)
+	if err != nil {
+		return nil, err
+	}
+	return out, nil
+}
+
+func (c *kmsETSIClient) ETSIRemoveKMSPeer(ctx context.Context, in *ETSIKMSPeerRequest, opts ...grpc.CallOption) (*ETSIKMSPeerReply, error) {
+	out := new(ETSIKMSPeerReply)
+	err := c.cc.Invoke(ctx, KmsETSI_ETSIRemoveKMSPeer_FullMethodName, in, out, opts...)
+	if err != nil {
+		return nil, err
+	}
+	return out, nil
+}
+
+func (c *kmsETSIClient) ETSIGetPeerList(ctx context.Context, in *ETSIKMSPeerListRequest, opts ...grpc.CallOption) (*ETSIKMSPeerListReply, error) {
+	out := new(ETSIKMSPeerListReply)
+	err := c.cc.Invoke(ctx, KmsETSI_ETSIGetPeerList_FullMethodName, in, out, opts...)
+	if err != nil {
+		return nil, err
+	}
+	return out, nil
+}
+
+func (c *kmsETSIClient) ETSIGetEncryptKeys256Bit(ctx context.Context, in *ETSIGetEncryptKeys256BitRequest, opts ...grpc.CallOption) (*ETSIGetEncryptKeys256BitReply, error) {
+	out := new(ETSIGetEncryptKeys256BitReply)
+	err := c.cc.Invoke(ctx, KmsETSI_ETSIGetEncryptKeys256Bit_FullMethodName, in, out, opts...)
+	if err != nil {
+		return nil, err
+	}
+	return out, nil
+}
+
+// KmsETSIServer is the server API for KmsETSI service.
+// All implementations must embed UnimplementedKmsETSIServer
+// for forward compatibility
+type KmsETSIServer interface {
+	// Sends a greeting
+	ETSICapabilities(context.Context, *ETSICapabilitiesRequest) (*ETSICapabilitiesReply, error)
+	ETSIGetQuantumInterfaces(context.Context, *ETSIKMSQuantumInterfaceListRequest) (*ETSIKMSQuantumInterfaceListReply, error)
+	ETSIAddKMSPeer(context.Context, *ETSIKMSPeerRequest) (*ETSIKMSPeerReply, error)
+	ETSIRemoveKMSPeer(context.Context, *ETSIKMSPeerRequest) (*ETSIKMSPeerReply, error)
+	ETSIGetPeerList(context.Context, *ETSIKMSPeerListRequest) (*ETSIKMSPeerListReply, error)
+	ETSIGetEncryptKeys256Bit(context.Context, *ETSIGetEncryptKeys256BitRequest) (*ETSIGetEncryptKeys256BitReply, error)
+	mustEmbedUnimplementedKmsETSIServer()
+}
+
+// UnimplementedKmsETSIServer must be embedded to have forward compatible implementations.
+type UnimplementedKmsETSIServer struct {
+}
+
+func (UnimplementedKmsETSIServer) ETSICapabilities(context.Context, *ETSICapabilitiesRequest) (*ETSICapabilitiesReply, error) {
+	return nil, status.Errorf(codes.Unimplemented, "method ETSICapabilities not implemented")
+}
+func (UnimplementedKmsETSIServer) ETSIGetQuantumInterfaces(context.Context, *ETSIKMSQuantumInterfaceListRequest) (*ETSIKMSQuantumInterfaceListReply, error) {
+	return nil, status.Errorf(codes.Unimplemented, "method ETSIGetQuantumInterfaces not implemented")
+}
+func (UnimplementedKmsETSIServer) ETSIAddKMSPeer(context.Context, *ETSIKMSPeerRequest) (*ETSIKMSPeerReply, error) {
+	return nil, status.Errorf(codes.Unimplemented, "method ETSIAddKMSPeer not implemented")
+}
+func (UnimplementedKmsETSIServer) ETSIRemoveKMSPeer(context.Context, *ETSIKMSPeerRequest) (*ETSIKMSPeerReply, error) {
+	return nil, status.Errorf(codes.Unimplemented, "method ETSIRemoveKMSPeer not implemented")
+}
+func (UnimplementedKmsETSIServer) ETSIGetPeerList(context.Context, *ETSIKMSPeerListRequest) (*ETSIKMSPeerListReply, error) {
+	return nil, status.Errorf(codes.Unimplemented, "method ETSIGetPeerList not implemented")
+}
+func (UnimplementedKmsETSIServer) ETSIGetEncryptKeys256Bit(context.Context, *ETSIGetEncryptKeys256BitRequest) (*ETSIGetEncryptKeys256BitReply, error) {
+	return nil, status.Errorf(codes.Unimplemented, "method ETSIGetEncryptKeys256Bit not implemented")
+}
+func (UnimplementedKmsETSIServer) mustEmbedUnimplementedKmsETSIServer() {}
+
+// UnsafeKmsETSIServer may be embedded to opt out of forward compatibility for this service.
+// Use of this interface is not recommended, as added methods to KmsETSIServer will
+// result in compilation errors.
+type UnsafeKmsETSIServer interface {
+	mustEmbedUnimplementedKmsETSIServer()
+}
+
+func RegisterKmsETSIServer(s grpc.ServiceRegistrar, srv KmsETSIServer) {
+	s.RegisterService(&KmsETSI_ServiceDesc, srv)
+}
+
+func _KmsETSI_ETSICapabilities_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+	in := new(ETSICapabilitiesRequest)
+	if err := dec(in); err != nil {
+		return nil, err
+	}
+	if interceptor == nil {
+		return srv.(KmsETSIServer).ETSICapabilities(ctx, in)
+	}
+	info := &grpc.UnaryServerInfo{
+		Server:     srv,
+		FullMethod: KmsETSI_ETSICapabilities_FullMethodName,
+	}
+	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+		return srv.(KmsETSIServer).ETSICapabilities(ctx, req.(*ETSICapabilitiesRequest))
+	}
+	return interceptor(ctx, in, info, handler)
+}
+
+func _KmsETSI_ETSIGetQuantumInterfaces_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+	in := new(ETSIKMSQuantumInterfaceListRequest)
+	if err := dec(in); err != nil {
+		return nil, err
+	}
+	if interceptor == nil {
+		return srv.(KmsETSIServer).ETSIGetQuantumInterfaces(ctx, in)
+	}
+	info := &grpc.UnaryServerInfo{
+		Server:     srv,
+		FullMethod: KmsETSI_ETSIGetQuantumInterfaces_FullMethodName,
+	}
+	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+		return srv.(KmsETSIServer).ETSIGetQuantumInterfaces(ctx, req.(*ETSIKMSQuantumInterfaceListRequest))
+	}
+	return interceptor(ctx, in, info, handler)
+}
+
+func _KmsETSI_ETSIAddKMSPeer_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+	in := new(ETSIKMSPeerRequest)
+	if err := dec(in); err != nil {
+		return nil, err
+	}
+	if interceptor == nil {
+		return srv.(KmsETSIServer).ETSIAddKMSPeer(ctx, in)
+	}
+	info := &grpc.UnaryServerInfo{
+		Server:     srv,
+		FullMethod: KmsETSI_ETSIAddKMSPeer_FullMethodName,
+	}
+	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+		return srv.(KmsETSIServer).ETSIAddKMSPeer(ctx, req.(*ETSIKMSPeerRequest))
+	}
+	return interceptor(ctx, in, info, handler)
+}
+
+func _KmsETSI_ETSIRemoveKMSPeer_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+	in := new(ETSIKMSPeerRequest)
+	if err := dec(in); err != nil {
+		return nil, err
+	}
+	if interceptor == nil {
+		return srv.(KmsETSIServer).ETSIRemoveKMSPeer(ctx, in)
+	}
+	info := &grpc.UnaryServerInfo{
+		Server:     srv,
+		FullMethod: KmsETSI_ETSIRemoveKMSPeer_FullMethodName,
+	}
+	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+		return srv.(KmsETSIServer).ETSIRemoveKMSPeer(ctx, req.(*ETSIKMSPeerRequest))
+	}
+	return interceptor(ctx, in, info, handler)
+}
+
+func _KmsETSI_ETSIGetPeerList_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+	in := new(ETSIKMSPeerListRequest)
+	if err := dec(in); err != nil {
+		return nil, err
+	}
+	if interceptor == nil {
+		return srv.(KmsETSIServer).ETSIGetPeerList(ctx, in)
+	}
+	info := &grpc.UnaryServerInfo{
+		Server:     srv,
+		FullMethod: KmsETSI_ETSIGetPeerList_FullMethodName,
+	}
+	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+		return srv.(KmsETSIServer).ETSIGetPeerList(ctx, req.(*ETSIKMSPeerListRequest))
+	}
+	return interceptor(ctx, in, info, handler)
+}
+
+func _KmsETSI_ETSIGetEncryptKeys256Bit_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+	in := new(ETSIGetEncryptKeys256BitRequest)
+	if err := dec(in); err != nil {
+		return nil, err
+	}
+	if interceptor == nil {
+		return srv.(KmsETSIServer).ETSIGetEncryptKeys256Bit(ctx, in)
+	}
+	info := &grpc.UnaryServerInfo{
+		Server:     srv,
+		FullMethod: KmsETSI_ETSIGetEncryptKeys256Bit_FullMethodName,
+	}
+	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+		return srv.(KmsETSIServer).ETSIGetEncryptKeys256Bit(ctx, req.(*ETSIGetEncryptKeys256BitRequest))
+	}
+	return interceptor(ctx, in, info, handler)
+}
+
+// KmsETSI_ServiceDesc is the grpc.ServiceDesc for KmsETSI service.
+// It's only intended for direct use with grpc.RegisterService,
+// and not to be introspected or modified (even as a copy)
+var KmsETSI_ServiceDesc = grpc.ServiceDesc{
+	ServiceName: "kmsetsi.KmsETSI",
+	HandlerType: (*KmsETSIServer)(nil),
+	Methods: []grpc.MethodDesc{
+		{
+			MethodName: "ETSICapabilities",
+			Handler:    _KmsETSI_ETSICapabilities_Handler,
+		},
+		{
+			MethodName: "ETSIGetQuantumInterfaces",
+			Handler:    _KmsETSI_ETSIGetQuantumInterfaces_Handler,
+		},
+		{
+			MethodName: "ETSIAddKMSPeer",
+			Handler:    _KmsETSI_ETSIAddKMSPeer_Handler,
+		},
+		{
+			MethodName: "ETSIRemoveKMSPeer",
+			Handler:    _KmsETSI_ETSIRemoveKMSPeer_Handler,
+		},
+		{
+			MethodName: "ETSIGetPeerList",
+			Handler:    _KmsETSI_ETSIGetPeerList_Handler,
+		},
+		{
+			MethodName: "ETSIGetEncryptKeys256Bit",
+			Handler:    _KmsETSI_ETSIGetEncryptKeys256Bit_Handler,
+		},
+	},
+	Streams:  []grpc.StreamDesc{},
+	Metadata: "kmsetsi/kmsetsiproto.proto",
+}
diff --git a/api/gen/proto/go/kmsintercom/kmsintercom.pb.go b/api/gen/proto/go/kmsintercom/kmsintercom.pb.go
new file mode 100644
index 0000000000000000000000000000000000000000..41fb9571aa6618d4ba597acae171d875c97969da
--- /dev/null
+++ b/api/gen/proto/go/kmsintercom/kmsintercom.pb.go
@@ -0,0 +1,375 @@
+// Code generated by protoc-gen-go. DO NOT EDIT.
+// versions:
+// 	protoc-gen-go v1.31.0
+// 	protoc        (unknown)
+// source: kmsintercom/kmsintercom.proto
+
+package kmsintercom
+
+import (
+	protoreflect "google.golang.org/protobuf/reflect/protoreflect"
+	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
+	reflect "reflect"
+	sync "sync"
+)
+
+const (
+	// Verify that this generated code is sufficiently up-to-date.
+	_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
+	// Verify that runtime/protoimpl is sufficiently up-to-date.
+	_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
+)
+
+// Capabilities
+// The request message containing the requesting kms' name.
+type InterComCapabilitiesRequest struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	MyKmsName string `protobuf:"bytes,1,opt,name=myKmsName,proto3" json:"myKmsName,omitempty"`
+}
+
+func (x *InterComCapabilitiesRequest) Reset() {
+	*x = InterComCapabilitiesRequest{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_kmsintercom_kmsintercom_proto_msgTypes[0]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *InterComCapabilitiesRequest) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*InterComCapabilitiesRequest) ProtoMessage() {}
+
+func (x *InterComCapabilitiesRequest) ProtoReflect() protoreflect.Message {
+	mi := &file_kmsintercom_kmsintercom_proto_msgTypes[0]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use InterComCapabilitiesRequest.ProtoReflect.Descriptor instead.
+func (*InterComCapabilitiesRequest) Descriptor() ([]byte, []int) {
+	return file_kmsintercom_kmsintercom_proto_rawDescGZIP(), []int{0}
+}
+
+func (x *InterComCapabilitiesRequest) GetMyKmsName() string {
+	if x != nil {
+		return x.MyKmsName
+	}
+	return ""
+}
+
+// The response message containing the replying kms' name.
+type InterComCapabilitiesReply struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	PeerKmsName string `protobuf:"bytes,1,opt,name=peerKmsName,proto3" json:"peerKmsName,omitempty"`
+}
+
+func (x *InterComCapabilitiesReply) Reset() {
+	*x = InterComCapabilitiesReply{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_kmsintercom_kmsintercom_proto_msgTypes[1]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *InterComCapabilitiesReply) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*InterComCapabilitiesReply) ProtoMessage() {}
+
+func (x *InterComCapabilitiesReply) ProtoReflect() protoreflect.Message {
+	mi := &file_kmsintercom_kmsintercom_proto_msgTypes[1]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use InterComCapabilitiesReply.ProtoReflect.Descriptor instead.
+func (*InterComCapabilitiesReply) Descriptor() ([]byte, []int) {
+	return file_kmsintercom_kmsintercom_proto_rawDescGZIP(), []int{1}
+}
+
+func (x *InterComCapabilitiesReply) GetPeerKmsName() string {
+	if x != nil {
+		return x.PeerKmsName
+	}
+	return ""
+}
+
+// KeyTransportSessionHandling
+// The request message containing the requesting kms' name.
+type InterComKeyTransportSessionHandlingRequest struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	RequestedKey string `protobuf:"bytes,1,opt,name=requestedKey,proto3" json:"requestedKey,omitempty"`
+}
+
+func (x *InterComKeyTransportSessionHandlingRequest) Reset() {
+	*x = InterComKeyTransportSessionHandlingRequest{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_kmsintercom_kmsintercom_proto_msgTypes[2]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *InterComKeyTransportSessionHandlingRequest) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*InterComKeyTransportSessionHandlingRequest) ProtoMessage() {}
+
+func (x *InterComKeyTransportSessionHandlingRequest) ProtoReflect() protoreflect.Message {
+	mi := &file_kmsintercom_kmsintercom_proto_msgTypes[2]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use InterComKeyTransportSessionHandlingRequest.ProtoReflect.Descriptor instead.
+func (*InterComKeyTransportSessionHandlingRequest) Descriptor() ([]byte, []int) {
+	return file_kmsintercom_kmsintercom_proto_rawDescGZIP(), []int{2}
+}
+
+func (x *InterComKeyTransportSessionHandlingRequest) GetRequestedKey() string {
+	if x != nil {
+		return x.RequestedKey
+	}
+	return ""
+}
+
+// The response message containing the replying kms' name.
+type InterComKeyTransportSessionHandlingReply struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	UsedKey string `protobuf:"bytes,1,opt,name=usedKey,proto3" json:"usedKey,omitempty"`
+}
+
+func (x *InterComKeyTransportSessionHandlingReply) Reset() {
+	*x = InterComKeyTransportSessionHandlingReply{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_kmsintercom_kmsintercom_proto_msgTypes[3]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *InterComKeyTransportSessionHandlingReply) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*InterComKeyTransportSessionHandlingReply) ProtoMessage() {}
+
+func (x *InterComKeyTransportSessionHandlingReply) ProtoReflect() protoreflect.Message {
+	mi := &file_kmsintercom_kmsintercom_proto_msgTypes[3]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use InterComKeyTransportSessionHandlingReply.ProtoReflect.Descriptor instead.
+func (*InterComKeyTransportSessionHandlingReply) Descriptor() ([]byte, []int) {
+	return file_kmsintercom_kmsintercom_proto_rawDescGZIP(), []int{3}
+}
+
+func (x *InterComKeyTransportSessionHandlingReply) GetUsedKey() string {
+	if x != nil {
+		return x.UsedKey
+	}
+	return ""
+}
+
+var File_kmsintercom_kmsintercom_proto protoreflect.FileDescriptor
+
+var file_kmsintercom_kmsintercom_proto_rawDesc = []byte{
+	0x0a, 0x1d, 0x6b, 0x6d, 0x73, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x63, 0x6f, 0x6d, 0x2f, 0x6b, 0x6d,
+	0x73, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x63, 0x6f, 0x6d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12,
+	0x0b, 0x6b, 0x6d, 0x73, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x63, 0x6f, 0x6d, 0x22, 0x3b, 0x0a, 0x1b,
+	0x49, 0x6e, 0x74, 0x65, 0x72, 0x43, 0x6f, 0x6d, 0x43, 0x61, 0x70, 0x61, 0x62, 0x69, 0x6c, 0x69,
+	0x74, 0x69, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x6d,
+	0x79, 0x4b, 0x6d, 0x73, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09,
+	0x6d, 0x79, 0x4b, 0x6d, 0x73, 0x4e, 0x61, 0x6d, 0x65, 0x22, 0x3d, 0x0a, 0x19, 0x49, 0x6e, 0x74,
+	0x65, 0x72, 0x43, 0x6f, 0x6d, 0x43, 0x61, 0x70, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x69, 0x65,
+	0x73, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x20, 0x0a, 0x0b, 0x70, 0x65, 0x65, 0x72, 0x4b, 0x6d,
+	0x73, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x70, 0x65, 0x65,
+	0x72, 0x4b, 0x6d, 0x73, 0x4e, 0x61, 0x6d, 0x65, 0x22, 0x50, 0x0a, 0x2a, 0x49, 0x6e, 0x74, 0x65,
+	0x72, 0x43, 0x6f, 0x6d, 0x4b, 0x65, 0x79, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74,
+	0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x48, 0x61, 0x6e, 0x64, 0x6c, 0x69, 0x6e, 0x67, 0x52,
+	0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x22, 0x0a, 0x0c, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73,
+	0x74, 0x65, 0x64, 0x4b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x72, 0x65,
+	0x71, 0x75, 0x65, 0x73, 0x74, 0x65, 0x64, 0x4b, 0x65, 0x79, 0x22, 0x44, 0x0a, 0x28, 0x49, 0x6e,
+	0x74, 0x65, 0x72, 0x43, 0x6f, 0x6d, 0x4b, 0x65, 0x79, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f,
+	0x72, 0x74, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x48, 0x61, 0x6e, 0x64, 0x6c, 0x69, 0x6e,
+	0x67, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x18, 0x0a, 0x07, 0x75, 0x73, 0x65, 0x64, 0x4b, 0x65,
+	0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x75, 0x73, 0x65, 0x64, 0x4b, 0x65, 0x79,
+	0x32, 0x91, 0x02, 0x0a, 0x09, 0x4b, 0x6d, 0x73, 0x54, 0x61, 0x6c, 0x6b, 0x65, 0x72, 0x12, 0x6a,
+	0x0a, 0x14, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x43, 0x6f, 0x6d, 0x43, 0x61, 0x70, 0x61, 0x62, 0x69,
+	0x6c, 0x69, 0x74, 0x69, 0x65, 0x73, 0x12, 0x28, 0x2e, 0x6b, 0x6d, 0x73, 0x69, 0x6e, 0x74, 0x65,
+	0x72, 0x63, 0x6f, 0x6d, 0x2e, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x43, 0x6f, 0x6d, 0x43, 0x61, 0x70,
+	0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x69, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
+	0x1a, 0x26, 0x2e, 0x6b, 0x6d, 0x73, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x63, 0x6f, 0x6d, 0x2e, 0x49,
+	0x6e, 0x74, 0x65, 0x72, 0x43, 0x6f, 0x6d, 0x43, 0x61, 0x70, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74,
+	0x69, 0x65, 0x73, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x00, 0x12, 0x97, 0x01, 0x0a, 0x23, 0x49,
+	0x6e, 0x74, 0x65, 0x72, 0x43, 0x6f, 0x6d, 0x4b, 0x65, 0x79, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x70,
+	0x6f, 0x72, 0x74, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x48, 0x61, 0x6e, 0x64, 0x6c, 0x69,
+	0x6e, 0x67, 0x12, 0x37, 0x2e, 0x6b, 0x6d, 0x73, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x63, 0x6f, 0x6d,
+	0x2e, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x43, 0x6f, 0x6d, 0x4b, 0x65, 0x79, 0x54, 0x72, 0x61, 0x6e,
+	0x73, 0x70, 0x6f, 0x72, 0x74, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x48, 0x61, 0x6e, 0x64,
+	0x6c, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x35, 0x2e, 0x6b, 0x6d,
+	0x73, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x63, 0x6f, 0x6d, 0x2e, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x43,
+	0x6f, 0x6d, 0x4b, 0x65, 0x79, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x53, 0x65,
+	0x73, 0x73, 0x69, 0x6f, 0x6e, 0x48, 0x61, 0x6e, 0x64, 0x6c, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x70,
+	0x6c, 0x79, 0x22, 0x00, 0x42, 0xaf, 0x01, 0x0a, 0x0f, 0x63, 0x6f, 0x6d, 0x2e, 0x6b, 0x6d, 0x73,
+	0x69, 0x6e, 0x74, 0x65, 0x72, 0x63, 0x6f, 0x6d, 0x42, 0x10, 0x4b, 0x6d, 0x73, 0x69, 0x6e, 0x74,
+	0x65, 0x72, 0x63, 0x6f, 0x6d, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x3e, 0x63, 0x6f,
+	0x64, 0x65, 0x2e, 0x66, 0x62, 0x69, 0x2e, 0x68, 0x2d, 0x64, 0x61, 0x2e, 0x64, 0x65, 0x2f, 0x64,
+	0x65, 0x6d, 0x6f, 0x71, 0x75, 0x61, 0x6e, 0x64, 0x74, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2d,
+	0x6b, 0x6d, 0x73, 0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x67, 0x6f,
+	0x2f, 0x6b, 0x6d, 0x73, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x63, 0x6f, 0x6d, 0xa2, 0x02, 0x03, 0x4b,
+	0x58, 0x58, 0xaa, 0x02, 0x0b, 0x4b, 0x6d, 0x73, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x63, 0x6f, 0x6d,
+	0xca, 0x02, 0x0b, 0x4b, 0x6d, 0x73, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x63, 0x6f, 0x6d, 0xe2, 0x02,
+	0x17, 0x4b, 0x6d, 0x73, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x63, 0x6f, 0x6d, 0x5c, 0x47, 0x50, 0x42,
+	0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x0b, 0x4b, 0x6d, 0x73, 0x69, 0x6e,
+	0x74, 0x65, 0x72, 0x63, 0x6f, 0x6d, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
+}
+
+var (
+	file_kmsintercom_kmsintercom_proto_rawDescOnce sync.Once
+	file_kmsintercom_kmsintercom_proto_rawDescData = file_kmsintercom_kmsintercom_proto_rawDesc
+)
+
+func file_kmsintercom_kmsintercom_proto_rawDescGZIP() []byte {
+	file_kmsintercom_kmsintercom_proto_rawDescOnce.Do(func() {
+		file_kmsintercom_kmsintercom_proto_rawDescData = protoimpl.X.CompressGZIP(file_kmsintercom_kmsintercom_proto_rawDescData)
+	})
+	return file_kmsintercom_kmsintercom_proto_rawDescData
+}
+
+var file_kmsintercom_kmsintercom_proto_msgTypes = make([]protoimpl.MessageInfo, 4)
+var file_kmsintercom_kmsintercom_proto_goTypes = []interface{}{
+	(*InterComCapabilitiesRequest)(nil),                // 0: kmsintercom.InterComCapabilitiesRequest
+	(*InterComCapabilitiesReply)(nil),                  // 1: kmsintercom.InterComCapabilitiesReply
+	(*InterComKeyTransportSessionHandlingRequest)(nil), // 2: kmsintercom.InterComKeyTransportSessionHandlingRequest
+	(*InterComKeyTransportSessionHandlingReply)(nil),   // 3: kmsintercom.InterComKeyTransportSessionHandlingReply
+}
+var file_kmsintercom_kmsintercom_proto_depIdxs = []int32{
+	0, // 0: kmsintercom.KmsTalker.InterComCapabilities:input_type -> kmsintercom.InterComCapabilitiesRequest
+	2, // 1: kmsintercom.KmsTalker.InterComKeyTransportSessionHandling:input_type -> kmsintercom.InterComKeyTransportSessionHandlingRequest
+	1, // 2: kmsintercom.KmsTalker.InterComCapabilities:output_type -> kmsintercom.InterComCapabilitiesReply
+	3, // 3: kmsintercom.KmsTalker.InterComKeyTransportSessionHandling:output_type -> kmsintercom.InterComKeyTransportSessionHandlingReply
+	2, // [2:4] is the sub-list for method output_type
+	0, // [0:2] is the sub-list for method input_type
+	0, // [0:0] is the sub-list for extension type_name
+	0, // [0:0] is the sub-list for extension extendee
+	0, // [0:0] is the sub-list for field type_name
+}
+
+func init() { file_kmsintercom_kmsintercom_proto_init() }
+func file_kmsintercom_kmsintercom_proto_init() {
+	if File_kmsintercom_kmsintercom_proto != nil {
+		return
+	}
+	if !protoimpl.UnsafeEnabled {
+		file_kmsintercom_kmsintercom_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*InterComCapabilitiesRequest); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_kmsintercom_kmsintercom_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*InterComCapabilitiesReply); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_kmsintercom_kmsintercom_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*InterComKeyTransportSessionHandlingRequest); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+		file_kmsintercom_kmsintercom_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*InterComKeyTransportSessionHandlingReply); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+	}
+	type x struct{}
+	out := protoimpl.TypeBuilder{
+		File: protoimpl.DescBuilder{
+			GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
+			RawDescriptor: file_kmsintercom_kmsintercom_proto_rawDesc,
+			NumEnums:      0,
+			NumMessages:   4,
+			NumExtensions: 0,
+			NumServices:   1,
+		},
+		GoTypes:           file_kmsintercom_kmsintercom_proto_goTypes,
+		DependencyIndexes: file_kmsintercom_kmsintercom_proto_depIdxs,
+		MessageInfos:      file_kmsintercom_kmsintercom_proto_msgTypes,
+	}.Build()
+	File_kmsintercom_kmsintercom_proto = out.File
+	file_kmsintercom_kmsintercom_proto_rawDesc = nil
+	file_kmsintercom_kmsintercom_proto_goTypes = nil
+	file_kmsintercom_kmsintercom_proto_depIdxs = nil
+}
diff --git a/api/gen/proto/go/kmsintercom/kmsintercom_grpc.pb.go b/api/gen/proto/go/kmsintercom/kmsintercom_grpc.pb.go
new file mode 100644
index 0000000000000000000000000000000000000000..41dac93ae286b25d52cd099f75f07c40377a6b8c
--- /dev/null
+++ b/api/gen/proto/go/kmsintercom/kmsintercom_grpc.pb.go
@@ -0,0 +1,146 @@
+// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
+// versions:
+// - protoc-gen-go-grpc v1.3.0
+// - protoc             (unknown)
+// source: kmsintercom/kmsintercom.proto
+
+package kmsintercom
+
+import (
+	context "context"
+	grpc "google.golang.org/grpc"
+	codes "google.golang.org/grpc/codes"
+	status "google.golang.org/grpc/status"
+)
+
+// This is a compile-time assertion to ensure that this generated file
+// is compatible with the grpc package it is being compiled against.
+// Requires gRPC-Go v1.32.0 or later.
+const _ = grpc.SupportPackageIsVersion7
+
+const (
+	KmsTalker_InterComCapabilities_FullMethodName                = "/kmsintercom.KmsTalker/InterComCapabilities"
+	KmsTalker_InterComKeyTransportSessionHandling_FullMethodName = "/kmsintercom.KmsTalker/InterComKeyTransportSessionHandling"
+)
+
+// KmsTalkerClient is the client API for KmsTalker service.
+//
+// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
+type KmsTalkerClient interface {
+	InterComCapabilities(ctx context.Context, in *InterComCapabilitiesRequest, opts ...grpc.CallOption) (*InterComCapabilitiesReply, error)
+	InterComKeyTransportSessionHandling(ctx context.Context, in *InterComKeyTransportSessionHandlingRequest, opts ...grpc.CallOption) (*InterComKeyTransportSessionHandlingReply, error)
+}
+
+type kmsTalkerClient struct {
+	cc grpc.ClientConnInterface
+}
+
+func NewKmsTalkerClient(cc grpc.ClientConnInterface) KmsTalkerClient {
+	return &kmsTalkerClient{cc}
+}
+
+func (c *kmsTalkerClient) InterComCapabilities(ctx context.Context, in *InterComCapabilitiesRequest, opts ...grpc.CallOption) (*InterComCapabilitiesReply, error) {
+	out := new(InterComCapabilitiesReply)
+	err := c.cc.Invoke(ctx, KmsTalker_InterComCapabilities_FullMethodName, in, out, opts...)
+	if err != nil {
+		return nil, err
+	}
+	return out, nil
+}
+
+func (c *kmsTalkerClient) InterComKeyTransportSessionHandling(ctx context.Context, in *InterComKeyTransportSessionHandlingRequest, opts ...grpc.CallOption) (*InterComKeyTransportSessionHandlingReply, error) {
+	out := new(InterComKeyTransportSessionHandlingReply)
+	err := c.cc.Invoke(ctx, KmsTalker_InterComKeyTransportSessionHandling_FullMethodName, in, out, opts...)
+	if err != nil {
+		return nil, err
+	}
+	return out, nil
+}
+
+// KmsTalkerServer is the server API for KmsTalker service.
+// All implementations must embed UnimplementedKmsTalkerServer
+// for forward compatibility
+type KmsTalkerServer interface {
+	InterComCapabilities(context.Context, *InterComCapabilitiesRequest) (*InterComCapabilitiesReply, error)
+	InterComKeyTransportSessionHandling(context.Context, *InterComKeyTransportSessionHandlingRequest) (*InterComKeyTransportSessionHandlingReply, error)
+	mustEmbedUnimplementedKmsTalkerServer()
+}
+
+// UnimplementedKmsTalkerServer must be embedded to have forward compatible implementations.
+type UnimplementedKmsTalkerServer struct {
+}
+
+func (UnimplementedKmsTalkerServer) InterComCapabilities(context.Context, *InterComCapabilitiesRequest) (*InterComCapabilitiesReply, error) {
+	return nil, status.Errorf(codes.Unimplemented, "method InterComCapabilities not implemented")
+}
+func (UnimplementedKmsTalkerServer) InterComKeyTransportSessionHandling(context.Context, *InterComKeyTransportSessionHandlingRequest) (*InterComKeyTransportSessionHandlingReply, error) {
+	return nil, status.Errorf(codes.Unimplemented, "method InterComKeyTransportSessionHandling not implemented")
+}
+func (UnimplementedKmsTalkerServer) mustEmbedUnimplementedKmsTalkerServer() {}
+
+// UnsafeKmsTalkerServer may be embedded to opt out of forward compatibility for this service.
+// Use of this interface is not recommended, as added methods to KmsTalkerServer will
+// result in compilation errors.
+type UnsafeKmsTalkerServer interface {
+	mustEmbedUnimplementedKmsTalkerServer()
+}
+
+func RegisterKmsTalkerServer(s grpc.ServiceRegistrar, srv KmsTalkerServer) {
+	s.RegisterService(&KmsTalker_ServiceDesc, srv)
+}
+
+func _KmsTalker_InterComCapabilities_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+	in := new(InterComCapabilitiesRequest)
+	if err := dec(in); err != nil {
+		return nil, err
+	}
+	if interceptor == nil {
+		return srv.(KmsTalkerServer).InterComCapabilities(ctx, in)
+	}
+	info := &grpc.UnaryServerInfo{
+		Server:     srv,
+		FullMethod: KmsTalker_InterComCapabilities_FullMethodName,
+	}
+	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+		return srv.(KmsTalkerServer).InterComCapabilities(ctx, req.(*InterComCapabilitiesRequest))
+	}
+	return interceptor(ctx, in, info, handler)
+}
+
+func _KmsTalker_InterComKeyTransportSessionHandling_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+	in := new(InterComKeyTransportSessionHandlingRequest)
+	if err := dec(in); err != nil {
+		return nil, err
+	}
+	if interceptor == nil {
+		return srv.(KmsTalkerServer).InterComKeyTransportSessionHandling(ctx, in)
+	}
+	info := &grpc.UnaryServerInfo{
+		Server:     srv,
+		FullMethod: KmsTalker_InterComKeyTransportSessionHandling_FullMethodName,
+	}
+	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+		return srv.(KmsTalkerServer).InterComKeyTransportSessionHandling(ctx, req.(*InterComKeyTransportSessionHandlingRequest))
+	}
+	return interceptor(ctx, in, info, handler)
+}
+
+// KmsTalker_ServiceDesc is the grpc.ServiceDesc for KmsTalker service.
+// It's only intended for direct use with grpc.RegisterService,
+// and not to be introspected or modified (even as a copy)
+var KmsTalker_ServiceDesc = grpc.ServiceDesc{
+	ServiceName: "kmsintercom.KmsTalker",
+	HandlerType: (*KmsTalkerServer)(nil),
+	Methods: []grpc.MethodDesc{
+		{
+			MethodName: "InterComCapabilities",
+			Handler:    _KmsTalker_InterComCapabilities_Handler,
+		},
+		{
+			MethodName: "InterComKeyTransportSessionHandling",
+			Handler:    _KmsTalker_InterComKeyTransportSessionHandling_Handler,
+		},
+	},
+	Streams:  []grpc.StreamDesc{},
+	Metadata: "kmsintercom/kmsintercom.proto",
+}
diff --git a/api/kmsetsi/kmsetsi/buf.lock b/api/kmsetsi/kmsetsi/buf.lock
new file mode 100644
index 0000000000000000000000000000000000000000..c91b5810c2976f1e6c940bfc491e8e1d8f871180
--- /dev/null
+++ b/api/kmsetsi/kmsetsi/buf.lock
@@ -0,0 +1,2 @@
+# Generated by buf. DO NOT EDIT.
+version: v1
diff --git a/api/kmsetsi/kmsetsi/buf.yaml b/api/kmsetsi/kmsetsi/buf.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..5fc4486b00f9a9afd5a9580343cc141ce855685d
--- /dev/null
+++ b/api/kmsetsi/kmsetsi/buf.yaml
@@ -0,0 +1,7 @@
+version: v1
+lint:
+  use:
+    - DEFAULT
+breaking:
+  use:
+    - FILE
diff --git a/api/kmsetsi/kmsetsi/kmsetsiproto.proto b/api/kmsetsi/kmsetsi/kmsetsiproto.proto
new file mode 100644
index 0000000000000000000000000000000000000000..ae04fa50d55d399bacde166c56242428773e860b
--- /dev/null
+++ b/api/kmsetsi/kmsetsi/kmsetsiproto.proto
@@ -0,0 +1,76 @@
+syntax = "proto3";
+
+package kmsetsi;
+
+service KmsETSI {
+	// Sends a greeting
+	rpc ETSICapabilities (ETSICapabilitiesRequest) returns (ETSICapabilitiesReply) {}
+  rpc ETSIGetQuantumInterfaces(ETSIKMSQuantumInterfaceListRequest) returns (ETSIKMSQuantumInterfaceListReply) {}
+  rpc ETSIAddKMSPeer(ETSIKMSPeerRequest) returns (ETSIKMSPeerReply) {}
+  rpc ETSIRemoveKMSPeer(ETSIKMSPeerRequest) returns (ETSIKMSPeerReply) {}
+  rpc ETSIGetPeerList(ETSIKMSPeerListRequest) returns (ETSIKMSPeerListReply) {}
+  rpc ETSIGetEncryptKeys256Bit (ETSIGetEncryptKeys256BitRequest) returns (ETSIGetEncryptKeys256BitReply) {}
+  }
+
+  // The request message containing the user's name.
+message ETSICapabilitiesRequest {
+	string myKmsName = 1;
+}
+
+  // The response message containing the greetings
+  message ETSICapabilitiesReply {
+	string peerKmsName = 1;
+}
+
+message ETSIKMSQuantumInterfaceListRequest {
+
+}
+
+// NB for myself: this be used to link QLE mit KMS-Session!
+message QuantumElementInfo {
+  uint64 qleID = 1;
+  string udpAddr = 2;
+}
+
+message ETSIKMSQuantumInterfaceListReply {
+  repeated QuantumElementInfo qlElementInfo = 1;
+}
+
+
+message ETSIKMSPeerRequest {
+  string kmsPeerSocket = 1;
+  uint32 kmsLocalQLEId = 2;
+}
+
+message ETSIKMSPeerReply {
+  string kmsPeerName  = 1;
+}
+
+message ETSIKMSPeerListRequest {
+}
+
+message ETSIKMSPeer {
+  string peerName = 1;
+  string peerStatus = 2;
+
+}
+
+message ETSIKMSPeerListReply {
+  repeated ETSIKMSPeer peer = 1;
+}
+
+message ETSIGetEncryptKeys256BitRequest {
+  int64 amount = 1;
+}
+
+/* out kms-keystore.go
+ * type kmsKSElement struct {
+ * 	  keyID string
+ *	  key   []byte // a 256 bit key
+ *  }
+ */
+
+message ETSIGetEncryptKeys256BitReply {
+  string keyID = 1;
+  bytes key = 2;
+}
diff --git a/api/kmsintercom/kmsintercom/buf.lock b/api/kmsintercom/kmsintercom/buf.lock
new file mode 100644
index 0000000000000000000000000000000000000000..c91b5810c2976f1e6c940bfc491e8e1d8f871180
--- /dev/null
+++ b/api/kmsintercom/kmsintercom/buf.lock
@@ -0,0 +1,2 @@
+# Generated by buf. DO NOT EDIT.
+version: v1
diff --git a/api/kmsintercom/kmsintercom/buf.yaml b/api/kmsintercom/kmsintercom/buf.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..5fc4486b00f9a9afd5a9580343cc141ce855685d
--- /dev/null
+++ b/api/kmsintercom/kmsintercom/buf.yaml
@@ -0,0 +1,7 @@
+version: v1
+lint:
+  use:
+    - DEFAULT
+breaking:
+  use:
+    - FILE
diff --git a/api/kmsintercom/kmsintercom/kmsintercom.proto b/api/kmsintercom/kmsintercom/kmsintercom.proto
new file mode 100644
index 0000000000000000000000000000000000000000..52af6f1e24f6dbd018a3a361349aa59446a1f686
--- /dev/null
+++ b/api/kmsintercom/kmsintercom/kmsintercom.proto
@@ -0,0 +1,30 @@
+syntax = "proto3";
+
+package kmsintercom;
+
+service KmsTalker {
+	rpc InterComCapabilities (InterComCapabilitiesRequest) returns (InterComCapabilitiesReply) {}
+	rpc InterComKeyTransportSessionHandling(InterComKeyTransportSessionHandlingRequest) returns (InterComKeyTransportSessionHandlingReply) {}
+}
+
+// Capabilities
+// The request message containing the requesting kms' name.
+message InterComCapabilitiesRequest {
+	string myKmsName = 1;
+  }
+
+// The response message containing the replying kms' name.
+message InterComCapabilitiesReply {
+	string peerKmsName= 1;
+}
+
+// KeyTransportSessionHandling
+// The request message containing the requesting kms' name.
+message InterComKeyTransportSessionHandlingRequest {
+	string requestedKey = 1;
+  }
+
+// The response message containing the replying kms' name.
+message InterComKeyTransportSessionHandlingReply {
+	string usedKey = 1;
+}
diff --git a/figures/BMBF_gefoerdert_2017_en.jpg b/figures/BMBF_gefoerdert_2017_en.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..97913aaca5bf44ccc412602549a565e6a42c9d5e
Binary files /dev/null and b/figures/BMBF_gefoerdert_2017_en.jpg differ
diff --git a/go.mod b/go.mod
index 0110e541810a7568d4d89d9bfc38bb45c014a1d6..67f5f869e3044817cc3706720a863c2e74a1aeaf 100644
--- a/go.mod
+++ b/go.mod
@@ -1,5 +1,17 @@
-module code.fbi.h-da.de/m.stiemerling/proto-kms
+module code.fbi.h-da.de/danet/proto-kms
 
 go 1.20
 
-require github.com/google/uuid v1.3.0
+require (
+	github.com/google/uuid v1.3.0
+	google.golang.org/grpc v1.56.2
+	google.golang.org/protobuf v1.31.0
+)
+
+require (
+	github.com/golang/protobuf v1.5.3 // indirect
+	golang.org/x/net v0.9.0 // indirect
+	golang.org/x/sys v0.7.0 // indirect
+	golang.org/x/text v0.9.0 // indirect
+	google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 // indirect
+)
diff --git a/go.sum b/go.sum
index 3dfe1c9f26d3953e435514c804a71a01721639fe..dd5cac2ad34df0f5e7bdbd392eb30bfea2ded46b 100644
--- a/go.sum
+++ b/go.sum
@@ -1,2 +1,22 @@
+github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
+github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
+github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
+github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
 github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
 github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
+golang.org/x/net v0.9.0 h1:aWJ/m6xSmxWBx+V0XRHTlrYrPG56jKsLdTFmsSsCzOM=
+golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns=
+golang.org/x/sys v0.7.0 h1:3jlCCIQZPdOYu1h8BkNvLz8Kgwtae2cagcG/VamtZRU=
+golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE=
+golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
+golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 h1:KpwkzHKEF7B9Zxg18WzOa7djJ+Ha5DzthMyZYQfEn2A=
+google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1/go.mod h1:nKE/iIaLqn2bQwXBg8f1g2Ylh6r5MN5CmZvuzZCgsCU=
+google.golang.org/grpc v1.56.2 h1:fVRFRnXvU+x6C4IlHZewvJOVHoOv1TUuQyoRsYnB4bI=
+google.golang.org/grpc v1.56.2/go.mod h1:I9bI3vqKfayGqPUAwGdOSu7kt6oIJLixfffKrpXqQ9s=
+google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
+google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
+google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8=
+google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
diff --git a/kms/grpcurl-sheet.md b/kms/grpcurl-sheet.md
new file mode 100644
index 0000000000000000000000000000000000000000..4aa7776be086d815e9b4b64cdc59847949ea83d5
--- /dev/null
+++ b/kms/grpcurl-sheet.md
@@ -0,0 +1,10 @@
+# Info for testing with grpcurl
+
+https://github.com/fullstorydev/grpcurl
+
+### 
+
+'grpcurl -d '{"myKmsName" : "grpcurl"}' --import-path ./kmsetsiproto --proto kmsetsiproto.proto  --plaintext localhost:50900  kmsetsiproto.KmsETSI.ETSICapabilities
+{  "peerKmsName": "whatever"}'
+
+'grpcurl -d '{"kmsPeerSocket" : "127.0.0.1:50901"}' --import-path ./kmsetsiproto --proto kmsetsiproto.proto  --plaintext localhost:50900  kmsetsiproto.KmsETSI.ETSIAddKMSPeer'
\ No newline at end of file
diff --git a/kms/kms-keystore.go b/kms/kms-keystore.go
new file mode 100644
index 0000000000000000000000000000000000000000..6828a08b38774a1ebff07afa668aeb2595ac5a0e
--- /dev/null
+++ b/kms/kms-keystore.go
@@ -0,0 +1,64 @@
+package kms
+
+import (
+	"errors"
+	"fmt"
+	"log"
+	"sync"
+
+	"code.fbi.h-da.de/danet/proto-kms/quantumlayer"
+)
+
+type kmsKS interface {
+	KeyChopper256Bit(bulkKey *quantumlayer.QuantumLayerBulkKey) (err error)
+	addKey(int64, [8]byte)
+}
+
+// holds a single ready to use 256 bit key
+type kmsKSElement struct {
+	keyID string
+	key   []byte // a 256 bit key
+}
+
+type kmsKeyStore struct {
+	keyStoreMutex sync.Mutex
+	keyStore      map[string]*kmsKSElement
+}
+
+func (ks *kmsKeyStore) addKey(bulkKeyId int64, keyToadd []byte) {
+	newKeyElement := kmsKSElement{}
+
+	//generate keyID out of bulkKeyId and has of keyToadd
+	newKeyElement.keyID = fmt.Sprintf("%x.%x", bulkKeyId, keyToadd)
+	newKeyElement.key = keyToadd
+
+	ks.keyStoreMutex.Lock()
+	defer ks.keyStoreMutex.Unlock()
+	// test for collisions
+	if _, notThere := ks.keyStore[newKeyElement.keyID]; notThere {
+		log.Printf("Whop: addKey collission of key id %s for bulkKeyID %d", newKeyElement.keyID, bulkKeyId)
+		return
+	}
+	// ok to add
+	ks.keyStore[newKeyElement.keyID] = &newKeyElement
+
+}
+
+// Takes a bulk of keys and chops them in 256bit keys each
+// Any remainder is discarded
+func (ks *kmsKeyStore) KeyChopper256Bit(bulkKey *quantumlayer.QuantumLayerBulkKey) (err error) {
+	if bulkKey.BulkKeyLength != len(*bulkKey.BulkKey) {
+		err = errors.New("bulkKey length mismatch")
+		return err
+	}
+
+	// Let's chop!
+	key := *bulkKey.BulkKey
+	for len(key) > 32 {
+		tmpkey := key[:32]
+		ks.addKey(bulkKey.BulkKeyId, tmpkey)
+		// shorten the key storage
+		key = key[32:]
+	}
+	return nil
+}
diff --git a/kms/kms.go b/kms/kms.go
index 586d8374c0e8a31d648f3edf467e9498cfe5a012..8c21b44209244141a0c3ab011ddd2755a426c8c7 100644
--- a/kms/kms.go
+++ b/kms/kms.go
@@ -5,53 +5,207 @@
 package kms
 
 import (
-	"code.fbi.h-da.de/m.stiemerling/proto-kms/quantumlayer"
+	"crypto/rand"
+	"encoding/binary"
+	"log"
+	"sync"
+	"time"
+
+	pbETSI "code.fbi.h-da.de/danet/proto-kms/api/gen/proto/go/kmsetsi"
+	pbIC "code.fbi.h-da.de/danet/proto-kms/api/gen/proto/go/kmsintercom"
+	"code.fbi.h-da.de/danet/proto-kms/quantumlayer"
 	"github.com/google/uuid"
 )
 
 type Qkdnkms interface {
+	//AddExternalNotifierGeneral(chan bool)   // used to indicate unspecific changes
+	AddExternalNotifierQLE(chan uint32)     // used to indicate changes to specific Quantum Link Element (QLE)
+	AddExternalNotifierKMSPeer(chan string) // used to indicate changes to specific KMSPeer
 	AddQuantumElement() *QuantumElement
+	GlobalKeyHandler(time.Duration) error
+	AddPeer(kmsPeerSocket string, servingQLE *QuantumElement)
+	RemovePeer(kmsPeerSocket string)
+	FindPeerUuid(uuid.UUID) *kmsPeer
 }
 
-type qlElementId uuid.UUID
 type qlElementLinkID int
 
 // The general emulated KMS
-type eKMS struct {
-	QuantumElements map[qlElementId]*QuantumElement
-	KeyStorages     map[qlElementId]map[qlElementLinkID]uint64
+type EKMS struct {
+	kmsName                 string
+	kmsUUID                 uuid.UUID
+	qleMapMutex             sync.Mutex
+	QuantumElements         map[uint32]*QuantumElement
+	externalNotifierQLE     chan uint32
+	kmsPeersMutex           sync.Mutex
+	KmsPeers                map[string]*kmsPeer
+	externalNotifierKMSPeer chan string
+	pbETSI.UnimplementedKmsETSIServer
+	pbIC.UnimplementedKmsTalkerServer
 }
 
-// Will keep information about the quantum elements that this eKMS is talking to
+// Will keep information about the quantum elements that this EKMS is talking to
+// This actually constitutes a quantum element with only a single link
+
+/*
+type QuantumElementInterface interface {
+	GetQlID() qlElementId
+}*/
+
 type QuantumElement struct {
-	qlElementName       string                                         // the name of this Quantum Element
-	qlElementUUID       uuid.UUID                                      // the uuid for this device
-	QlElement           *quantumlayer.QuantumlayerEmuPRNG              // the actual quantum element
-	QuantumElementLinks map[qlElementLinkID]*quantumlayer.QuantumLayer // contains information about the quantum links
+	QlID               uint32
+	QuantumElementLink *quantumlayer.QuantumlayerEmuPRNG // contains information about the quantum links
+	//key stores go here
+	keyStoreLocal  *kmsKeyStore // the keys this local entity has produced and are ready to use
+	keyStoreRemote *kmsKeyStore // the keys th remote entity (peer) has produced and are ready to use
 }
 
-func NeweKMS() (newekms *eKMS) {
+func NewEKMS(kmsName string, kmsUUID uuid.UUID) (newEKMS *EKMS) {
 
-	return &eKMS{
-		QuantumElements: make(map[qlElementId]*QuantumElement),
-		KeyStorages:     make(map[qlElementId]map[qlElementLinkID]uint64),
+	return &EKMS{
+		kmsName:                 kmsName,
+		kmsUUID:                 kmsUUID,
+		QuantumElements:         make(map[uint32]*QuantumElement),
+		KmsPeers:                make(map[string]*kmsPeer),
+		externalNotifierQLE:     nil, // just be surely set to nil!
+		externalNotifierKMSPeer: nil, // just be surely set to nil!
 	}
 }
 
-func (kms *eKMS) AddQuantumElement(kmsName string, kmsUUID uuid.UUID, kmsUDPAddrr string) *QuantumElement {
+func (kms *EKMS) AddQuantumElement(kmsUDPAddrr string) *QuantumElement {
 
 	//Get an emulated Quantumlayer
 	ql := quantumlayer.NewQuantumlayerEmuPRNG()
-	ql.PowerOn(kmsUDPAddrr)
+	ql.Configure(kmsUDPAddrr)
+	ql.PowerOn()
+
+	ksl := kmsKeyStore{
+		keyStore: make(map[string]*kmsKSElement),
+	}
+	ksr := kmsKeyStore{
+		keyStore: make(map[string]*kmsKSElement),
+	}
 
 	qle := QuantumElement{
-		qlElementName:       kmsName,
-		qlElementUUID:       kmsUUID,
-		QlElement:           ql,
-		QuantumElementLinks: make(map[qlElementLinkID]*quantumlayer.QuantumLayer),
+		QuantumElementLink: ql,
+		keyStoreLocal:      &ksl,
+		keyStoreRemote:     &ksr,
+	}
+
+	// generate a ID for this quantum element that is unique locally
+	var randError error
+	qle.QlID, randError = kms.GenerateNewQleID()
+	if randError != nil {
+		log.Fatalf("GenerateNewQleID: %s", randError)
+		return nil
 	}
 
-	kms.QuantumElements[qlElementId(kmsUUID)] = &qle
+	kms.QuantumElements[qle.QlID] = &qle
 
 	return &qle
 }
+
+func (kms *EKMS) GlobalKeyHandler(waitTime time.Duration) error {
+
+	// periodically walk through QuantumElements and retrieve their
+	// - local key bulk buffer
+	// - remote key bulk buffer
+	// feed this into the corresponding key buffers of the kmss
+	for {
+		for currentQE := range kms.QuantumElements {
+			log.Printf("%s GlobalKeyHandler reading...\n", kms.kmsName)
+
+			bulkKeysLocal, err := kms.QuantumElements[currentQE].QuantumElementLink.GetKeyBatchLocal()
+			if err != nil {
+				log.Printf("%s failed to retrieve local bulkkeys with error %s", kms.kmsName, err)
+			} else {
+				// process bulkKeysLocal
+				log.Printf("%s produced %d bytes of key locally", kms.kmsName, bulkKeysLocal.BulkKeyLength)
+				kms.QuantumElements[currentQE].keyStoreLocal.KeyChopper256Bit(&bulkKeysLocal)
+
+			}
+
+			bulkKeysRemote, err := kms.QuantumElements[currentQE].QuantumElementLink.GetKeyBatchPeer()
+			if err != nil {
+				log.Printf("%s failed to retrieve remote bulkkeys with error %s", kms.kmsName, err)
+			} else {
+				// process bulkKeysRemote
+				log.Printf("%s received %d bytes of key from remote peer", kms.kmsName, bulkKeysRemote.BulkKeyLength)
+				kms.QuantumElements[currentQE].keyStoreRemote.KeyChopper256Bit(&bulkKeysRemote)
+			}
+		}
+		time.Sleep(waitTime)
+	}
+}
+
+// This has a design flaw, as the generated ID is returned to the calling function and used there.
+// However, when being used a potential other caller might received the same qlElementId
+// TODO/XXX: This would be collision and must be eventually avoided
+func (kms *EKMS) GenerateNewQleID() (uint32, error) {
+	for { // this needs a condiction to stop!
+		// create buffer for uint32, so reserve 4 bytes
+		buf := make([]byte, 4)
+
+		// fill the buffer from rand
+		_, err := rand.Read(buf)
+		if err != nil {
+			return 0, err
+		}
+
+		propopsedQlElementID := binary.BigEndian.Uint32(buf)
+
+		// check if ID is already taken
+		if kms.QuantumElements[propopsedQlElementID] == nil {
+			return propopsedQlElementID, nil
+		}
+		//keep going....
+	}
+}
+
+// TODO/XXX error handling
+func (kms *EKMS) AddPeer(kmsPeerSocket string, servingQLE *QuantumElement) {
+	//check if peer exists
+	if _, there := kms.KmsPeers[kmsPeerSocket]; there {
+		log.Printf("Trying to add existing peer %s", kmsPeerSocket)
+		return
+	}
+	peer := NewKmsPeer(servingQLE, kms.externalNotifierKMSPeer)
+	peer.tcpSocketStr = kmsPeerSocket
+
+	kms.kmsPeersMutex.Lock()
+	kms.KmsPeers[kmsPeerSocket] = &peer
+	kms.kmsPeersMutex.Unlock()
+
+	go peer.PeerHandler(kms.kmsName)
+}
+
+// TODO/XXX error handling
+func (kms *EKMS) RemovePeer(kmsPeerSocket string) {
+	if _, there := kms.KmsPeers[kmsPeerSocket]; there {
+		//peer.quit <- true
+		delete(kms.KmsPeers, kmsPeerSocket)
+		return
+	}
+	log.Printf("Can not find a peer with socekt: %s", kmsPeerSocket)
+	return
+}
+
+func (kms *EKMS) AddExternalNotifierQLE(in chan uint32) {
+	kms.externalNotifierQLE = in
+}
+
+func (kms *EKMS) AddExternalNotifierKMSPeer(in chan string) {
+	kms.externalNotifierKMSPeer = in
+}
+
+func (kms *EKMS) FindPeerUuid(lookup uuid.UUID) (peer *kmsPeer) {
+	if kms.KmsPeers != nil {
+		for _, peer = range kms.KmsPeers {
+			if peer.id == lookup {
+				return peer
+			}
+		}
+	}
+
+	return nil
+}
diff --git a/kms/kmsetsi.go b/kms/kmsetsi.go
new file mode 100644
index 0000000000000000000000000000000000000000..826499979c6946f69a93056242b912cae6d80dae
--- /dev/null
+++ b/kms/kmsetsi.go
@@ -0,0 +1,152 @@
+package kms
+
+import (
+	"context"
+	"encoding/base64"
+	"errors"
+	"flag"
+	"fmt"
+	"log"
+	"net"
+	"os/exec"
+
+	pb "code.fbi.h-da.de/danet/proto-kms/api/gen/proto/go/kmsetsi"
+	"google.golang.org/grpc"
+	"google.golang.org/grpc/codes"
+	"google.golang.org/grpc/status"
+)
+
+var (
+	etsiPort = flag.Int("port", 50900, "The server port")
+)
+
+type etsiServer struct {
+	pb.UnimplementedKmsETSIServer
+	handlingEkms *EKMS
+	visitedKeys  map[*kmsKSElement]bool
+}
+
+func (es *etsiServer) ETSICapabilities(ctx context.Context, in *pb.ETSICapabilitiesRequest) (capReply *pb.ETSICapabilitiesReply, err error) {
+	log.Printf("Received: %v", in.GetMyKmsName())
+
+	return &pb.ETSICapabilitiesReply{
+		PeerKmsName: "whatever",
+	}, nil
+}
+
+func (es *etsiServer) ETSIGetQuantumInterfaces(ctx context.Context, in *pb.ETSIKMSQuantumInterfaceListRequest) (qleReply *pb.ETSIKMSQuantumInterfaceListReply, err error) {
+	qleList := make([]*pb.QuantumElementInfo, 1)
+
+	// Walk through QuantumLayerInterfaces and return their information
+	for _, qlWorks := range es.handlingEkms.QuantumElements {
+		qleElement := pb.QuantumElementInfo{
+			QleID:   uint64(qlWorks.QlID),
+			UdpAddr: fmt.Sprintf("%s:%d", qlWorks.QuantumElementLink.GetLocalQLPort().IP.String(), qlWorks.QuantumElementLink.GetLocalQLPort().Port),
+		}
+		qleList = append(qleList, &qleElement)
+	}
+	return &pb.ETSIKMSQuantumInterfaceListReply{
+		QlElementInfo: qleList,
+	}, nil
+}
+
+func (es *etsiServer) ETSIAddKMSPeer(ctx context.Context, in *pb.ETSIKMSPeerRequest) (*pb.ETSIKMSPeerReply, error) {
+	//determine the kms structure to call
+	log.Printf("AddKMSPeer called.")
+
+	// Check first if KmsLocalQLEId is actually one of ours...
+	qleID := in.KmsLocalQLEId
+	servingQLE, _ := es.handlingEkms.QuantumElements[qleID]
+	if servingQLE == nil {
+		//no such element!
+		err := errors.New(fmt.Sprintf("Unknown local quantum element with ID %d", qleID))
+
+		return &pb.ETSIKMSPeerReply{}, err
+	}
+
+	es.handlingEkms.AddPeer(in.GetKmsPeerSocket(), servingQLE)
+
+	return &pb.ETSIKMSPeerReply{
+		KmsPeerName: es.handlingEkms.kmsName,
+	}, nil
+}
+
+func (es *etsiServer) ETSIRemoveKMSPeer(ctx context.Context, in *pb.ETSIKMSPeerRequest) (*pb.ETSIKMSPeerReply, error) {
+	//kms.RemovePeer(in.GetKmsPeerSocket())
+
+	return &pb.ETSIKMSPeerReply{
+		//KmsPeerName: kms.kmsName,
+	}, nil
+}
+
+func (es *etsiServer) ETSIGetPeerList(ctx context.Context, in *pb.ETSIKMSPeerListRequest) (*pb.ETSIKMSPeerListReply, error) {
+
+	ep := make([]*pb.ETSIKMSPeer, 2)
+
+	r := new(pb.ETSIKMSPeerListReply)
+
+	r.Peer = ep
+
+	p := pb.ETSIKMSPeer{
+		PeerName:   "Yo",
+		PeerStatus: "bla",
+	}
+
+	r.Peer[0] = &p
+
+	return r, nil
+}
+
+func (es *etsiServer) ETSIGetEncryptKeys256Bit(ctx context.Context, in *pb.ETSIGetEncryptKeys256BitRequest) (*pb.ETSIGetEncryptKeys256BitReply, error) {
+	log.Printf("Received request for n=%d keys", in.GetAmount())
+
+	var randomKey *kmsKSElement
+	var err error
+	// NOTE: change change change!
+	for _, qe := range es.handlingEkms.QuantumElements {
+		quantumElementLocalKeyStore := qe.keyStoreLocal
+		randomKey, err = randomItemFromMap[string, *kmsKSElement](quantumElementLocalKeyStore.keyStore, es.visitedKeys)
+		if err != nil {
+			return nil, status.Errorf(codes.Internal, "%v", err)
+		}
+		es.visitedKeys[randomKey] = true
+	}
+
+	keyAsString := base64.StdEncoding.EncodeToString(randomKey.key)
+	// push the key to the encryptor via ssh
+	ssh := "ssh"
+	complexArg := fmt.Sprintf("(rc=$(sed \"12 c PresharedKey = %s\" /etc/wireguard/wg0.conf); echo \"$rc\" > /etc/wireguard/wg0.conf)", keyAsString)
+	args := []string{"root@172.20.0.5", "-oStrictHostKeyChecking=no", complexArg}
+
+	cmd := exec.Command(ssh, args...)
+	err = cmd.Run()
+	if err != nil {
+		log.Println("could not execute command")
+		return nil, status.Errorf(codes.Internal, "%v", err)
+	}
+
+	// Construct any response
+	return &pb.ETSIGetEncryptKeys256BitReply{
+		KeyID: randomKey.keyID,
+		Key:   randomKey.key,
+	}, nil
+}
+
+func StartETSI(listenAddr string, callingKMS *EKMS) {
+	flag.Parse()
+
+	//lis, err := net.Listen("tcp", fmt.Sprintf(":%d", *etsiPort))
+	lis, err := net.Listen("tcp", listenAddr)
+	if err != nil {
+		log.Fatalf("failed to listen: %v", err)
+	}
+	s := grpc.NewServer()
+	pb.RegisterKmsETSIServer(s, &etsiServer{
+		handlingEkms: callingKMS,
+		visitedKeys:  make(map[*kmsKSElement]bool),
+	})
+	log.Printf("server listening at %v", lis.Addr())
+	if err := s.Serve(lis); err != nil {
+		log.Fatalf("failed to serve: %v", err)
+	}
+}
diff --git a/kms/kmsintercom.go b/kms/kmsintercom.go
new file mode 100644
index 0000000000000000000000000000000000000000..d9ab896d9f407ea843e9570c952e286b5e9bcd8b
--- /dev/null
+++ b/kms/kmsintercom.go
@@ -0,0 +1,46 @@
+package kms
+
+import (
+	"context"
+	"flag"
+	"fmt"
+	"log"
+	"net"
+
+	pb "code.fbi.h-da.de/danet/proto-kms/api/gen/proto/go/kmsintercom"
+	"google.golang.org/grpc"
+)
+
+type kmsTalkerServer struct {
+	pb.UnimplementedKmsTalkerServer
+}
+
+func (s *kmsTalkerServer) InterComCapabilities(ctx context.Context, in *pb.InterComCapabilitiesRequest) (capReply *pb.InterComCapabilitiesReply, err error) {
+	log.Printf("Received: %v", in.GetMyKmsName())
+
+	return &pb.InterComCapabilitiesReply{
+		PeerKmsName: "whatever",
+	}, nil
+}
+
+func (s *kmsTalkerServer) InterComKeyTransportSessionHandling(ctx context.Context, in *pb.InterComKeyTransportSessionHandlingRequest) (*pb.InterComKeyTransportSessionHandlingReply, error) {
+
+	return &pb.InterComKeyTransportSessionHandlingReply{
+		UsedKey: "whatever",
+	}, nil
+}
+
+func StartInterComm(interComPort int) {
+	flag.Parse()
+
+	lis, err := net.Listen("tcp", fmt.Sprintf(":%d", interComPort))
+	if err != nil {
+		log.Fatalf("failed to listen: %v", err)
+	}
+	s := grpc.NewServer()
+	pb.RegisterKmsTalkerServer(s, &kmsTalkerServer{})
+	log.Printf("server listening at %v", lis.Addr())
+	if err := s.Serve(lis); err != nil {
+		log.Fatalf("failed to serve: %v", err)
+	}
+}
diff --git a/kms/kmspeers.go b/kms/kmspeers.go
new file mode 100644
index 0000000000000000000000000000000000000000..9b938306ee4318b18d067cb39b2ebc1bf61ca38b
--- /dev/null
+++ b/kms/kmspeers.go
@@ -0,0 +1,173 @@
+package kms
+
+import (
+	"context"
+	"encoding/base64"
+	"fmt"
+	"log"
+	"net"
+	"os/exec"
+	"time"
+
+	pb "code.fbi.h-da.de/danet/proto-kms/api/gen/proto/go/kmsetsi"
+	"github.com/google/uuid"
+	"google.golang.org/grpc"
+	"google.golang.org/grpc/credentials/insecure"
+)
+
+type KmsPeerStatus int16
+
+const (
+	KmsPeerUp      KmsPeerStatus = iota // peer was seen up lately
+	KmsPeerDown                         // peer not reachable anymore
+	KmsPeerPending                      // peer was added and has to be succesfully contacted once
+	KmsPeerUnknown                      // not known, not initialized
+)
+
+type kmsPeerInfo interface {
+	GetKmsPeerStatus() KmsPeerStatus
+	GetKmsPeerId() uuid.UUID
+	GetKmsPeerQkdiId() uint32
+}
+
+type kmsPeer struct {
+	externalNotifierKMSPeer chan string
+	peerStatus              KmsPeerStatus
+	servingQLE              *QuantumElement
+	tcpSocket               net.TCPAddr // the IP address and TCP port (aka socket) of the kms peer
+	tcpSocketStr            string      // string rep. of tcpSocket
+	name                    string      // the name of the kms peer
+	id                      uuid.UUID   // uuid of the peer
+	quit                    chan bool   // cancel the peer goroutine
+}
+
+func NewKmsPeer(servQLE *QuantumElement, in chan string) (peer kmsPeer) {
+	return kmsPeer{
+		peerStatus:              KmsPeerUnknown,
+		servingQLE:              servQLE,
+		id:                      uuid.New(),
+		externalNotifierKMSPeer: in,
+		quit:                    make(chan bool),
+	}
+}
+
+// Handles everything with respect to a specific KMS peer
+func (ph *kmsPeer) PeerHandler(kmsName string) {
+	log.Printf("%s started PeerHandler for %s:", kmsName, ph.tcpSocketStr)
+
+	// contact peer
+	newPeerConn, err := grpc.Dial(ph.tcpSocketStr, grpc.WithTransportCredentials(insecure.NewCredentials()))
+	if err != nil {
+		log.Printf("did not connect: %v", err)
+		ph.peerStatus = KmsPeerDown
+		return
+	}
+	defer newPeerConn.Close()
+
+	c := pb.NewKmsETSIClient(newPeerConn)
+
+	// Contact the server and print out its response.
+	ctx, cancel := context.WithTimeout(context.Background(), time.Second)
+	defer cancel()
+	r, err := c.ETSICapabilities(ctx, &pb.ETSICapabilitiesRequest{MyKmsName: kmsName})
+	if err != nil {
+		log.Printf("could not greet: %v", err)
+		ph.peerStatus = KmsPeerDown
+		// Send notification about change
+		if ph.externalNotifierKMSPeer != nil {
+			ph.externalNotifierKMSPeer <- ph.tcpSocketStr
+		}
+	}
+
+	// NOTE: If a session is created, we also request a encryption key for now
+	//quantumElementRequest, err := c.ETSIGetQuantumInterfaces(ctx, &pb.ETSIKMSQuantumInterfaceListRequest{})
+	//if err != nil {
+	//	log.Println("Could not request quantum elements: ", err)
+	//	ph.peerStatus = KmsPeerDown
+	//	// Send notification about change
+	//	if ph.externalNotifierKMSPeer != nil {
+	//		ph.externalNotifierKMSPeer <- ph.tcpSocketStr
+	//	}
+	//	return
+	//}
+
+	//if quantumElementRequest.QlElementInfo != nil {
+	//	peerQuantumElement := quantumElementRequest.QlElementInfo[0].QleID
+	//} else {
+	//	// return error?!
+	//}
+
+	// Works and peer moves to kmsPeerUp
+	ph.peerStatus = KmsPeerUp
+
+	encryptKeyRequest, err := c.ETSIGetEncryptKeys256Bit(ctx, &pb.ETSIGetEncryptKeys256BitRequest{Amount: 1})
+	if err != nil {
+		log.Println("could not request a encryption key: ", err)
+		ph.peerStatus = KmsPeerDown
+		// Send notification about change
+		if ph.externalNotifierKMSPeer != nil {
+			ph.externalNotifierKMSPeer <- ph.tcpSocketStr
+		}
+		return
+	}
+
+	// check if key is in remoteKeyStore
+	if key, ok := ph.servingQLE.keyStoreRemote.keyStore[encryptKeyRequest.KeyID]; ok {
+		keyAsString := base64.StdEncoding.EncodeToString(key.key)
+		log.Printf("Agreed Key: %s", keyAsString)
+
+		// push the key to the encryptor via ssh
+		ssh := "ssh"
+		complexArg := fmt.Sprintf("(rc=$(sed \"12 c PresharedKey = %s\" /etc/wireguard/wg0.conf); echo \"$rc\" > /etc/wireguard/wg0.conf)", keyAsString)
+		args := []string{"root@172.20.0.4", "-oStrictHostKeyChecking=no", complexArg}
+
+		cmd := exec.Command(ssh, args...)
+		err := cmd.Run()
+		if err != nil {
+			log.Println("could not execute command")
+			return
+		}
+	}
+
+	// Send notification about change
+	if ph.externalNotifierKMSPeer != nil {
+		ph.externalNotifierKMSPeer <- ph.tcpSocketStr
+	}
+
+	log.Printf("Greeting: %s which is now in peerStatus %d", r.GetPeerKmsName(), ph.peerStatus)
+
+	// NOTE: should be possible to cancel!
+	// By now, do check only the liveliness of the peer, nothing else.
+	//for {
+	//	select {
+	//	case <-ph.quit:
+	//		return
+	//	default:
+	//		// Contact the server and print out its response.
+	//		ctx, cancel := context.WithTimeout(context.Background(), time.Second)
+	//		defer cancel()
+	//		_, err := c.ETSICapabilities(ctx, &pb.ETSICapabilitiesRequest{MyKmsName: kmsName})
+	//		if err != nil {
+	//			log.Printf("could not greet: %v", err)
+	//			ph.peerStatus = KmsPeerDown
+	//			// Send notification about change
+	//			if ph.externalNotifierKMSPeer != nil {
+	//				ph.externalNotifierKMSPeer <- ph.tcpSocketStr
+	//			}
+	//		}
+	//		time.Sleep(30 * time.Second)
+	//	}
+	//}
+}
+
+func (ph *kmsPeer) GetKmsPeerStatus() KmsPeerStatus {
+	return ph.peerStatus
+}
+
+func (ph *kmsPeer) GetKmsPeerId() uuid.UUID {
+	return ph.id
+}
+
+func (ph *kmsPeer) GetKmsPeerQkdiId() uint32 {
+	return uint32(ph.servingQLE.QlID)
+}
diff --git a/kms/util.go b/kms/util.go
new file mode 100644
index 0000000000000000000000000000000000000000..b9b5c35056b54c27409fb6a35aa35ad51f58560e
--- /dev/null
+++ b/kms/util.go
@@ -0,0 +1,16 @@
+package kms
+
+import "fmt"
+
+// Ewww... don't
+func randomItemFromMap[T, M comparable](m map[T]M, v map[M]bool) (M, error) {
+	for _, item := range m {
+		if v[item] {
+			continue
+		}
+		return item, nil
+	}
+
+	var r M
+	return r, fmt.Errorf("Could not return a random item from map %v", m)
+}
diff --git a/main.go b/main_test.go
similarity index 60%
rename from main.go
rename to main_test.go
index bad82803d0c00f5a15b8b7de415da26b36f14d43..df2c4abef5e37c036dc1c0fb63d77d9b3f1eb325 100644
--- a/main.go
+++ b/main_test.go
@@ -1,15 +1,22 @@
 package main
 
+// go generate protoc --proto_path=kmsintercomproto --go_out=kmsintercomproto --go_opt=paths=source_relative --go-grpc_out=kmsintercomproto --go-grpc_opt=paths=source_relative  kmsintercom.proto
+// go generate protoc --proto_path=kmsetsiproto  --go_out=kmsetsiproto --go_opt=paths=source_relative --go-grpc_out=kmsetsiproto --go-grpc_opt=paths=source_relative  kmsetsiproto.proto
+
 import (
 	"flag"
 	"log"
 	"net"
+	"testing"
+	"time"
 
-	"code.fbi.h-da.de/m.stiemerling/proto-kms/kms"
+	"code.fbi.h-da.de/danet/proto-kms/kms"
 	"github.com/google/uuid"
 )
 
-func main() {
+//func main() {
+
+func TestMain(m *testing.M) {
 	// run a self-test if set to yes
 	var selfTesting bool
 	// my own Name
@@ -22,7 +29,7 @@ func main() {
 	// quantumlayer so generated keys can be fetched. This is mainly to simplify
 	// the initial setup process.
 
-	flag.BoolVar(&selfTesting, "selfTesting", true,
+	flag.BoolVar(&selfTesting, "selftesting", true,
 		"Will perform self-testing with second quantum link if set to true")
 
 	flag.StringVar(&udpQL1AddrString, "my-address", "[::1]:50900",
@@ -43,10 +50,12 @@ func main() {
 	log.Println("Welcome to the proto-kms called: ", ql1Name)
 
 	if selfTesting == true {
+		log.Printf("%s in self-testing mode", ql1Name)
 		go emulatedKMS(ql2Name, udpQL2AddrString, udpQL1AddrString)
 		emulatedKMS(ql1Name, udpQL1AddrString, udpQL2AddrString)
 	} else {
-		emulatedKMS(ql1Name, udpQL1AddrString, "")
+		log.Printf("%s in regular operations mode", ql1Name)
+		emulatedKMS(ql1Name, udpQL1AddrString, udpQL2AddrString)
 	}
 
 	return
@@ -54,10 +63,10 @@ func main() {
 
 func emulatedKMS(myName string, myUDPAddr string, peerUDPAddr string) {
 	// Attach to eKMS
-	emuKMS := kms.NeweKMS()
+	emuKMS := kms.NewEKMS(myName, uuid.New())
 
 	// Fire up Quantum LinK
-	myQL := emuKMS.AddQuantumElement(myName, uuid.New(), myUDPAddr)
+	myQL := emuKMS.AddQuantumElement(myUDPAddr)
 
 	udpQL2Addr, err := net.ResolveUDPAddr("udp", peerUDPAddr)
 	if err != nil {
@@ -65,18 +74,11 @@ func emulatedKMS(myName string, myUDPAddr string, peerUDPAddr string) {
 		return
 	}
 
-	myQL.QlElement.AddPeer(*udpQL2Addr)
+	myQL.QuantumElementLink.AddPeer(udpQL2Addr)
 
-	for {
-		resultQLLocal, err := myQL.QlElement.GetKeyBatchLocal()
-		if err == nil {
-			log.Printf("Current key IDs are for %s local %d:", myName, resultQLLocal.BulkKeyId)
+	// Start the SDN/management and key retrieval interface
+	go kms.StartETSI(peerUDPAddr, emuKMS)
 
-		}
-		resultQLRemote, err := myQL.QlElement.GetKeyBatchPeer()
-		if err == nil {
-			log.Printf("Current key IDs are for remote %d:", resultQLRemote.BulkKeyId)
-
-		}
-	}
+	// TODO/XXX catch errors!
+	emuKMS.GlobalKeyHandler(7 * time.Second)
 }
diff --git a/quantumlayer/quantumlayer-emu-prng.go b/quantumlayer/quantumlayer-emu-prng.go
index a074502454d58e05e618a6f73730734677fa9d4c..d6c0cc00cea2b79bd05ca59a0cc2b2345f457523 100644
--- a/quantumlayer/quantumlayer-emu-prng.go
+++ b/quantumlayer/quantumlayer-emu-prng.go
@@ -29,11 +29,13 @@ type QuantumPayloadElement struct {
 }
 
 type QuantumlayerEmuPRNG struct {
+	configured       bool
 	poweron          bool
 	incomingRandNums chan QuantumPayloadElement
 	outgoingRandNums chan QuantumPayloadElement
 	peerNumbers      *NumberStore
 	myNumbers        *NumberStore
+	localQLAddress   string
 	udpSrvConn       *net.UDPConn
 	qlPeer           string
 	qlPeerCancel     context.CancelFunc
@@ -43,6 +45,7 @@ type QuantumlayerEmuPRNG struct {
 
 func NewQuantumlayerEmuPRNG() (newql *QuantumlayerEmuPRNG) {
 	return &QuantumlayerEmuPRNG{
+		configured:       false,
 		poweron:          false,
 		incomingRandNums: make(chan QuantumPayloadElement),
 		outgoingRandNums: make(chan QuantumPayloadElement),
@@ -52,81 +55,94 @@ func NewQuantumlayerEmuPRNG() (newql *QuantumlayerEmuPRNG) {
 	}
 }
 
-// Power on the quantum layer, i.e., open up the communication ports for the
-// other quantum module
-func (qlemuprng *QuantumlayerEmuPRNG) PowerOn(localQLAddress ...string) {
-	qlemuprng.poweron = false
-	log.Println("QuantumlayerEmuPRNG is powering on...charging.")
+// Configure the quantum emulation, but do not start if yet
+func (qlemuprng *QuantumlayerEmuPRNG) Configure(localQLAddress ...string) {
 
 	// Start receiving numberstores
 	go qlemuprng.peerNumbers.receiveNumbers(qlemuprng.incomingRandNums)
 	go qlemuprng.myNumbers.receiveNumbers(qlemuprng.outgoingRandNums)
 
-	// serve UDP incoming
-	go func() {
-		// Get UDP server part going...
-		// Determine if a local UDP address should be used or not
-		var udpAddrString string
-		if len(localQLAddress) == 0 {
-			// No input
-			udpAddrString = ":0"
-		} else {
-			udpAddrString = localQLAddress[0]
-		}
-		log.Printf("localQLAddress is %s", localQLAddress[0])
-
-		// This reads random numbers from other Quantum end
-		udpSrvPort, err := net.ResolveUDPAddr("udp", udpAddrString)
-		if err != nil {
-			log.Fatalf("QuantumlayerEmuPRNG UDP failure: %s", err)
-			return
-		}
+	// Determine if a local UDP address should be used or not
+	if len(localQLAddress) == 0 {
+		// No input
+		qlemuprng.localQLAddress = ":0"
+	} else {
+		qlemuprng.localQLAddress = localQLAddress[0]
+	}
+	qlemuprng.configured = true
+}
 
-		qlemuprng.udpSrvConn, err = net.ListenUDP("udp", udpSrvPort)
-		if err != nil {
-			log.Fatalf("QuantumlayerEmuPRNG UDP failure: %s", err)
-			return
-		}
-		defer qlemuprng.udpSrvConn.Close()
+// Power on the quantum layer, i.e., open up the communication ports for the
+// other quantum module
+func (qlemuprng *QuantumlayerEmuPRNG) PowerOn() {
+	if qlemuprng.configured == false {
+		// nothing do here move on
+		log.Printf("Sorry, the quantum layer is not configured for action. You've missed Configure()")
+		return
+	}
+	//qlemuprng.poweron = false
+	log.Println("QuantumlayerEmuPRNG is powering on...charging.")
 
-		// Retrieve local UDP address and store it for further actions.
-		qlemuprng.qlLocalPort = qlemuprng.udpSrvConn.LocalAddr().(*net.UDPAddr)
+	// serve UDP incoming
+	if qlemuprng.udpSrvConn == nil {
+		go func() {
+			// Get UDP server part going...
+			log.Printf("localQLAddress is %s", qlemuprng.localQLAddress)
 
-		// Ready, set, go!
-		qlemuprng.poweron = true
+			// This reads random numbers from other Quantum end
+			udpSrvPort, err := net.ResolveUDPAddr("udp", qlemuprng.localQLAddress)
+			if err != nil {
+				log.Fatalf("QuantumlayerEmuPRNG UDP failure: %s", err)
+				return
+			}
 
-		log.Printf("QuantumlayerEmuPRNG: started server, waiting for incoming rands on port %s \n", qlemuprng.udpSrvConn.LocalAddr().(*net.UDPAddr).String())
-		inBuffer := make([]byte, 1500)
-		for {
-			// Buffer for reading from "Quantum link"
-			n, addr, err := qlemuprng.udpSrvConn.ReadFromUDP(inBuffer)
+			qlemuprng.udpSrvConn, err = net.ListenUDP("udp", udpSrvPort)
 			if err != nil {
-				log.Printf("QuantumlayerEmuPRNG: Could not read from UDP: %s", err)
-			} else {
-				log.Printf("QuantumlayerEmuPRNG: read %d bytes from %s\n", n, addr)
-
-				// Check if sender of datagram is qlPeer
-				// Warning this is not checking the validity of the sender, i.e., spoofing is possible
-				if addr.String() == qlemuprng.qlPeer {
-					log.Printf("QuantumlayerEmuPRNG: Peer %s listed", addr)
-					//dumb the received data into the channel and carry on
-					// TODO/XXX: no vetting for anything
-					// Unmarshall out of JSON
-					var inQBuffer QuantumPayloadElement
-					unmarshallErr := json.Unmarshal(inBuffer[0:n], &inQBuffer)
-					if unmarshallErr == nil {
-						qlemuprng.incomingRandNums <- inQBuffer
-					}
+				log.Fatalf("QuantumlayerEmuPRNG UDP failure: %s", err)
+				return
+			}
+			defer qlemuprng.udpSrvConn.Close()
+
+			// Retrieve local UDP address and store it for further actions.
+			qlemuprng.qlLocalPort = qlemuprng.udpSrvConn.LocalAddr().(*net.UDPAddr)
+
+			log.Printf("QuantumlayerEmuPRNG: started server, waiting for incoming rands on port %s \n", qlemuprng.udpSrvConn.LocalAddr().(*net.UDPAddr).String())
+			inBuffer := make([]byte, 1500)
+			for {
+				// Buffer for reading from "Quantum link"
+				n, addr, err := qlemuprng.udpSrvConn.ReadFromUDP(inBuffer)
+				if err != nil {
+					log.Printf("QuantumlayerEmuPRNG: Could not read from UDP: %s", err)
 				} else {
-					log.Printf("QuantumlayerEmuPRNG: Peer %s NOT listed", addr)
+					log.Printf("QuantumlayerEmuPRNG: read %d bytes from %s\n", n, addr)
+
+					// Check if sender of datagram is qlPeer
+					// Warning this is not checking the validity of the sender, i.e., spoofing is possible
+					if addr.String() == qlemuprng.qlPeer {
+						log.Printf("QuantumlayerEmuPRNG: Peer %s listed", addr)
+						//dumb the received data into the channel and carry on
+						// TODO/XXX: no vetting for anything
+						// Unmarshall out of JSON
+						var inQBuffer QuantumPayloadElement
+						unmarshallErr := json.Unmarshal(inBuffer[0:n], &inQBuffer)
+						if unmarshallErr == nil {
+							qlemuprng.incomingRandNums <- inQBuffer
+						}
+					} else {
+						log.Printf("QuantumlayerEmuPRNG: Peer %s NOT listed", addr)
+					}
 				}
 			}
-		}
-	}()
+		}()
+	}
 
 	// Wait for listening UDP socket in the above go-routine to get ready
-	for qlemuprng.poweron != true {
+	for qlemuprng.udpSrvConn == nil {
 	}
+
+	// Ready, set, go!
+	qlemuprng.poweron = true
+
 	log.Println("QuantumlayerEmuPRNG is charged and powered on.")
 }
 
@@ -137,7 +153,7 @@ func (qlemuprng *QuantumlayerEmuPRNG) PowerOff() {
 	log.Println("QuantumlayerEmuPRNG is powered off...discharging.")
 }
 
-func (qlemuprng *QuantumlayerEmuPRNG) AddPeer(addr net.UDPAddr) {
+func (qlemuprng *QuantumlayerEmuPRNG) AddPeer(addr *net.UDPAddr) {
 	if qlemuprng.poweron == false {
 		return
 	}
@@ -158,23 +174,25 @@ func (qlemuprng *QuantumlayerEmuPRNG) AddPeer(addr net.UDPAddr) {
 			case <-ctx.Done():
 				return
 			default:
-				// retrieve a new back of random numbers
-				newNumberBatch := qlemuprng.GenerateRandomNumbers()
-				// TODO: Replace this by some generic encapsulation reader and not just JSON
-				//Get JSON for transmission ready
-				qpe := QuantumPayloadElement{time.Now().UnixNano(), len(newNumberBatch), &newNumberBatch}
-
-				// XXX/TODO: error must be handled
-				jsonPayload, err := json.Marshal(qpe)
-				if err != nil {
-					log.Printf("json.Marshal error %s", err)
-				}
+				if qlemuprng.poweron == true {
+					// retrieve a new back of random numbers
+					newNumberBatch := qlemuprng.GenerateRandomNumbers()
+					// TODO: Replace this by some generic encapsulation reader and not just JSON
+					//Get JSON for transmission ready
+					qpe := QuantumPayloadElement{time.Now().UnixNano(), len(newNumberBatch), &newNumberBatch}
+
+					// XXX/TODO: error must be handled
+					jsonPayload, err := json.Marshal(qpe)
+					if err != nil {
+						log.Printf("json.Marshal error %s", err)
+					}
 
-				_, _, err = qlemuprng.udpSrvConn.WriteMsgUDPAddrPort(jsonPayload, nil, addr.AddrPort())
-				if err != nil {
-					log.Fatalf("WriteMsgUDPAddrPort failed: %s", err)
+					_, _, err = qlemuprng.udpSrvConn.WriteMsgUDP(jsonPayload, nil, addr)
+					if err != nil {
+						log.Fatalf("WriteMsgUDPAddrPort failed: %s", err)
+					}
+					qlemuprng.outgoingRandNums <- qpe
 				}
-				qlemuprng.outgoingRandNums <- qpe
 				time.Sleep(5 * time.Second)
 			}
 		}
@@ -223,6 +241,10 @@ func (qlemuprng *QuantumlayerEmuPRNG) GetKeyBatchLocal() (QuantumLayerBulkKey, e
 	return qlemuprng.myNumbers.GetBulk()
 }
 
+func (qlemuprng *QuantumlayerEmuPRNG) GetStatus() (poweredOn bool) {
+	return qlemuprng.poweron
+}
+
 type NumberStore struct {
 	mu             sync.Mutex
 	maxBytes       int
diff --git a/quantumlayer/quantumlayer-emu-prng_test.go b/quantumlayer/quantumlayer-emu-prng_test.go
index 69d30b582e35da3b1ebd99fca9a1ba38eb78a3a4..502377abd7c2564449749ebe78f38bbe611ceba7 100644
--- a/quantumlayer/quantumlayer-emu-prng_test.go
+++ b/quantumlayer/quantumlayer-emu-prng_test.go
@@ -35,8 +35,8 @@ func TestQuantumLayer(t *testing.T) {
 		return
 	}
 
-	ql1.AddPeer(*udpQL2Addr)
-	ql2.AddPeer(*udpQL1Addr)
+	ql1.AddPeer(udpQL2Addr)
+	ql2.AddPeer(udpQL1Addr)
 
 	for n := 0; n < 2; n++ {
 		resultQl1, err := ql1.GetKeyBatchPeer()
@@ -59,5 +59,4 @@ func TestQuantumLayer(t *testing.T) {
 		time.Sleep(5 * time.Second)
 
 	}
-
 }
diff --git a/quantumlayer/quantumlayer.go b/quantumlayer/quantumlayer.go
index 603027867ccebb915f712cc3a36071a9ac15a887..fc31056d9ffb37684e59ce2365bbb92c287f1ca4 100644
--- a/quantumlayer/quantumlayer.go
+++ b/quantumlayer/quantumlayer.go
@@ -11,8 +11,10 @@ type QuantumLayerBulkKey struct {
 }
 
 type QuantumLayer interface {
-	PowerOn(...string)                              // switch on the quantum layer element
+	Configure(...string)                            // configure the interface, e.g., used IP/Port config if emulated
+	PowerOn()                                       // switch on the quantum layer element
 	PowerOff()                                      // switch off the quantum layer element
+	GetStatus() (poweredOn bool)                    // returns true if quantum layer element is powered on
 	AddPeer()                                       // Adds a Quantum Layer Peer to the peer list
 	RemovePeer()                                    // Remmoves a Quantum Layer Peer to the peer list
 	GetLocalQLPort()                                // Returns the information about the local quantum layer IP and port