diff --git a/src/git.xdrm.io/schastsp/client/client.go b/src/git.xdrm.io/schastsp/client/client.go index ec0a673..3813953 100644 --- a/src/git.xdrm.io/schastsp/client/client.go +++ b/src/git.xdrm.io/schastsp/client/client.go @@ -66,22 +66,20 @@ func New(ctx *context.T, saveDir string) (*T, error) { func (c *T) Send(w io.Writer) error { /* (1) Generate the request */ - var x1, x2 []byte + x1 := make([]byte, scha.HSIZE) + x2 := make([]byte, scha.HSIZE) err := c.generateRequest(x1, x2) - if err != nil { - return err - } + if err != nil { return err } /* (2) Write request into writer */ - _, err = w.Write(x1) - if err != nil { - return err - } - _, err = w.Write(x2) - if err != nil { - return err - } + written, err := w.Write(x1) + if err != nil { return err } + if written != len(x1) { return errors.New("Cannot write x1") } + + written, err = w.Write(x2) + if err != nil { return err } + if written != len(x1) { return errors.New("Cannot write x2") } return nil } @@ -100,8 +98,9 @@ func (c *T) Receive(r io.Reader) error { errCode := make([]byte, 1) read, err := r.Read(errCode) if err != nil { return err } - if uint16(read) != 1 { return errors.New("Cannot read enough bytes") } + if uint16(read) != 1 { return errors.New("Cannot read error code") } + fmt.Printf("ERROR CODE : %d\n", errCode[0]); /* (2) Manage success ---------------------------------------------------------*/ if errCode[0] == 0 { @@ -125,13 +124,13 @@ func (c *T) Receive(r io.Reader) error { y1 := make([]byte, scha.HSIZE) read, err = r.Read(y1) if err != nil { return err } - if uint16(read) != scha.HSIZE { return errors.New("Cannot read enough bytes") } + if uint16(read) != scha.HSIZE { return errors.New("Cannot read y1") } /* (2) Read y2 */ y2 := make([]byte, scha.HSIZE) read, err = r.Read(y2) if err != nil { return err } - if uint16(read) != scha.HSIZE { return errors.New("Cannot read enough bytes") } + if uint16(read) != scha.HSIZE { return errors.New("Cannot read enough y2") } /* (3) Manage rescue mode */ err = c.rescue(y1, y2) @@ -140,3 +139,18 @@ func (c *T) Receive(r io.Reader) error { return err } + + + + +/* (5) TMP +* +---------------------------------------------------------*/ +func (c *T) TMP() []byte { + hash, err := c.key.CurrentHash() + if err != nil { panic(err) } + + c.key.Decrement() + + return hash; +} diff --git a/src/git.xdrm.io/schastsp/client/client.internal.go b/src/git.xdrm.io/schastsp/client/client.internal.go index b3c11c3..513e091 100644 --- a/src/git.xdrm.io/schastsp/client/client.internal.go +++ b/src/git.xdrm.io/schastsp/client/client.internal.go @@ -226,7 +226,7 @@ func (c *T) generateRequest(x1 []byte, x2 []byte) error { ---------------------------------------------------------*/ /* (1) Get current time id */ timeId, timeMod := timeid.Generate(c.ctx.Window()) - + fmt.Printf("Client.time[%d, %d]\n", timeId, timeMod); /* (2) Convert time id to byte array */ timeIdBytes := make([]byte, 4) binary.BigEndian.PutUint32(timeIdBytes, timeId) @@ -237,22 +237,20 @@ func (c *T) generateRequest(x1 []byte, x2 []byte) error { /* (5) Calculate x1 and x2 ---------------------------------------------------------*/ /* (1) Calculate x1 = h ^ h(timeId) */ - x1 = xor.ByteArray(h0, hashedTimeId) + copy(x1, xor.ByteArray(h0, hashedTimeId)) if DEBUG { fmt.Printf("\n=== x1 ===\n") fmt.Printf(" hash is h0 = %x\n", h0) fmt.Printf(" time id is n = %x[%d]\n", timeIdBytes, timeId) fmt.Printf(" h(t) = %x\n", hashedTimeId) - fmt.Printf(" ---\n") - fmt.Printf(" x1 is h0+h(t) = %x\n", x1) - fmt.Printf(" ---\n") + fmt.Printf(" x1 is h0+h(t) = %X\n", x1) fmt.Printf(" check x1+h(t) eq h0 = %x\n", xor.ByteArray(x1, hashedTimeId)) fmt.Printf(" check x1+h0 eq h(t) = %x\n", xor.ByteArray(x1, h0)) } /* (2) Calculate x2 = h ^ h(timeId) ^ timeMod */ - x2 = xor.ByteArray(h1, hashedTimeId) + copy(x2, xor.ByteArray(h1, hashedTimeId)) // only add time mod if code = 0 if c.key.MigrationCode() == 0 { @@ -264,10 +262,10 @@ func (c *T) generateRequest(x1 []byte, x2 []byte) error { fmt.Printf(" next is h1 = %x\n", h1) fmt.Printf(" time mod is m = %x[%d]\n", timeMod, timeMod) fmt.Printf(" h(t) = %x\n", hashedTimeId) - fmt.Printf(" ---\n") - fmt.Printf(" x2 is h1+h(t)+m = %x\n", x2) - fmt.Printf(" ---\n") - fmt.Printf(" check x2+x1 %% 2 eq m = %d (%t)\n", uint8(xor.ByteArray(x1, x2)[0]%2), xor.ByteArray(x1, x2)[0]%2 == byte(timeMod)) + if c.key.MigrationCode() == 0 { fmt.Printf(" x2 is h1+h(t)+m = %X\n", x2) + } else { fmt.Printf(" x2 is h1+h(t) = %X\n", x2) } + if c.key.MigrationCode() == 0 { fmt.Printf(" check x2+x1 %% 2 eq m = %d (%t)\n", uint8(xor.ByteArray(x1, x2)[0]%2), xor.ByteArray(x1, x2)[0]%2 == byte(timeMod)) + } else { fmt.Printf(" check x2+x1 %% 2 eq m = %d (%t)\n", uint8(xor.ByteArray(x1, x2)[0]%2), xor.ByteArray(x1, x2)[0]%2 == byte(timeMod)) } fmt.Printf(" check x2+x1 %% 3 eq o = %d (%t)\n", uint8(xor.ByteArray(x1, x2)[1]%3), uint8(xor.ByteArray(x1, x2)[1]%3) == c.key.MigrationCode()) } @@ -289,7 +287,7 @@ func (c *T) rescue(y1 []byte, y2 []byte) error { /* (2) Try to guess time id from timeM */ timeId := timeid.Guess(c.ctx.Window(), timeMod) - var timeIdBytes []byte + timeIdBytes := make([]byte, 4) binary.BigEndian.PutUint32(timeIdBytes, timeId) /* (3) Hash timeId */ diff --git a/src/git.xdrm.io/schastsp/client/keyset/keyset.go b/src/git.xdrm.io/schastsp/client/keyset/keyset.go index 583fd7f..20f70f6 100644 --- a/src/git.xdrm.io/schastsp/client/keyset/keyset.go +++ b/src/git.xdrm.io/schastsp/client/keyset/keyset.go @@ -57,7 +57,7 @@ func Create(ctx *context.T) (*T, error) { func (s T) CurrentHash() ([]byte, error) { /* (1) Get digest */ - digest, err := scha.Hash(s.sec, uint(s.depth)) + digest, err := scha.Hash(s.sec, s.depth) /* (2) Dispatch error */ if err != nil { diff --git a/src/git.xdrm.io/schastsp/lib/scha/hash.go b/src/git.xdrm.io/schastsp/lib/scha/hash.go index 975e783..1a8cbbc 100644 --- a/src/git.xdrm.io/schastsp/lib/scha/hash.go +++ b/src/git.xdrm.io/schastsp/lib/scha/hash.go @@ -50,7 +50,7 @@ func hash(input []byte) []byte{ * @return err If consistence error * ---------------------------------------------------------*/ -func Hash(input []byte, depth uint, options... []byte) ([]byte, error) { +func Hash(input []byte, depth uint16, options... []byte) ([]byte, error) { /* (1) Manage errors errors diff --git a/src/git.xdrm.io/schastsp/server/server.go b/src/git.xdrm.io/schastsp/server/server.go index 6d8f16c..1208e28 100644 --- a/src/git.xdrm.io/schastsp/server/server.go +++ b/src/git.xdrm.io/schastsp/server/server.go @@ -1,6 +1,7 @@ package server import ( + "git.xdrm.io/schastsp/lib/scha" "io" "os" "path/filepath" @@ -57,6 +58,7 @@ func New(ctx *context.T, savePath string) (*T, error) { inst.conf = absolutePath; /* (5) Try to fetch hash from conf */ + inst.hash = make([]byte, scha.HSIZE) err = inst.fetch(); if err != nil { return nil, err } @@ -74,4 +76,63 @@ func New(ctx *context.T, savePath string) (*T, error) { * @return err Error or NIL if not * ---------------------------------------------------------*/ -func (s *T) HandleRequest(req io.Reader, res io.Writer) error { return nil } \ No newline at end of file +func (s *T) HandleRequest(req io.Reader, res io.Writer) error { + + /* (1) Manage request + ---------------------------------------------------------*/ + /* (1) Read x1 */ + x1 := make([]byte, scha.HSIZE); + read, err := req.Read(x1); + if err != nil { return err } + if uint16(read) != scha.HSIZE { return errors.New("Cannot read enough bytes") } + + /* (2) Read x2 */ + x2 := make([]byte, scha.HSIZE); + read, err = req.Read(x2); + if err != nil { return err } + if uint16(read) != scha.HSIZE { return errors.New("Cannot read enough bytes") } + + /* (3) Manage request */ + errCode, err := s.manageRequest(x1, x2) + if err != nil { return err } + + /* (4) Valid authentication */ + if errCode == 0 { + + response := []byte{0x00} + written, err := res.Write(response) + if written != 1 || err != nil { return err } + + return nil; + + } + + + /* (2) If not authenticated -> build resynchronisation response + ---------------------------------------------------------*/ + /* (1) Init y1 + y2 */ + y1 := make([]byte, scha.HSIZE) + y2 := make([]byte, scha.HSIZE) + + /* (2) Generate response */ + err = s.generateResynchronisationResponse(y1, y2) + if err != nil { return err } + + /* (3) Write error code */ + responseCode := []byte{errCode} + written, err := res.Write(responseCode); + if err != nil { return err } + if written != len(responseCode) { return errors.New("Cannot write response code") } + + /* (4) Write y1 into response */ + written, err = res.Write(y1) + if err != nil { return err } + if written != len(y1) { return errors.New("Cannot write y1") } + + /* (5) Write y2 into response */ + written, err = res.Write(y2) + if err != nil { return err } + if written != len(y1) { return errors.New("Cannot write y2") } + + return nil +} \ No newline at end of file diff --git a/src/git.xdrm.io/schastsp/server/server.internal.go b/src/git.xdrm.io/schastsp/server/server.internal.go index 634779a..04be474 100644 --- a/src/git.xdrm.io/schastsp/server/server.internal.go +++ b/src/git.xdrm.io/schastsp/server/server.internal.go @@ -1,6 +1,9 @@ package server import ( + "fmt" + "git.xdrm.io/schastsp/lib/timeid" + "git.xdrm.io/schastsp/lib/xor" "git.xdrm.io/schastsp/lib/scha" "encoding/binary" "os" @@ -49,7 +52,7 @@ func (s *T) fetch() error { /* (3) Try to fetch hash from file */ fetchedHash := make([]byte, scha.HSIZE) - err = binary.Read(file, binary.BigEndian, s.hash) + err = binary.Read(file, binary.BigEndian, fetchedHash) if err != nil { return err } /* (4) Fail if wrong size */ @@ -58,8 +61,149 @@ func (s *T) fetch() error { } /* (5) Copy fetched hash into real one */ - s.hash = fetchedHash + copy(s.hash, fetchedHash) return nil -} \ No newline at end of file +} + + + +/* (3) Request management +* +* @x1<[]byte> First request component +* @x2<[]byte> Second request component +* +* @return code Error code +* 0 -> authenticated +* 1 -> request error -> may resynchronise +* 2 -> Unknown error (check in returned 'err') +* @return err Error or NIL if not +* +---------------------------------------------------------*/ +func (s *T) manageRequest(x1 []byte, x2 []byte) (byte, error) { + + if DEBUG { fmt.Printf(" stored hash is H = %x\n", s.hash) } + + /* (1) Extract meta data + ---------------------------------------------------------*/ + /* (1) Get xor between x1 and x2 */ + x := xor.ByteArray(x1, x2) + + /* (2) Extract migration code */ + mcode := uint8(x[1]) % 3; + + /* (3) Fail if no migration but different hashes */ + if mcode == 0 && string(x1[2:]) != string(x2[2:]) { + return 1, nil + } + + + /* (2) TimeID management + ---------------------------------------------------------*/ + /* (1) Extract time mod */ + timeMod := uint32(x[0]) % 2 + + /* (2) Try to guess time id */ + timeId := timeid.Guess(s.ctx.Window(), timeMod) + timeIdBytes := make([]byte, 4) + fmt.Printf("Server.time[%d, %d]\n", timeId, timeMod); + binary.BigEndian.PutUint32(timeIdBytes, timeId) + + /* (3) Hash guessed time id */ + hashedTimeId, err := scha.Hash(timeIdBytes, 1); + if err != nil { return 2, err } + + + /* (3) Extract hashes + ---------------------------------------------------------*/ + /* (1) Extract hash from x0 */ + h0 := xor.ByteArray(x1, hashedTimeId) + if DEBUG { fmt.Printf(" supposing hash is h0 = %x\n", h0) } + + /* (2) Extract next hash from x1 */ + h1 := xor.ByteArray(x2, hashedTimeId) + if DEBUG { fmt.Printf(" supposing next is h1 = %x\n", h1) } + + /* (3) Only remove timeMod if migration code = 0 */ + if mcode == 0 { + h1[0] = xor.Byte(h1[0], byte(timeMod)) + } + + + + /* (4) Hash h0 to compare with stored hash 's.hash' + ---------------------------------------------------------*/ + /* (1) Hash 1 time to check if matches */ + hashedH0, err := scha.Hash(h0, 1) + if err != nil { return 2, err } + if DEBUG { fmt.Printf(" hashed is h(h0) = %x\n", hashedH0) } + + /* (2) If migration code = 2 (Rescue mode) -> hash MIN times */ + if mcode == 2 { + hashedH0, err = scha.Hash(h0, s.ctx.MinDepth()) + if err != nil { return 2, err } + } + + /* (3) Fail if does not match */ + if string(hashedH0) != string(s.hash) { + return 1, nil + } + + + /* (5) Store next hash + ---------------------------------------------------------*/ + copy(s.hash, h1) + s.store(); + + return 0, nil + +} + + + +/* (4) Generate resynchronisation response +* +* @y1<[]byte> First response component to write into +* @y2<[]byte> Second response component to write into +* +* @return err Error or nil if not +* +---------------------------------------------------------*/ +func (s *T) generateResynchronisationResponse(y1 []byte, y2 []byte) error { + + /* (1) Get current time id */ + timeId, timeMod := timeid.Generate(s.ctx.Window()) + + /* (3) Hash the time id */ + timeIdBytes := make([]byte, 4) + binary.BigEndian.PutUint32(timeIdBytes, timeId) + + hashedTimeId, err := scha.Hash(timeIdBytes, 1); + if err != nil { return err } + + /* (4) Process y1 = H ^ h(timeId) */ + copy(y1, xor.ByteArray(s.hash, hashedTimeId)) + + /* (5) Process y2 = H ^ h(timeId) ^ timeMod = y1 ^ timeMod */ + copy(y2, xor.ByteArray(s.hash, hashedTimeId)) + y2[0] = xor.Byte(y2[0], byte(timeMod)) + + if DEBUG { + + fmt.Printf("=== y1 ===\n") + fmt.Printf(" hash is H = %x\n", s.hash) + fmt.Printf(" time id is t = %x[%d]\n", timeId, timeId) + fmt.Printf(" h(t) = %x\n", hashedTimeId) + fmt.Printf(" y1 is H+h(t) = %x\n", y1) + fmt.Printf(" check y1+h(t) eq H = %x\n", xor.ByteArray(y1, hashedTimeId)) + fmt.Printf(" check y1+H eq h(t) = %x\n", xor.ByteArray(y1, s.hash)) + + fmt.Printf("=== y2 ===\n") + fmt.Printf(" time mod is m = %x[%d]\n", timeMod, timeMod) + fmt.Printf(" y2 is y1+m = %x\n", y2) + } + + return nil + +}