diff --git a/api/authenticatedChannel.go b/api/authenticatedChannel.go index 424d3f830174445334a48de0ced69eaa5424f191..01d486c577d8c50752f19e706511fd71455eaba7 100644 --- a/api/authenticatedChannel.go +++ b/api/authenticatedChannel.go @@ -86,7 +86,7 @@ func (c *Client) MakePrecannedAuthenticatedChannel(precannedID uint) (contact.Co precan := c.MakePrecannedContact(precannedID) - //add the precanned user as a e2e contact + // add the precanned user as a e2e contact sesParam := e2e.GetDefaultSessionParams() err := c.storage.E2e().AddPartner(precan.ID, precan.DhPubKey, c.storage.E2e().GetDHPrivateKey(), sesParam, sesParam) @@ -99,11 +99,11 @@ func (c *Client) MakePrecannedContact(precannedID uint) contact.Contact { e2eGrp := c.storage.E2e().GetGroup() - //get the user definition + // get the user definition precanned := createPrecannedUser(precannedID, c.rng.GetStream(), c.storage.Cmix().GetGroup(), e2eGrp) - //compute their public e2e key + // compute their public e2e key partnerPubKey := e2eGrp.ExpG(precanned.E2eDhPrivateKey, e2eGrp.NewInt(1)) return contact.Contact{ diff --git a/bindings/client.go b/bindings/client.go index 7a8a6779735320d5c201c4695d1a9940835b071c..364f9d14a41f222f923244c7bdefaeb15db316cd 100644 --- a/bindings/client.go +++ b/bindings/client.go @@ -10,7 +10,6 @@ import ( "encoding/json" "errors" "fmt" - "github.com/spf13/jwalterweatherman" jww "github.com/spf13/jwalterweatherman" "gitlab.com/elixxir/client/api" "gitlab.com/elixxir/client/interfaces/contact" @@ -23,6 +22,12 @@ import ( "time" ) +// sets the log level +func init() { + jww.SetLogThreshold(jww.LevelInfo) + jww.SetStdoutThreshold(jww.LevelInfo) +} + // BindingsClient wraps the api.Client, implementing additional functions // to support the gomobile Client interface type Client struct { @@ -36,8 +41,6 @@ type Client struct { // // Users of this function should delete the storage directory on error. func NewClient(network, storageDir string, password []byte, regCode string) error { - jwalterweatherman.SetLogThreshold(jwalterweatherman.LevelInfo) - if err := api.NewClient(network, storageDir, password, regCode); err != nil { return errors.New(fmt.Sprintf("Failed to create new client: %+v", err)) @@ -53,7 +56,6 @@ func NewClient(network, storageDir string, password []byte, regCode string) erro // // Users of this function should delete the storage directory on error. func NewPrecannedClient(precannedID int, network, storageDir string, password []byte) error { - jwalterweatherman.SetLogThreshold(jwalterweatherman.LevelInfo) if precannedID < 0 { return errors.New("Cannot create precanned client with negative ID") } @@ -73,10 +75,6 @@ func NewPrecannedClient(precannedID int, network, storageDir string, password [] // Login does not block on network connection, and instead loads and // starts subprocesses to perform network operations. func Login(storageDir string, password []byte) (*Client, error) { - // TODO: This should wrap the bindings ClientImpl, when available. - jww.SetStdoutThreshold(jww.LevelTrace) - jww.SetLogThreshold(jww.LevelTrace) - client, err := api.Login(storageDir, password) if err != nil { return nil, errors.New(fmt.Sprintf("Failed to login: %+v", err)) @@ -84,6 +82,48 @@ func Login(storageDir string, password []byte) (*Client, error) { return &Client{*client}, nil } +// sets level of logging. All logs the set level and above will be displayed +// options are: +// TRACE - 0 +// DEBUG - 1 +// INFO - 2 +// WARN - 3 +// ERROR - 4 +// CRITICAL - 5 +// FATAL - 6 +// The default state without updates is: INFO +func LogLevel(level int) error { + if level < 0 || level > 6 { + return errors.New(fmt.Sprintf("log level is not valid: log level: %d", level)) + } + + threshold := jww.Threshold(level) + jww.SetLogThreshold(threshold) + jww.SetStdoutThreshold(threshold) + + switch threshold { + case jww.LevelTrace: + fallthrough + case jww.LevelDebug: + fallthrough + case jww.LevelInfo: + jww.INFO.Printf("Log level set to: %s", threshold) + case jww.LevelWarn: + jww.WARN.Printf("Log level set to: %s", threshold) + case jww.LevelError: + jww.ERROR.Printf("Log level set to: %s", threshold) + case jww.LevelCritical: + jww.CRITICAL.Printf("Log level set to: %s", threshold) + case jww.LevelFatal: + jww.FATAL.Printf("Log level set to: %s", threshold) + } + + return nil +} + + + + //Unmarshals a marshaled contact object, returns an error if it fails func UnmarshalContact(b []byte) (*Contact, error) { c, err := contact.Unmarshal(b) diff --git a/network/message/parse/firstMessagePart.go b/network/message/parse/firstMessagePart.go index 1d928536a4a105446ec1bc87b255138980b027f0..6da28c32f3fda0f16dd8a125bd483691e23c1049 100644 --- a/network/message/parse/firstMessagePart.go +++ b/network/message/parse/firstMessagePart.go @@ -2,7 +2,6 @@ package parse import ( "encoding/binary" - jww "github.com/spf13/jwalterweatherman" "gitlab.com/elixxir/client/interfaces/message" "time" ) @@ -41,11 +40,11 @@ func newFirstMessagePart(mt message.Type, id uint32, numParts uint8, m.NumParts[0] = numParts //Serialize and add the timestamp to the payload - timestampBytes, err := timestamp.MarshalBinary() + /*timestampBytes, err := timestamp.MarshalBinary() if err != nil { jww.FATAL.Panicf("Failed to create firstMessagePart: %s", err.Error()) } - copy(m.Timestamp, timestampBytes) + copy(m.Timestamp, timestampBytes)*/ //set the contents length binary.BigEndian.PutUint16(m.Len, uint16(len(contents))) diff --git a/network/message/sendCmix.go b/network/message/sendCmix.go index 20bfc853026eacd402adf1cc2f0605ea78a9c04a..4d7fd3403ae4971232b0151d5014c31dd79c6cc4 100644 --- a/network/message/sendCmix.go +++ b/network/message/sendCmix.go @@ -67,14 +67,14 @@ func (m *Manager) SendCMIX(msg format.Message, param params.CMIX) (id.Round, err //encrypt the message salt := make([]byte, 32) - stream := m.Rng.GetStream() - _, err = stream.Read(salt) - stream.Close() + //stream := rand.New(rand.NewSource(42)) + //_, err = stream.Read(salt) + //stream.Close() - if err != nil { + /*if err != nil { return 0, errors.WithMessage(err, "Failed to generate "+ "salt, this should never happen") - } + }*/ encMsg, kmacs := roundKeys.Encrypt(msg, salt) @@ -87,12 +87,18 @@ func (m *Manager) SendCMIX(msg format.Message, param params.CMIX) (id.Round, err KMACs: kmacs, } + jww.INFO.Printf("PlainText Payload: %v", msg.Marshal()) + jww.INFO.Printf("Encrypted Payload: %v", encMsg.Marshal()) + jww.INFO.Printf("Transmission Packet: %+v", msgPacket) + //create the wrapper to the gateway msg := &mixmessages.GatewaySlot{ Message: msgPacket, RoundID: bestRound.ID, } + jww.INFO.Printf("Gateway Slot: %+v", msgPacket) + //Add the mac proving ownership msg.MAC = roundKeys.MakeClientGatewayKey(salt, network.GenerateSlotDigest(msg)) diff --git a/storage/cmix/roundKeys.go b/storage/cmix/roundKeys.go index c7bce0608c31f85a0331f2046a96bf877b54757b..5e0e22b91414ed48793933115019fdbe94f15dcd 100644 --- a/storage/cmix/roundKeys.go +++ b/storage/cmix/roundKeys.go @@ -1,11 +1,14 @@ package cmix import ( + "crypto/sha256" + "crypto/sha512" jww "github.com/spf13/jwalterweatherman" "gitlab.com/elixxir/crypto/cmix" "gitlab.com/elixxir/crypto/cyclic" "gitlab.com/elixxir/crypto/hash" "gitlab.com/elixxir/primitives/format" + "golang.org/x/crypto/blake2b" ) type RoundKeys struct { @@ -26,10 +29,11 @@ func (rk *RoundKeys) Encrypt(msg format.Message, keys := make([]*cyclic.Int, len(rk.keys)) for i, k := range rk.keys { + jww.INFO.Printf("CMIXKEY: num: %d, key: %s", i, k.Get().Text(16)) keys[i] = k.Get() } - ecrMsg := cmix.ClientEncrypt(rk.g, msg, salt, keys) + ecrMsg := ClientEncrypt(rk.g, msg, salt, keys) h, err := hash.NewCMixHash() if err != nil { @@ -52,3 +56,99 @@ func (rk *RoundKeys) MakeClientGatewayKey(salt, digest []byte) []byte { h.Write(digest) return h.Sum(nil) } + +func ClientEncrypt(grp *cyclic.Group, msg format.Message, + salt []byte, baseKeys []*cyclic.Int) format.Message { + + // Get the salt for associated data + hash, err := blake2b.New256(nil) + if err != nil { + panic("E2E Client Encrypt could not get blake2b Hash") + } + hash.Reset() + hash.Write(salt) + salt2 := hash.Sum(nil) + + jww.INFO.Printf("SALT_A: %v", salt) + jww.INFO.Printf("SALT_B: %v", salt2) + + // Get encryption keys + keyEcrA := ClientKeyGen(grp, salt, baseKeys) + jww.INFO.Printf("Key A: %s", keyEcrA.Text(16)) + keyEcrB := ClientKeyGen(grp, salt2, baseKeys) + jww.INFO.Printf("Key B: %s", keyEcrA.Text(16)) + + // Get message payloads as cyclic integers + payloadA := grp.NewIntFromBytes(msg.GetPayloadA()) + payloadB := grp.NewIntFromBytes(msg.GetPayloadB()) + + jww.INFO.Printf("Payload A: %s", payloadA.Text(16)) + jww.INFO.Printf("Payload B: %s", payloadB.Text(16)) + + // Encrypt payload A with the key + EcrPayloadA := grp.Mul(keyEcrA, payloadA, grp.NewInt(1)) + jww.INFO.Printf("Encrypted Payload A: %s", EcrPayloadA.Text(16)) + EcrPayloadB := grp.Mul(keyEcrB, payloadB, grp.NewInt(1)) + jww.INFO.Printf("Encrypted Payload B: %s", EcrPayloadB.Text(16)) + + primeLen := grp.GetP().ByteLen() + + // Create the encrypted message + encryptedMsg := format.NewMessage(primeLen) + + encryptedMsg.SetPayloadA(EcrPayloadA.LeftpadBytes(uint64(primeLen))) + encryptedMsg.SetPayloadB(EcrPayloadB.LeftpadBytes(uint64(primeLen))) + + jww.INFO.Printf("Encrypted message: %v", encryptedMsg.Marshal()) + + return encryptedMsg + +} + +func ClientKeyGen(grp *cyclic.Group, salt []byte, baseKeys []*cyclic.Int) *cyclic.Int { + output := grp.NewInt(1) + tmpKey := grp.NewInt(1) + + // Multiply all the generated keys together as they are generated. + for i, baseKey := range baseKeys { + jww.INFO.Printf("Input to Gen Key: num: %v, baseKey: %s", i, baseKey.Text(16)) + keyGen(grp, salt, baseKey, tmpKey) + jww.INFO.Printf("Gen Key: num: %v, key: %s", i, tmpKey.Text(16)) + grp.Mul(tmpKey, output, output) + jww.INFO.Printf("Partial full Key: num: %v, key: %s", i, output.Text(16)) + } + + jww.INFO.Printf("final full Key: %s", output.Text(16)) + + grp.Inverse(output, output) + + jww.INFO.Printf("inverted Key: %s", output.Text(16)) + + return output +} + +// keyGen combines the salt with the baseKey to generate a new key inside the group. +func keyGen(grp *cyclic.Group, salt []byte, baseKey, output *cyclic.Int) *cyclic.Int { + h1, _ := hash.NewCMixHash() + h2 := sha256.New() + + a := baseKey.Bytes() + + // Blake2b Hash of the result of previous stage (base key + salt) + h1.Reset() + h1.Write(a) + h1.Write(salt) + x := h1.Sum(nil) + jww.INFO.Printf("keygen x: %v", x) + + // Different Hash (SHA256) of the previous result to add entropy + h2.Reset() + h2.Write(x) + y := h2.Sum(nil) + jww.INFO.Printf("keygen y: %v", x) + + // Expand Key using SHA512 + k := hash.ExpandKey(sha512.New(), grp, y, output) + jww.INFO.Printf("keygen expandedKey: %s", k.Text(16)) + return k +}