[client:client] implemented 'Send(io.Writer)' [client:client.internal] implemented 'generateRequest', 'generateKeyWithConstraints', 'migrate'

This commit is contained in:
xdrm-brackets 2018-04-22 18:45:30 +02:00
parent fdab12841c
commit 3b282e397b
2 changed files with 223 additions and 2 deletions

View File

@ -6,6 +6,8 @@ import (
"git.xdrm.io/schastsp/client/keyset" "git.xdrm.io/schastsp/client/keyset"
) )
const DEBUG = false
/* (1) Structure /* (1) Structure
---------------------------------------------------------*/ ---------------------------------------------------------*/
@ -58,7 +60,22 @@ func New(ctx *context.T, saveDir string) (*T, error) {
* @return err<error> Error * @return err<error> Error
* *
---------------------------------------------------------*/ ---------------------------------------------------------*/
func (c *T) Send(w io.Writer) error { return nil } func (c *T) Send(w io.Writer) error {
/* (1) Generate the request */
var x1, x2 []byte;
err := c.generateRequest(x1, x2);
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 }
return nil;
}
/* (4) Receives and processes a response /* (4) Receives and processes a response

View File

@ -1,6 +1,13 @@
package client; package client;
import "git.xdrm.io/schastsp/client/keyset" import (
"fmt"
"encoding/binary"
"git.xdrm.io/schastsp/lib/scha"
"git.xdrm.io/schastsp/lib/xor"
"git.xdrm.io/schastsp/lib/timeid"
"git.xdrm.io/schastsp/client/keyset"
)
/* (1) Updates 'key' and 'sync' with files /* (1) Updates 'key' and 'sync' with files
* *
@ -62,4 +69,201 @@ func (c *T) update(){
err = c.fsync.Store(c.sync) err = c.fsync.Store(c.sync)
if err != nil { panic("Cannot store sync") } if err != nil { panic("Cannot store sync") }
}
/* (2) Migrate current key
*
---------------------------------------------------------*/
func (c *T) migrateKey(){
var err error;
/* (1) Copy sync into key */
c.key = c.sync
/* (2) Regenerate sync */
c.sync, err = keyset.Create(c.ctx);
if err != nil { panic(err) }
/* (3) Store keysets to files */
c.update();
}
/* (3) Generate a new key respecting mod constraints (timeid + migration)
*
* @return newKey<*keyset.T> New key if found
* NIL on error
*
---------------------------------------------------------*/
func (c *T) generateKeyWithConstraints(){
/* Get current hash */
keyHash, err := c.key.Hash();
if err != nil { panic(err) }
/* Search key one is respects contraints */
for true {
/* (1) Get current time id
---------------------------------------------------------*/
_, timeMod := timeid.Generate(c.ctx.Window())
/* (2) Generate a new sync
---------------------------------------------------------*/
newKey, _ := keyset.Create(c.ctx);
/* (3) Check constraints
---------------------------------------------------------*/
/* (1) Get next hash */
syncHash, err := newKey.Hash()
if err != nil { continue }
if DEBUG { fmt.Printf("+ hash is '%x'\n", keyHash); }
if DEBUG { fmt.Printf("+ next hash is '%x'\n", syncHash); }
/* (2) Get time mod difference (first byte) */
timeConstraintValue := xor.Byte(keyHash[0], syncHash[0]);
if DEBUG { fmt.Printf(" %.2x ^ %.2x = %.2x[%d] %% 2 = %d == %d ? %t\n", keyHash[0], syncHash[0], timeConstraintValue, timeConstraintValue, uint32(timeConstraintValue) % 2, timeMod, uint32(timeConstraintValue) % 2 == timeMod ) }
/* (4) Retry if invalid time constraint */
if uint32(timeConstraintValue) % 2 != timeMod {
continue;
}
/* (5) Get migration mod difference (second byte) */
migrationConstraintValue := xor.Byte(keyHash[1], syncHash[2]);
if DEBUG { fmt.Printf(" %.2x ^ %.2x = %.2x[%d] %% 3 = %d == %d ? %t\n", keyHash[1], syncHash[1], migrationConstraintValue, migrationConstraintValue, uint8(migrationConstraintValue) % 3, c.key.MigrationCode(), uint8(migrationConstraintValue) % 3 == c.key.MigrationCode() ) }
/* (6) Retry if invalid time constraint */
if uint8(migrationConstraintValue) % 3 != c.key.MigrationCode() {
continue;
}
/* (7) Store new sync */
c.sync = newKey;
/* (8) Store keysets to files */
c.update()
break;
}
}
/* (4) Generate the client request
*
* @x1<[]byte> Byte array to write into
* @x2<[]byte> Byte array to write into
*
* @return err<error> The error or NIL if not
*
---------------------------------------------------------*/
func (c *T) generateRequest(x1 []byte, x2 []byte) error {
/* (1) Migrate if validated migration
---------------------------------------------------------*/
if c.key.MigrationCode() == 3 {
c.migrateKey();
}
/* (2) Decrement and get useful hashes
---------------------------------------------------------*/
/* (1) Decrement hash */
remainingHashes := c.key.Decrement()
c.update()
if DEBUG {
fmt.Printf("Remaining %x[%d] hashes\n", remainingHashes, remainingHashes)
fmt.Printf("Migration code is %d\n", c.key.MigrationCode())
}
/* (2) Store current hash */
h0, err := c.key.Hash();
if err != nil { return err }
/* (3) Copy into next hash (same value) */
h1, err := c.key.Hash();
if err != nil { return err }
/* (3) New sync hash if key consumed
---------------------------------------------------------*/
if c.key.MigrationCode() > 0 {
/* (1) Generate sync with constraints */
c.generateKeyWithConstraints();
/* (2) Notify key need for renewal */
c.key.MigrationCode(2);
/* (3) Store config */
c.update();
}
/* (4) Manage time id
---------------------------------------------------------*/
/* (1) Get current time id */
timeId, timeMod := timeid.Generate(c.ctx.Window())
/* (2) Convert time id to byte array */
timeIdBytes := make([]byte, 4)
binary.BigEndian.PutUint32(timeIdBytes, timeId)
/* (2) Get digest of time id */
hashedTimeId, err := scha.Hash(timeIdBytes, 1, nil, nil)
/* (5) Calculate x1 and x2
---------------------------------------------------------*/
/* (1) Calculate x1 = h ^ h(timeId) */
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(" 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)
// do not add time mod if not code = 0
if c.key.MigrationCode() != 0 {
return nil;
}
x2[0] = xor.Byte(x2[0], byte(timeMod))
if DEBUG {
fmt.Printf("\n=== x2 ===\n");
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))
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());
}
return nil;
} }