Newer
Older
// This package kms implements a simplistic key managment system (kms) for
// Quantum Key Distribution Networks (QKDN) which is a simple emulated KMS. x
// It relies on the emulated quantum link out of the quantumlayer package
package kms
import (
pbETSI "code.fbi.h-da.de/demoquandt/proto-kms/kmsetsiproto"
pbIC "code.fbi.h-da.de/demoquandt/proto-kms/kmsintercomproto"
"code.fbi.h-da.de/demoquandt/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
AddPeer(kmsPeerSocket string, servingQLE *QuantumElement)
RemovePeer(kmsPeerSocket string)
}
type qlElementLinkID int
// The general emulated KMS
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
// This actually constitutes a quantum element with only a single link
/*
type QuantumElementInterface interface {
GetQlID() qlElementId
}*/
type QuantumElement struct {
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(kmsName string, kmsUUID uuid.UUID) (newEKMS *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(kmsUDPAddrr string) *QuantumElement {
//Get an emulated Quantumlayer
ql := quantumlayer.NewQuantumlayerEmuPRNG()
ql.Configure(kmsUDPAddrr)
ql.PowerOn()
ksl := kmsKeyStore{
keyStore: make(map[string]kmsKSElement),
}
ksr := kmsKeyStore{
keyStore: make(map[string]kmsKSElement),
}
qle := QuantumElement{
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[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) {
func (kms *EKMS) AddExternalNotifierQLE(in chan uint32) {
kms.externalNotifierQLE = in
}
func (kms *EKMS) AddExternalNotifierKMSPeer(in chan string) {
kms.externalNotifierKMSPeer = in
}