2018-04-22 19:46:31 +00:00
|
|
|
package server
|
|
|
|
|
|
|
|
import (
|
2018-04-24 16:26:54 +00:00
|
|
|
"encoding/binary"
|
|
|
|
"errors"
|
2018-04-22 22:02:55 +00:00
|
|
|
"fmt"
|
2018-04-25 06:17:20 +00:00
|
|
|
"git.xdrm.io/schastsp/util/scha"
|
|
|
|
"git.xdrm.io/schastsp/util/timeid"
|
|
|
|
"git.xdrm.io/schastsp/util/xor"
|
2018-04-22 19:46:31 +00:00
|
|
|
"os"
|
|
|
|
)
|
|
|
|
|
|
|
|
/* (1) Store hash into file
|
|
|
|
*
|
|
|
|
* @return err<error> 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 */
|
2018-04-24 16:26:54 +00:00
|
|
|
defer file.Close()
|
2018-04-22 19:46:31 +00:00
|
|
|
|
|
|
|
/* (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> 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 */
|
2018-04-24 16:26:54 +00:00
|
|
|
defer file.Close()
|
2018-04-22 19:46:31 +00:00
|
|
|
|
|
|
|
/* (3) Try to fetch hash from file */
|
|
|
|
fetchedHash := make([]byte, scha.HSIZE)
|
2018-04-22 22:02:55 +00:00
|
|
|
err = binary.Read(file, binary.BigEndian, fetchedHash)
|
2018-04-22 19:46:31 +00:00
|
|
|
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 */
|
2018-04-22 22:02:55 +00:00
|
|
|
copy(s.hash, fetchedHash)
|
2018-04-22 19:46:31 +00:00
|
|
|
|
|
|
|
return nil
|
|
|
|
|
2018-04-22 22:02:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* (3) Request management
|
|
|
|
*
|
|
|
|
* @x1<[]byte> First request component
|
|
|
|
* @x2<[]byte> Second request component
|
|
|
|
*
|
|
|
|
* @return code<byte> Error code
|
|
|
|
* 0 -> authenticated
|
|
|
|
* 1 -> request error -> may resynchronise
|
|
|
|
* 2 -> Unknown error (check in returned 'err')
|
|
|
|
* @return err<error> 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 */
|
2018-04-24 16:26:54 +00:00
|
|
|
mcode := uint8(x[1]) % 3
|
|
|
|
if DEBUG { fmt.Printf(" extracted code is o = %d\n", mcode) }
|
2018-04-22 22:02:55 +00:00
|
|
|
|
|
|
|
/* (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
|
2018-04-24 16:26:54 +00:00
|
|
|
if DEBUG { fmt.Printf(" extracted time mod m = %d\n", timeMod) }
|
2018-04-22 22:02:55 +00:00
|
|
|
|
|
|
|
/* (2) Try to guess time id */
|
2018-04-24 16:26:54 +00:00
|
|
|
timeID := timeid.Guess(s.ctx.Window(), timeMod)
|
|
|
|
timeIDBytes := make([]byte, 4)
|
|
|
|
binary.BigEndian.PutUint32(timeIDBytes, timeID)
|
2018-04-22 22:02:55 +00:00
|
|
|
|
|
|
|
/* (3) Hash guessed time id */
|
2018-04-24 16:26:54 +00:00
|
|
|
hashedTimeID, err := scha.Hash(timeIDBytes, 1)
|
2018-04-22 22:02:55 +00:00
|
|
|
if err != nil { return 2, err }
|
|
|
|
|
|
|
|
|
|
|
|
/* (3) Extract hashes
|
|
|
|
---------------------------------------------------------*/
|
|
|
|
/* (1) Extract hash from x0 */
|
2018-04-24 16:26:54 +00:00
|
|
|
h0 := xor.ByteArray(x1, hashedTimeID)
|
|
|
|
if DEBUG { fmt.Printf(" supposing hash is h0 = %x\n", h0) }
|
2018-04-22 22:02:55 +00:00
|
|
|
|
|
|
|
/* (2) Extract next hash from x1 */
|
2018-04-24 16:26:54 +00:00
|
|
|
h1 := xor.ByteArray(x2, hashedTimeID)
|
|
|
|
if DEBUG { fmt.Printf(" supposing next is h1 = %x\n", h1) }
|
2018-04-22 22:02:55 +00:00
|
|
|
|
|
|
|
/* (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 }
|
2018-04-24 16:26:54 +00:00
|
|
|
|
|
|
|
if DEBUG {
|
|
|
|
fmt.Printf(" hashed is h(min) = %x\n", hashedH0)
|
|
|
|
}
|
|
|
|
} else if DEBUG {
|
|
|
|
fmt.Printf(" hashed is h(h0) = %x\n", hashedH0)
|
|
|
|
}
|
2018-04-22 22:02:55 +00:00
|
|
|
|
|
|
|
/* (3) Fail if does not match */
|
|
|
|
if string(hashedH0) != string(s.hash) {
|
|
|
|
return 1, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* (5) Store next hash
|
|
|
|
---------------------------------------------------------*/
|
|
|
|
copy(s.hash, h1)
|
2018-04-24 16:26:54 +00:00
|
|
|
s.store()
|
2018-04-22 22:02:55 +00:00
|
|
|
|
|
|
|
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> Error or nil if not
|
|
|
|
*
|
|
|
|
---------------------------------------------------------*/
|
|
|
|
func (s *T) generateResynchronisationResponse(y1 []byte, y2 []byte) error {
|
|
|
|
|
|
|
|
/* (1) Get current time id */
|
2018-04-24 16:26:54 +00:00
|
|
|
timeID, timeMod := timeid.Generate(s.ctx.Window())
|
2018-04-22 22:02:55 +00:00
|
|
|
|
|
|
|
/* (3) Hash the time id */
|
2018-04-24 16:26:54 +00:00
|
|
|
timeIDBytes := make([]byte, 4)
|
|
|
|
binary.BigEndian.PutUint32(timeIDBytes, timeID)
|
2018-04-22 22:02:55 +00:00
|
|
|
|
2018-04-24 16:26:54 +00:00
|
|
|
hashedTimeID, err := scha.Hash(timeIDBytes, 1)
|
2018-04-22 22:02:55 +00:00
|
|
|
if err != nil { return err }
|
|
|
|
|
|
|
|
/* (4) Process y1 = H ^ h(timeId) */
|
2018-04-24 16:26:54 +00:00
|
|
|
copy(y1, xor.ByteArray(s.hash, hashedTimeID))
|
2018-04-22 22:02:55 +00:00
|
|
|
|
|
|
|
/* (5) Process y2 = H ^ h(timeId) ^ timeMod = y1 ^ timeMod */
|
2018-04-24 16:26:54 +00:00
|
|
|
copy(y2, xor.ByteArray(s.hash, hashedTimeID))
|
2018-04-22 22:02:55 +00:00
|
|
|
y2[0] = xor.Byte(y2[0], byte(timeMod))
|
|
|
|
|
|
|
|
if DEBUG {
|
|
|
|
fmt.Printf("=== y1 ===\n")
|
|
|
|
fmt.Printf(" hash is H = %x\n", s.hash)
|
2018-04-24 16:26:54 +00:00
|
|
|
fmt.Printf(" time id is t = %x[%d]\n", timeID, timeID)
|
|
|
|
fmt.Printf(" h(t) = %x\n", hashedTimeID)
|
2018-04-22 22:02:55 +00:00
|
|
|
fmt.Printf(" y1 is H+h(t) = %x\n", y1)
|
2018-04-24 16:26:54 +00:00
|
|
|
fmt.Printf(" check y1+h(t) eq H = %x\n", xor.ByteArray(y1, hashedTimeID))
|
2018-04-22 22:02:55 +00:00
|
|
|
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
|
|
|
|
|
|
|
|
}
|