mirror of
https://github.com/cloudflare/redoctober.git
synced 2026-01-07 05:56:56 +00:00
Return to idiomatic style & Backwards compatible left&right owners
This commit is contained in:
13
core/core.go
13
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 {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user