diff --git a/core/core.go b/core/core.go index a8b16da..965c4d6 100644 --- a/core/core.go +++ b/core/core.go @@ -94,6 +94,7 @@ type SummaryData struct { type DecryptWithDelegates struct { Data []byte + Secure bool Delegates []string } @@ -299,7 +300,7 @@ func Decrypt(jsonIn []byte) ([]byte, error) { return jsonStatusError(err) } - data, names, err := crypt.Decrypt(s.Data, s.Name) + data, names, secure, err := crypt.Decrypt(s.Data, s.Name) if err != nil { log.Println("Error decrypting:", err) return jsonStatusError(err) @@ -307,6 +308,7 @@ func Decrypt(jsonIn []byte) ([]byte, error) { resp := &DecryptWithDelegates{ Data: data, + Secure: secure, Delegates: names, } diff --git a/cryptor/cryptor.go b/cryptor/cryptor.go index 6978865..ea316d7 100644 --- a/cryptor/cryptor.go +++ b/cryptor/cryptor.go @@ -53,11 +53,11 @@ type SingleWrappedKey struct { // keys necessary to decrypt it when delegated. type EncryptedData struct { Version int - VaultId int - Labels []string - KeySet []MultiWrappedKey - KeySetRSA map[string]SingleWrappedKey - IV []byte + VaultId int `json:",omitempty"` + Labels []string `json:",omitempty"` + KeySet []MultiWrappedKey `json:",omitempty"` + KeySetRSA map[string]SingleWrappedKey `json:",omitempty"` + IV []byte `json:",omitempty"` Data []byte Signature []byte } @@ -141,6 +141,42 @@ func (encrypted *EncryptedData) computeHmac(key []byte) []byte { return mac.Sum(nil) } +func (encrypted *EncryptedData) lock(key []byte) (err error) { + payload, err := json.Marshal(encrypted) + if err != nil { + return + } + + mac := hmac.New(sha1.New, key) + mac.Write(payload) + sig := mac.Sum(nil) + + *encrypted = EncryptedData{ + Version: -1, + Data: payload, + Signature: sig, + } + + return +} + +func (encrypted *EncryptedData) unlock(key []byte) (err error) { + if encrypted.Version != -1 { + return + } + + mac := hmac.New(sha1.New, key) + mac.Write(encrypted.Data) + sig := mac.Sum(nil) + + if !hmac.Equal(encrypted.Signature, sig) { + err = errors.New("Signature mismatch") + return + } + + return json.Unmarshal(encrypted.Data, encrypted) +} + // 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) { @@ -298,35 +334,44 @@ func (c *Cryptor) Encrypt(in []byte, labels, names []string, min int) (resp []by return } encrypted.Signature = encrypted.computeHmac(hmacKey) + encrypted.lock(hmacKey) return json.Marshal(encrypted) } // Decrypt decrypts a file using the keys in the key cache. -func (c *Cryptor) Decrypt(in []byte, user string) (resp []byte, names []string, err error) { +func (c *Cryptor) Decrypt(in []byte, user string) (resp []byte, names []string, secure bool, err error) { // unwrap encrypted file var encrypted EncryptedData if err = json.Unmarshal(in, &encrypted); err != nil { return } - if encrypted.Version != DEFAULT_VERSION { - return nil, nil, errors.New("Unknown version") + if encrypted.Version != DEFAULT_VERSION && encrypted.Version != -1 { + return nil, nil, secure, errors.New("Unknown version") } + secure = encrypted.Version == -1 + + hmacKey, err := c.records.GetHmacKey() + if err != nil { + return + } + + if err = encrypted.unlock(hmacKey); err != nil { + return + } + + // make sure file was encrypted with the active vault vaultId, err := c.records.GetVaultId() if err != nil { return } if encrypted.VaultId != vaultId { - return nil, nil, errors.New("Wrong vault") + return nil, nil, secure, errors.New("Wrong vault") } // compute HMAC - hmacKey, err := c.records.GetHmacKey() - if err != nil { - return - } expectedMAC := encrypted.computeHmac(hmacKey) if !hmac.Equal(encrypted.Signature, expectedMAC) { err = errors.New("Signature mismatch") diff --git a/index.html b/index.html index 1776365..20a7889 100644 --- a/index.html +++ b/index.html @@ -485,7 +485,7 @@ data : data, success : function(d){ d = JSON.parse(window.atob(d.Response)); - $form.find('.feedback').empty().append( makeAlert({ type: 'success', message: '
Successfully decrypted data:
'+ window.atob(d.Data)+'
Delegates: '+d.Delegates.sort().join(', ')+'
' }) ); + $form.find('.feedback').empty().append( makeAlert({ type: (d.Secure ? 'success' : 'warning'), message: 'Successfully decrypted data:
'+ window.atob(d.Data)+'
Delegates: '+d.Delegates.sort().join(', ')+'
' }) ); } }); }); diff --git a/redoctober.go b/redoctober.go index 924f8bd..e7e909b 100644 --- a/redoctober.go +++ b/redoctober.go @@ -732,7 +732,7 @@ var indexHtml = []byte(` data : data, success : function(d){ d = JSON.parse(window.atob(d.Response)); - $form.find('.feedback').empty().append( makeAlert({ type: 'success', message: 'Successfully decrypted data:
'+ window.atob(d.Data)+'
Delegates: '+d.Delegates.sort().join(', ')+'
' }) ); + $form.find('.feedback').empty().append( makeAlert({ type: (d.Secure ? 'success' : 'warning'), message: 'Successfully decrypted data:
'+ window.atob(d.Data)+'
Delegates: '+d.Delegates.sort().join(', ')+'
' }) ); } }); });