Skip to content
Snippets Groups Projects
module.go 4.79 KiB
Newer Older
  • Learn to ignore specific revisions
  • 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
    	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) 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
    }
    
    Malte Bauch's avatar
    Malte Bauch committed
    
    type ETSI014HTTPQuantumModule struct {
    	id       uuid.UUID
    	keyStore *kmsKeyStore
    	peer     *kmsPeer
    }