// encryptKey encrypts data with the key associated with name inner, // then name outer func encryptKey(nameInner, nameOuter string, clearKey []byte, rsaKeys map[string]SingleWrappedKey) (out MultiWrappedKey, err error) { out.Name = []string{nameOuter, nameInner} recInner, ok := passvault.GetRecord(nameInner) if !ok { err = errors.New("Missing user on disk") return } recOuter, ok := passvault.GetRecord(nameOuter) if !ok { err = errors.New("Missing user on disk") return } if recInner.Type != recOuter.Type { err = errors.New("Mismatched record types") return } var keyBytes []byte var overrideInner SingleWrappedKey var overrideOuter SingleWrappedKey // For AES records, use the live user key // For RSA records, use the public key from the passvault switch recInner.Type { case passvault.RSARecord: if overrideInner, ok = rsaKeys[nameInner]; !ok { err = errors.New("Missing user in file") return } if overrideOuter, ok = rsaKeys[nameOuter]; !ok { err = errors.New("Missing user in file") return } case passvault.AESRecord: break default: return out, errors.New("Unknown record type inner") } // double-wrap the keys if keyBytes, err = keycache.EncryptKey(clearKey, nameInner, overrideInner.aesKey); err != nil { return out, err } if keyBytes, err = keycache.EncryptKey(keyBytes, nameOuter, overrideOuter.aesKey); err != nil { return out, err } out.Key = keyBytes return }
// Delegate processes a delegation request. func Delegate(jsonIn []byte) ([]byte, error) { var s delegate if err := json.Unmarshal(jsonIn, &s); err != nil { return jsonStatusError(err) } if passvault.NumRecords() == 0 { return jsonStatusError(errors.New("Vault is not created yet")) } // Find password record for user and verify that their password // matches. If not found then add a new entry for this user. pr, found := passvault.GetRecord(s.Name) if found { if err := pr.ValidatePassword(s.Password); err != nil { return jsonStatusError(err) } } else { var err error if pr, err = passvault.AddNewRecord(s.Name, s.Password, false); err != nil { log.Printf("Error adding record for %s: %s\n", s.Name, err) return jsonStatusError(err) } } // add signed-in record to active set if err := keycache.AddKeyFromRecord(pr, s.Name, s.Password, s.Uses, s.Time); err != nil { log.Printf("Error adding key to cache for %s: %s\n", s.Name, err) return jsonStatusError(err) } return jsonStatusOk() }
// validateAdmin checks that the username and password passed in are // correct and that the user is an admin func validateAdmin(name, password string) error { if passvault.NumRecords() == 0 { return errors.New("Vault is not created yet") } pr, ok := passvault.GetRecord(name) if !ok { return errors.New("User not present") } if err := pr.ValidatePassword(password); err != nil { return err } if !pr.IsAdmin() { return errors.New("Admin required") } return nil }
// Modify processes a modify request. func Modify(jsonIn []byte) ([]byte, error) { var s modify if err := json.Unmarshal(jsonIn, &s); err != nil { return jsonStatusError(err) } if err := validateAdmin(s.Name, s.Password); err != nil { log.Printf("Error validating admin status of %s: %s", s.Name, err) return jsonStatusError(err) } if _, ok := passvault.GetRecord(s.ToModify); !ok { return jsonStatusError(errors.New("Record to modify missing")) } if s.Name == s.ToModify { return jsonStatusError(errors.New("Cannot modify own record")) } var err error switch s.Command { case "delete": err = passvault.DeleteRecord(s.ToModify) case "revoke": err = passvault.RevokeRecord(s.ToModify) case "admin": err = passvault.MakeAdmin(s.ToModify) default: return jsonStatusError(errors.New("Unknown command")) } if err != nil { return jsonStatusError(err) } else { return jsonStatusOk() } }
// 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 Encrypt(in []byte, names []string, min int) (resp []byte, err error) { if min > 2 { return nil, errors.New("Minimum restricted to 2") } var encrypted EncryptedData encrypted.Version = DEFAULT_VERSION if encrypted.VaultId, err = passvault.GetVaultId(); err != nil { return } // Generate random IV and encryption key ivBytes, err := makeRandom(16) if err != nil { return } // append used here to make a new slice from ivBytes and assign to // encrypted.IV encrypted.IV = append([]byte{}, ivBytes...) clearKey, err := makeRandom(16) if err != nil { return } // Allocate set of keys to be able to cover all ordered subsets of // length 2 of names encrypted.KeySet = make([]MultiWrappedKey, len(names)*(len(names)-1)) encrypted.KeySetRSA = make(map[string]SingleWrappedKey) var singleWrappedKey SingleWrappedKey for _, name := range names { rec, ok := passvault.GetRecord(name) if !ok { err = errors.New("Missing user on disk") return } if rec.GetType() == passvault.RSARecord { // only wrap key with RSA key if found if singleWrappedKey.aesKey, err = makeRandom(16); err != nil { return nil, err } if singleWrappedKey.Key, err = rec.EncryptKey(singleWrappedKey.aesKey); err != nil { return nil, err } encrypted.KeySetRSA[name] = singleWrappedKey } else { err = nil } } // encrypt file key with every combination of two keys var n int for _, nameOuter := range names { for _, nameInner := range names { if nameInner != nameOuter { encrypted.KeySet[n], err = encryptKey(nameInner, nameOuter, clearKey, encrypted.KeySetRSA) n += 1 } if err != nil { return } } } // encrypt file with clear key aesCrypt, err := aes.NewCipher(clearKey) if err != nil { return } clearFile := padding.AddPadding(in) encryptedFile := make([]byte, len(clearFile)) aesCBC := cipher.NewCBCEncrypter(aesCrypt, ivBytes) aesCBC.CryptBlocks(encryptedFile, clearFile) encrypted.Data = encryptedFile hmacKey, err := passvault.GetHmacKey() if err != nil { return } encrypted.Signature = computeHmac(hmacKey, encrypted) return json.Marshal(encrypted) }