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 (
"crypto/rand"
"log"
"math/big"
"sync"
"time"
pbETSI "code.fbi.h-da.de/m.stiemerling/proto-kms/kmsetsiproto"
pbIC "code.fbi.h-da.de/m.stiemerling/proto-kms/kmsintercomproto"
"code.fbi.h-da.de/m.stiemerling/proto-kms/quantumlayer"
"github.com/google/uuid"
)
type Qkdnkms interface {
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[qlElementId]*QuantumElement
kmsPeersMutex sync.Mutex
KmsPeers map[string]*kmsPeer
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 QuantumElement struct {
qlID qlElementId
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[qlElementId]*QuantumElement),
KmsPeers: make(map[string]*kmsPeer),
}
}
func (kms *EKMS) AddQuantumElement(kmsUDPAddrr string) *QuantumElement {
//Get an emulated Quantumlayer
ql := quantumlayer.NewQuantumlayerEmuPRNG()
ql.PowerOn(kmsUDPAddrr)
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() (qlElementId, error) {
for { // this needs a condiction to stop!
bigRand, randError := rand.Int(rand.Reader, big.NewInt(100000))
if randError != nil {
return 0, randError
}
propopsedQlElementID := qlElementId(bigRand.Uint64())
// 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.Fatalf("Trying to add existing peer %s", kmsPeerSocket)
}
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) {