Skip to content
Snippets Groups Projects
Commit c30f9da5 authored by Malte Bauch's avatar Malte Bauch
Browse files

Initial refactoring of quantum elements to quantum modules

parent beba7ee1
Branches
Tags
1 merge request!1Move proto kms into ekms
......@@ -27,7 +27,7 @@ type QuantumElementInfo struct {
unknownFields protoimpl.UnknownFields
Timestamp int64 `protobuf:"varint,1,opt,name=timestamp,proto3" json:"timestamp,omitempty"`
QleID uint64 `protobuf:"varint,2,opt,name=qleID,proto3" json:"qleID,omitempty"`
QleID string `protobuf:"bytes,2,opt,name=qleID,proto3" json:"qleID,omitempty"`
UdpAddr string `protobuf:"bytes,3,opt,name=udpAddr,proto3" json:"udpAddr,omitempty"`
}
......@@ -70,11 +70,11 @@ func (x *QuantumElementInfo) GetTimestamp() int64 {
return 0
}
func (x *QuantumElementInfo) GetQleID() uint64 {
func (x *QuantumElementInfo) GetQleID() string {
if x != nil {
return x.QleID
}
return 0
return ""
}
func (x *QuantumElementInfo) GetUdpAddr() string {
......@@ -305,7 +305,7 @@ type ETSIKMSPeerRequest struct {
Timestamp int64 `protobuf:"varint,1,opt,name=timestamp,proto3" json:"timestamp,omitempty"`
KmsPeerSocket string `protobuf:"bytes,2,opt,name=kmsPeerSocket,proto3" json:"kmsPeerSocket,omitempty"`
KmsLocalQLEId uint32 `protobuf:"varint,3,opt,name=kmsLocalQLEId,proto3" json:"kmsLocalQLEId,omitempty"`
KmsLocalQLEId string `protobuf:"bytes,3,opt,name=kmsLocalQLEId,proto3" json:"kmsLocalQLEId,omitempty"`
}
func (x *ETSIKMSPeerRequest) Reset() {
......@@ -354,11 +354,11 @@ func (x *ETSIKMSPeerRequest) GetKmsPeerSocket() string {
return ""
}
func (x *ETSIKMSPeerRequest) GetKmsLocalQLEId() uint32 {
func (x *ETSIKMSPeerRequest) GetKmsLocalQLEId() string {
if x != nil {
return x.KmsLocalQLEId
}
return 0
return ""
}
type ETSIKMSPeerReply struct {
......@@ -912,7 +912,7 @@ var file_kmsetsi_kmsetsiproto_proto_rawDesc = []byte{
0x45, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x1c, 0x0a, 0x09, 0x74,
0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09,
0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x14, 0x0a, 0x05, 0x71, 0x6c, 0x65,
0x49, 0x44, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x71, 0x6c, 0x65, 0x49, 0x44, 0x12,
0x49, 0x44, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x71, 0x6c, 0x65, 0x49, 0x44, 0x12,
0x18, 0x0a, 0x07, 0x75, 0x64, 0x70, 0x41, 0x64, 0x64, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09,
0x52, 0x07, 0x75, 0x64, 0x70, 0x41, 0x64, 0x64, 0x72, 0x22, 0x55, 0x0a, 0x17, 0x45, 0x54, 0x53,
0x49, 0x43, 0x61, 0x70, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x69, 0x65, 0x73, 0x52, 0x65, 0x71,
......@@ -945,7 +945,7 @@ var file_kmsetsi_kmsetsiproto_proto_rawDesc = []byte{
0x65, 0x72, 0x53, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x18, 0x02, 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, 0x03,
0x20, 0x01, 0x28, 0x0d, 0x52, 0x0d, 0x6b, 0x6d, 0x73, 0x4c, 0x6f, 0x63, 0x61, 0x6c, 0x51, 0x4c,
0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x6b, 0x6d, 0x73, 0x4c, 0x6f, 0x63, 0x61, 0x6c, 0x51, 0x4c,
0x45, 0x49, 0x64, 0x22, 0x52, 0x0a, 0x10, 0x45, 0x54, 0x53, 0x49, 0x4b, 0x4d, 0x53, 0x50, 0x65,
0x65, 0x72, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73,
0x74, 0x61, 0x6d, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65,
......
......@@ -18,7 +18,7 @@ service KmsETSI{
// NB for myself: this be used to link QLE mit KMS-Session!
message QuantumElementInfo {
int64 timestamp = 1;
uint64 qleID = 2;
string qleID = 2;
string udpAddr = 3;
}
......@@ -46,7 +46,7 @@ message ETSIKMSQuantumInterfaceListReply {
message ETSIKMSPeerRequest {
int64 timestamp = 1;
string kmsPeerSocket = 2;
uint32 kmsLocalQLEId = 3;
string kmsLocalQLEId = 3;
}
message ETSIKMSPeerReply {
......
grpcurl -d '{"pathId" : "f6a575e5-c7f9-4765-8890-134ae5b8f451", "nextHop" : "", "prevHop" : "[::1]:50932"}' --import-path ../api/kmsetsi/kmsetsi --proto kmsetsiproto.proto --plaintext [::1]:50901 kmsetsi.KmsETSI.ETSIAssignForwarding
grpcurl -d '{"pathId" : "f6a575e5-c7f9-4765-8890-134ae5b8f451", "nextHop" : "[::1]:50931", "prevHop": "[::1]:50930"}' --import-path ../api/kmsetsi//kmsetsi --proto kmsetsiproto.proto --plaintext [::1]:50902 kmsetsi.KmsETSI.ETSIAssignForwarding
grpcurl -d '{"pathId" : "f6a575e5-c7f9-4765-8890-134ae5b8f451", "nextHop" : "[::1]:50932"}' --import-path ../api/kmsetsi//kmsetsi --proto kmsetsiproto.proto --plaintext [::1]:50900 kmsetsi.KmsETSI.ETSIAssignForwarding
grpcurl -d '{"pathId" : "f6a575e5-c7f9-4765-8890-134ae5b8f451", "nextHop" : "[::1]:50931", "prevHop": "[::1]:50930"}' --import-path ../api/kmsetsi/kmsetsi --proto kmsetsiproto.proto --plaintext [::1]:50902 kmsetsi.KmsETSI.ETSIAssignForwarding
grpcurl -d '{"pathId" : "f6a575e5-c7f9-4765-8890-134ae5b8f451", "nextHop" : "[::1]:50932"}' --import-path ../api/kmsetsi/kmsetsi --proto kmsetsiproto.proto --plaintext [::1]:50900 kmsetsi.KmsETSI.ETSIAssignForwarding
package kms
import (
"errors"
"fmt"
"sync"
......@@ -32,19 +31,18 @@ type kmsKSElement struct {
}
type kmsKeyStore struct {
keyStoreMutex sync.Mutex
underlyingBulkId int64
keyStore map[uint64]*kmsKSElement
keySingleSize uint // the size of a single key, given as unit of bits
indexCounter uint64
keyStoreMutex sync.Mutex
keyStore map[uint64]*kmsKSElement
keySingleSize uint // the size of a single key, given as unit of bits
indexCounter uint64
}
func NewKmsKeyStore(desiredkeySingleSizeLength uint) *kmsKeyStore {
return &kmsKeyStore{
underlyingBulkId: 0,
keyStore: make(map[uint64]*kmsKSElement),
keySingleSize: desiredkeySingleSizeLength,
indexCounter: 0,
// NOTE: could be useful to use something like a ordered map here
keyStore: make(map[uint64]*kmsKSElement),
keySingleSize: desiredkeySingleSizeLength,
indexCounter: 0,
}
}
......@@ -54,7 +52,7 @@ func (ks *kmsKeyStore) addKey(keyId uint64, keyToadd []byte) {
// test for collisions
if _, notThere := ks.keyStore[keyId]; notThere {
log.Errorf("Whop: addKey collission of key id %s for bulkKeyID %d", keyId, ks.underlyingBulkId)
log.Errorf("Whop: addKey collission of key id %s", keyId)
return
}
......@@ -86,37 +84,27 @@ func (ks *kmsKeyStore) GetKey() (*kmsKSElement, error) {
return nil, fmt.Errorf("Key with index: %d is already reserved.", ks.indexCounter)
}
// Takes a bulk of keys and chops them in chopFactor keys each
// Any remainder is discarded
func (ks *kmsKeyStore) KeyChopper(bulkKey *quantumlayer.QuantumLayerBulkKey) (err error) {
if ks.keySingleSize == 0 {
err = errors.New("KeyChopper: no keySingleSize set")
return err
}
// TODO check if multiple of 8 (1 Byte)
func (ks *kmsKeyStore) GetKeyWithID(id uint64) (*kmsKSElement, error) {
ks.keyStoreMutex.Lock()
defer ks.keyStoreMutex.Unlock()
if bulkKey.BulkKeyLength != len(*bulkKey.BulkKey) {
err = errors.New("bulkKey length mismatch")
return err
key, ok := ks.keyStore[id]
if !ok {
return nil, fmt.Errorf("Could not find a key for id: %d", ks.indexCounter)
}
if key.status == AVAILABLE {
// change status of key to reserved
key.status = RESERVED
// increase index counter
ks.indexCounter = ks.indexCounter + 1
// Store underlying bulkID
ks.underlyingBulkId = bulkKey.BulkKeyId
// reset indexCounter
ks.indexCounter = 0
var keyId uint64
keyId = 0
// Let's chop!
chopFactor := ks.keySingleSize >> 3
key := *bulkKey.BulkKey
for len(key) > int(chopFactor) {
tmpkey := key[:chopFactor]
ks.addKey(keyId, tmpkey)
keyId++
// shorten the key storage
key = key[chopFactor:]
return key, nil
}
return nil
return nil, fmt.Errorf("Key with index: %d is already reserved.", ks.indexCounter)
}
func (ks *kmsKeyStore) DeleteKey(keyId uint64) {
ks.keyStoreMutex.Lock()
delete(ks.keyStore, keyId)
ks.keyStoreMutex.Unlock()
}
......@@ -5,31 +5,27 @@
package kms
import (
"crypto/rand"
"encoding/binary"
"fmt"
"io"
"sync"
"time"
log "github.com/sirupsen/logrus"
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 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() *EmulatedQuantumModule
// GlobalKeyHandler(time.Duration) error
// AddPeer(kmsPeerSocket string, servingQLE *EmulatedQuantumModule)
// RemovePeer(kmsPeerSocket string)
// FindPeerUuid(uuid.UUID) *kmsPeer
//}
type Route struct {
Previous *kmsPeer
......@@ -50,7 +46,8 @@ type EKMS struct {
kmsUUID uuid.UUID
interComAddr string
qleMapMutex sync.Mutex
QuantumElements map[uint32]*QuantumElement
quantumModules map[uuid.UUID]QuantumModule
quantumModulesMutex sync.RWMutex
externalNotifierQLE chan uint32
kmsPeersMutex sync.Mutex
// TODO(maba): find a better name for this
......@@ -71,15 +68,6 @@ type QuantumElementInterface interface {
GetQlID() qlElementId
}*/
type QuantumElement struct {
QlID uint32
QuantumElementLink *quantumlayer.QuantumlayerEmuPRNG // contains information about the quantum links
//key stores of unchopped bulk keys go here
rawBulkKeysMutex sync.Mutex
rawBulkKeys map[int64]*quantumlayer.QuantumLayerBulkKey
keyStorePeer *kmsKeyStore // the keys used between two peers.
}
func NewEKMS(kmsName string, kmsUUID uuid.UUID, logOutput io.Writer, logLevel log.Level, logInJson bool, interComAddr string) (newEKMS *EKMS) {
/*
* Setup logging
......@@ -105,7 +93,7 @@ func NewEKMS(kmsName string, kmsUUID uuid.UUID, logOutput io.Writer, logLevel lo
kmsName: kmsName,
kmsUUID: kmsUUID,
interComAddr: interComAddr,
QuantumElements: make(map[uint32]*QuantumElement),
quantumModules: make(map[uuid.UUID]QuantumModule),
routingTable: make(map[uuid.UUID]*Route),
KmsPeers: make(map[string]*kmsPeer),
externalNotifierQLE: nil, // just be surely set to nil!
......@@ -121,86 +109,14 @@ func NewEKMS(kmsName string, kmsUUID uuid.UUID, logOutput io.Writer, logLevel lo
return createdEKMS
}
func (kms *EKMS) AddQuantumElement(kmsUDPAddrr string, generateKeys bool, logOutput io.Writer, logLevel log.Level, logInJson bool) *QuantumElement {
//Get an emulated Quantumlayer
ql := quantumlayer.NewQuantumlayerEmuPRNG(logOutput, logLevel, logInJson)
ql.Configure(kmsUDPAddrr)
ql.PowerOn(generateKeys)
qle := QuantumElement{
QuantumElementLink: ql,
rawBulkKeys: make(map[int64]*quantumlayer.QuantumLayerBulkKey),
// keyStorePeer: not set, will be set later on, if key size is negotiated.
}
// generate a ID for this quantum element that is unique locally
var randError error
qle.QlID, randError = kms.GenerateNewQleID()
if randError != nil {
log.Fatalf("%s: GenerateNewQleID: %s", kms.kmsName, randError)
return nil
}
kms.QuantumElements[qle.QlID] = &qle
return &qle
}
// TODO: Name of this function is misleading, as it only reads the bulk keys, but nothing more else
func (kms *EKMS) GlobalKeyHandler(waitTime time.Duration) error {
// periodically walk through QuantumElements and retrieve the
// - key bulk buffer for each peer
// feed this into the corresponding key buffers of the kmss
for {
for currentQE := range kms.QuantumElements {
log.Debugf("%s GlobalKeyHandler reading...\n", kms.kmsName)
bulkKeys, err := kms.QuantumElements[currentQE].QuantumElementLink.GetKeyBulkPeer()
if err != nil {
log.Errorf("%s failed to retrieve bulkkeys with error %s", kms.kmsName, err)
} else {
// Add to the slice, but not process yet.
log.Debugf("%s produced %d bytes of key", kms.kmsName, bulkKeys.BulkKeyLength)
kms.QuantumElements[currentQE].rawBulkKeysMutex.Lock()
//kms.QuantumElements[currentQE].rawBulkKeys = append(kms.QuantumElements[currentQE].rawBulkKeys, &bulkKeys)
kms.QuantumElements[currentQE].rawBulkKeys[bulkKeys.BulkKeyId] = &bulkKeys
kms.QuantumElements[currentQE].rawBulkKeysMutex.Unlock()
//kms.QuantumElements[currentQE].keyStorePeer.KeyChopper256Bit(&bulkKeys)
}
}
// TODO: Better approach required than a sleep timer!
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 condition 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....
}
func (kms *EKMS) AddQuantumElement(qm QuantumModule) error {
kms.quantumModulesMutex.Lock()
kms.quantumModules[qm.ID()] = qm
kms.quantumModulesMutex.Unlock()
return nil
}
func (kms *EKMS) AddPeer(kmsPeerSocket string, servingQLE *QuantumElement) (*kmsPeer, error) {
func (kms *EKMS) AddPeer(kmsPeerSocket string, servingQLE QuantumModule) (*kmsPeer, error) {
//check if peer exists
if _, there := kms.KmsPeers[kmsPeerSocket]; there {
log.Errorf("Trying to add existing peer %s", kmsPeerSocket)
......
......@@ -2,7 +2,6 @@ package kms
import (
"context"
"encoding/json"
"errors"
"flag"
"fmt"
......@@ -40,10 +39,10 @@ func (es *etsiServer) ETSIGetQuantumInterfaces(ctx context.Context, in *pb.ETSIK
qleList := make([]*pb.QuantumElementInfo, 1)
// Walk through QuantumLayerInterfaces and return their information
for _, qlWorks := range es.handlingEkms.QuantumElements {
for _, qlWorks := range es.handlingEkms.quantumModules {
qleElement := pb.QuantumElementInfo{
QleID: uint64(qlWorks.QlID),
UdpAddr: fmt.Sprintf("%s:%d", qlWorks.QuantumElementLink.GetLocalQLPort().IP.String(), qlWorks.QuantumElementLink.GetLocalQLPort().Port),
QleID: qlWorks.ID().String(),
UdpAddr: qlWorks.Address().String(),
}
qleList = append(qleList, &qleElement)
}
......@@ -57,8 +56,8 @@ func (es *etsiServer) ETSIAddKMSPeer(ctx context.Context, in *pb.ETSIKMSPeerRequ
log.Debugf("AddKMSPeer called.")
// Check first if KmsLocalQLEId is actually one of ours...
qleID := in.KmsLocalQLEId
servingQLE, _ := es.handlingEkms.QuantumElements[qleID]
qleID := uuid.MustParse(in.KmsLocalQLEId)
servingQLE, _ := es.handlingEkms.quantumModules[qleID]
if servingQLE == nil {
//no such element!
err := errors.New(fmt.Sprintf("Unknown local quantum element with ID %d", qleID))
......@@ -146,19 +145,19 @@ func (es *etsiServer) ETSISendPayload(ctx context.Context, in *pb.ETSISendPayloa
}
// NOTE: For demo purpose only
json, err := json.Marshal(KMSInfo{
Name: es.handlingEkms.kmsName,
EncryptedMessage: in.Payload,
DecryptedMessage: in.Payload,
})
if err != nil {
log.Println("Failed to marshal: ", err)
}
err = sendKmsInfoMessage("http://172.20.10.21:4000/kmsinfo", json)
if err != nil {
log.Println("Failed to send KMS info message: ", err)
}
//json, err := json.Marshal(KMSInfo{
// Name: es.handlingEkms.kmsName,
// EncryptedMessage: in.Payload,
// DecryptedMessage: in.Payload,
//})
//if err != nil {
// log.Println("Failed to marshal: ", err)
//}
//err = sendKmsInfoMessage("http://172.20.10.21:4000/kmsinfo", json)
//if err != nil {
// log.Println("Failed to send KMS info message: ", err)
//}
if err := route.Next.SendPayload([]byte(in.GetPayload()), pathId); err != nil {
return nil, status.Errorf(codes.Internal, "Failed to send payload: ", err)
......@@ -169,42 +168,6 @@ func (es *etsiServer) ETSISendPayload(ctx context.Context, in *pb.ETSISendPayloa
}, 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.keyStorePeer
// randomKey, err = randomItemFromMap[uint64, *kmsKSElement](quantumElementLocalKeyStore.keyStore, es.visitedKeys)
// if err != nil {
// return nil, status.Errorf(codes.Internal, "%v", err)
// }
// es.visitedKeys[randomKey] = true
// }
//
// // TODO: Remove/move ssh-kind prototype code below
// 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.Errorf("could not execute ssh command with parameters")
// 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()
......
......@@ -3,7 +3,6 @@ package kms
import (
"context"
"encoding/base64"
"encoding/json"
"flag"
"net"
"time"
......@@ -39,6 +38,8 @@ func (s *kmsTalkerServer) InterComCapabilities(ctx context.Context, in *pb.Inter
}, nil
}
// TODO: should be removed as soon as the emulated quantum module has been
// changed; is specific for emulated quantum module
func (s *kmsTalkerServer) SyncQkdBulk(ctx context.Context, in *pb.SyncQkdBulkRequest) (*pb.SyncQkdBulkResponse, error) {
// NOTE: with "google.golang.org/grpc/peer" it would be possible to get the client ip directly
......@@ -49,19 +50,24 @@ func (s *kmsTalkerServer) SyncQkdBulk(ctx context.Context, in *pb.SyncQkdBulkReq
return nil, status.Errorf(codes.Internal, "peer does not exist")
}
eqm, ok := peer.servingQuantumModul.(*EmulatedQuantumModule)
if !ok {
return nil, status.Errorf(codes.Internal, "expected emulated quantum module")
}
for _, bulkId := range in.BulkId {
rawBulkKeyIds := keysOfMap[int64](peer.servingQLE.rawBulkKeys)
rawBulkKeyIds := keysOfMap[int64](eqm.rawBulkKeys)
log.Info("PEER BULK KEYS: ", rawBulkKeyIds)
if bulk, ok := peer.servingQLE.rawBulkKeys[bulkId]; ok {
peer.servingQLE.keyStorePeer = NewKmsKeyStore(256)
if err := peer.servingQLE.keyStorePeer.KeyChopper(bulk); err != nil {
if bulk, ok := eqm.rawBulkKeys[bulkId]; ok {
eqm.keyStore = NewKmsKeyStore(256)
if err := eqm.KeyChopper(bulk); err != nil {
//TODO: proper error message
return nil, status.Errorf(codes.Internal, "chopping failed")
}
peer.servingQLE.rawBulkKeysMutex.Lock()
delete(peer.servingQLE.rawBulkKeys, bulkId)
peer.servingQLE.rawBulkKeysMutex.Unlock()
eqm.rawBulkKeysMutex.Lock()
delete(eqm.rawBulkKeys, bulkId)
eqm.rawBulkKeysMutex.Unlock()
return &pb.SyncQkdBulkResponse{
Timestamp: time.Now().Unix(),
......@@ -101,13 +107,14 @@ func (s *kmsTalkerServer) InterComTransportKeyNegotiation(ctx context.Context, i
// return nil, status.Errorf(codes.Internal, "A transport key for pathID: %s has already been negotiated.", in.PathID)
//}
quantumElementRemoteKeyStore := route.Previous.servingQLE.keyStorePeer
quantumModuleKeyStore := route.Previous.servingQuantumModul.KeyStore()
key, ok := quantumElementRemoteKeyStore.keyStore[keyID]
if !ok {
return nil, status.Errorf(codes.Internal, "Key with ID: %s could not be found.", keyID)
key, err := quantumModuleKeyStore.GetKeyWithID(keyID)
if err != nil {
return nil, status.Errorf(codes.Internal, "%v", err)
}
// TODO: mutex
s.keyNegotiationMap[pathId] = key
return &pb.InterComTransportKeyNegotiationResponse{Timestamp: time.Now().Unix()}, nil
......@@ -148,21 +155,21 @@ func (s *kmsTalkerServer) KeyForwarding(ctx context.Context, in *pb.KeyForwardin
log.Infof("%s received the final payload: ", s.eKMS.kmsName, string(decryptedPayload))
}
// NOTE: For demo purpose only
json, err := json.Marshal(KMSInfo{
Name: s.eKMS.kmsName,
EncryptedMessage: in.Payload,
DecryptedMessage: string(decryptedPayload),
Key: base64.StdEncoding.EncodeToString(decryptKey.key),
})
if err != nil {
log.Println("Failed to marshal: ", err)
}
//// NOTE: For demo purpose only
//json, err := json.Marshal(KMSInfo{
// Name: s.eKMS.kmsName,
// EncryptedMessage: in.Payload,
// DecryptedMessage: string(decryptedPayload),
// Key: base64.StdEncoding.EncodeToString(decryptKey.key),
//})
//if err != nil {
// log.Println("Failed to marshal: ", err)
//}
err = sendKmsInfoMessage("http://172.20.10.21:4000/kmsinfo", json)
if err != nil {
log.Println("Failed to send KMS info message: ", err)
}
//err = sendKmsInfoMessage("http://172.20.10.21:4000/kmsinfo", json)
//if err != nil {
// log.Println("Failed to send KMS info message: ", err)
//}
return &pb.KeyForwardingResponse{Timestamp: time.Now().Unix()}, nil
}
......
......@@ -9,7 +9,6 @@ import (
pbIC "code.fbi.h-da.de/danet/proto-kms/api/gen/proto/go/kmsintercom"
"github.com/google/uuid"
"github.com/sirupsen/logrus"
log "github.com/sirupsen/logrus"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials/insecure"
......@@ -36,7 +35,7 @@ type kmsPeer struct {
peerClient pbIC.KmsTalkerClient
peerStatus KmsPeerStatus
interComAddr string
servingQLE *QuantumElement
servingQuantumModul QuantumModule
tcpSocket net.TCPAddr // the IP address and TCP port (aka socket) of the kms peer
tcpSocketStr string // string rep. of tcpSocket
et CryptoAlgorithm
......@@ -45,178 +44,42 @@ type kmsPeer struct {
quit chan bool // cancel the peer goroutine
}
func NewKmsPeer(servQLE *QuantumElement, tcpSocketStr string, interComAddr string, in chan string) (peer *kmsPeer, err error) {
func NewKmsPeer(servQM QuantumModule, tcpSocketStr string, interComAddr string, in chan string) (*kmsPeer, error) {
if servQM.Peer() != nil {
return nil, fmt.Errorf("QuantumModule with ID: , already has a peer", servQM.ID())
}
newPeerConn, err := grpc.Dial(tcpSocketStr, grpc.WithTransportCredentials(insecure.NewCredentials()))
if err != nil {
return nil, err
}
peerClient := pbIC.NewKmsTalkerClient(newPeerConn)
return &kmsPeer{
peer := &kmsPeer{
externalNotifierKMSPeer: in,
peerClient: peerClient,
// TODO: rename to client
peerClient: peerClient,
// TODO: change this, only for demo purposes
peerStatus: KmsPeerUp,
// TODO: move this into a config
interComAddr: interComAddr,
servingQLE: servQLE,
tcpSocketStr: tcpSocketStr,
et: NewAES(),
id: uuid.New(),
quit: make(chan bool),
}, nil
}
// Handles everything with respect to a specific KMS peer
//func (ph *kmsPeer) PeerHandler(kmsName string) {
// // log.Infof("%s started PeerHandler for %s:", kmsName, ph.tcpSocketStr)
//
// // contact peer
// newPeerConn, err := grpc.Dial(ph.tcpSocketStr, grpc.WithTransportCredentials(insecure.NewCredentials()))
// if err != nil {
// log.Errorf("%s: did not connect: %v", kmsName, 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.Errorf("%s: could not greet: %v", kmsName, 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.Errorf("%s: could not request a encryption key: %s", kmsName, err)
// ph.peerStatus = KmsPeerDown
// // Send notification about change
// if ph.externalNotifierKMSPeer != nil {
// ph.externalNotifierKMSPeer <- ph.tcpSocketStr
// }
// return
// }
//
// // check if key is in KeyStore
// if key, ok := ph.servingQLE.keyStorePeer.keyStore[encryptKeyRequest.KeyID]; ok {
// keyAsString := base64.StdEncoding.EncodeToString(key.key)
// log.Debugf("Agreed Key: %s", keyAsString)
//
// // TODO: Remove/move ssh-kind prototype code below
// // 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.Errorf("%s: could not execute ssh command with parameters", kmsName)
// 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) SyncBulkKeys() error {
rawBulkKeyIds := keysOfMap[int64](ph.servingQLE.rawBulkKeys)
logrus.Info("Found the following bulk key ids for usage: ", rawBulkKeyIds)
ctx, cancel := context.WithTimeout(context.Background(), time.Second)
defer cancel()
initialPeerSetupResponse, err := ph.peerClient.SyncQkdBulk(ctx, &pbIC.SyncQkdBulkRequest{
Timestamp: time.Now().Unix(),
InterComAddr: ph.interComAddr,
BulkId: rawBulkKeyIds,
})
if err != nil {
return err
interComAddr: interComAddr,
servingQuantumModul: servQM,
tcpSocketStr: tcpSocketStr,
et: NewAES(),
id: uuid.New(),
quit: make(chan bool),
}
bulkKey, ok := ph.servingQLE.rawBulkKeys[initialPeerSetupResponse.BulkId]
if !ok {
// TODO: add proper error message
return fmt.Errorf("Could not find raw bulk key with id: %d", initialPeerSetupResponse.BulkId)
}
// TODO: Initially the peer partners should discuss about the key length,
// for now it is hardcoded.
ph.servingQLE.keyStorePeer = NewKmsKeyStore(256)
servQM.SetPeer(peer)
if err := ph.servingQLE.keyStorePeer.KeyChopper(bulkKey); err != nil {
return err
if err := servQM.Initialize(); err != nil {
return nil, err
}
ph.servingQLE.rawBulkKeysMutex.Lock()
delete(ph.servingQLE.rawBulkKeys, initialPeerSetupResponse.BulkId)
ph.servingQLE.rawBulkKeysMutex.Unlock()
// update the peer status to up
ph.peerStatus = KmsPeerUp
// Send notification about change
if ph.externalNotifierKMSPeer != nil {
ph.externalNotifierKMSPeer <- ph.tcpSocketStr
}
return peer, nil
}
return nil
func (ph *kmsPeer) SyncBulkKeys() error {
return ph.servingQuantumModul.Sync()
}
// TransportKeyNegotiation sends a request for a transport key negotiation to
......@@ -229,7 +92,9 @@ func (ph *kmsPeer) TransportKeyNegotiation() error {
}
func (ph *kmsPeer) SendPayload(payload []byte, pathId uuid.UUID) error {
if len(ph.servingQLE.keyStorePeer.keyStore) <= int(ph.servingQLE.keyStorePeer.indexCounter) {
// NOTE: It should be assumed that there are keys available if we try to
// send.
if len(ph.servingQuantumModul.KeyStore().keyStore) <= int(ph.servingQuantumModul.KeyStore().indexCounter) {
log.Debug("Syncing bulk keys before sending the payload")
err := ph.SyncBulkKeys()
if err != nil {
......@@ -237,11 +102,10 @@ func (ph *kmsPeer) SendPayload(payload []byte, pathId uuid.UUID) error {
}
}
// TODO: Remove; for demo purposes only
time.Sleep(5 * time.Second)
// TODO: Return a message if keys are empty
// select a key from key store
key, err := ph.servingQLE.keyStorePeer.GetKey()
key, err := ph.servingQuantumModul.KeyStore().GetKey()
if err != nil {
return err
}
......@@ -292,7 +156,3 @@ func (ph *kmsPeer) GetKmsPeerStatus() KmsPeerStatus {
func (ph *kmsPeer) GetKmsPeerId() uuid.UUID {
return ph.id
}
func (ph *kmsPeer) GetKmsPeerQkdiId() uint32 {
return uint32(ph.servingQLE.QlID)
}
package kms
import (
"context"
"errors"
"fmt"
"io"
"net"
"sync"
"time"
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"
"github.com/sirupsen/logrus"
log "github.com/sirupsen/logrus"
)
// QuantumModule ...
type QuantumModule interface {
ID() uuid.UUID
Initialize() error
// NOTE: Sync will be removed as soon as the emulated quantum module has been
// changed to push a constant byte stream.
Sync() error
Manufacturer() string
KeyStore() *kmsKeyStore
Peer() *kmsPeer
SetPeer(*kmsPeer)
Address() net.Addr
}
type EmulatedQuantumModule struct {
QlID uuid.UUID
QuantumElementLink *quantumlayer.QuantumlayerEmuPRNG // contains information about the quantum links
//key stores of unchopped bulk keys go here
rawBulkKeysMutex sync.Mutex
rawBulkKeys map[int64]*quantumlayer.QuantumLayerBulkKey
keyStore *kmsKeyStore // the keys used between two peers.
peer *kmsPeer
}
func NewEmulatedQuantumModule(kmsUDPAddr string, generateKeys bool, logOutput io.Writer, logLevel log.Level, logInJson bool) *EmulatedQuantumModule {
// create an emulated quantum layer
ql := quantumlayer.NewQuantumlayerEmuPRNG(logOutput, logLevel, logInJson)
ql.Configure(kmsUDPAddr)
ql.PowerOn(generateKeys)
return &EmulatedQuantumModule{
QlID: uuid.New(),
QuantumElementLink: ql,
rawBulkKeys: make(map[int64]*quantumlayer.QuantumLayerBulkKey),
keyStore: NewKmsKeyStore(256),
peer: nil,
}
}
func (eqe *EmulatedQuantumModule) ID() uuid.UUID {
return eqe.QlID
}
func (eqe *EmulatedQuantumModule) Manufacturer() string {
return "danet"
}
func (eqe *EmulatedQuantumModule) Initialize() error {
// TODO: error handling
go eqe.keyHandler()
return nil
}
func (eqe *EmulatedQuantumModule) Address() net.Addr {
return eqe.QuantumElementLink.GetLocalQLPort()
}
func (eqe *EmulatedQuantumModule) KeyStore() *kmsKeyStore {
return eqe.keyStore
}
func (eqe *EmulatedQuantumModule) Sync() error {
rawBulkKeyIds := keysOfMap[int64](eqe.rawBulkKeys)
logrus.Info("Found the following bulk key ids for usage: ", rawBulkKeyIds)
ctx, cancel := context.WithTimeout(context.Background(), time.Second)
defer cancel()
initialPeerSetupResponse, err := eqe.peer.peerClient.SyncQkdBulk(ctx, &pbIC.SyncQkdBulkRequest{
Timestamp: time.Now().Unix(),
InterComAddr: eqe.peer.interComAddr,
BulkId: rawBulkKeyIds,
})
if err != nil {
return err
}
bulkKey, ok := eqe.rawBulkKeys[initialPeerSetupResponse.BulkId]
if !ok {
// TODO: add proper error message
return fmt.Errorf("Could not find raw bulk key with id: %d", initialPeerSetupResponse.BulkId)
}
// TODO: Initially the peer partners should discuss about the key length,
// for now it is hardcoded.
eqe.keyStore = NewKmsKeyStore(256)
if err := eqe.KeyChopper(bulkKey); err != nil {
return err
}
eqe.rawBulkKeysMutex.Lock()
delete(eqe.rawBulkKeys, initialPeerSetupResponse.BulkId)
eqe.rawBulkKeysMutex.Unlock()
// update the peer status to up
eqe.peer.peerStatus = KmsPeerUp
// Send notification about change
if eqe.peer.externalNotifierKMSPeer != nil {
eqe.peer.externalNotifierKMSPeer <- eqe.peer.tcpSocketStr
}
return nil
}
func (eqe *EmulatedQuantumModule) Peer() *kmsPeer {
return eqe.peer
}
func (eqe *EmulatedQuantumModule) SetPeer(peer *kmsPeer) {
eqe.peer = peer
}
func (eqe *EmulatedQuantumModule) keyHandler() {
// periodically walk through quantum element and retrieve the key bulk buffer
for {
log.Debugf("%s: KeyHandler reading...\n", eqe.ID())
bulkKeys, err := eqe.QuantumElementLink.GetKeyBulkPeer()
if err != nil {
log.Errorf("%s: failed to retrieve bulkkeys with error %s", eqe.ID(), err)
} else {
// Add to the slice, but not process yet.
log.Debugf("%s: produced %d bytes of key", eqe.ID(), bulkKeys.BulkKeyLength)
eqe.rawBulkKeysMutex.Lock()
eqe.rawBulkKeys[bulkKeys.BulkKeyId] = &bulkKeys
eqe.rawBulkKeysMutex.Unlock()
}
// TODO: hardcoded
time.Sleep(5 * time.Second)
}
}
// Takes a bulk of keys and chops them in chopFactor keys each
// Any remainder is discarded
func (eqe *EmulatedQuantumModule) KeyChopper(bulkKey *quantumlayer.QuantumLayerBulkKey) error {
if eqe.keyStore.keySingleSize == 0 {
return errors.New("KeyChopper: no keySingleSize set")
}
// TODO check if multiple of 8 (1 Byte)
if bulkKey.BulkKeyLength != len(*bulkKey.BulkKey) {
return errors.New("bulkKey length mismatch")
}
// reset indexCounter
eqe.keyStore.indexCounter = 0
var keyId uint64
keyId = 0
// Let's chop!
chopFactor := eqe.keyStore.keySingleSize >> 3
key := *bulkKey.BulkKey
for len(key) > int(chopFactor) {
tmpkey := key[:chopFactor]
eqe.keyStore.addKey(keyId, tmpkey)
keyId++
// shorten the key storage
key = key[chopFactor:]
}
return nil
}
......@@ -64,8 +64,14 @@ func emulatedKMS(myName, myUDPAddr, myInterComAddr, peerUDPAddr, peerInterComAdd
// Attach to eKMS
emuKMS := kms.NewEKMS(myName, uuid.New(), os.Stdout, log.TraceLevel, false, myInterComAddr)
eqm := kms.NewEmulatedQuantumModule(myUDPAddr, false, os.Stdout, log.TraceLevel, false)
// Fire up Quantum LinK
myQL := emuKMS.AddQuantumElement(myUDPAddr, false, os.Stdout, log.TraceLevel, false)
err := emuKMS.AddQuantumElement(eqm)
if err != nil {
log.Println("failed to create emulated quantum module")
return
}
udpQL2Addr, err := net.ResolveUDPAddr("udp", peerUDPAddr)
if err != nil {
......@@ -73,9 +79,9 @@ func emulatedKMS(myName, myUDPAddr, myInterComAddr, peerUDPAddr, peerInterComAdd
return
}
myQL.QuantumElementLink.AddPeer(udpQL2Addr)
eqm.QuantumElementLink.AddPeer(udpQL2Addr)
_, err = emuKMS.AddPeer(peerInterComAddr, myQL)
_, err = emuKMS.AddPeer(peerInterComAddr, eqm)
if err != nil {
log.Println("PEERERROR: ", err)
}
......@@ -83,8 +89,8 @@ func emulatedKMS(myName, myUDPAddr, myInterComAddr, peerUDPAddr, peerInterComAdd
// Start the SDN/management and key retrieval interface
go kms.StartETSI(myUDPAddr, emuKMS)
// TODO/XXX catch errors!
emuKMS.GlobalKeyHandler(7 * time.Second)
// // TODO/XXX catch errors!
// emuKMS.GlobalKeyHandler(7 * time.Second)
}
func middleKMS(myName, myUDPAddr, myInterComAddr, leftUDPAddr, leftInterComAddr, rightUDPAddr, rightInterComAddr string) {
......@@ -92,8 +98,8 @@ func middleKMS(myName, myUDPAddr, myInterComAddr, leftUDPAddr, leftInterComAddr,
emuKMS := kms.NewEKMS(myName, uuid.New(), os.Stdout, log.TraceLevel, false, myInterComAddr)
// create two quantum modules that generate keys
qlForLeft := emuKMS.AddQuantumElement("[::1]:50910", true, os.Stdout, log.TraceLevel, false)
qlForRight := emuKMS.AddQuantumElement("[::1]:50911", true, os.Stdout, log.TraceLevel, false)
qlForLeft := kms.NewEmulatedQuantumModule("[::1]:50910", true, os.Stdout, log.TraceLevel, false)
qlForRight := kms.NewEmulatedQuantumModule("[::1]:50911", true, os.Stdout, log.TraceLevel, false)
netLeftUDPAddr, err := net.ResolveUDPAddr("udp", leftUDPAddr)
if err != nil {
......@@ -107,6 +113,19 @@ func middleKMS(myName, myUDPAddr, myInterComAddr, leftUDPAddr, leftInterComAddr,
return
}
// Fire up Quantum LinK
err = emuKMS.AddQuantumElement(qlForLeft)
if err != nil {
log.Println("failed to create emulated quantum module")
return
}
err = emuKMS.AddQuantumElement(qlForRight)
if err != nil {
log.Println("failed to create emulated quantum module")
return
}
qlForLeft.QuantumElementLink.AddPeer(netLeftUDPAddr)
qlForRight.QuantumElementLink.AddPeer(netRightUDPAddr)
......@@ -123,9 +142,6 @@ func middleKMS(myName, myUDPAddr, myInterComAddr, leftUDPAddr, leftInterComAddr,
// Start the SDN/management and key retrieval interface
go kms.StartETSI(myUDPAddr, emuKMS)
// TODO/XXX catch errors!
go emuKMS.GlobalKeyHandler(7 * time.Second)
time.Sleep(time.Second * 15)
if err := peerLeft.SyncBulkKeys(); err != nil {
log.Println("SYNC ERROR: ", err)
......
......@@ -137,6 +137,7 @@ func (qlemuprng *QuantumlayerEmuPRNG) PowerOn(enableKeyGeneration bool) {
// Retrieve local UDP address and store it for further actions.
qlemuprng.qlLocalPort = qlemuprng.udpSrvConn.LocalAddr().(*net.UDPAddr)
// TODO: This does not seem to be necessary if the gle is not generating rands
log.Infof("QuantumlayerEmuPRNG: started server, waiting for incoming rands on port %s \n", qlemuprng.udpSrvConn.LocalAddr().(*net.UDPAddr).String())
inBuffer := make([]byte, 1500)
for {
......@@ -248,8 +249,8 @@ func (qlemuprng *QuantumlayerEmuPRNG) RemovePeer() {
qlemuprng.qlPeerMutex.Unlock()
}
func (qlemuprng *QuantumlayerEmuPRNG) GetLocalQLPort() (myAddr net.UDPAddr) {
return *qlemuprng.qlLocalPort
func (qlemuprng *QuantumlayerEmuPRNG) GetLocalQLPort() (myAddr *net.UDPAddr) {
return qlemuprng.qlLocalPort
}
func (qlemuprng *QuantumlayerEmuPRNG) GenerateRandomNumbers() (randNums []byte) {
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment