package server import ( "encoding/binary" "errors" "fmt" "git.xdrm.io/schastsp/pkg/scha" "git.xdrm.io/schastsp/pkg/timeid" "git.xdrm.io/schastsp/pkg/xor" "os" ) /* (1) Store hash into file * * @return err Error or NIL if not * ---------------------------------------------------------*/ func (s T) store() error { /* (1) Try to open file for writing */ file, err := os.OpenFile(s.conf, os.O_RDWR|os.O_CREATE, 0755) if err != nil { return err } /* (2) Defer close */ defer file.Close() /* (3) Write hash into file */ err = binary.Write(file, binary.BigEndian, s.hash) if err != nil { return err } return nil } /* (2) Fetch hash from file * * @return err Error or NIL if not * ---------------------------------------------------------*/ func (s *T) fetch() error { /* (1) Try to open file for reading */ file, err := os.Open(s.conf) if err != nil { return err } /* (2) Defer close */ defer file.Close() /* (3) Try to fetch hash from file */ fetchedHash := make([]byte, scha.HSIZE) err = binary.Read(file, binary.BigEndian, fetchedHash) if err != nil { return err } /* (4) Fail if wrong size */ if uint16(len(fetchedHash)) != scha.HSIZE { return errors.New("Invalid hash size in file") } /* (5) Copy fetched hash into real one */ copy(s.hash, fetchedHash) return nil } /* (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 if DEBUG { fmt.Printf(" extracted code is o = %d\n", mcode) } /* (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 if DEBUG { fmt.Printf(" extracted time mod m = %d\n", timeMod) } /* (2) Try to guess time id */ timeID := timeid.Guess(s.ctx.Window(), timeMod) timeIDBytes := make([]byte, 4) 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 } /* (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 } if DEBUG { fmt.Printf(" hashed is h(min) = %x\n", hashedH0) } } else if DEBUG { fmt.Printf(" hashed is h(h0) = %x\n", hashedH0) } /* (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 }