Commit 79373dbd authored by David Stainton's avatar David Stainton

Fix encrypted state file

fixes #18
fixes #14
parent dfba0b1e
Pipeline #1037 passed with stage
in 3 minutes and 50 seconds
......@@ -348,6 +348,7 @@ func (c *Client) Shutdown() {
c.save()
c.Halt()
c.client.Shutdown()
c.stateWorker.Halt()
close(c.fatalErrCh)
}
......@@ -579,7 +580,7 @@ func (c *Client) decryptMessage(messageID *[cConstants.MessageIDLength]byte, cip
c.eventCh.In() <- &MessageReceivedEvent{
Nickname: nickname,
Message: message.Plaintext,
Timestamp: time.Now(),
Timestamp: message.Timestamp,
}
return
}
......
......@@ -19,6 +19,7 @@
package catshadow
import (
"bytes"
"fmt"
"io/ioutil"
"os"
......@@ -27,10 +28,26 @@ import (
"github.com/katzenpost/catshadow/config"
"github.com/katzenpost/client"
cConfig "github.com/katzenpost/client/config"
"github.com/katzenpost/core/crypto/rand"
"github.com/stretchr/testify/require"
)
func getClientState(c *Client) *State {
contacts := []*Contact{}
for _, contact := range c.contacts {
contacts = append(contacts, contact)
}
return &State{
SpoolReadDescriptor: c.spoolReadDescriptor,
Contacts: contacts,
LinkKey: c.linkKey,
User: c.user,
Provider: c.client.Provider(),
Conversations: c.GetAllConversations(),
}
}
func createRandomStateFile(t *testing.T) string {
require := require.New(t)
......@@ -77,6 +94,43 @@ func createCatshadowClientWithState(t *testing.T, stateFile string) *Client {
return catShadowClient
}
func reloadCatshadowState(t *testing.T, stateFile string) *Client {
require := require.New(t)
// Load catshadow config file.
catshadowCfg, err := config.LoadFile("testdata/catshadow.toml")
require.NoError(err)
var stateWorker *StateWriter
var catShadowClient *Client
cfg, err := catshadowCfg.ClientConfig()
require.NoError(err)
passphrase := []byte("")
state, _, err := GetStateFromFile(stateFile, passphrase)
require.NoError(err)
cfg.Account = &cConfig.Account{
User: state.User,
Provider: state.Provider,
}
logBackend, err := catshadowCfg.InitLogBackend()
require.NoError(err)
c, err := client.New(cfg)
require.NoError(err)
stateWorker, state, err = LoadStateWriter(c.GetLogger("catshadow_state"), stateFile, passphrase)
require.NoError(err)
catShadowClient, err = New(logBackend, c, stateWorker, state)
require.NoError(err)
// Start catshadow client.
stateWorker.Start()
catShadowClient.Start()
return catShadowClient
}
func TestDockerPandaSuccess(t *testing.T) {
require := require.New(t)
......@@ -123,10 +177,10 @@ loop2:
func TestDockerPandaTagContendedError(t *testing.T) {
require := require.New(t)
aliceState := createRandomStateFile(t)
alice := createCatshadowClientWithState(t, aliceState)
bobState := createRandomStateFile(t)
bob := createCatshadowClientWithState(t, bobState)
aliceStateFilePath := createRandomStateFile(t)
alice := createCatshadowClientWithState(t, aliceStateFilePath)
bobStateFilePath := createRandomStateFile(t)
bob := createCatshadowClientWithState(t, bobStateFilePath)
sharedSecret := []byte("twas brillig and the slithy toves")
randBytes := [8]byte{}
......@@ -201,10 +255,10 @@ loop4:
func TestDockerSendReceive(t *testing.T) {
require := require.New(t)
aliceState := createRandomStateFile(t)
alice := createCatshadowClientWithState(t, aliceState)
bobState := createRandomStateFile(t)
bob := createCatshadowClientWithState(t, bobState)
aliceStateFilePath := createRandomStateFile(t)
alice := createCatshadowClientWithState(t, aliceStateFilePath)
bobStateFilePath := createRandomStateFile(t)
bob := createCatshadowClientWithState(t, bobStateFilePath)
sharedSecret := []byte(`oxcart pillage village bicycle gravity socks`)
randBytes := [8]byte{}
......@@ -276,6 +330,45 @@ and can readily scale to millions of users.
<-aliceDeliveredChan
<-bobReceivedMessageChan
// Test statefile persistence of conversation.
alice.log.Debug("LOADING ALICE'S CONVERSATION")
aliceConvesation := alice.GetConversation("bob")
for i, mesg := range aliceConvesation {
alice.log.Debugf("%d outbound %v message:\n%s\n", i, mesg.Outbound, mesg.Plaintext)
}
bob.log.Debug("LOADING BOB'S CONVERSATION")
bobConvesation := bob.GetConversation("alice")
for i, mesg := range bobConvesation {
bob.log.Debugf("%d outbound %v message:\n%s\n", i, mesg.Outbound, mesg.Plaintext)
}
alice.Shutdown()
bob.Shutdown()
newAlice := reloadCatshadowState(t, aliceStateFilePath)
newAlice.log.Debug("LOADING ALICE'S CONVERSATION")
aliceConvesation = newAlice.GetConversation("bob")
for i, mesg := range aliceConvesation {
newAlice.log.Debugf("%d outbound %v message:\n%s\n", i, mesg.Outbound, mesg.Plaintext)
}
newBob := reloadCatshadowState(t, bobStateFilePath)
newBob.log.Debug("LOADING BOB'S CONVERSATION")
bobConvesation = newBob.GetConversation("alice")
for i, mesg := range bobConvesation {
newBob.log.Debugf("%d outbound %v message:\n%s\n", i, mesg.Outbound, mesg.Plaintext)
}
newAliceState := getClientState(newAlice)
aliceState := getClientState(alice)
aliceBobConvo1 := aliceState.Conversations["bob"]
aliceBobConvo2 := newAliceState.Conversations["bob"]
newAlice.log.Debug("convo1\n")
for i, message := range aliceBobConvo1 {
require.True(bytes.Equal(message.Plaintext, aliceBobConvo2[i].Plaintext))
// XXX require.True(message.Timestamp.Equal(aliceBobConvo2[i].Timestamp))
}
newAlice.Shutdown()
newBob.Shutdown()
}
......@@ -23,6 +23,7 @@ import (
"time"
"github.com/katzenpost/core/crypto/ecdh"
"github.com/katzenpost/core/crypto/rand"
"github.com/katzenpost/core/worker"
"github.com/katzenpost/memspool/client"
"github.com/ugorji/go/codec"
......@@ -64,27 +65,21 @@ type StateWriter struct {
stateCh chan []byte
stateFile string
key [32]byte
nonce [24]byte
key [32]byte
}
// LoadStateWriter decrypts the given stateFile and returns the State
// as well as a new StateWriter.
func LoadStateWriter(log *logging.Logger, stateFile string, passphrase []byte) (*StateWriter, *State, error) {
secret := argon2.Key(passphrase, nil, 3, 32*1024, 4, keySize+nonceSize)
worker := &StateWriter{
log: log,
stateCh: make(chan []byte),
stateFile: stateFile,
}
copy(worker.key[:], secret[0:32])
copy(worker.nonce[:], secret[32:])
ciphertext, err := ioutil.ReadFile(stateFile)
func GetStateFromFile(stateFile string, passphrase []byte) (*State, *[keySize]byte, error) {
secret := argon2.Key(passphrase, nil, 3, 32*1024, 4, keySize)
rawFile, err := ioutil.ReadFile(stateFile)
if err != nil {
return nil, nil, err
}
plaintext, ok := secretbox.Open(nil, ciphertext, &worker.nonce, &worker.key)
nonce := [nonceSize]byte{}
copy(nonce[:], rawFile[:nonceSize])
ciphertext := rawFile[nonceSize:]
key := [keySize]byte{}
copy(key[:], secret)
plaintext, ok := secretbox.Open(nil, ciphertext, &nonce, &key)
if !ok {
return nil, nil, errors.New("failed to decrypted statefile")
}
......@@ -93,20 +88,35 @@ func LoadStateWriter(log *logging.Logger, stateFile string, passphrase []byte) (
if err != nil {
return nil, nil, err
}
return state, &key, nil
}
// LoadStateWriter decrypts the given stateFile and returns the State
// as well as a new StateWriter.
func LoadStateWriter(log *logging.Logger, stateFile string, passphrase []byte) (*StateWriter, *State, error) {
worker := &StateWriter{
log: log,
stateCh: make(chan []byte),
stateFile: stateFile,
}
state, key, err := GetStateFromFile(stateFile, passphrase)
if err != nil {
return nil, nil, err
}
copy(worker.key[:], key[:])
return worker, state, nil
}
// NewStateWriter is a constructor for StateWriter which is to be used when creating
// the statefile for the first time.
func NewStateWriter(log *logging.Logger, stateFile string, passphrase []byte) (*StateWriter, error) {
secret := argon2.Key(passphrase, nil, 3, 32*1024, 4, keySize+nonceSize)
secret := argon2.Key(passphrase, nil, 3, 32*1024, 4, keySize)
worker := &StateWriter{
log: log,
stateCh: make(chan []byte),
stateFile: stateFile,
}
copy(worker.key[:], secret[0:32])
copy(worker.nonce[:], secret[32:])
return worker, nil
}
......@@ -117,12 +127,18 @@ func (w *StateWriter) Start() {
}
func (w *StateWriter) writeState(payload []byte) error {
ciphertext := secretbox.Seal(nil, payload, &w.nonce, &w.key)
nonce := [nonceSize]byte{}
_, err := rand.Reader.Read(nonce[:])
if err != nil {
return err
}
ciphertext := secretbox.Seal(nil, payload, &nonce, &w.key)
out, err := os.OpenFile(w.stateFile+".tmp", os.O_TRUNC|os.O_CREATE|os.O_WRONLY, 0600)
if err != nil {
return err
}
_, err = out.Write(ciphertext)
outBytes := append(nonce[:], ciphertext...)
_, err = out.Write(outBytes)
if err != nil {
return err
}
......
......@@ -57,20 +57,8 @@ github.com/katzenpost/client v0.0.3-0.20190910170722-ae354c4fb533 h1:+AkyYQET33f
github.com/katzenpost/client v0.0.3-0.20190910170722-ae354c4fb533/go.mod h1:D/E1XFYzPUZiUHxkNAao5zdMwOY7BV6dbDpkKH3i5D8=
github.com/katzenpost/client v0.0.3-0.20190920100131-361636bf6f9c h1:mVFgttMDhh1mNc39QykZWQfwzKKTsGAOsGWnK/LA5LM=
github.com/katzenpost/client v0.0.3-0.20190920100131-361636bf6f9c/go.mod h1:TugbuaRJTthySzXBKyLK9Vjf15M7u+NoQGju8oBqwwU=
github.com/katzenpost/client v0.0.3-0.20190927151016-81d0a12412f2 h1:ifY4r0SSGJThgt4v56Y2yNojqiBFlU5gZtjsm93gi7I=
github.com/katzenpost/client v0.0.3-0.20190927151016-81d0a12412f2/go.mod h1:SrzTAedisDlFx70XC7vrXwzkBPE60Zjc5GOw3kQ0T2E=
github.com/katzenpost/client v0.0.3-0.20190928113438-7005603e0739 h1:cG97h3xGgpPat22TgzmblYiAt/u1nJznhZ1XlWS14P0=
github.com/katzenpost/client v0.0.3-0.20190928113438-7005603e0739/go.mod h1:SrzTAedisDlFx70XC7vrXwzkBPE60Zjc5GOw3kQ0T2E=
github.com/katzenpost/client v0.0.3-0.20190928135818-1dc6e4ba58ce h1:yhnQ6CBDySwzuXE+CEyxl+R98hQRiwmyAz6xEqLjyu4=
github.com/katzenpost/client v0.0.3-0.20190928135818-1dc6e4ba58ce/go.mod h1:SrzTAedisDlFx70XC7vrXwzkBPE60Zjc5GOw3kQ0T2E=
github.com/katzenpost/client v0.0.3-0.20190929084952-6620f9fb6cd2 h1:RPdI3fp8oHgoJTia5I6Az4iQn1+wjDmDdko6/lHofG8=
github.com/katzenpost/client v0.0.3-0.20190929084952-6620f9fb6cd2/go.mod h1:aXOJDR21ukOxxJF/RufBlJ3tFR6pkSrruA3WVLVaZCs=
github.com/katzenpost/client v0.0.3-0.20191001202308-de4f67ebf78a h1:UBBDe1AAnDtaKTnkC4afJDXu27q/99IDamoC3vkxvww=
github.com/katzenpost/client v0.0.3-0.20191001202308-de4f67ebf78a/go.mod h1:aXOJDR21ukOxxJF/RufBlJ3tFR6pkSrruA3WVLVaZCs=
github.com/katzenpost/client v0.0.3-0.20191006152514-6ced40e1159f h1:038D2nW2L47bC+OUTn35P3S40PYTYqtnTkumLIVzxos=
github.com/katzenpost/client v0.0.3-0.20191006152514-6ced40e1159f/go.mod h1:aXOJDR21ukOxxJF/RufBlJ3tFR6pkSrruA3WVLVaZCs=
github.com/katzenpost/client v0.0.3-0.20191018145826-19d2864402e5 h1:QKm9zFgGk9W+rwTVBRQqmjBt4BTxU5zOppqojtMIsEw=
github.com/katzenpost/client v0.0.3-0.20191018145826-19d2864402e5/go.mod h1:aXOJDR21ukOxxJF/RufBlJ3tFR6pkSrruA3WVLVaZCs=
github.com/katzenpost/client v0.0.3-0.20191020112934-aa5a26c4c1a4 h1:9NbXEQBD9tepRcHHAZVsE5TZff3eYvJESVgvGEZcf0U=
github.com/katzenpost/client v0.0.3-0.20191020112934-aa5a26c4c1a4/go.mod h1:aXOJDR21ukOxxJF/RufBlJ3tFR6pkSrruA3WVLVaZCs=
github.com/katzenpost/core v0.0.8-0.20190730121401-926fce1cae50 h1:Zrp+qrhOsD8S9QQv0G3F1wZYny/+173ZbMPTFuFvm/0=
......@@ -88,12 +76,6 @@ github.com/katzenpost/kimchi v0.0.0-20190920152505-0ced4b468812 h1:BXxUPZw0PzLFK
github.com/katzenpost/kimchi v0.0.0-20190920152505-0ced4b468812/go.mod h1:h1u/GqNvbeLjRfQQlsjkmlzFzi88X8OsFgrYcE8ufyw=
github.com/katzenpost/memspool v0.0.1 h1:IRvrfTUm5pSF5YaopGYGMUIleszgQwCE67vX9DhifDc=
github.com/katzenpost/memspool v0.0.1/go.mod h1:0pUZ4ZsVRbpkcymI1t6p2JiLz4DorRncXAS2if7fDdQ=
github.com/katzenpost/memspool v0.0.2-0.20190927170136-d6030c17ac32 h1:9aRAHUVxug8BKXlc33/Gcw6dxLll+4+0OzZ2buMLZIY=
github.com/katzenpost/memspool v0.0.2-0.20190927170136-d6030c17ac32/go.mod h1:v18U52QvNpiwSDxFckwsC7WC/QrpOOa9ZxUfVMy/dbI=
github.com/katzenpost/memspool v0.0.2-0.20190929092656-1e50db6c549a h1:Pt7CAumLD1emMnp33S0x+Y4A8L1ul8ClAVjPxs203gw=
github.com/katzenpost/memspool v0.0.2-0.20190929092656-1e50db6c549a/go.mod h1:1U80lViFiI5ye132ajU9jfzvScEeHozh4imfL23qR1A=
github.com/katzenpost/memspool v0.0.2-0.20191020121940-76c251c38e8c h1:w0TU+pd0a3o0pHNdAwuvylmEz62JGUO5rVpJzRGVhqQ=
github.com/katzenpost/memspool v0.0.2-0.20191020121940-76c251c38e8c/go.mod h1:1U80lViFiI5ye132ajU9jfzvScEeHozh4imfL23qR1A=
github.com/katzenpost/memspool v0.0.2-0.20191020142539-1987138adafa h1:EVS4EsAuXo7bwKr4aEkx86klx5gVfaUdhjbk1UFYe/g=
github.com/katzenpost/memspool v0.0.2-0.20191020142539-1987138adafa/go.mod h1:1U80lViFiI5ye132ajU9jfzvScEeHozh4imfL23qR1A=
github.com/katzenpost/minclient v0.0.5 h1:lUPG4D7MQkBb1qEQOx/EFKjrJMVZJOLctiSUY1sWJ5I=
......@@ -112,10 +94,6 @@ github.com/katzenpost/noise v0.0.0-20190907211420-4c2fa3a5d7a1 h1:bD6fNKhG5mnTWp
github.com/katzenpost/noise v0.0.0-20190907211420-4c2fa3a5d7a1/go.mod h1:TqIOjVOESMlMl9Z+XElrJlY9gtBthOFpolLV3tA0vSg=
github.com/katzenpost/panda v0.0.4-0.20190801155026-ac87cceaf056 h1:JGTovSTaFmi8z1Agto2c1gmSR22ERPPBkccZQnAOL4k=
github.com/katzenpost/panda v0.0.4-0.20190801155026-ac87cceaf056/go.mod h1:ZWlRxTlGXjFdVnFNP1EFuOyl6QwfQQDQWIrnZnhnl1A=
github.com/katzenpost/panda v0.0.4-0.20190927160940-3f1bf1a9acfc h1:x2b9YWMEE98laMrHfSIjnMQOZpPY7pBQrReK0esj0DE=
github.com/katzenpost/panda v0.0.4-0.20190927160940-3f1bf1a9acfc/go.mod h1:MfcxFhX9D7RupwTVITWDJDaWr0sB195zHHbaeQFAsdU=
github.com/katzenpost/panda v0.0.4-0.20190929092452-fb46420c8d6d h1:/lK9WZL56IOtW6ExFquyNwmr5Of+PDlm/3b/kJrLwsI=
github.com/katzenpost/panda v0.0.4-0.20190929092452-fb46420c8d6d/go.mod h1:dPbAxBF2MSlShipgpNw8jOnpmMeyuu7PdbYFJL7h7GM=
github.com/katzenpost/panda v0.0.4-0.20190930092228-e6aa54df75d2 h1:YJYhCExYBZH8cuRX2sduS5u9GWta8eKFZuvuF2bZ0V0=
github.com/katzenpost/panda v0.0.4-0.20190930092228-e6aa54df75d2/go.mod h1:dPbAxBF2MSlShipgpNw8jOnpmMeyuu7PdbYFJL7h7GM=
github.com/katzenpost/registration_client v0.0.1 h1:ZvlEQ0rfVEGEV67x7KVxMi0veiLn2QyM1bxfWb8u7Q8=
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment