mirror of
https://github.com/cloudflare/redoctober.git
synced 2026-01-10 07:58:03 +00:00
Patched HMAC vulnerability.
This commit is contained in:
@@ -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,
|
||||
}
|
||||
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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: '<p>Successfully decrypted data:</p><pre>'+ window.atob(d.Data)+'</pre><p>Delegates: '+d.Delegates.sort().join(', ')+'</p>' }) );
|
||||
$form.find('.feedback').empty().append( makeAlert({ type: (d.Secure ? 'success' : 'warning'), message: '<p>Successfully decrypted data:</p><pre>'+ window.atob(d.Data)+'</pre><p>Delegates: '+d.Delegates.sort().join(', ')+'</p>' }) );
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@@ -732,7 +732,7 @@ var indexHtml = []byte(`<!DOCTYPE html>
|
||||
data : data,
|
||||
success : function(d){
|
||||
d = JSON.parse(window.atob(d.Response));
|
||||
$form.find('.feedback').empty().append( makeAlert({ type: 'success', message: '<p>Successfully decrypted data:</p><pre>'+ window.atob(d.Data)+'</pre><p>Delegates: '+d.Delegates.sort().join(', ')+'</p>' }) );
|
||||
$form.find('.feedback').empty().append( makeAlert({ type: (d.Secure ? 'success' : 'warning'), message: '<p>Successfully decrypted data:</p><pre>'+ window.atob(d.Data)+'</pre><p>Delegates: '+d.Delegates.sort().join(', ')+'</p>' }) );
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user