Skip to content
Snippets Groups Projects
Select Git revision
  • f24abef729b7389d3af11f7397b467a7f40cf58f
  • main default protected
  • development
  • integration
  • v1.1.5
  • v1.1.4
  • v1.1.3
  • v1.1.2
  • v1.1.1
  • v1.1.0
  • v1.0.0
11 results

E2EGetReceivedRequest.swift

Blame
  • user.go 8.83 KiB
    ///////////////////////////////////////////////////////////////////////////////
    // Copyright © 2020 xx network SEZC                                          //
    //                                                                           //
    // Use of this source code is governed by a license that can be found in the //
    // LICENSE file                                                              //
    ///////////////////////////////////////////////////////////////////////////////
    
    package api
    
    import (
    	"encoding/binary"
    	jww "github.com/spf13/jwalterweatherman"
    	"gitlab.com/elixxir/client/interfaces/user"
    	"gitlab.com/elixxir/crypto/cyclic"
    	"gitlab.com/elixxir/crypto/fastRNG"
    	"gitlab.com/xx_network/crypto/csprng"
    	"gitlab.com/xx_network/crypto/signature/rsa"
    	"gitlab.com/xx_network/crypto/xx"
    	"gitlab.com/xx_network/primitives/id"
    	"math/rand"
    	"regexp"
    	"runtime"
    	"strings"
    	"sync"
    )
    
    const (
    	// SaltSize size of user salts
    	SaltSize = 32
    )
    
    // createNewUser generates an identity for cMix
    func createNewUser(rng *fastRNG.StreamGenerator, cmix, e2e *cyclic.Group) user.User {
    	// CMIX Keygen
    	var transmissionRsaKey, receptionRsaKey *rsa.PrivateKey
    
    	var cMixKeyBytes, e2eKeyBytes, transmissionSalt, receptionSalt []byte
    
    	cMixKeyBytes, e2eKeyBytes, transmissionSalt, receptionSalt,
    		transmissionRsaKey, receptionRsaKey = createDhKeys(rng, cmix, e2e)
    
    	// Salt, UID, etc gen
    	stream := rng.GetStream()
    	transmissionSalt = make([]byte, SaltSize)
    
    	n, err := stream.Read(transmissionSalt)
    
    	if err != nil {
    		jww.FATAL.Panicf(err.Error())
    	}
    	if n != SaltSize {
    		jww.FATAL.Panicf("transmissionSalt size too small: %d", n)
    	}
    
    	receptionSalt = make([]byte, SaltSize)
    
    	n, err = stream.Read(receptionSalt)
    
    	if err != nil {
    		jww.FATAL.Panicf(err.Error())
    	}
    	if n != SaltSize {
    		jww.FATAL.Panicf("transmissionSalt size too small: %d", n)
    	}
    
    	stream.Close()
    
    	transmissionID, err := xx.NewID(transmissionRsaKey.GetPublic(), transmissionSalt, id.User)
    	if err != nil {
    		jww.FATAL.Panicf(err.Error())
    	}
    
    	receptionID, err := xx.NewID(receptionRsaKey.GetPublic(), receptionSalt, id.User)
    	if err != nil {
    		jww.FATAL.Panicf(err.Error())
    	}
    
    	return user.User{
    		TransmissionID:   transmissionID.DeepCopy(),
    		TransmissionSalt: transmissionSalt,
    		TransmissionRSA:  transmissionRsaKey,
    		ReceptionID:      receptionID.DeepCopy(),
    		ReceptionSalt:    receptionSalt,
    		ReceptionRSA:     receptionRsaKey,
    		Precanned:        false,
    		CmixDhPrivateKey: cmix.NewIntFromBytes(cMixKeyBytes),
    		E2eDhPrivateKey:  e2e.NewIntFromBytes(e2eKeyBytes),
    	}
    }
    
    func createDhKeys(rng *fastRNG.StreamGenerator,
    	cmix, e2e *cyclic.Group) (cMixKeyBytes, e2eKeyBytes,
    	transmissionSalt, receptionSalt []byte,
    	transmissionRsaKey, receptionRsaKey *rsa.PrivateKey) {
    	wg := sync.WaitGroup{}
    
    	wg.Add(4)
    
    	go func() {
    		defer wg.Done()
    		var err error
    		// FIXME: Why 256 bits? -- this is spec but not explained, it has
    		// to do with optimizing operations on one side and still preserves
    		// decent security -- cite this.
    		stream := rng.GetStream()
    		cMixKeyBytes, err = csprng.GenerateInGroup(cmix.GetPBytes(), 256, stream)
    		stream.Close()
    		if err != nil {
    			jww.FATAL.Panicf(err.Error())
    		}
    	}()
    
    	go func() {
    		defer wg.Done()
    		var err error
    		// DH Keygen
    		// FIXME: Why 256 bits? -- this is spec but not explained, it has
    		// to do with optimizing operations on one side and still preserves
    		// decent security -- cite this. Why valid for BOTH e2e and cmix?
    		stream := rng.GetStream()
    		e2eKeyBytes, err = csprng.GenerateInGroup(e2e.GetPBytes(), 256, stream)
    		stream.Close()
    		if err != nil {
    			jww.FATAL.Panicf(err.Error())
    		}
    	}()
    
    	// RSA Keygen (4096 bit defaults)
    	go func() {
    		defer wg.Done()
    		var err error
    		stream := rng.GetStream()
    		transmissionRsaKey, err = rsa.GenerateKey(stream, rsa.DefaultRSABitLen)
    		stream.Close()
    		if err != nil {
    			jww.FATAL.Panicf(err.Error())
    		}
    	}()
    
    	go func() {
    		defer wg.Done()
    		var err error
    		stream := rng.GetStream()
    		receptionRsaKey, err = rsa.GenerateKey(stream, rsa.DefaultRSABitLen)
    		stream.Close()
    		if err != nil {
    			jww.FATAL.Panicf(err.Error())
    		}
    	}()
    	wg.Wait()
    
    	return
    
    }
    
    // TODO: Add precanned user code structures here.
    // creates a precanned user
    func createPrecannedUser(precannedID uint, rng csprng.Source, cmix, e2e *cyclic.Group) user.User {
    	// DH Keygen
    	// FIXME: Why 256 bits? -- this is spec but not explained, it has
    	// to do with optimizing operations on one side and still preserves
    	// decent security -- cite this. Why valid for BOTH e2e and cmix?
    	prng := rand.New(rand.NewSource(int64(precannedID)))
    	e2eKeyBytes, err := csprng.GenerateInGroup(e2e.GetPBytes(), 256, prng)
    	if err != nil {
    		jww.FATAL.Panicf(err.Error())
    	}
    
    	// Salt, UID, etc gen
    	salt := make([]byte, SaltSize)
    
    	userID := id.ID{}
    	binary.BigEndian.PutUint64(userID[:], uint64(precannedID))
    	userID.SetType(id.User)
    
    	// NOTE: not used... RSA Keygen (4096 bit defaults)
    	rsaKey, err := rsa.GenerateKey(rng, rsa.DefaultRSABitLen)
    	if err != nil {
    		jww.FATAL.Panicf(err.Error())
    	}
    
    	return user.User{
    		TransmissionID:   &userID,
    		TransmissionSalt: salt,
    		ReceptionID:      &userID,
    		ReceptionSalt:    salt,
    		Precanned:        true,
    		E2eDhPrivateKey:  e2e.NewIntFromBytes(e2eKeyBytes),
    		// NOTE: These are dummy/not used
    		CmixDhPrivateKey: cmix.NewInt(1),
    		TransmissionRSA:  rsaKey,
    		ReceptionRSA:     rsaKey,
    	}
    }
    
    // createNewVanityUser generates an identity for cMix
    // The identity's ReceptionID is not random but starts with the supplied prefix
    func createNewVanityUser(rng csprng.Source, cmix, e2e *cyclic.Group, prefix string) user.User {
    	// CMIX Keygen
    	// FIXME: Why 256 bits? -- this is spec but not explained, it has
    	// to do with optimizing operations on one side and still preserves
    	// decent security -- cite this.
    	cMixKeyBytes, err := csprng.GenerateInGroup(cmix.GetPBytes(), 256, rng)
    	if err != nil {
    		jww.FATAL.Panicf(err.Error())
    	}
    
    	// DH Keygen
    	// FIXME: Why 256 bits? -- this is spec but not explained, it has
    	// to do with optimizing operations on one side and still preserves
    	// decent security -- cite this. Why valid for BOTH e2e and cmix?
    	e2eKeyBytes, err := csprng.GenerateInGroup(e2e.GetPBytes(), 256, rng)
    	if err != nil {
    		jww.FATAL.Panicf(err.Error())
    	}
    
    	// RSA Keygen (4096 bit defaults)
    	transmissionRsaKey, err := rsa.GenerateKey(rng, rsa.DefaultRSABitLen)
    	if err != nil {
    		jww.FATAL.Panicf(err.Error())
    	}
    
    	// Salt, UID, etc gen
    	transmissionSalt := make([]byte, SaltSize)
    	n, err := csprng.NewSystemRNG().Read(transmissionSalt)
    	if err != nil {
    		jww.FATAL.Panicf(err.Error())
    	}
    	if n != SaltSize {
    		jww.FATAL.Panicf("transmissionSalt size too small: %d", n)
    	}
    	transmissionID, err := xx.NewID(transmissionRsaKey.GetPublic(), transmissionSalt, id.User)
    	if err != nil {
    		jww.FATAL.Panicf(err.Error())
    	}
    
    	receptionRsaKey, err := rsa.GenerateKey(rng, rsa.DefaultRSABitLen)
    	if err != nil {
    		jww.FATAL.Panicf(err.Error())
    	}
    
    	var mu sync.Mutex // just in case more than one go routine tries to access receptionSalt and receptionID
    	done := make(chan struct{})
    	found := make(chan bool)
    	wg := &sync.WaitGroup{}
    	cores := runtime.NumCPU()
    
    	var receptionSalt []byte
    	var receptionID *id.ID
    
    	pref := prefix
    	ignoreCase := false
    	// check if case-insensitivity is enabled
    	if strings.HasPrefix(prefix, "(?i)") {
    		pref = strings.ToLower(pref[4:])
    		ignoreCase = true
    	}
    	// Check if prefix contains valid Base64 characters
    	match, _ := regexp.MatchString("^[A-Za-z0-9+/]+$", pref)
    	if match == false {
    		jww.FATAL.Panicf("Prefix contains non-Base64 characters")
    	}
    	jww.INFO.Printf("Vanity userID generation started. Prefix: %s Ignore-Case: %v NumCPU: %d", pref, ignoreCase, cores)
    	for w := 0; w < cores; w++ {
    		wg.Add(1)
    		go func() {
    			rSalt := make([]byte, SaltSize)
    			for {
    				select {
    				case <-done:
    					defer wg.Done()
    					return
    				default:
    					n, err = csprng.NewSystemRNG().Read(rSalt)
    					if err != nil {
    						jww.FATAL.Panicf(err.Error())
    					}
    					if n != SaltSize {
    						jww.FATAL.Panicf("receptionSalt size too small: %d", n)
    					}
    					rID, err := xx.NewID(receptionRsaKey.GetPublic(), rSalt, id.User)
    					if err != nil {
    						jww.FATAL.Panicf(err.Error())
    					}
    					id := rID.String()
    					if ignoreCase {
    						id = strings.ToLower(id)
    					}
    					if strings.HasPrefix(id, pref) {
    						mu.Lock()
    						receptionID = rID
    						receptionSalt = rSalt
    						mu.Unlock()
    						found <- true
    						defer wg.Done()
    						return
    					}
    				}
    			}
    		}()
    	}
    	// wait for a solution then close the done channel to signal the workers to exit
    	<-found
    	close(done)
    	wg.Wait()
    	return user.User{
    		TransmissionID:   transmissionID.DeepCopy(),
    		TransmissionSalt: transmissionSalt,
    		TransmissionRSA:  transmissionRsaKey,
    		ReceptionID:      receptionID.DeepCopy(),
    		ReceptionSalt:    receptionSalt,
    		ReceptionRSA:     receptionRsaKey,
    		Precanned:        false,
    		CmixDhPrivateKey: cmix.NewIntFromBytes(cMixKeyBytes),
    		E2eDhPrivateKey:  e2e.NewIntFromBytes(e2eKeyBytes),
    	}
    }