Skip to content
Snippets Groups Projects
kms.go 4.11 KiB
Newer Older
  • Learn to ignore specific revisions
  • // 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"
    
    
    	"code.fbi.h-da.de/m.stiemerling/proto-kms/quantumlayer"
    	"github.com/google/uuid"
    )
    
    type Qkdnkms interface {
    	AddQuantumElement() *QuantumElement
    
    	GlobalKeyHandler(time.Duration) error
    
    	AddPeer(kmsPeerSocket string)
    	RemovePeer(kmsPeerSocket string)
    
    type qlElementId uint64
    
    type qlElementLinkID int
    
    // The general emulated KMS
    type eKMS struct {
    
    	kmsName         string
    	kmsUUID         uuid.UUID
    	qleMapMutex     sync.Mutex
    
    	QuantumElements map[qlElementId]*QuantumElement
    
    	KmsPeers        map[string]*kmsPeer
    
    }
    
    // Will keep information about the quantum elements that this eKMS is talking to
    
    // This actually constitutes a quantum element with only a single link
    
    	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),
    	}
    }
    
    
    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),
    	}
    
    
    		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
    
    
    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....
    	}
    }