From becabb40e9b6e3cea15480256576627ccc2419ba Mon Sep 17 00:00:00 2001 From: Brendan Mc Date: Tue, 26 May 2015 21:06:08 -0700 Subject: [PATCH] Integration with Bren2010/MSP --- core/core.go | 2 + cryptor/cryptor.go | 162 ++++++++++++++++++++++++++++++++----------- keycache/keycache.go | 57 +++++++++++++-- 3 files changed, 178 insertions(+), 43 deletions(-) diff --git a/core/core.go b/core/core.go index fa487c2..e3fccb1 100644 --- a/core/core.go +++ b/core/core.go @@ -72,6 +72,7 @@ type EncryptRequest struct { Owners []string LeftOwners []string RightOwners []string + Predicate string Data []byte @@ -454,6 +455,7 @@ func Encrypt(jsonIn []byte) ([]byte, error) { Names: s.Owners, LeftNames: s.LeftOwners, RightNames: s.RightOwners, + Predicate: s.Predicate, } resp, err := crypt.Encrypt(s.Data, s.Labels, access) diff --git a/cryptor/cryptor.go b/cryptor/cryptor.go index 830b188..65aa035 100644 --- a/cryptor/cryptor.go +++ b/cryptor/cryptor.go @@ -15,6 +15,7 @@ import ( "sort" "strconv" + "github.com/Bren2010/msp" "github.com/cloudflare/redoctober/keycache" "github.com/cloudflare/redoctober/padding" "github.com/cloudflare/redoctober/passvault" @@ -44,6 +45,39 @@ type AccessStructure struct { LeftNames []string RightNames []string + + Predicate string +} + +// Implements msp.UserDatabase +type UserDatabase struct { + records *passvault.Records + cache *keycache.Cache + + user string + labels []string + keySet map[string]SingleWrappedKey + shareSet map[string][][]byte +} + +func (u UserDatabase) ValidUser(name string) bool { + _, ok := u.records.GetRecord(name) + return ok +} + +func (u UserDatabase) CanGetShare(name string) bool { + _, _, ok := u.cache.MatchUser(name, u.user, u.labels) + return ok +} + +func (u UserDatabase) GetShare(name string) ([][]byte, error) { + return u.cache.DecryptShares( + u.shareSet[name], + name, + u.user, + u.labels, + u.keySet[name].Key, + ) } // MultiWrappedKey is a structure containing a 16-byte key encrypted @@ -67,8 +101,10 @@ type EncryptedData struct { Version int VaultId int `json:",omitempty"` Labels []string `json:",omitempty"` + Predicate string `json:",omitempty"` KeySet []MultiWrappedKey `json:",omitempty"` KeySetRSA map[string]SingleWrappedKey `json:",omitempty"` + ShareSet map[string][][]byte `json:",omitempty"` IV []byte `json:",omitempty"` Data []byte Signature []byte @@ -259,8 +295,6 @@ func (encrypted *EncryptedData) wrapKey(records *passvault.Records, clearKey []b encrypted.KeySet = append(encrypted.KeySet, out) } } - - return nil } else if len(access.LeftNames) > 0 && len(access.RightNames) > 0 { // Generate a random AES key for each user and RSA/ECIES encrypt it encrypted.KeySetRSA = make(map[string]SingleWrappedKey) @@ -301,11 +335,41 @@ func (encrypted *EncryptedData) wrapKey(records *passvault.Records, clearKey []b encrypted.KeySet = append(encrypted.KeySet, out) } } + } else if len(access.Predicate) > 0 { + encrypted.KeySetRSA = make(map[string]SingleWrappedKey) - return nil + sss, err := msp.StringToMSP(access.Predicate) + if err != nil { + return err + } + + db := msp.UserDatabase(UserDatabase{records: records}) + shareSet, err := sss.DistributeShares(clearKey, msp.Modulus(127), &db) + if err != nil { + return err + } + + for name, _ := range shareSet { + encrypted.KeySetRSA[name], err = generateRandomKey(name) + crypt, err := aes.NewCipher(encrypted.KeySetRSA[name].aesKey) + if err != nil { + return err + } + + for i, _ := range shareSet[name] { + tmp := make([]byte, 16) + crypt.Encrypt(tmp, shareSet[name][i]) + shareSet[name][i] = tmp + } + } + + encrypted.ShareSet = shareSet + encrypted.Predicate = access.Predicate } else { return errors.New("Invalid access structure.") } + + return nil } // unwrapKey decrypts first key in keys whose encryption keys are in keycache @@ -316,50 +380,70 @@ func (encrypted *EncryptedData) unwrapKey(cache *keycache.Cache, user string) (u nameSet = map[string]bool{} ) - for _, mwKey := range encrypted.KeySet { - // validate the size of the keys - if len(mwKey.Key) != 16 { - err = errors.New("Invalid Input") + if len(encrypted.Predicate) == 0 { + for _, mwKey := range encrypted.KeySet { + // validate the size of the keys + if len(mwKey.Key) != 16 { + err = errors.New("Invalid Input") + } + + if err != nil { + return nil, nil, err + } + + // loop through users to see if they are all delegated + fullMatch = true + for _, mwName := range mwKey.Name { + if valid := cache.Valid(mwName, user, encrypted.Labels); !valid { + fullMatch = false + break + } + nameSet[mwName] = true + } + + // if the keys are delegated, decrypt the mwKey with them + if fullMatch == true { + tmpKeyValue := mwKey.Key + for _, mwName := range mwKey.Name { + pubEncrypted := encrypted.KeySetRSA[mwName] + if tmpKeyValue, keyFound = cache.DecryptKey(tmpKeyValue, mwName, user, encrypted.Labels, pubEncrypted.Key); keyFound != nil { + break + } + } + unwrappedKey = tmpKeyValue + break + } } + if !fullMatch { + err = errors.New("Need more delegated keys") + names = nil + } + + names = make([]string, 0, len(nameSet)) + for name := range nameSet { + names = append(names, name) + } + return + } else { + var sss msp.MSP + sss, err = msp.StringToMSP(encrypted.Predicate) if err != nil { return nil, nil, err } - // loop through users to see if they are all delegated - fullMatch = true - for _, mwName := range mwKey.Name { - if valid := cache.Valid(mwName, user, encrypted.Labels); !valid { - fullMatch = false - break - } - nameSet[mwName] = true - } + db := msp.UserDatabase(UserDatabase{ + cache: cache, + user: user, + labels: encrypted.Labels, + keySet: encrypted.KeySetRSA, + shareSet: encrypted.ShareSet, + }) + unwrappedKey, err = sss.RecoverSecret(msp.Modulus(127), &db) + names = []string{"Shares"} - // if the keys are delegated, decrypt the mwKey with them - if fullMatch == true { - tmpKeyValue := mwKey.Key - for _, mwName := range mwKey.Name { - pubEncrypted := encrypted.KeySetRSA[mwName] - if tmpKeyValue, keyFound = cache.DecryptKey(tmpKeyValue, mwName, user, encrypted.Labels, pubEncrypted.Key); keyFound != nil { - break - } - } - unwrappedKey = tmpKeyValue - break - } + return } - - if !fullMatch { - err = errors.New("Need more delegated keys") - names = nil - } - - names = make([]string, 0, len(nameSet)) - for name := range nameSet { - names = append(names, name) - } - return } // Encrypt encrypts data with the keys associated with names. This diff --git a/keycache/keycache.go b/keycache/keycache.go index 2c1082f..4e6df4f 100644 --- a/keycache/keycache.go +++ b/keycache/keycache.go @@ -112,9 +112,9 @@ func (cache *Cache) Valid(name, user string, labels []string) (present bool) { return false } -// matchUser returns the matching active user if present +// MatchUser returns the matching active user if present // and a boolean to indicate its presence. -func (cache *Cache) matchUser(name, user string, labels []string) (ActiveUser, string, bool) { +func (cache *Cache) MatchUser(name, user string, labels []string) (ActiveUser, string, bool) { var key ActiveUser for d, key := range cache.UserKeys { if d.Name != name { @@ -131,7 +131,7 @@ func (cache *Cache) matchUser(name, user string, labels []string) (ActiveUser, s // useKey decrements the counter on an active key // for decryption or symmetric encryption func (cache *Cache) useKey(name, user, slot string, labels []string) { - if val, slot, present := cache.matchUser(name, user, labels); present { + if val, slot, present := cache.MatchUser(name, user, labels); present { val.Usage.Uses -= 1 cache.setUser(val, name, slot) } @@ -214,7 +214,7 @@ func (cache *Cache) AddKeyFromRecord(record passvault.PasswordRecord, name, pass func (cache *Cache) DecryptKey(in []byte, name, user string, labels []string, pubEncryptedKey []byte) (out []byte, err error) { cache.Refresh() - decryptKey, slot, ok := cache.matchUser(name, user, labels) + decryptKey, slot, ok := cache.MatchUser(name, user, labels) if !ok { return nil, errors.New("Key not delegated") } @@ -252,3 +252,52 @@ func (cache *Cache) DecryptKey(in []byte, name, user string, labels []string, pu return } + +// DecryptShares decrypts an array of 16 byte shares using the key corresponding +// to the name parameter. +func (cache *Cache) DecryptShares(in [][]byte, name, user string, labels []string, pubEncryptedKey []byte) (out [][]byte, err error) { + cache.Refresh() + + decryptKey, slot, ok := cache.MatchUser(name, user, labels) + if !ok { + return nil, errors.New("Key not delegated") + } + + var aesKey []byte + + // pick the aesKey to use for decryption + switch decryptKey.Type { + case passvault.RSARecord: + // extract the aes key from the pubEncryptedKey + aesKey, err = rsa.DecryptOAEP(sha1.New(), rand.Reader, &decryptKey.rsaKey, pubEncryptedKey, nil) + if err != nil { + return + } + case passvault.ECCRecord: + // extract the aes key from the pubEncryptedKey + aesKey, err = ecdh.Decrypt(decryptKey.eccKey, pubEncryptedKey) + + if err != nil { + return + } + default: + return nil, errors.New("unknown type") + } + + // decrypt + aesSession, err := aes.NewCipher(aesKey) + if err != nil { + return + } + + for _, encShare := range in { + tmp := make([]byte, 16) + aesSession.Decrypt(tmp, encShare) + + out = append(out, tmp) + } + + cache.useKey(name, user, slot, labels) + + return +}