Merge pull request #104 from andrewbuss/single_owner

Allow encryption with a single owner
This commit is contained in:
Nick Sullivan
2015-12-03 17:36:45 -08:00
4 changed files with 109 additions and 48 deletions

View File

@@ -69,6 +69,7 @@ type EncryptRequest struct {
Name string
Password string
Minimum int
Owners []string
LeftOwners []string
RightOwners []string
@@ -453,6 +454,7 @@ func Encrypt(jsonIn []byte) ([]byte, error) {
}
access := cryptor.AccessStructure{
Minimum: s.Minimum,
Names: s.Owners,
LeftNames: s.LeftOwners,
RightNames: s.RightOwners,
@@ -497,6 +499,7 @@ func ReEncrypt(jsonIn []byte) ([]byte, error) {
}
access := cryptor.AccessStructure{
Minimum: s.Minimum,
Names: s.Owners,
LeftNames: s.LeftOwners,
RightNames: s.RightOwners,

View File

@@ -400,8 +400,10 @@ func TestEncryptDecrypt(t *testing.T) {
delegateJson3 := []byte("{\"Name\":\"Carol\",\"Password\":\"Hello\",\"Time\":\"0s\",\"Uses\":0}")
delegateJson4 := []byte("{\"Name\":\"Bob\",\"Password\":\"Hello\",\"Time\":\"10s\",\"Uses\":2,\"Users\":[\"Alice\"],\"Labels\":[\"blue\"]}")
delegateJson5 := []byte("{\"Name\":\"Carol\",\"Password\":\"Hello\",\"Time\":\"10s\",\"Uses\":2,\"Users\":[\"Alice\"],\"Labels\":[\"blue\"]}")
encryptJson := []byte("{\"Name\":\"Carol\",\"Password\":\"Hello\",\"Minumum\":2,\"Owners\":[\"Alice\",\"Bob\",\"Carol\"],\"Data\":\"SGVsbG8gSmVsbG8=\"}")
encryptJson2 := []byte("{\"Name\":\"Alice\",\"Password\":\"Hello\",\"Minumum\":2,\"Owners\":[\"Alice\",\"Bob\",\"Carol\"],\"Data\":\"SGVsbG8gSmVsbG8=\",\"Labels\":[\"blue\",\"red\"]}")
delegateJson6 := []byte("{\"Name\":\"Alice\",\"Password\":\"Hello\",\"Time\":\"10s\",\"Uses\":1}")
encryptJson := []byte("{\"Name\":\"Carol\",\"Password\":\"Hello\",\"Minimum\":2,\"Owners\":[\"Alice\",\"Bob\",\"Carol\"],\"Data\":\"SGVsbG8gSmVsbG8=\"}")
encryptJson2 := []byte("{\"Name\":\"Alice\",\"Password\":\"Hello\",\"Minimum\":2,\"Owners\":[\"Alice\",\"Bob\",\"Carol\"],\"Data\":\"SGVsbG8gSmVsbG8=\",\"Labels\":[\"blue\",\"red\"]}")
encryptJson3 := []byte("{\"Name\":\"Alice\",\"Password\":\"Hello\",\"Minimum\":1,\"Owners\":[\"Alice\"],\"Data\":\"SGVsbG8gSmVsbG8=\"}")
Init("memory")
@@ -575,6 +577,49 @@ func TestEncryptDecrypt(t *testing.T) {
t.Fatalf("Error in decrypt, %v", d.Delegates)
}
}
// Encrypt with only a single owner
respJson, err = Encrypt(encryptJson3)
if err != nil {
t.Fatalf("Error in encrypt, %v", err)
}
err = json.Unmarshal(respJson, &s)
if err != nil {
t.Fatalf("Error in encrypt, %v", err)
}
if s.Status != "ok" {
t.Fatalf("Error in encrypt, %v", s.Status)
}
respJson, err = Delegate(delegateJson6)
if err != nil {
t.Fatalf("Error in delegating account, %v", err)
}
err = json.Unmarshal(respJson, &s)
if err != nil {
t.Fatalf("Error in delegating account, %v", err)
}
if s.Status != "ok" {
t.Fatalf("Error in delegating account, %v", s.Status)
}
// decrypt file
decryptJson2, err := json.Marshal(DecryptRequest{Name: "Alice", Password: "Hello", Data: s.Response})
if err != nil {
t.Fatalf("Error in marshalling decryption, %v", err)
}
respJson2, err = Decrypt(decryptJson2)
if err != nil {
t.Fatalf("Error in decrypt, %v", err)
}
err = json.Unmarshal(respJson2, &s)
if err != nil {
t.Fatalf("Error in decrypt, %v", err)
}
if s.Status != "ok" {
t.Fatalf("Error in decrypt, %v", s.Status)
}
}
func TestReEncrypt(t *testing.T) {
@@ -585,7 +630,7 @@ func TestReEncrypt(t *testing.T) {
delegateJson5 := []byte(`{"Name":"Carol","Password":"Hello","Time":"10s","Uses":2,"Users":["Alice"],"Labels":["blue"]}`)
delegateJson6 := []byte(`{"Name":"Bob","Password":"Hello","Time":"10s","Uses":2,"Users":["Alice"],"Labels":["red"]}`)
delegateJson7 := []byte(`{"Name":"Carol","Password":"Hello","Time":"10s","Uses":2,"Users":["Alice"],"Labels":["red"]}`)
encryptJson := []byte(`{"Name":"Carol","Password":"Hello","Minumum":2,"Owners":["Alice","Bob","Carol"],"Data":"SGVsbG8gSmVsbG8=","Labels":["blue"]}`)
encryptJson := []byte(`{"Name":"Carol","Password":"Hello","Minimum":2,"Owners":["Alice","Bob","Carol"],"Data":"SGVsbG8gSmVsbG8=","Labels":["blue"]}`)
Init("memory")
@@ -671,6 +716,7 @@ func TestReEncrypt(t *testing.T) {
Name: "Alice",
Password: "Hello",
Data: s.Response,
Minimum: 2,
Owners: []string{"Alice", "Bob", "Carol"},
Labels: []string{"red"},
})
@@ -761,7 +807,7 @@ func TestOwners(t *testing.T) {
delegateJson := []byte("{\"Name\":\"Alice\",\"Password\":\"Hello\",\"Time\":\"0s\",\"Uses\":0}")
delegateJson2 := []byte("{\"Name\":\"Bob\",\"Password\":\"Hello\",\"Time\":\"0s\",\"Uses\":0}")
delegateJson3 := []byte("{\"Name\":\"Carol\",\"Password\":\"Hello\",\"Time\":\"0s\",\"Uses\":0}")
encryptJson := []byte("{\"Name\":\"Carol\",\"Password\":\"Hello\",\"Minumum\":2,\"Owners\":[\"Alice\",\"Bob\",\"Carol\"],\"Data\":\"SGVsbG8gSmVsbG8=\"}")
encryptJson := []byte("{\"Name\":\"Carol\",\"Password\":\"Hello\",\"Minimum\":2,\"Owners\":[\"Alice\",\"Bob\",\"Carol\"],\"Data\":\"SGVsbG8gSmVsbG8=\"}")
var s ResponseData
var l OwnersData

View File

@@ -42,7 +42,8 @@ func New(records *passvault.Records, cache *keycache.Cache) Cryptor {
// both, then he can decrypt it alone). If a predicate is present, it must be
// satisfied to decrypt.
type AccessStructure struct {
Names []string
Minimum int
Names []string
LeftNames []string
RightNames []string
@@ -253,23 +254,19 @@ func (encrypted *EncryptedData) wrapKey(records *passvault.Records, clearKey []b
return
}
encryptKey := func(outer, inner string, clearKey []byte) (keyBytes []byte, err error) {
var outerCrypt, innerCrypt cipher.Block
encryptKey := func(keyNames []string, clearKey []byte) (keyBytes []byte, err error) {
keyBytes = make([]byte, 16)
copy(keyBytes, clearKey)
for _, keyName := range keyNames {
var keyCrypt cipher.Block
keyCrypt, err = aes.NewCipher(encrypted.KeySetRSA[keyName].aesKey)
if err != nil {
return
}
outerCrypt, err = aes.NewCipher(encrypted.KeySetRSA[outer].aesKey)
if err != nil {
return
keyCrypt.Encrypt(keyBytes, keyBytes)
}
innerCrypt, err = aes.NewCipher(encrypted.KeySetRSA[inner].aesKey)
if err != nil {
return
}
innerCrypt.Encrypt(keyBytes, clearKey)
outerCrypt.Encrypt(keyBytes, keyBytes)
return
}
@@ -282,26 +279,40 @@ func (encrypted *EncryptedData) wrapKey(records *passvault.Records, clearKey []b
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 access.Minimum == 1 {
keyBytes, err := encryptKey([]string{access.Names[0]}, clearKey)
if err != nil {
return err
}
out := MultiWrappedKey{
Name: []string{access.Names[i], access.Names[j]},
encrypted.KeySet = append(encrypted.KeySet, MultiWrappedKey{
Name: []string{access.Names[0]},
Key: keyBytes,
}
encrypted.KeySet = append(encrypted.KeySet, out)
})
}
}
if access.Minimum == 2 {
for i := 0; i < len(access.Names); i++ {
for j := i + 1; j < len(access.Names); j++ {
keyBytes, err := encryptKey([]string{access.Names[j], access.Names[i]}, clearKey)
if err != nil {
return err
}
out := MultiWrappedKey{
Name: []string{access.Names[i], access.Names[j]},
Key: keyBytes,
}
encrypted.KeySet = append(encrypted.KeySet, out)
}
}
} else if access.Minimum > 3 {
err = errors.New("Encryption to a list of owners with minimum > 2 is not implemented")
return err
}
} 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)
@@ -329,7 +340,7 @@ func (encrypted *EncryptedData) wrapKey(records *passvault.Records, clearKey []b
continue
}
keyBytes, err := encryptKey(leftName, rightName, clearKey)
keyBytes, err := encryptKey([]string{rightName, leftName}, clearKey)
if err != nil {
return err
}

View File

@@ -33,19 +33,20 @@ var (
createUserInput3 = &core.CreateUserRequest{Name: "Dodo", Password: "Dodgson"}
delegateInput1 = &core.DelegateRequest{
Name: createUserInput1.Name,
Name: createUserInput1.Name,
Password: createUserInput1.Password,
Time: "2h34m",
Uses: 1,
Time: "2h34m",
Uses: 1,
}
delegateInput2 = &core.DelegateRequest{
Name: createUserInput2.Name,
Name: createUserInput2.Name,
Password: createUserInput2.Password,
Time: "2h34m",
Uses: 1,
Time: "2h34m",
Uses: 1,
}
encryptInput = &core.EncryptRequest{
encryptInput = &core.EncryptRequest{
Minimum: 2,
Name: createVaultInput.Name,
Password: createVaultInput.Password,
Owners: []string{createUserInput1.Name, createUserInput2.Name},
@@ -378,9 +379,9 @@ func TestDecrypt(t *testing.T) {
encryptedData := s.Response
decryptInput := &core.DecryptRequest{
Name: "Alice",
Name: "Alice",
Password: "Lewis",
Data: encryptedData,
Data: encryptedData,
}
// Check the first decrypt command (where not enough owners have decrypted yet).
@@ -612,8 +613,8 @@ func TestPassword(t *testing.T) {
// Check changing password with invalid password.
passwordInput := &core.PasswordRequest{
Name: createUserInput1.Name,
Password: "badpassword",
Name: createUserInput1.Name,
Password: "badpassword",
NewPassword: "worsepassword",
}
if err := postAndTest("password", passwordInput, 200, "Wrong Password"); err != nil {
@@ -623,8 +624,8 @@ func TestPassword(t *testing.T) {
// Check changing password with nonexistent user.
passwordInput = &core.PasswordRequest{
Name: createUserInput2.Name,
Password: "badpassword",
Name: createUserInput2.Name,
Password: "badpassword",
NewPassword: "worsepassword",
}
if err := postAndTest("password", passwordInput, 200, "Record not present"); err != nil {
@@ -634,8 +635,8 @@ func TestPassword(t *testing.T) {
// Check changing the password properly.
passwordInput = &core.PasswordRequest{
Name: createUserInput1.Name,
Password: createUserInput1.Password,
Name: createUserInput1.Name,
Password: createUserInput1.Password,
NewPassword: "foobar",
}
if err := postAndTest("password", passwordInput, 200, "ok"); err != nil {
@@ -662,7 +663,7 @@ func TestPurge(t *testing.T) {
// Check purging with non-admin user
purgeInput := &core.PurgeRequest{
Name: createUserInput1.Name,
Name: createUserInput1.Name,
Password: createUserInput1.Password,
}
if err := postAndTest("purge", purgeInput, 200, "Admin required"); err != nil {
@@ -672,7 +673,7 @@ func TestPurge(t *testing.T) {
// Check purging with admin user
purgeInput = &core.PurgeRequest{
Name: createVaultInput.Name,
Name: createVaultInput.Name,
Password: createVaultInput.Password,
}
if err := postAndTest("purge", purgeInput, 200, "ok"); err != nil {