simplify commit-reveal: only client sends commitment

streamline http handling and decrease RAM usage
This commit is contained in:
themighty1
2022-03-12 12:27:47 +03:00
parent f7f0ad5a24
commit b0fb0857e6
7 changed files with 400 additions and 635 deletions

View File

@@ -1,7 +1,6 @@
package evaluator package evaluator
import ( import (
"math"
"notary/meta" "notary/meta"
u "notary/utils" u "notary/utils"
) )
@@ -13,26 +12,22 @@ type Evaluator struct {
// they are meant to be read-only for evaluator // they are meant to be read-only for evaluator
meta []*meta.Circuit meta []*meta.Circuit
ttBlobs [][]byte // truth table blobs for each circuit ttBlobs [][]byte // truth table blobs for each circuit
olBlobs [][]byte // output labels blobs for each circuit
} }
func (e *Evaluator) Init(circuits []*meta.Circuit, c6Count int) { func (e *Evaluator) Init(circuits []*meta.Circuit, c6Count int) {
e.C6Count = c6Count e.C6Count = c6Count
e.meta = circuits e.meta = circuits
e.ttBlobs = make([][]byte, len(e.meta)) e.ttBlobs = make([][]byte, len(e.meta))
e.olBlobs = make([][]byte, len(e.meta))
} }
// Evaluate evaluates a circuit number cNo // Evaluate evaluates a circuit number cNo
func (e *Evaluator) Evaluate(cNo int, notaryLabels, clientLabels, func (e *Evaluator) Evaluate(cNo int, notaryLabels, clientLabels,
truthTables, decodingTable []byte) []byte { truthTables []byte) []byte {
type batch_t struct { type batch_t struct {
// wl is wire labels // wl is wire labels
wl *[][]byte wl *[][]byte
// tt is truth tables // tt is truth tables
tt *[]byte tt *[]byte
// dt is decoding table
dt *[]byte
} }
c := (e.meta)[cNo] c := (e.meta)[cNo]
@@ -40,7 +35,6 @@ func (e *Evaluator) Evaluate(cNo int, notaryLabels, clientLabels,
nlBatch := u.SplitIntoChunks(notaryLabels, c.NotaryInputSize*16) nlBatch := u.SplitIntoChunks(notaryLabels, c.NotaryInputSize*16)
clBatch := u.SplitIntoChunks(clientLabels, c.ClientInputSize*16) clBatch := u.SplitIntoChunks(clientLabels, c.ClientInputSize*16)
ttBatch := u.SplitIntoChunks(truthTables, c.AndGateCount*48) ttBatch := u.SplitIntoChunks(truthTables, c.AndGateCount*48)
dtBatch := u.SplitIntoChunks(decodingTable, int(math.Ceil(float64(c.OutputSize)/8)))
// exeCount is how many executions of this circuit we need // exeCount is how many executions of this circuit we need
exeCount := []int{0, 1, 1, 1, 1, 1, e.C6Count, 1}[cNo] exeCount := []int{0, 1, 1, 1, 1, 1, e.C6Count, 1}[cNo]
@@ -49,41 +43,17 @@ func (e *Evaluator) Evaluate(cNo int, notaryLabels, clientLabels,
// put all input labels into wire labels // put all input labels into wire labels
wireLabels := make([][]byte, c.WireCount) wireLabels := make([][]byte, c.WireCount)
copy(wireLabels, u.SplitIntoChunks(u.Concat(nlBatch[r], clBatch[r]), 16)) copy(wireLabels, u.SplitIntoChunks(u.Concat(nlBatch[r], clBatch[r]), 16))
batch[r] = batch_t{&wireLabels, &ttBatch[r], &dtBatch[r]} batch[r] = batch_t{&wireLabels, &ttBatch[r]}
} }
var output []byte encodedOutput := make([][]byte, exeCount)
for r := 0; r < exeCount; r++ { for r := 0; r < exeCount; r++ {
plaintext := evaluate(c, batch[r].wl, batch[r].tt, batch[r].dt) encodedOutput[r] = evaluate(c, batch[r].wl, batch[r].tt)
// plaintext has a padding in MSB to make it a multiple of 8 bits. We
// decompose into bits and drop the padding
outBits := u.BytesToBits(plaintext)[0:c.OutputSize]
// reverse output bits so that the values of the output be placed in
// the same order as they appear in the *.casm files
outBytes := e.parseOutputBits(cNo, outBits)
output = append(output, outBytes...)
} }
return output return u.Concat(encodedOutput...)
} }
// parseOutputBits converts the output bits of the circuit into a flat slice func evaluate(c *meta.Circuit, wireLabels *[][]byte, truthTables *[]byte) []byte {
// of bytes so that output values are in the same order as they appear in the *.casm files
func (e *Evaluator) parseOutputBits(cNo int, outBits []int) []byte {
o := 0 // offset
var outBytes []byte
for _, v := range (e.meta)[cNo].OutputsSizes {
output := u.BitsToBytes(outBits[o : o+v])
outBytes = append(outBytes, output...)
o += v
}
if o != (e.meta)[cNo].OutputSize {
panic("o != e.g.Cs[cNo].OutputSize")
}
return outBytes
}
func evaluate(c *meta.Circuit, wireLabels *[][]byte, truthTables *[]byte,
decodingTable *[]byte) []byte {
andGateIdx := 0 andGateIdx := 0
// gate type XOR==0 AND==1 INV==2 // gate type XOR==0 AND==1 INV==2
for i := 0; i < len(c.Gates); i++ { for i := 0; i < len(c.Gates); i++ {
@@ -99,16 +69,12 @@ func evaluate(c *meta.Circuit, wireLabels *[][]byte, truthTables *[]byte,
panic("Unknown gate") panic("Unknown gate")
} }
} }
// return encoded output
// decode output labels
// get decoding table: LSB of label0 for each output wire
outLSBs := make([]int, c.OutputSize) outLSBs := make([]int, c.OutputSize)
for i := 0; i < c.OutputSize; i++ { for i := 0; i < c.OutputSize; i++ {
outLSBs[i] = int((*wireLabels)[c.WireCount-c.OutputSize+i][15]) & 1 outLSBs[i] = int((*wireLabels)[c.WireCount-c.OutputSize+i][15]) & 1
} }
encodings := u.BitsToBytes(outLSBs) return u.BitsToBytes(outLSBs)
plaintext := u.XorBytes(*decodingTable, encodings)
return plaintext
} }
func evaluateAnd(g meta.Gate, wireLabels *[][]byte, truthTables *[]byte, andGateIdx int) { func evaluateAnd(g meta.Gate, wireLabels *[][]byte, truthTables *[]byte, andGateIdx int) {

View File

@@ -25,16 +25,16 @@ type gc struct {
// Blob is what is returned when gc is read from disk // Blob is what is returned when gc is read from disk
type Blob struct { type Blob struct {
Il *[]byte Il *[]byte
// we dont return bytes of tt and dt because we gonna be streaming the file // we dont return bytes of tt because we gonna be streaming the file
// directly into the HTTP response to save memory // directly into the HTTP response to save memory
TtFile *os.File TtFile *os.File
DtFile *os.File Dt *[]byte
} }
type GarbledPool struct { type GarbledPool struct {
// gPDirPath is full path to the garbled pool dir // gPDirPath is full path to the garbled pool dir
gPDirPath string gPDirPath string
// AES-GCM keys to encrypt/authenticate circuits' labels. // AES-GCM keys to encrypt/authenticate circuits' blob.
// We need to encrypt them in case we want to store them outside the enclave. // We need to encrypt them in case we want to store them outside the enclave.
// When the encryption key changes, older keys are kept because we still // When the encryption key changes, older keys are kept because we still
// have labels on disk encrypted with old keys. // have labels on disk encrypted with old keys.
@@ -55,7 +55,7 @@ type GarbledPool struct {
// the amount of c5 circuits will be poolSize*100 because on average one // the amount of c5 circuits will be poolSize*100 because on average one
// session needs that many garbled c5 circuits // session needs that many garbled c5 circuits
poolSize int poolSize int
// Circuits's count starts from 1 // Circuits contains metainfo for each circuit. Circuit count starts from 1
Circuits []*meta.Circuit Circuits []*meta.Circuit
grb garbler.Garbler grb garbler.Garbler
// noSandbox is set to true when not running in a sandboxed environment // noSandbox is set to true when not running in a sandboxed environment
@@ -112,12 +112,13 @@ func (g *GarbledPool) Init(noSandbox bool) {
} }
// returns 1 garbling of each circuit and c5Count garblings for circuit 5 // returns 1 garbling of each circuit and c5Count garblings for circuit 5
func (g *GarbledPool) GetBlobs(c6Count int) []Blob { func (g *GarbledPool) GetBlobs(c6Count int) [][]Blob {
if c6Count > 1026 { if c6Count > 1026 {
panic("c6Count > 1026") panic("c6Count > 1026")
} }
var allBlobs []Blob
// we don't use index 0 for clarity, count starts from 1
allBlobs := make([][]Blob, len(g.Circuits))
// fetch blobs // fetch blobs
for i := 1; i < len(g.Circuits); i++ { for i := 1; i < len(g.Circuits); i++ {
iStr := strconv.Itoa(i) iStr := strconv.Itoa(i)
@@ -140,7 +141,7 @@ func (g *GarbledPool) GetBlobs(c6Count int) []Blob {
g.pool[iStr] = g.pool[iStr][1:] g.pool[iStr] = g.pool[iStr][1:]
g.Unlock() g.Unlock()
blob := g.fetchBlob(iStr, gc) blob := g.fetchBlob(iStr, gc)
allBlobs = append(allBlobs, blob) allBlobs[i] = append(allBlobs[i], blob)
} }
} }
return allBlobs return allBlobs
@@ -244,12 +245,16 @@ func (g *GarbledPool) monitor() {
func (g *GarbledPool) saveBlob(path string, il *[]byte, tt *[]byte, dt *[]byte) { func (g *GarbledPool) saveBlob(path string, il *[]byte, tt *[]byte, dt *[]byte) {
var ilToWrite *[]byte var ilToWrite *[]byte
// we only encrypt input labels var dtToWrite *[]byte
// we encrypt input labels and decoding table
if !g.noSandbox { if !g.noSandbox {
ilEnc := u.AESGCMencrypt(g.key, *il) ilEnc := u.AESGCMencrypt(g.key, *il)
ilToWrite = &ilEnc ilToWrite = &ilEnc
dtEnc := u.AESGCMencrypt(g.key, *dt)
dtToWrite = &dtEnc
} else { } else {
ilToWrite = il ilToWrite = il
dtToWrite = dt
} }
err := os.WriteFile(path+"_il", *ilToWrite, 0644) err := os.WriteFile(path+"_il", *ilToWrite, 0644)
if err != nil { if err != nil {
@@ -259,13 +264,14 @@ func (g *GarbledPool) saveBlob(path string, il *[]byte, tt *[]byte, dt *[]byte)
if err != nil { if err != nil {
panic(err) panic(err)
} }
err = os.WriteFile(path+"_dt", *dt, 0644) err = os.WriteFile(path+"_dt", *dtToWrite, 0644)
if err != nil { if err != nil {
panic(err) panic(err)
} }
} }
// fetches the blob from disk and deletes it // fetches the blob from disk and deletes il and dt. tt will be deleted later
// by the caller.
func (g *GarbledPool) fetchBlob(circuitNo string, c gc) Blob { func (g *GarbledPool) fetchBlob(circuitNo string, c gc) Blob {
fullPath := filepath.Join(g.gPDirPath, "c"+circuitNo, c.id) fullPath := filepath.Join(g.gPDirPath, "c"+circuitNo, c.id)
il, err := os.ReadFile(fullPath + "_il") il, err := os.ReadFile(fullPath + "_il")
@@ -276,7 +282,16 @@ func (g *GarbledPool) fetchBlob(circuitNo string, c gc) Blob {
if err != nil { if err != nil {
panic(err) panic(err)
} }
// only the file handle of truth tables and decoding tables is returned, dt, err2 := os.ReadFile(fullPath + "_dt")
if err2 != nil {
panic(err2)
}
err = os.Remove(fullPath + "_dt")
if err != nil {
panic(err)
}
// only the file handle of truth tables is returned,
// so that the file could be streamed (avoiding a full copy into memory) // so that the file could be streamed (avoiding a full copy into memory)
// The session which receives this handle will be responsible for // The session which receives this handle will be responsible for
// deleting the file // deleting the file
@@ -284,17 +299,16 @@ func (g *GarbledPool) fetchBlob(circuitNo string, c gc) Blob {
if err3 != nil { if err3 != nil {
panic(err3) panic(err3)
} }
dtFile, err4 := os.Open(fullPath + "_dt")
if err4 != nil {
panic(err4)
}
var ilToReturn = &il var ilToReturn = &il
var dtToReturn = &dt
if !g.noSandbox { if !g.noSandbox {
// decrypt data from disk when in a sandbox // decrypt data from disk when in a sandbox
ilDec := u.AESGCMdecrypt(g.keys[c.keyIdx], il) ilDec := u.AESGCMdecrypt(g.keys[c.keyIdx], il)
ilToReturn = &ilDec ilToReturn = &ilDec
dtDec := u.AESGCMdecrypt(g.keys[c.keyIdx], dt)
dtToReturn = &dtDec
} }
return Blob{ilToReturn, ttFile, dtFile} return Blob{ilToReturn, ttFile, dtToReturn}
} }
// Convert the circuits from the "Bristol fashion" format into a compact // Convert the circuits from the "Bristol fashion" format into a compact

View File

@@ -16,34 +16,32 @@ type Garbler struct {
Cs []CData Cs []CData
} }
// CData is circuit's data // CData is data for one circuit
type CData struct { type CData struct {
Il []byte // input labels // Il contains a flat slice of all input labels for all executions of
// InputBits start with least input bit at index [0] // one circuit
InputBits []int // notary's input for this circuit Il []byte
Masks [][]byte // InputBits is notary's input for this circuit. Starts with the least
Meta *meta.Circuit // input bit at index [0].
InputBits []int
// Masks are notary's masks. They are inputs to the circuit. Their purpose
// is to mask the circuit's output. Mask numbering starts with 1 for
// convenience. Consult circuits/*.casm files for description of what each
// mask does.
Masks [][]byte
Meta *meta.Circuit
} }
// Init puts input labels into correspondign circuits and creates masks for // Init puts input labels into correspondign circuits and creates masks for
// notary's inputs to the circuits. // notary's inputs to the circuits.
// ilBlobs contains slices of input labels for each execution // il contains input labels for each execution of each circuit
func (g *Garbler) Init(ilBlobs []*[]byte, circuits []*meta.Circuit, c6Count int) { func (g *Garbler) Init(il [][][]byte, circuits []*meta.Circuit, c6Count int) {
g.C6Count = c6Count g.C6Count = c6Count
g.Cs = make([]CData, len(circuits)) g.Cs = make([]CData, len(circuits))
for i := 1; i < len(g.Cs); i++ { for i := 1; i < len(g.Cs); i++ {
if i < 6 { g.Cs[i].Il = u.Concat(il[i]...)
g.Cs[i].Il = *ilBlobs[i-1]
} else if i == 6 {
g.Cs[i].Il = u.ConcatP(ilBlobs[5 : 5+c6Count]...)
} else if i > 6 {
g.Cs[i].Il = *ilBlobs[c6Count-1+i-1]
}
g.Cs[i].Meta = circuits[i] g.Cs[i].Meta = circuits[i]
// mask numbering starts at 1 for convenience
// consult circuits/*.casm files for what each mask does
if i == 1 { if i == 1 {
g.Cs[i].Masks = make([][]byte, 2) g.Cs[i].Masks = make([][]byte, 2)
g.Cs[i].Masks[1] = u.GetRandom(32) g.Cs[i].Masks[1] = u.GetRandom(32)

View File

@@ -21,9 +21,9 @@ import (
type KeyManager struct { type KeyManager struct {
sync.Mutex sync.Mutex
// Blob contains validFrom|validUntil|pubkey|signature // KeyData contains validFrom|validUntil|pubkey|signature
// the client will verify the signature (made with the masterKey) // the client will verify the signature (made with the masterKey)
Blob []byte KeyData []byte
// PrivKey is the ephemeral key used to sign a session. Also used // PrivKey is the ephemeral key used to sign a session. Also used
// in ECDH with the the client to derive symmetric keys to encrypt the communication // in ECDH with the the client to derive symmetric keys to encrypt the communication
PrivKey *ecdsa.PrivateKey PrivKey *ecdsa.PrivateKey
@@ -40,6 +40,19 @@ func (k *KeyManager) Init() {
go k.rotateEphemeralKeys() go k.rotateEphemeralKeys()
} }
// GetActiveKey returns the currently active signing key as well as KeyData
// associated with it
func (k *KeyManager) GetActiveKey() (ecdsa.PrivateKey, []byte) {
// copying data so that it doesn't change from under us if
// ephemeral key happens to change while this session is running
k.Lock()
keyData := make([]byte, len(k.KeyData))
copy(keyData, k.KeyData)
key := *k.PrivKey
k.Unlock()
return key, keyData
}
// generateMasterKey generates a P-256 master key. The corresponding public key // generateMasterKey generates a P-256 master key. The corresponding public key
// in PEM format is written to disk // in PEM format is written to disk
func (k *KeyManager) generateMasterKey() { func (k *KeyManager) generateMasterKey() {
@@ -94,7 +107,7 @@ func (k *KeyManager) rotateEphemeralKeys() {
signature := u.ECDSASign(k.masterKey, validFrom, validUntil, pubkey) signature := u.ECDSASign(k.masterKey, validFrom, validUntil, pubkey)
blob := u.Concat(validFrom, validUntil, pubkey, signature) blob := u.Concat(validFrom, validUntil, pubkey, signature)
k.Lock() k.Lock()
k.Blob = blob k.KeyData = blob
k.PrivKey = newKey k.PrivKey = newKey
k.Unlock() k.Unlock()
} }

View File

@@ -67,49 +67,43 @@ func destroyOnPanic(s *session.Session) {
s.DestroyChan <- s.Sid s.DestroyChan <- s.Sid
} }
func init1(w http.ResponseWriter, req *http.Request) { func httpHandler(w http.ResponseWriter, req *http.Request) {
log.Println("in init1", req.RemoteAddr) // sessionId is the part of the URL after ?
s := sm.AddSession(string(req.URL.RawQuery)) sessionId := string(req.URL.RawQuery)
// command is URL path without the leading /
command := req.URL.Path[1:]
log.Println("got request ", command, " from ", req.RemoteAddr)
var out []byte
if command == "init1" {
s := sm.AddSession(sessionId)
s.Gp = gp
key, keyData := km.GetActiveKey()
s.SigningKey = key
// keyData is sent to Client unencrypted
out = append(out, keyData...)
}
s := sm.GetSession(sessionId)
defer destroyOnPanic(s) defer destroyOnPanic(s)
method := sm.GetMethod(command, sessionId)
body := readBody(req) body := readBody(req)
s.Gp = gp out = append(out, method(body)...)
// copying data so that it doesn't change from under us if
// ephemeral key happens to change while this session is running
km.Lock()
blob := make([]byte, len(km.Blob))
copy(blob, km.Blob)
key := *km.PrivKey
km.Unlock()
out := s.Init1(body, blob, key)
writeResponse(out, w)
}
func init2(w http.ResponseWriter, req *http.Request) {
log.Println("in init2", req.RemoteAddr)
s := sm.GetSession(string(req.URL.RawQuery))
defer destroyOnPanic(s)
body := readBody(req)
out := s.Init2(body)
writeResponse(out, w) writeResponse(out, w)
if command == "commitHash" {
// this was the final message of the session. Destroying the session...
s.DestroyChan <- s.Sid
}
} }
// getBlob is called when user wants to download garbled circuits
func getBlob(w http.ResponseWriter, req *http.Request) { func getBlob(w http.ResponseWriter, req *http.Request) {
log.Println("in getBlob", req.RemoteAddr) log.Println("in getBlob", req.RemoteAddr)
s := sm.GetSession(string(req.URL.RawQuery)) s := sm.GetSession(string(req.URL.RawQuery))
defer destroyOnPanic(s) defer destroyOnPanic(s)
body := readBody(req) body := readBody(req)
tt, dt := s.GetBlob(body) fileHandles := s.GetBlob(body)
// send headers first
writeResponse(nil, w) writeResponse(nil, w)
// stream decoding table directly from file // stream directly from file
for _, f := range dt { for _, f := range fileHandles {
_, err := io.Copy(w, f)
if err != nil {
panic("err != nil")
}
}
// stream decoding table directly from file
for _, f := range tt {
_, err := io.Copy(w, f) _, err := io.Copy(w, f)
if err != nil { if err != nil {
panic("err != nil") panic("err != nil")
@@ -117,6 +111,7 @@ func getBlob(w http.ResponseWriter, req *http.Request) {
} }
} }
// setBlob is called when user wants to upload garbled circuits
func setBlob(w http.ResponseWriter, req *http.Request) { func setBlob(w http.ResponseWriter, req *http.Request) {
log.Println("in setBlob", req.RemoteAddr) log.Println("in setBlob", req.RemoteAddr)
s := sm.GetSession(string(req.URL.RawQuery)) s := sm.GetSession(string(req.URL.RawQuery))
@@ -125,298 +120,9 @@ func setBlob(w http.ResponseWriter, req *http.Request) {
writeResponse(out, w) writeResponse(out, w)
} }
func getUploadProgress(w http.ResponseWriter, req *http.Request) {
log.Println("in getUploadProgress", req.RemoteAddr)
s := sm.GetSession(string(req.URL.RawQuery))
defer destroyOnPanic(s)
out := s.GetUploadProgress()
writeResponse(out, w)
}
func step1(w http.ResponseWriter, req *http.Request) {
log.Println("in step1", req.RemoteAddr)
s := sm.GetSession(string(req.URL.RawQuery))
defer destroyOnPanic(s)
body := readBody(req)
out := s.Step1(body)
writeResponse(out, w)
}
func step2(w http.ResponseWriter, req *http.Request) {
log.Println("in step2", req.RemoteAddr)
s := sm.GetSession(string(req.URL.RawQuery))
defer destroyOnPanic(s)
body := readBody(req)
out := s.Step2(body)
writeResponse(out, w)
}
func step3(w http.ResponseWriter, req *http.Request) {
log.Println("in step3", req.RemoteAddr)
s := sm.GetSession(string(req.URL.RawQuery))
defer destroyOnPanic(s)
body := readBody(req)
out := s.Step3(body)
writeResponse(out, w)
}
func step4(w http.ResponseWriter, req *http.Request) {
log.Println("in step4", req.RemoteAddr)
s := sm.GetSession(string(req.URL.RawQuery))
defer destroyOnPanic(s)
body := readBody(req)
out := s.Step4(body)
writeResponse(out, w)
}
func c1_step1(w http.ResponseWriter, req *http.Request) {
log.Println("in c1_step1", req.RemoteAddr)
s := sm.GetSession(string(req.URL.RawQuery))
defer destroyOnPanic(s)
body := readBody(req)
out := s.C1_step1(body)
writeResponse(out, w)
}
func c1_step2(w http.ResponseWriter, req *http.Request) {
log.Println("in c1_step2", req.RemoteAddr)
s := sm.GetSession(string(req.URL.RawQuery))
defer destroyOnPanic(s)
body := readBody(req)
out := s.C1_step2(body)
writeResponse(out, w)
}
func c1_step3(w http.ResponseWriter, req *http.Request) {
log.Println("in c1_step3", req.RemoteAddr)
s := sm.GetSession(string(req.URL.RawQuery))
defer destroyOnPanic(s)
body := readBody(req)
out := s.C1_step3(body)
writeResponse(out, w)
}
func c1_step4(w http.ResponseWriter, req *http.Request) {
log.Println("in c1_step4", req.RemoteAddr)
s := sm.GetSession(string(req.URL.RawQuery))
defer destroyOnPanic(s)
body := readBody(req)
out := s.C1_step4(body)
writeResponse(out, w)
}
func c1_step5(w http.ResponseWriter, req *http.Request) {
log.Println("in c1_step5", req.RemoteAddr)
s := sm.GetSession(string(req.URL.RawQuery))
defer destroyOnPanic(s)
body := readBody(req)
out := s.C1_step5(body)
writeResponse(out, w)
}
func c2_step1(w http.ResponseWriter, req *http.Request) {
log.Println("in c2_step1", req.RemoteAddr)
s := sm.GetSession(string(req.URL.RawQuery))
defer destroyOnPanic(s)
body := readBody(req)
out := s.C2_step1(body)
writeResponse(out, w)
}
func c2_step2(w http.ResponseWriter, req *http.Request) {
log.Println("in c2_step2", req.RemoteAddr)
s := sm.GetSession(string(req.URL.RawQuery))
defer destroyOnPanic(s)
body := readBody(req)
out := s.C2_step2(body)
writeResponse(out, w)
}
func c2_step3(w http.ResponseWriter, req *http.Request) {
log.Println("in c2_step3", req.RemoteAddr)
s := sm.GetSession(string(req.URL.RawQuery))
defer destroyOnPanic(s)
body := readBody(req)
out := s.C2_step3(body)
writeResponse(out, w)
}
func c2_step4(w http.ResponseWriter, req *http.Request) {
log.Println("in c2_step4", req.RemoteAddr)
s := sm.GetSession(string(req.URL.RawQuery))
defer destroyOnPanic(s)
body := readBody(req)
out := s.C2_step4(body)
writeResponse(out, w)
}
func c3_step1(w http.ResponseWriter, req *http.Request) {
log.Println("in c3_step1", req.RemoteAddr)
s := sm.GetSession(string(req.URL.RawQuery))
defer destroyOnPanic(s)
body := readBody(req)
out := s.C3_step1(body)
writeResponse(out, w)
}
func c3_step2(w http.ResponseWriter, req *http.Request) {
log.Println("in c3_step2", req.RemoteAddr)
s := sm.GetSession(string(req.URL.RawQuery))
defer destroyOnPanic(s)
body := readBody(req)
out := s.C3_step2(body)
writeResponse(out, w)
}
func c4_step1(w http.ResponseWriter, req *http.Request) {
log.Println("in c4_step1", req.RemoteAddr)
s := sm.GetSession(string(req.URL.RawQuery))
defer destroyOnPanic(s)
body := readBody(req)
out := s.C4_step1(body)
writeResponse(out, w)
}
func c4_step2(w http.ResponseWriter, req *http.Request) {
log.Println("in c4_step2", req.RemoteAddr)
s := sm.GetSession(string(req.URL.RawQuery))
defer destroyOnPanic(s)
body := readBody(req)
out := s.C4_step2(body)
writeResponse(out, w)
}
func c4_step3(w http.ResponseWriter, req *http.Request) {
log.Println("in c4_step3", req.RemoteAddr)
s := sm.GetSession(string(req.URL.RawQuery))
defer destroyOnPanic(s)
body := readBody(req)
out := s.C4_step3(body)
writeResponse(out, w)
}
func c5_pre1(w http.ResponseWriter, req *http.Request) {
log.Println("in c5_pre1", req.RemoteAddr)
s := sm.GetSession(string(req.URL.RawQuery))
defer destroyOnPanic(s)
body := readBody(req)
out := s.C5_pre1(body)
writeResponse(out, w)
}
func c5_step1(w http.ResponseWriter, req *http.Request) {
log.Println("in c5_step1", req.RemoteAddr)
s := sm.GetSession(string(req.URL.RawQuery))
defer destroyOnPanic(s)
body := readBody(req)
out := s.C5_step1(body)
writeResponse(out, w)
}
func c5_step2(w http.ResponseWriter, req *http.Request) {
log.Println("in c5_step2", req.RemoteAddr)
s := sm.GetSession(string(req.URL.RawQuery))
defer destroyOnPanic(s)
body := readBody(req)
out := s.C5_step2(body)
writeResponse(out, w)
}
func c5_step3(w http.ResponseWriter, req *http.Request) {
log.Println("in c5_step3", req.RemoteAddr)
s := sm.GetSession(string(req.URL.RawQuery))
defer destroyOnPanic(s)
body := readBody(req)
out := s.C5_step3(body)
writeResponse(out, w)
}
func c6_step1(w http.ResponseWriter, req *http.Request) {
log.Println("in c6_step1", req.RemoteAddr)
s := sm.GetSession(string(req.URL.RawQuery))
defer destroyOnPanic(s)
body := readBody(req)
out := s.C6_step1(body)
writeResponse(out, w)
}
func c6_step2(w http.ResponseWriter, req *http.Request) {
log.Println("in c6_step2", req.RemoteAddr)
s := sm.GetSession(string(req.URL.RawQuery))
defer destroyOnPanic(s)
body := readBody(req)
out := s.C6_step2(body)
writeResponse(out, w)
}
func c7_step1(w http.ResponseWriter, req *http.Request) {
log.Println("in c7_step1", req.RemoteAddr)
s := sm.GetSession(string(req.URL.RawQuery))
defer destroyOnPanic(s)
body := readBody(req)
out := s.C7_step1(body)
writeResponse(out, w)
}
func c7_step2(w http.ResponseWriter, req *http.Request) {
log.Println("in c7_step2", req.RemoteAddr)
s := sm.GetSession(string(req.URL.RawQuery))
defer destroyOnPanic(s)
body := readBody(req)
out := s.C7_step2(body)
writeResponse(out, w)
}
func checkC7Commit(w http.ResponseWriter, req *http.Request) {
log.Println("in checkC7Commit", req.RemoteAddr)
s := sm.GetSession(string(req.URL.RawQuery))
defer destroyOnPanic(s)
body := readBody(req)
out := s.CheckC7Commit(body)
writeResponse(out, w)
}
func ghash_step1(w http.ResponseWriter, req *http.Request) {
log.Println("in ghash_step1", req.RemoteAddr)
s := sm.GetSession(string(req.URL.RawQuery))
defer destroyOnPanic(s)
body := readBody(req)
out := s.Ghash_step1(body)
writeResponse(out, w)
}
func ghash_step2(w http.ResponseWriter, req *http.Request) {
log.Println("in ghash_step2", req.RemoteAddr)
s := sm.GetSession(string(req.URL.RawQuery))
defer destroyOnPanic(s)
body := readBody(req)
out := s.Ghash_step2(body)
writeResponse(out, w)
}
func ghash_step3(w http.ResponseWriter, req *http.Request) {
log.Println("in ghash_step3", req.RemoteAddr)
s := sm.GetSession(string(req.URL.RawQuery))
defer destroyOnPanic(s)
body := readBody(req)
out := s.Ghash_step3(body)
writeResponse(out, w)
}
func commitHash(w http.ResponseWriter, req *http.Request) {
log.Println("in commitHash", req.RemoteAddr)
s := sm.GetSession(string(req.URL.RawQuery))
defer destroyOnPanic(s)
body := readBody(req)
out := s.CommitHash(body)
writeResponse(out, w)
s.DestroyChan <- s.Sid
}
// when notary starts we expect the admin to upload a URLFetcher document // when notary starts we expect the admin to upload a URLFetcher document
// it can be uploaded e.g. with: // it can be uploaded e.g. with:
// curl --data-binary '@URLFetcherDoc' 127.0.0.1:10012/setURLFetcherDoc // curl --data-binary '@URLFetcherDoc' 127.0.0.1:10012/setURLFetcherDoc
func awaitURLFetcherDoc() { func awaitURLFetcherDoc() {
serverMux := http.NewServeMux() serverMux := http.NewServeMux()
srv := &http.Server{Addr: ":10012", Handler: serverMux} srv := &http.Server{Addr: ":10012", Handler: serverMux}
@@ -443,7 +149,7 @@ func getPubKey(w http.ResponseWriter, req *http.Request) {
} }
// initially the circuits are in the human-readable c*.casm format; assemble.js // initially the circuits are in the human-readable c*.casm format; assemble.js
// converts them into a "Bristol fashion" format and write to disk c*.out files // converts them into a "Bristol fashion" format and writes to disk c*.out files
func assembleCircuits() { func assembleCircuits() {
curDir, _ := filepath.Abs(filepath.Dir(os.Args[0])) curDir, _ := filepath.Abs(filepath.Dir(os.Args[0]))
baseDir := filepath.Dir(curDir) baseDir := filepath.Dir(curDir)
@@ -457,11 +163,16 @@ func assembleCircuits() {
log.Println("Error. Could not run: node assemble.js. Please make sure that node is installed on your system.") log.Println("Error. Could not run: node assemble.js. Please make sure that node is installed on your system.")
os.Exit(1) os.Exit(1)
} }
log.Println("Finished assembling circuits.")
} }
} }
func main() { func main() {
// uncomment the below to profile the process's RAM usage // uncomment the below to profile the process's RAM usage
// install with: go get github.com/pkg/profile
// then run: curl http://localhost:8080/debug/pprof/heap > heap
// go tool pprof -png heap
// defer profile.Start(profile.MemProfile).Stop() // defer profile.Start(profile.MemProfile).Stop()
// go func() { // go func() {
// http.ListenAndServe(":8080", nil) // http.ListenAndServe(":8080", nil)
@@ -487,64 +198,11 @@ func main() {
// can be useful when debugging sandboxed notary // can be useful when debugging sandboxed notary
http.HandleFunc("/getPubKey", getPubKey) http.HandleFunc("/getPubKey", getPubKey)
http.HandleFunc("/init1", init1)
http.HandleFunc("/init2", init2)
http.HandleFunc("/getBlob", getBlob) http.HandleFunc("/getBlob", getBlob)
http.HandleFunc("/setBlob", setBlob) http.HandleFunc("/setBlob", setBlob)
http.HandleFunc("/getUploadProgress", getUploadProgress)
// step1 thru step4 deal with Paillier 2PC // all the other request will end up in the httpHandler
http.HandleFunc("/step1", step1) http.HandleFunc("/", httpHandler)
http.HandleFunc("/step2", step2)
http.HandleFunc("/step3", step3)
http.HandleFunc("/step4", step4)
// c1_step1 thru c1_step1 deal with TLS Handshake
http.HandleFunc("/c1_step1", c1_step1)
http.HandleFunc("/c1_step2", c1_step2)
http.HandleFunc("/c1_step3", c1_step3)
http.HandleFunc("/c1_step4", c1_step4)
http.HandleFunc("/c1_step5", c1_step5)
// c2_step1 thru c2_step4 deal with TLS Handshake
http.HandleFunc("/c2_step1", c2_step1)
http.HandleFunc("/c2_step2", c2_step2)
http.HandleFunc("/c2_step3", c2_step3)
http.HandleFunc("/c2_step4", c2_step4)
// c3_step1 thru c4_step3 deal with TLS Handshake and also prepare data
// needed to send Client Finished
http.HandleFunc("/c3_step1", c3_step1)
http.HandleFunc("/c3_step2", c3_step2)
http.HandleFunc("/c4_step1", c4_step1)
http.HandleFunc("/c4_step2", c4_step2)
http.HandleFunc("/c4_step3", c4_step3)
// c5_pre1 thru c5_step3 check Server Finished
http.HandleFunc("/c5_pre1", c5_pre1)
http.HandleFunc("/c5_step1", c5_step1)
http.HandleFunc("/c5_step2", c5_step2)
http.HandleFunc("/c5_step3", c5_step3)
// c6_step1 thru c6_step2 prepare encrypted counter blocks for the
// client's request to the webserver
http.HandleFunc("/c6_step1", c6_step1)
http.HandleFunc("/c6_step2", c6_step2)
// c7_step1 thru c7_step2 prepare the GCTR block needed to compute the MAC
// for the client's request
http.HandleFunc("/c7_step1", c7_step1)
http.HandleFunc("/c7_step2", c7_step2)
http.HandleFunc("/checkC7Commit", checkC7Commit)
// steps ghash_step1 thru ghash_step3 compute the GHASH output needed to
// compute the MAC for the client's request
http.HandleFunc("/ghash_step1", ghash_step1)
http.HandleFunc("/ghash_step2", ghash_step2)
http.HandleFunc("/ghash_step3", ghash_step3)
http.HandleFunc("/commitHash", commitHash)
http.ListenAndServe("0.0.0.0:10011", nil) http.ListenAndServe("0.0.0.0:10011", nil)
} }

View File

@@ -7,7 +7,6 @@ import (
"encoding/binary" "encoding/binary"
"io" "io"
"log" "log"
"math"
"math/big" "math/big"
"notary/evaluator" "notary/evaluator"
"notary/garbled_pool" "notary/garbled_pool"
@@ -72,8 +71,8 @@ type Session struct {
notaryKey []byte notaryKey []byte
// clientKey is a symmetric key used to decrypt messages FROM the client // clientKey is a symmetric key used to decrypt messages FROM the client
clientKey []byte clientKey []byte
// signingKey is an ephemeral key used to sign the notarization session // SigningKey is an ephemeral key used to sign the notarization session
signingKey *ecdsa.PrivateKey SigningKey ecdsa.PrivateKey
// StorageDir is where the blobs from the client are stored // StorageDir is where the blobs from the client are stored
StorageDir string StorageDir string
// msgsSeen contains a list of all messages seen from the client // msgsSeen contains a list of all messages seen from the client
@@ -84,16 +83,21 @@ type Session struct {
PmsOuterHashState []byte PmsOuterHashState []byte
// MsOuterHashState is the state of the outer hash of HMAC needed to compute the MS // MsOuterHashState is the state of the outer hash of HMAC needed to compute the MS
MsOuterHashState []byte MsOuterHashState []byte
// Commitment is the hash of plaintext output for each circuit // hisCommitment is client's salted commitment for each circuit
Commitment [][]byte hisCommitment [][]byte
// Salt is used to salt Commitment before sending it to the client // encodedOutput is notary's encoded output for each circuit
Salt [][]byte encodedOutput [][]byte
// c6CheckValue is encoded outputs and decoding table which must the sent to
// Client as part of dual execution garbling. We store it here until Client
// sends her commitment. Then we send it out.
c6CheckValue []byte
// meta contains information about circuits // meta contains information about circuits
meta []*meta.Circuit meta []*meta.Circuit
// Tt/Dt are file handles for truth tables/decoding tables which are used // Tt are file handles for truth tables which are used
// to stream directly to the HTTP response (saving memory) // to stream directly to the HTTP response (saving memory)
Dt []*os.File Tt [][]*os.File
Tt []*os.File // dt are decoding tables for each execution of each garbled circuit
dt [][][]byte
// streamCounter is used when client uploads his blob to the notary // streamCounter is used when client uploads his blob to the notary
streamCounter *StreamCounter streamCounter *StreamCounter
// Gp is used to access the garbled pool // Gp is used to access the garbled pool
@@ -108,7 +112,7 @@ type Session struct {
// Init1 is the first message from the client. It starts Oblivious Transfer // Init1 is the first message from the client. It starts Oblivious Transfer
// setup and we also initialize all of Session's structures. // setup and we also initialize all of Session's structures.
func (s *Session) Init1(body, blob []byte, signingKey ecdsa.PrivateKey) []byte { func (s *Session) Init1(body []byte) []byte {
s.sequenceCheck(1) s.sequenceCheck(1)
s.g = new(garbler.Garbler) s.g = new(garbler.Garbler)
s.e = new(evaluator.Evaluator) s.e = new(evaluator.Evaluator)
@@ -116,10 +120,9 @@ func (s *Session) Init1(body, blob []byte, signingKey ecdsa.PrivateKey) []byte {
s.otR = new(ot.OTReceiver) s.otR = new(ot.OTReceiver)
s.p2pc = new(paillier2pc.Paillier2PC) s.p2pc = new(paillier2pc.Paillier2PC)
s.ghash = new(ghash.GHASH) s.ghash = new(ghash.GHASH)
s.signingKey = &signingKey
// the first 64 bytes are client pubkey for ECDH // the first 64 bytes are client pubkey for ECDH
o := 0 o := 0
s.clientKey, s.notaryKey = s.getSymmetricKeys(body[o:o+64], &signingKey) s.clientKey, s.notaryKey = s.getSymmetricKeys(body[o:o+64], &s.SigningKey)
o += 64 o += 64
c6Count := int(new(big.Int).SetBytes(body[o : o+2]).Uint64()) c6Count := int(new(big.Int).SetBytes(body[o : o+2]).Uint64())
o += 2 o += 2
@@ -153,26 +156,33 @@ func (s *Session) Init1(body, blob []byte, signingKey ecdsa.PrivateKey) []byte {
panic(err) panic(err)
} }
// get already garbled circuits // get already garbled circuits ...
blobs := s.Gp.GetBlobs(c6Count) blobs := s.Gp.GetBlobs(c6Count)
// separate into input labels, truth tables, decoding table // and separate into input labels, truth tables, decoding table
il := make([]*[]byte, len(blobs)) il := make([][][]byte, len(s.Gp.Circuits))
s.Tt = make([]*os.File, len(blobs)) s.Tt = make([][]*os.File, len(s.Gp.Circuits))
s.Dt = make([]*os.File, len(blobs)) s.dt = make([][][]byte, len(s.Gp.Circuits))
for i := 0; i < len(blobs); i++ { // depending on the number of circuit executions, there may be more than
il[i] = blobs[i].Il // one Blob for every circuit
s.Tt[i] = blobs[i].TtFile for i := 1; i < len(s.Gp.Circuits); i++ {
s.Dt[i] = blobs[i].DtFile il[i] = make([][]byte, len(blobs[i]))
s.Tt[i] = make([]*os.File, len(blobs[i]))
s.dt[i] = make([][]byte, len(blobs[i]))
for j, blob := range blobs[i] {
il[i][j] = *blob.Il
s.Tt[i][j] = blob.TtFile
s.dt[i][j] = *blob.Dt
}
} }
s.meta = s.Gp.Circuits s.meta = s.Gp.Circuits
s.g.Init(il, s.meta, c6Count) s.g.Init(il, s.meta, c6Count)
s.e.Init(s.meta, c6Count) s.e.Init(s.meta, c6Count)
s.Salt = make([][]byte, len(s.g.Cs)) s.hisCommitment = make([][]byte, len(s.g.Cs))
s.Commitment = make([][]byte, len(s.g.Cs)) s.encodedOutput = make([][]byte, len(s.g.Cs))
s.p2pc.Init() s.p2pc.Init()
return u.Concat(blob, s.encryptToClient(u.Concat(A, seedCommit, allBs, return s.encryptToClient(u.Concat(A, seedCommit, allBs, senderSeedShare))
senderSeedShare)))
} }
// continue initialization. Setting up the Oblivious Transfer. // continue initialization. Setting up the Oblivious Transfer.
@@ -201,10 +211,18 @@ func (s *Session) Init2(encrypted []byte) []byte {
return s.encryptToClient(u.Concat(encryptedColumns, receiverSeedShare, x, t)) return s.encryptToClient(u.Concat(encryptedColumns, receiverSeedShare, x, t))
} }
// GetBlobChunk returns file handles to truth tables and decoding table // GetBlob returns file handles to truth tables
func (s *Session) GetBlob(encrypted []byte) ([]*os.File, []*os.File) { func (s *Session) GetBlob(encrypted []byte) []*os.File {
s.sequenceCheck(3) s.sequenceCheck(3)
return s.Tt, s.Dt // flatten into one slice
var flat []*os.File
for _, sliceOfFiles := range s.Tt {
if len(sliceOfFiles) == 0 {
continue
}
flat = append(flat, sliceOfFiles...)
}
return flat
} }
// SetBlobChunk stores a blob from the client. // SetBlobChunk stores a blob from the client.
@@ -224,7 +242,7 @@ func (s *Session) SetBlob(respBody io.ReadCloser) []byte {
return nil return nil
} }
func (s *Session) GetUploadProgress() []byte { func (s *Session) GetUploadProgress(dummy []byte) []byte {
// special case. This message may be repeated many times // special case. This message may be repeated many times
s.sequenceCheck(100) s.sequenceCheck(100)
bytes := make([]byte, 4) bytes := make([]byte, 4)
@@ -273,22 +291,18 @@ func (s *Session) C1_step1(encrypted []byte) []byte {
func (s *Session) C1_step2(encrypted []byte) []byte { func (s *Session) C1_step2(encrypted []byte) []byte {
s.sequenceCheck(10) s.sequenceCheck(10)
body := s.decryptFromClient(encrypted) body := s.decryptFromClient(encrypted)
ttBlob, dtBlob := s.RetrieveBlobsForNotary(1) return s.encryptToClient(s.common_step2(1, body))
notaryLabels, clientLabels := s.c_step2(1, body)
output := s.e.Evaluate(1, notaryLabels, clientLabels, ttBlob, dtBlob)
s.Commitment[1] = u.Sha256(output)
s.Salt[1] = u.GetRandom(32)
hash := u.Sha256(u.Concat(s.Commitment[1], s.Salt[1]))
// unmask the output
s.PmsOuterHashState = u.XorBytes(output[0:32], s.g.Cs[1].Masks[1])
return s.encryptToClient(hash)
} }
// [REF 1] Step 4. N computes a1 and passes it to C. // [REF 1] Step 4. N computes a1 and passes it to C.
func (s *Session) C1_step3(encrypted []byte) []byte { func (s *Session) C1_step3(encrypted []byte) []byte {
s.sequenceCheck(11) s.sequenceCheck(11)
body := s.decryptFromClient(encrypted) body := s.decryptFromClient(encrypted)
a1 := u.FinishHash(s.PmsOuterHashState, body) output := s.processDecommit(1, body[:len(body)-32])
hisInnerHash := body[len(body)-32:]
// unmask the output
s.PmsOuterHashState = u.XorBytes(output[0:32], s.g.Cs[1].Masks[1])
a1 := u.FinishHash(s.PmsOuterHashState, hisInnerHash)
return s.encryptToClient(a1) return s.encryptToClient(a1)
} }
@@ -321,23 +335,19 @@ func (s *Session) C2_step1(encrypted []byte) []byte {
func (s *Session) C2_step2(encrypted []byte) []byte { func (s *Session) C2_step2(encrypted []byte) []byte {
s.sequenceCheck(15) s.sequenceCheck(15)
body := s.decryptFromClient(encrypted) body := s.decryptFromClient(encrypted)
ttBlob, olBlob := s.RetrieveBlobsForNotary(2) return s.encryptToClient(s.common_step2(2, body))
notaryLabels, clientLabels := s.c_step2(2, body)
output := s.e.Evaluate(2, notaryLabels, clientLabels, ttBlob, olBlob)
s.Commitment[2] = u.Sha256(output)
s.Salt[2] = u.GetRandom(32)
hash := u.Sha256(u.Concat(s.Commitment[2], s.Salt[2]))
// unmask the output
s.MsOuterHashState = u.XorBytes(output[0:32], s.g.Cs[2].Masks[1])
return s.encryptToClient(hash)
} }
// [REF 1] Step 14 and Step 21. N computes a1 and a1 and sends it to C. // [REF 1] Step 14 and Step 21. N computes a1 and a1 and sends it to C.
func (s *Session) C2_step3(encrypted []byte) []byte { func (s *Session) C2_step3(encrypted []byte) []byte {
s.sequenceCheck(16) s.sequenceCheck(16)
body := s.decryptFromClient(encrypted) body := s.decryptFromClient(encrypted)
a1inner := body[:32] output := s.processDecommit(2, body[:len(body)-64])
a1inner_vd := body[32:64] a1inner := body[len(body)-64 : len(body)-32]
a1inner_vd := body[len(body)-32:]
// unmask the output
s.MsOuterHashState = u.XorBytes(output[0:32], s.g.Cs[2].Masks[1])
a1 := u.FinishHash(s.MsOuterHashState, a1inner) a1 := u.FinishHash(s.MsOuterHashState, a1inner)
a1_vd := u.FinishHash(s.MsOuterHashState, a1inner_vd) a1_vd := u.FinishHash(s.MsOuterHashState, a1inner_vd)
return s.encryptToClient(u.Concat(a1, a1_vd)) return s.encryptToClient(u.Concat(a1, a1_vd))
@@ -380,21 +390,20 @@ func (s *Session) C3_step1(encrypted []byte) []byte {
func (s *Session) C3_step2(encrypted []byte) []byte { func (s *Session) C3_step2(encrypted []byte) []byte {
s.sequenceCheck(19) s.sequenceCheck(19)
body := s.decryptFromClient(encrypted) body := s.decryptFromClient(encrypted)
ttBlob, olBlob := s.RetrieveBlobsForNotary(3) return s.encryptToClient(s.common_step2(3, body))
notaryLabels, clientLabels := s.c_step2(3, body)
output := s.e.Evaluate(3, notaryLabels, clientLabels, ttBlob, olBlob)
// notary doesn't need to parse the output of the circuit, since we
// already know what out TLS key shares are
s.Commitment[3] = u.Sha256(output)
s.Salt[3] = u.GetRandom(32)
hash := u.Sha256(u.Concat(s.Commitment[3], s.Salt[3]))
return s.encryptToClient(hash)
} }
// [REF 1] Step 18. // [REF 1] Step 18.
func (s *Session) C4_step1(encrypted []byte) []byte { func (s *Session) C4_step1(encrypted []byte) []byte {
s.sequenceCheck(20) s.sequenceCheck(20)
body := s.decryptFromClient(encrypted) body := s.decryptFromClient(encrypted)
// to save a round-trip, circuit 3 piggy-backs on this message to parse the
// decommitment. Notary doesn't need to parse the output of the circuit,
// since we already know what out TLS key shares are
decommitSize := len(s.encodedOutput[3]) + len(u.Concat(s.dt[3]...)) + 32
s.processDecommit(3, body[:decommitSize])
body = body[decommitSize:]
g := s.g g := s.g
s.setCircuitInputs(4, s.setCircuitInputs(4,
s.swkShare, s.swkShare,
@@ -404,14 +413,14 @@ func (s *Session) C4_step1(encrypted []byte) []byte {
g.Cs[4].Masks[1], g.Cs[4].Masks[1],
g.Cs[4].Masks[2]) g.Cs[4].Masks[2])
hisOtReq := s.c_step1A(4, body) hisOtReq := body
// instead of the usual c_step1B, we have a special case // instead of the usual c_step1B, we have a special case
otResp, encryptedLabels := s.c4_step1B(hisOtReq) otResp, encryptedLabels := s.c4_step1A(hisOtReq)
out := s.c_step1C(4, otResp) out := s.c_step1B(4, otResp)
return s.encryptToClient(u.Concat(out, encryptedLabels)) return s.encryptToClient(u.Concat(out, encryptedLabels))
} }
func (s *Session) c4_step1B(hisOtReq []byte) ([]byte, []byte) { func (s *Session) c4_step1A(hisOtReq []byte) ([]byte, []byte) {
// We need to make sure that the same input labels which we give // We need to make sure that the same input labels which we give
// to the client for c4's client_write_key (cwk) and client_write_iv // to the client for c4's client_write_key (cwk) and client_write_iv
// (civ) will also be given for all invocations of circuit 6. This ensures // (civ) will also be given for all invocations of circuit 6. This ensures
@@ -492,20 +501,11 @@ func (s *Session) c4_step1B(hisOtReq []byte) ([]byte, []byte) {
return newOtResp, encryptedLabels return newOtResp, encryptedLabels
} }
// [REF 1] Step 18. Notary doesn't need to parse the circuit's output because // [REF 1] Step 18.
// the masks that he inputted become his TLS keys' shares.
func (s *Session) C4_step2(encrypted []byte) []byte { func (s *Session) C4_step2(encrypted []byte) []byte {
s.sequenceCheck(21) s.sequenceCheck(21)
body := s.decryptFromClient(encrypted) body := s.decryptFromClient(encrypted)
ttBlob, olBlob := s.RetrieveBlobsForNotary(4) return s.encryptToClient(s.common_step2(4, body))
notaryLabels, clientLabels := s.c_step2(4, body)
output := s.e.Evaluate(4, notaryLabels, clientLabels, ttBlob, olBlob)
// notary doesn't need to parse the output of the circuit, since we
// already know what out TLS key shares are
s.Commitment[4] = u.Sha256(output)
s.Salt[4] = u.GetRandom(32)
hash := u.Sha256(u.Concat(s.Commitment[4], s.Salt[4]))
return s.encryptToClient(hash)
} }
// compute MAC for Client_Finished using Oblivious Transfer // compute MAC for Client_Finished using Oblivious Transfer
@@ -514,9 +514,11 @@ func (s *Session) C4_step2(encrypted []byte) []byte {
func (s *Session) C4_step3(encrypted []byte) []byte { func (s *Session) C4_step3(encrypted []byte) []byte {
s.sequenceCheck(22) s.sequenceCheck(22)
body := s.decryptFromClient(encrypted) body := s.decryptFromClient(encrypted)
// Notary doesn't need to parse circuit's 4 output because
// the masks that he inputted become his TLS keys' shares.
s.processDecommit(4, body[:len(body)-(16+33)])
body = body[len(body)-(16+33):]
g := s.g g := s.g
u.Assert(len(body) == 16+33)
o := 0 o := 0
encCF := body[o : o+16] encCF := body[o : o+16]
o += 16 o += 16
@@ -578,14 +580,13 @@ func (s *Session) C5_pre1(encrypted []byte) []byte {
func (s *Session) C5_step1(encrypted []byte) []byte { func (s *Session) C5_step1(encrypted []byte) []byte {
s.sequenceCheck(24) s.sequenceCheck(24)
body := s.decryptFromClient(encrypted) body := s.decryptFromClient(encrypted)
g := s.g
s.setCircuitInputs(5, s.setCircuitInputs(5,
s.MsOuterHashState, s.MsOuterHashState,
s.swkShare, s.swkShare,
s.sivShare, s.sivShare,
g.Cs[5].Masks[1], s.g.Cs[5].Masks[1],
g.Cs[5].Masks[2]) s.g.Cs[5].Masks[2])
u.Assert(len(g.Cs[5].InputBits)/8 == 84) u.Assert(len(s.g.Cs[5].InputBits)/8 == 84)
out := s.c_step1(5, body) out := s.c_step1(5, body)
return s.encryptToClient(out) return s.encryptToClient(out)
} }
@@ -594,13 +595,7 @@ func (s *Session) C5_step1(encrypted []byte) []byte {
func (s *Session) C5_step2(encrypted []byte) []byte { func (s *Session) C5_step2(encrypted []byte) []byte {
s.sequenceCheck(25) s.sequenceCheck(25)
body := s.decryptFromClient(encrypted) body := s.decryptFromClient(encrypted)
ttBlob, olBlob := s.RetrieveBlobsForNotary(5) return s.encryptToClient(s.common_step2(5, body))
notaryLabels, clientLabels := s.c_step2(5, body)
output := s.e.Evaluate(5, notaryLabels, clientLabels, ttBlob, olBlob)
s.Commitment[5] = u.Sha256(output)
s.Salt[5] = u.GetRandom(32)
hash := u.Sha256(u.Concat(s.Commitment[5], s.Salt[5]))
return s.encryptToClient(hash)
} }
// compute MAC for Server_Finished using Oblivious Transfer // compute MAC for Server_Finished using Oblivious Transfer
@@ -608,9 +603,9 @@ func (s *Session) C5_step2(encrypted []byte) []byte {
func (s *Session) C5_step3(encrypted []byte) []byte { func (s *Session) C5_step3(encrypted []byte) []byte {
s.sequenceCheck(26) s.sequenceCheck(26)
body := s.decryptFromClient(encrypted) body := s.decryptFromClient(encrypted)
s.processDecommit(5, body[:len(body)-(16+33)])
body = body[len(body)-(16+33):]
g := s.g g := s.g
u.Assert(len(body) == 16+33)
o := 0 o := 0
encSF := body[o : o+16] encSF := body[o : o+16]
o += 16 o += 16
@@ -657,7 +652,7 @@ func (s *Session) C6_step1(encrypted []byte) []byte {
} }
s.setCircuitInputs(6, allInputs...) s.setCircuitInputs(6, allInputs...)
hisOtReq := s.c_step1A(6, body) hisOtReq := body
// --------------------------------------- // ---------------------------------------
// instead of the usual c_step1B, we have a special case: // instead of the usual c_step1B, we have a special case:
// we need to remove all the labels corresponding to client_write_key // we need to remove all the labels corresponding to client_write_key
@@ -674,25 +669,34 @@ func (s *Session) C6_step1(encrypted []byte) []byte {
// proceed with the regular step1 flow // proceed with the regular step1 flow
// --------------------------------------- // ---------------------------------------
otResp := s.otS.ProcessRequest(hisOtReq, labels) otResp := s.otS.ProcessRequest(hisOtReq, labels)
out := s.c_step1C(6, otResp) out := s.c_step1B(6, otResp)
return s.encryptToClient(out) return s.encryptToClient(out)
} }
func (s *Session) C6_step2(encrypted []byte) []byte { func (s *Session) C6_pre2(encrypted []byte) []byte {
s.sequenceCheck(28) s.sequenceCheck(28)
body := s.decryptFromClient(encrypted) body := s.decryptFromClient(encrypted)
ttBlob, olBlob := s.RetrieveBlobsForNotary(6) // add a dummy 32-byte commitment to keep common_step2() happy
notaryLabels, clientLabels := s.c_step2(6, body) body = append(body, make([]byte, 32)...)
output := s.e.Evaluate(6, notaryLabels, clientLabels, ttBlob, olBlob) s.c6CheckValue = s.common_step2(6, body)
s.Commitment[6] = u.Sha256(output) // do not send c6CheckValue until Client sends his commitment
s.Salt[6] = u.GetRandom(32) return nil
hash := u.Sha256(u.Concat(s.Commitment[6], s.Salt[6])) }
return s.encryptToClient(hash)
func (s *Session) C6_step2(encrypted []byte) []byte {
s.sequenceCheck(29)
body := s.decryptFromClient(encrypted)
u.Assert(len(body) == 32)
s.hisCommitment[6] = body
return s.encryptToClient(s.c6CheckValue)
} }
func (s *Session) C7_step1(encrypted []byte) []byte { func (s *Session) C7_step1(encrypted []byte) []byte {
s.sequenceCheck(29) s.sequenceCheck(30)
body := s.decryptFromClient(encrypted) body := s.decryptFromClient(encrypted)
decommitSize := len(s.encodedOutput[6]) + len(u.Concat(s.dt[6]...)) + 32
s.processDecommit(6, body[:decommitSize])
body = body[decommitSize:]
g := s.g g := s.g
var allInputs [][]byte var allInputs [][]byte
allInputs = append(allInputs, s.cwkShare) allInputs = append(allInputs, s.cwkShare)
@@ -706,32 +710,18 @@ func (s *Session) C7_step1(encrypted []byte) []byte {
} }
func (s *Session) C7_step2(encrypted []byte) []byte { func (s *Session) C7_step2(encrypted []byte) []byte {
s.sequenceCheck(30)
body := s.decryptFromClient(encrypted)
ttBlob, olBlob := s.RetrieveBlobsForNotary(7)
notaryLabels, clientLabels := s.c_step2(7, body)
output := s.e.Evaluate(7, notaryLabels, clientLabels, ttBlob, olBlob)
s.Commitment[7] = u.Sha256(output)
s.Salt[7] = u.GetRandom(32)
hash := u.Sha256(u.Concat(s.Commitment[7], s.Salt[7]))
return s.encryptToClient(hash)
}
// one extra communication round trip to check the hash
func (s *Session) CheckC7Commit(encrypted []byte) []byte {
s.sequenceCheck(31) s.sequenceCheck(31)
body := s.decryptFromClient(encrypted) body := s.decryptFromClient(encrypted)
hisCommit := body return s.encryptToClient(s.common_step2(7, body))
if !bytes.Equal(hisCommit, s.Commitment[7]) {
panic("commit hash doesn't match")
}
return s.encryptToClient(s.Salt[7])
} }
// compute MAC for client's request using Oblivious Transfer // compute MAC for client's request using Oblivious Transfer
func (s *Session) Ghash_step1(encrypted []byte) []byte { func (s *Session) Ghash_step1(encrypted []byte) []byte {
s.sequenceCheck(32) s.sequenceCheck(32)
body := s.decryptFromClient(encrypted) body := s.decryptFromClient(encrypted)
decommitSize := len(s.encodedOutput[7]) + len(u.Concat(s.dt[7]...)) + 32
s.processDecommit(7, body[:decommitSize])
body = body[decommitSize:]
o := 0 o := 0
mpnBytes := body[o : o+2] mpnBytes := body[o : o+2]
o += 2 o += 2
@@ -814,7 +804,7 @@ func (s *Session) CommitHash(encrypted []byte) []byte {
hisPMSShareHash := body[64:96] hisPMSShareHash := body[64:96]
timeBytes := make([]byte, 8) timeBytes := make([]byte, 8)
binary.BigEndian.PutUint64(timeBytes, uint64(time.Now().Unix())) binary.BigEndian.PutUint64(timeBytes, uint64(time.Now().Unix()))
signature := u.ECDSASign(s.signingKey, signature := u.ECDSASign(&s.SigningKey,
hisCommitHash, hisCommitHash,
hisKeyShareHash, hisKeyShareHash,
hisPMSShareHash, hisPMSShareHash,
@@ -895,75 +885,51 @@ func (s *Session) sequenceCheck(seqNo int) {
s.msgsSeen = append(s.msgsSeen, seqNo) s.msgsSeen = append(s.msgsSeen, seqNo)
} }
// returns truth tables and decoding tables for the circuit number cNo from the // returns truth tables for the circuit number cNo from the
// blob which we received earlier from the client // blob which we received earlier from the client
func (s *Session) RetrieveBlobsForNotary(cNo int) ([]byte, []byte) { func (s *Session) RetrieveBlobsForNotary(cNo int) []byte {
off, ttSize, dtSize := s.getCircuitBlobOffset(cNo) off, ttSize := s.getCircuitBlobOffset(cNo)
path := filepath.Join(s.StorageDir, "blobForNotary") path := filepath.Join(s.StorageDir, "blobForNotary")
file, err := os.Open(path) file, err := os.Open(path)
if err != nil { if err != nil {
panic(err) panic(err)
} }
buffer := make([]byte, ttSize+dtSize) buffer := make([]byte, ttSize)
_, err = file.ReadAt(buffer, int64(off)) _, err = file.ReadAt(buffer, int64(off))
if err != nil && err != io.EOF { if err != nil && err != io.EOF {
panic(err) panic(err)
} }
tt := buffer[:ttSize] tt := buffer[:ttSize]
dt := buffer[ttSize:] return tt
return tt, dt
} }
// GetCircuitBlobOffset finds the offset and size of the tt+dt blob for circuit cNo // GetCircuitBlobOffset finds the offset and size of the tt+dt blob for circuit cNo
// in the blob of all circuits // in the blob of all circuits
func (s *Session) getCircuitBlobOffset(cNo int) (int, int, int) { func (s *Session) getCircuitBlobOffset(cNo int) (int, int) {
offset := 0 offset := 0
ttLen := 0 ttLen := 0
dtLen := 0
for i := 1; i < len(s.g.Cs); i++ { for i := 1; i < len(s.g.Cs); i++ {
offset += ttLen + dtLen offset += ttLen
ttLen = s.g.Cs[i].Meta.AndGateCount * 48 ttLen = s.g.Cs[i].Meta.AndGateCount * 48
dtLen = int(math.Ceil(float64(s.g.Cs[i].Meta.OutputSize) / 8))
if i == 6 { if i == 6 {
ttLen = s.g.C6Count * ttLen ttLen = s.g.C6Count * ttLen
dtLen = s.g.C6Count * dtLen
} }
if i == cNo { if i == cNo {
break break
} }
} }
return offset, ttLen, dtLen return offset, ttLen
} }
func (s *Session) c_step1A(cNo int, body []byte) []byte { func (s *Session) c_step1A(cNo int, hisOtReq []byte) []byte {
o := 0
// check client's commitment to the previous circuit's output
if cNo > 1 {
hisCommit := body[:32]
o += 32
if !bytes.Equal(hisCommit, s.Commitment[cNo-1]) {
panic("commitments don't match")
}
}
hisOtReq := body[o:]
return hisOtReq
}
func (s *Session) c_step1B(cNo int, hisOtReq []byte) []byte {
otResp := s.otS.ProcessRequest(hisOtReq, s.g.GetClientLabels(cNo)) otResp := s.otS.ProcessRequest(hisOtReq, s.g.GetClientLabels(cNo))
return otResp return otResp
} }
func (s *Session) c_step1C(cNo int, otResp []byte) []byte { func (s *Session) c_step1B(cNo int, otResp []byte) []byte {
inputLabels := s.g.GetNotaryLabels(cNo) inputLabels := s.g.GetNotaryLabels(cNo)
myOtReq := s.otR.CreateRequest(s.g.Cs[cNo].InputBits) myOtReq := s.otR.CreateRequest(s.g.Cs[cNo].InputBits)
// send salt for the previous circuit's commitment
var salt []byte = nil
if cNo > 1 {
salt = s.Salt[cNo-1]
}
return u.Concat( return u.Concat(
salt,
inputLabels, inputLabels,
otResp, otResp,
myOtReq) myOtReq)
@@ -971,13 +937,12 @@ func (s *Session) c_step1C(cNo int, otResp []byte) []byte {
// c_step1 is common for all circuits // c_step1 is common for all circuits
func (s *Session) c_step1(cNo int, body []byte) []byte { func (s *Session) c_step1(cNo int, body []byte) []byte {
hisOtReq := s.c_step1A(cNo, body) hisOtReq := body
// because of the dual execution, both client and notary need to // because of the dual execution, both client and notary need to
// receive their input labels via OT. // receive their input labels via OT.
// we process client's OT request and create a notary's OT request. // we process client's OT request and create a notary's OT request.
otResp := s.c_step1B(cNo, hisOtReq) otResp := s.c_step1A(cNo, hisOtReq)
out := s.c_step1C(cNo, otResp) return s.c_step1B(cNo, otResp)
return out
} }
// given a slice of circuit inputs in the same order as expected by the c*.casm file, // given a slice of circuit inputs in the same order as expected by the c*.casm file,
@@ -988,15 +953,93 @@ func (s *Session) setCircuitInputs(cNo int, inputs ...[]byte) {
} }
} }
// c_step2 is common for all circuits. Returns notary's and client's input // common_step2 is Step2 which is the same for all circuits. Returns a value
// which must be sent to the Client as part of dual execution garbling.
func (s *Session) common_step2(cNo int, body []byte) []byte {
ttBlob := s.RetrieveBlobsForNotary(cNo)
notaryLabels, clientLabels, clientCommitment := s.parse_step2(cNo, body)
s.hisCommitment[cNo] = clientCommitment
s.encodedOutput[cNo] = s.e.Evaluate(cNo, notaryLabels, clientLabels, ttBlob)
return u.Concat(s.encodedOutput[cNo], u.Concat(s.dt[cNo]...))
}
// parse_step2 is common for all circuits. Returns notary's and client's input
// labels for the circuit number cNo. // labels for the circuit number cNo.
// Notary is acting as the evaluator. Client sent its input labels in the clear // Notary is acting as the evaluator. Client sent his input labels in the clear
// and also sent notary's input labels via OT. // and he also sent notary's input labels via OT.
func (s *Session) c_step2(cNo int, body []byte) ([]byte, []byte) { func (s *Session) parse_step2(cNo int, body []byte) ([]byte, []byte, []byte) {
o := 0
// exeCount is how many executions of this circuit we need // exeCount is how many executions of this circuit we need
exeCount := []int{0, 1, 1, 1, 1, 1, s.g.C6Count, 1}[cNo] exeCount := []int{0, 1, 1, 1, 1, 1, s.g.C6Count, 1}[cNo]
otResp := body[:s.g.Cs[cNo].Meta.NotaryInputSize*32*exeCount] allNotaryOtSize := s.g.Cs[cNo].Meta.NotaryInputSize * 32 * exeCount
clientLabels := body[s.g.Cs[cNo].Meta.NotaryInputSize*32*exeCount:] otResp := body[o : o+allNotaryOtSize]
o += allNotaryOtSize
allClientLabelsSize := s.g.Cs[cNo].Meta.ClientInputSize * 16 * exeCount
clientLabels := body[o : o+allClientLabelsSize]
o += allClientLabelsSize
clientCommitment := body[o : o+32]
o += 32
u.Assert(o == len(body))
notaryLabels := s.otR.ParseResponse(s.g.Cs[cNo].InputBits, otResp) notaryLabels := s.otR.ParseResponse(s.g.Cs[cNo].InputBits, otResp)
return notaryLabels, clientLabels return notaryLabels, clientLabels, clientCommitment
}
// processDecommit processes Client's decommitment, makes sure it matches the
// commitment, decodes and parses the Notary's circuit output.
// Client committed first, then Notary revealed his encoded outputs and
// decoding table and now the Client decommits.
func (s *Session) processDecommit(cNo int, decommit []byte) []byte {
o := 0
hisEncodedOutput := decommit[o : o+len(s.encodedOutput[cNo])]
o += len(s.encodedOutput[cNo])
myDecodingTable := u.Concat(s.dt[cNo]...)
hisDecodingTable := decommit[o : o+len(myDecodingTable)]
o += len(myDecodingTable)
hisSalt := decommit[o : o+32]
o += 32
u.Assert(o == len(decommit))
u.Assert(bytes.Equal(s.hisCommitment[cNo], u.Sha256(u.Concat(
hisEncodedOutput, hisDecodingTable, hisSalt))))
// decode his output, my output and compare them
hisPlaintext := u.XorBytes(myDecodingTable, hisEncodedOutput)
myPlaintext := u.XorBytes(hisDecodingTable, s.encodedOutput[cNo])
u.Assert(bytes.Equal(hisPlaintext, myPlaintext))
output := s.parsePlaintextOutput(cNo, myPlaintext)
return output
}
// parsePlaintextOutput parses the plaintext of each circuit execution into
// output bit and converts the output bits into a flat slice of bytes so that
// output values are in the same order as they appear in the *.casm files
func (s *Session) parsePlaintextOutput(cNo int, ptBytes []byte) []byte {
c := (s.meta)[cNo]
exeCount := []int{0, 1, 1, 1, 1, 1, s.g.C6Count, 1}[cNo]
chunks := u.SplitIntoChunks(ptBytes, len(ptBytes)/exeCount)
var output []byte
for i := 0; i < exeCount; i++ {
// plaintext has a padding in MSB to make it a multiple of 8 bits. We
// decompose into bits and drop the padding
outBits := u.BytesToBits(chunks[i])[0:c.OutputSize]
// reverse output bits so that the values of the output be placed in
// the same order as they appear in the *.casm files
outBytes := s.parseOutputBits(cNo, outBits)
output = append(output, outBytes...)
}
return output
}
// parseOutputBits converts the output bits of the circuit into a flat slice
// of bytes so that output values are in the same order as they appear in the *.casm files
func (s *Session) parseOutputBits(cNo int, outBits []int) []byte {
o := 0 // offset
var outBytes []byte
for _, v := range (s.meta)[cNo].OutputsSizes {
output := u.BitsToBytes(outBits[o : o+v])
outBytes = append(outBytes, output...)
o += v
}
if o != (s.meta)[cNo].OutputSize {
panic("o != e.g.Cs[cNo].OutputSize")
}
return outBytes
} }

View File

@@ -8,9 +8,13 @@ import (
"time" "time"
) )
type method func([]byte) []byte
// smItem is stored internally by SessionManager // smItem is stored internally by SessionManager
type smItem struct { type smItem struct {
session *session.Session session *session.Session
// methodLookup is a map used to look up the session's method by its name
methodLookup map[string]method
lastSeen int64 // timestamp of last activity lastSeen int64 // timestamp of last activity
creationTime int64 // timestamp creationTime int64 // timestamp
} }
@@ -41,9 +45,67 @@ func (sm *SessionManager) AddSession(key string) *session.Session {
s.Sid = key s.Sid = key
s.DestroyChan = sm.destroyChan s.DestroyChan = sm.destroyChan
now := int64(time.Now().UnixNano() / 1e9) now := int64(time.Now().UnixNano() / 1e9)
methodLookup := map[string]method{
"init1": s.Init1,
"init2": s.Init2,
"getUploadProgress": s.GetUploadProgress,
// step1 thru step4 deal with Paillier 2PC
"step1": s.Step1,
"step2": s.Step2,
"step3": s.Step3,
"step4": s.Step4,
// // c1_step1 thru c1_step1 deal with TLS Handshake
"c1_step1": s.C1_step1,
"c1_step2": s.C1_step2,
"c1_step3": s.C1_step3,
"c1_step4": s.C1_step4,
"c1_step5": s.C1_step5,
// // c2_step1 thru c2_step4 deal with TLS Handshake
"c2_step1": s.C2_step1,
"c2_step2": s.C2_step2,
"c2_step3": s.C2_step3,
"c2_step4": s.C2_step4,
// // c3_step1 thru c4_step3 deal with TLS Handshake and also prepare data
// // needed to send Client Finished
"c3_step1": s.C3_step1,
"c3_step2": s.C3_step2,
"c4_step1": s.C4_step1,
"c4_step2": s.C4_step2,
"c4_step3": s.C4_step3,
// // c5_pre1 thru c5_step3 check Server Finished
"c5_pre1": s.C5_pre1,
"c5_step1": s.C5_step1,
"c5_step2": s.C5_step2,
"c5_step3": s.C5_step3,
// // c6_step1 thru c6_step2 prepare encrypted counter blocks for the
// // client's request to the webserver
"c6_step1": s.C6_step1,
"c6_pre2": s.C6_pre2,
"c6_step2": s.C6_step2,
// // c7_step1 thru c7_step2 prepare the GCTR block needed to compute the MAC
// // for the client's request
"c7_step1": s.C7_step1,
"c7_step2": s.C7_step2,
// // steps ghash_step1 thru ghash_step3 compute the GHASH output needed to
// // compute the MAC for the client's request
"ghash_step1": s.Ghash_step1,
"ghash_step2": s.Ghash_step2,
"ghash_step3": s.Ghash_step3,
"commitHash": s.CommitHash,
}
sm.Lock() sm.Lock()
defer sm.Unlock() defer sm.Unlock()
sm.sessions[key] = &smItem{s, now, now} sm.sessions[key] = &smItem{s, methodLookup, now, now}
return s return s
} }
@@ -59,6 +121,22 @@ func (sm *SessionManager) GetSession(key string) *session.Session {
return val.session return val.session
} }
// GetMethod looks up and return Session's method corresponding to the method
// string
func (sm *SessionManager) GetMethod(methodStr string, key string) method {
val, ok := sm.sessions[key]
if !ok {
log.Println("Error: the requested session does not exist ", key)
panic("Error: the requested session does not exist")
}
f, ok2 := val.methodLookup[methodStr]
if !ok2 {
log.Println("Error: the requested method does not exist ", key)
panic("Error: the requested method does not exist")
}
return f
}
// removeSession removes the session and associated storage data // removeSession removes the session and associated storage data
func (sm *SessionManager) removeSession(key string) { func (sm *SessionManager) removeSession(key string) {
s, ok := sm.sessions[key] s, ok := sm.sessions[key]
@@ -70,18 +148,13 @@ func (sm *SessionManager) removeSession(key string) {
log.Println("Error while removing session ", key) log.Println("Error while removing session ", key)
log.Println(err) log.Println(err)
} }
for _, f := range s.session.Tt { for _, sliceOfFiles := range s.session.Tt {
err = os.Remove(f.Name()) for _, f := range sliceOfFiles {
if err != nil { err = os.Remove(f.Name())
log.Println("Error while removing session ", key) if err != nil {
log.Println(err) log.Println("Error while removing session ", key)
} log.Println(err)
} }
for _, f := range s.session.Dt {
err = os.Remove(f.Name())
if err != nil {
log.Println("Error while removing session ", key)
log.Println(err)
} }
} }
sm.Lock() sm.Lock()