diff --git a/app/app.go b/app/app.go index 709e7f7..e57c666 100644 --- a/app/app.go +++ b/app/app.go @@ -34,7 +34,7 @@ func (app *Application) NewProfile(name string, filename string, password string } // SetProfile loads an existing profile from the given filename. -func (app *Application) SetProfile(filename string) error { +func (app *Application) SetProfile(filename string, password string) error { profile, err := peer.LoadCwtchPeer(filename, password) if err != nil { return err diff --git a/app/cli/main.go b/app/cli/main.go index 7198198..fb50bb1 100644 --- a/app/cli/main.go +++ b/app/cli/main.go @@ -9,8 +9,8 @@ import ( "time" "bytes" - "syscall" "golang.org/x/crypto/ssh/terminal" + "syscall" ) var app app2.Application @@ -187,7 +187,7 @@ func main() { fmt.Print("** WARNING: PASSWORDS CANNOT BE RECOVERED! **\n") password := "" - failcount := 0; + failcount := 0 for ; failcount < 3; failcount++ { fmt.Print("Enter a password to encrypt the profile: ") bytePassword, _ := terminal.ReadPassword(int(syscall.Stdin)) @@ -197,25 +197,25 @@ func main() { } fmt.Print("\nRe-enter password: ") bytePassword2, _ := terminal.ReadPassword(int(syscall.Stdin)) - if(bytes.Equal(bytePassword, bytePassword2)){ + if bytes.Equal(bytePassword, bytePassword2) { password = string(bytePassword) break - }else{ + } else { fmt.Print("\nPASSWORDS DIDN'T MATCH! Try again.\n") } } - if(failcount >= 3){ - fmt.Printf("Error creating profile for %v: Your password entries must match!\n", commands[1]) - }else{ - err := app.NewProfile(commands[1], commands[2], password) - profilefile = commands[2] - if err == nil { - fmt.Printf("\nNew profile created for %v\n", commands[1]) - } else { - fmt.Printf("\nError creating profile for %v: %v\n", commands[1], err) - } - } + if failcount >= 3 { + fmt.Printf("Error creating profile for %v: Your password entries must match!\n", commands[1]) + } else { + err := app.NewProfile(commands[1], commands[2], password) + profilefile = commands[2] + if err == nil { + fmt.Printf("\nNew profile created for %v\n", commands[1]) + } else { + fmt.Printf("\nError creating profile for %v: %v\n", commands[1], err) + } + } } else { fmt.Printf("Error creating NewProfile, usage: %s\n", usages["new-profile"]) } diff --git a/peer/cwtch_peer.go b/peer/cwtch_peer.go index eb53740..a0d70f5 100644 --- a/peer/cwtch_peer.go +++ b/peer/cwtch_peer.go @@ -1,6 +1,7 @@ package peer import ( + "crypto/rand" "crypto/rsa" "cwtch.im/cwtch/model" "cwtch.im/cwtch/peer/connections" @@ -9,11 +10,17 @@ import ( "encoding/base64" "encoding/json" "errors" - "github.com/golang/protobuf/proto" + "fmt" "git.openprivacy.ca/openprivacy/libricochet-go/application" "git.openprivacy.ca/openprivacy/libricochet-go/channels" "git.openprivacy.ca/openprivacy/libricochet-go/connection" + "github.com/golang/protobuf/proto" + "github.com/ulule/deepcopier" "golang.org/x/crypto/ed25519" + "golang.org/x/crypto/nacl/secretbox" + "golang.org/x/crypto/pbkdf2" + "golang.org/x/crypto/sha3" + "io" "io/ioutil" "log" "strings" @@ -67,18 +74,17 @@ type CwtchPeerInterface interface { Shutdown() } -// CreateHash hashes the user's password to a length suitable for file encryption +// CreateKey derives a key and salt for use in encrypting the Profile func CreateKey(key string) ([32]byte, [128]byte) { -var salt [128]byte -if _, err := io.ReadFull(rand.Reader, salt[:]); -err != nil { - panic(err) -} -dk := pbkdf2.Key([]byte(key), salt[:], 4096, 32, sha3.New512) + var salt [128]byte + if _, err := io.ReadFull(rand.Reader, salt[:]); err != nil { + panic(err) + } + dk := pbkdf2.Key([]byte(key), salt[:], 4096, 32, sha3.New512) -var dkr [32]byte -copy(dkr[:], dk) -return dkr, salt + var dkr [32]byte + copy(dkr[:], dk) + return dkr, salt } //EncryptMessage takes a message and encrypts the message under the group key. @@ -101,21 +107,21 @@ func EncryptProfile(p *cwtchPeer, password [32]byte) []byte { } //EncryptMessage takes a message and encrypts the message under the group key. -func DecryptProfile(ciphertext []byte, password [32]byte) (error, *cwtchPeer){ +func DecryptProfile(ciphertext []byte, password [32]byte) (error, *cwtchPeer) { var decryptNonce [24]byte - copy(decryptNonce[:], ciphertext[:24]) - decrypted, ok := secretbox.Open(nil, ciphertext[24:], &decryptNonce, &password) - if ok { - cp := &cwtchPeer{} - err := json.Unmarshal(decrypted, &cp) - if err == nil { - return nil, cp - } else { + copy(decryptNonce[:], ciphertext[:24]) + decrypted, ok := secretbox.Open(nil, ciphertext[24:], &decryptNonce, &password) + if ok { + cp := &cwtchPeer{} + err := json.Unmarshal(decrypted, &cp) + if err == nil { + return nil, cp + } else { return err, nil } - } - return fmt.Errorf("Failed to decrypt"), nil + } + return fmt.Errorf("Failed to decrypt"), nil } func (cp *cwtchPeer) setup() { @@ -139,7 +145,7 @@ func (cp *cwtchPeer) setup() { } // NewCwtchPeer creates and returns a new CwtchPeer with the given name. -func NewCwtchPeer(name string, password string) *cwtchPeer { +func NewCwtchPeer(name string, password string) CwtchPeerInterface { cp := new(cwtchPeer) cp.Profile = model.GenerateNewProfile(name) cp.setup() @@ -153,7 +159,7 @@ func NewCwtchPeer(name string, password string) *cwtchPeer { func (cp *cwtchPeer) Save(profilefile string) error { cp.mutex.Lock() encryptedbytes := EncryptProfile(cp, cp.password) - encryptedbytes = append(cp.salt[:],encryptedbytes...) + encryptedbytes = append(cp.salt[:], encryptedbytes...) err := ioutil.WriteFile(profilefile, encryptedbytes, 0600) cp.profilefile = profilefile cp.mutex.Unlock() @@ -173,13 +179,13 @@ func LoadCwtchPeer(profilefile string, password string) (*cwtchPeer, error) { err, cp := DecryptProfile(encryptedbytes, dkr) if err == nil { - cp.setup() - cp.profilefile = profilefile - cp.password = dkr - return cp, nil - } else { - return nil, err - } + cp.setup() + cp.profilefile = profilefile + cp.password = dkr + return cp, nil + } else { + return nil, err + } } // ImportGroup intializes a group from an imported source rather than a peer invite diff --git a/peer/cwtch_peer_test.go b/peer/cwtch_peer_test.go index fee56d9..312ac9a 100644 --- a/peer/cwtch_peer_test.go +++ b/peer/cwtch_peer_test.go @@ -6,10 +6,10 @@ import ( func TestCwtchPeerGenerate(t *testing.T) { - alice := NewCwtchPeer("alice") + alice := NewCwtchPeer("alice","testpass") alice.Save("./test_profile") - aliceLoaded, err := LoadCwtchPeer("./test_profile") + aliceLoaded, err := LoadCwtchPeer("./test_profile","testpass") if err != nil || aliceLoaded.GetProfile().Name != "alice" { t.Errorf("something went wrong saving and loading profiles %v %v", err, aliceLoaded) } diff --git a/testing/cwtch_peer_server_intergration_test.go b/testing/cwtch_peer_server_intergration_test.go index fe72e90..79b3456 100644 --- a/testing/cwtch_peer_server_intergration_test.go +++ b/testing/cwtch_peer_server_intergration_test.go @@ -143,17 +143,17 @@ func TestCwtchPeerIntegration(t *testing.T) { // ***** Peer setup ***** fmt.Println("Creating Alice...") - alice := peer.NewCwtchPeer("Alice") + alice := peer.NewCwtchPeer("Alice","alicepass") go alice.Listen() fmt.Println("Alice created:", alice.GetProfile().Onion) fmt.Println("Creating Bob...") - bob := peer.NewCwtchPeer("Bob") + bob := peer.NewCwtchPeer("Bob","bobpass") go bob.Listen() fmt.Println("Bob created:", bob.GetProfile().Onion) fmt.Println("Creating Carol...") - carol := peer.NewCwtchPeer("Carol") + carol := peer.NewCwtchPeer("Carol","carolpass") go carol.Listen() fmt.Println("Carol created:", carol.GetProfile().Onion)