Skip to content
Snippets Groups Projects
kms.go 5.78 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"
    
    	"encoding/binary"
    
    	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
    
    	GlobalKeyHandler(time.Duration) error
    
    	AddPeer(kmsPeerSocket string, servingQLE *QuantumElement)
    
    	RemovePeer(kmsPeerSocket string)
    
    }
    
    type qlElementLinkID int
    
    // The general emulated KMS
    
    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
    
    // This actually constitutes a quantum element with only a single link
    
    
    /*
    type QuantumElementInterface interface {
    	GetQlID() 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) {
    
    	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(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),
    	}
    
    
    		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() (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....
    	}
    }
    
    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
    }