From 935b929dd575920e0105ef59f5ff22c565338d2a Mon Sep 17 00:00:00 2001 From: Brendan Mc Date: Mon, 4 May 2015 02:37:42 -0700 Subject: [PATCH] Return to idiomatic style & Backwards compatible left&right owners --- core/core.go | 13 ++-- cryptor/cryptor.go | 151 +++++++++++++++++++++++++++++------------ passvault/passvault.go | 30 ++++---- 3 files changed, 127 insertions(+), 67 deletions(-) diff --git a/core/core.go b/core/core.go index 965c4d6..b182026 100644 --- a/core/core.go +++ b/core/core.go @@ -57,9 +57,11 @@ type EncryptRequest struct { Name string Password string - Minimum int - Owners []string - Data []byte + Owners []string + LeftOwners []string + RightOwners []string + + Data []byte Labels []string } @@ -277,8 +279,9 @@ func Encrypt(jsonIn []byte) ([]byte, error) { return jsonStatusError(err) } - // Encrypt file with list of owners - if resp, err := crypt.Encrypt(s.Data, s.Labels, s.Owners, s.Minimum); err != nil { + // Encrypt file + access := cryptor.AccessStructure{s.Owners, s.LeftOwners, s.RightOwners} + if resp, err := crypt.Encrypt(s.Data, s.Labels, access); err != nil { log.Println("Error encrypting:", err) return jsonStatusError(err) } else { diff --git a/cryptor/cryptor.go b/cryptor/cryptor.go index ea316d7..7c3aa14 100644 --- a/cryptor/cryptor.go +++ b/cryptor/cryptor.go @@ -34,6 +34,18 @@ func New(records *passvault.Records, cache *keycache.Cache) Cryptor { return Cryptor{records, cache} } +// AccessStructure represents different possible access structures for +// encrypted data. If len(Names) > 0, then at least 2 of the users in the list +// must be delegated to decrypt. If len(LeftNames) > 0 & len(RightNames) > 0, +// then at least one from each list must be delegated (if the same user is in +// both, then he can decrypt it alone). +type AccessStructure struct { + Names []string + + LeftNames []string + RightNames []string +} + // MultiWrappedKey is a structure containing a 16-byte key encrypted // once for each of the keys corresponding to the names of the users // in Name in order. @@ -179,61 +191,117 @@ func (encrypted *EncryptedData) unlock(key []byte) (err error) { // wrapKey encrypts the clear key such that a minimum number of delegated keys // are required to decrypt. NOTE: Currently the max value for min is 2. -func (encrypted *EncryptedData) wrapKey(records *passvault.Records, clearKey []byte, names []string, min int) (err error) { - // Generate a random AES key for each user and RSA/ECIES encrypt it - encrypted.KeySetRSA = make(map[string]SingleWrappedKey, len(names)) - - for _, name := range names { +func (encrypted *EncryptedData) wrapKey(records *passvault.Records, clearKey []byte, access AccessStructure) (err error) { + generateRandomKey := func(name string) (singleWrappedKey SingleWrappedKey, err error) { rec, ok := records.GetRecord(name) if !ok { err = errors.New("Missing user on disk") return } - var singleWrappedKey SingleWrappedKey - if singleWrappedKey.aesKey, err = symcrypt.MakeRandom(16); err != nil { - return err + return } if singleWrappedKey.Key, err = rec.EncryptKey(singleWrappedKey.aesKey); err != nil { - return err + return } - encrypted.KeySetRSA[name] = singleWrappedKey + return } - // encrypt file key with every combination of two keys - encrypted.KeySet = make([]MultiWrappedKey, 0) + encryptKey := func(outer, inner string, clearKey []byte) (keyBytes []byte, err error) { + var outerCrypt, innerCrypt cipher.Block + keyBytes = make([]byte, 16) - for i := 0; i < len(names); i++ { - for j := i + 1; j < len(names); j++ { - var outerCrypt, innerCrypt cipher.Block - keyBytes := make([]byte, 16) - - outerCrypt, err = aes.NewCipher(encrypted.KeySetRSA[names[i]].aesKey) - if err != nil { - return - } - - innerCrypt, err = aes.NewCipher(encrypted.KeySetRSA[names[j]].aesKey) - if err != nil { - return - } - - innerCrypt.Encrypt(keyBytes, clearKey) - outerCrypt.Encrypt(keyBytes, keyBytes) - - out := MultiWrappedKey{ - Name: []string{names[i], names[j]}, - Key: keyBytes, - } - - encrypted.KeySet = append(encrypted.KeySet, out) + outerCrypt, err = aes.NewCipher(encrypted.KeySetRSA[outer].aesKey) + if err != nil { + return } + + innerCrypt, err = aes.NewCipher(encrypted.KeySetRSA[inner].aesKey) + if err != nil { + return + } + + innerCrypt.Encrypt(keyBytes, clearKey) + outerCrypt.Encrypt(keyBytes, keyBytes) + + return } - return nil + if len(access.Names) > 0 { + // Generate a random AES key for each user and RSA/ECIES encrypt it + encrypted.KeySetRSA = make(map[string]SingleWrappedKey) + + for _, name := range access.Names { + encrypted.KeySetRSA[name], err = generateRandomKey(name) + if err != nil { + return err + } + } + + // encrypt file key with every combination of two keys + encrypted.KeySet = make([]MultiWrappedKey, 0) + + for i := 0; i < len(access.Names); i++ { + for j := i + 1; j < len(access.Names); j++ { + keyBytes, err := encryptKey(access.Names[i], access.Names[j], clearKey) + if err != nil { + return err + } + + out := MultiWrappedKey{ + Name: []string{access.Names[i], access.Names[j]}, + Key: keyBytes, + } + + 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) + + for _, name := range access.LeftNames { + encrypted.KeySetRSA[name], err = generateRandomKey(name) + if err != nil { + return err + } + } + + for _, name := range access.RightNames { + encrypted.KeySetRSA[name], err = generateRandomKey(name) + if err != nil { + return err + } + } + + // encrypt file key with every combination of one left key and one right key + encrypted.KeySet = make([]MultiWrappedKey, 0) + + for _, leftName := range access.LeftNames { + for _, rightName := range access.RightNames { + keyBytes, err := encryptKey(leftName, rightName, clearKey) + if err != nil { + return err + } + + out := MultiWrappedKey{ + Name: []string{leftName, rightName}, + Key: keyBytes, + } + + encrypted.KeySet = append(encrypted.KeySet, out) + } + } + + return nil + } else { + return errors.New("Invalid access structure.") + } } // unwrapKey decrypts first key in keys whose encryption keys are in keycache @@ -287,11 +355,7 @@ func (encrypted *EncryptedData) unwrapKey(cache *keycache.Cache, user string) (u // Encrypt encrypts data with the keys associated with names. This // requires a minimum of min keys to decrypt. NOTE: as currently // implemented, the maximum value for min is 2. -func (c *Cryptor) Encrypt(in []byte, labels, names []string, min int) (resp []byte, err error) { - if min > 2 { - return nil, errors.New("Minimum restricted to 2") - } - +func (c *Cryptor) Encrypt(in []byte, labels []string, access AccessStructure) (resp []byte, err error) { var encrypted EncryptedData encrypted.Version = DEFAULT_VERSION if encrypted.VaultId, err = c.records.GetVaultId(); err != nil { @@ -309,7 +373,7 @@ func (c *Cryptor) Encrypt(in []byte, labels, names []string, min int) (resp []by return } - err = encrypted.wrapKey(c.records, clearKey, names, min) + err = encrypted.wrapKey(c.records, clearKey, access) if err != nil { return } @@ -361,7 +425,6 @@ func (c *Cryptor) Decrypt(in []byte, user string) (resp []byte, names []string, return } - // make sure file was encrypted with the active vault vaultId, err := c.records.GetVaultId() if err != nil { diff --git a/passvault/passvault.go b/passvault/passvault.go index a595cca..3a434dc 100644 --- a/passvault/passvault.go +++ b/passvault/passvault.go @@ -343,13 +343,13 @@ func InitFrom(path string) (records Records, err error) { func (records *Records) WriteRecordsToDisk() error { if records.localPath == "memory" { return nil - } else { - jsonDiskRecord, err := json.Marshal(records) - if err != nil { - return err - } - return ioutil.WriteFile(records.localPath, jsonDiskRecord, 0644) } + + jsonDiskRecord, err := json.Marshal(records) + if err != nil { + return err + } + return ioutil.WriteFile(records.localPath, jsonDiskRecord, 0644) } // AddNewRecord adds a new record for a given username and password. @@ -429,9 +429,8 @@ func (records *Records) DeleteRecord(name string) error { if _, ok := records.GetRecord(name); ok { delete(records.Passwords, name) return records.WriteRecordsToDisk() - } else { - return errors.New("Record missing") } + return errors.New("Record missing") } // RevokeRecord removes admin status from a record. @@ -440,9 +439,8 @@ func (records *Records) RevokeRecord(name string) error { rec.Admin = false records.SetRecord(rec, name) return records.WriteRecordsToDisk() - } else { - return errors.New("Record missing") } + return errors.New("Record missing") } // MakeAdmin adds admin status to a given record. @@ -451,9 +449,8 @@ func (records *Records) MakeAdmin(name string) error { rec.Admin = true records.SetRecord(rec, name) return records.WriteRecordsToDisk() - } else { - return errors.New("Record missing") } + return errors.New("Record missing") } // SetRecord puts a record into the global status. @@ -516,18 +513,16 @@ func (pr *PasswordRecord) EncryptKey(in []byte) (out []byte, err error) { func (pr *PasswordRecord) GetKeyRSAPub() (out *rsa.PublicKey, err error) { if pr.Type != RSARecord { return out, errors.New("Invalid function for record type") - } else { - return &pr.RSAKey.RSAPublic, err } + return &pr.RSAKey.RSAPublic, err } // GetKeyECCPub returns the ECDSA public key out of the record. func (pr *PasswordRecord) GetKeyECCPub() (out *ecdsa.PublicKey, err error) { if pr.Type != ECCRecord { return out, errors.New("Invalid function for record type") - } else { - return pr.ECKey.ECPublic.toECDSA(), err } + return pr.ECKey.ECPublic.toECDSA(), err } // GetKeyECC returns the ECDSA private key of the record given the correct password. @@ -623,7 +618,6 @@ func (pr *PasswordRecord) ValidatePassword(password string) error { if bytes.Compare(h, pr.HashedPassword) != 0 { return errors.New("Wrong Password") - } else { - return nil } + return nil }