updated deps; updated healthchecks.io integration

This commit is contained in:
Aine
2024-04-07 14:42:12 +03:00
parent 271a4a0e31
commit 15d61f174e
122 changed files with 3432 additions and 4613 deletions

View File

@@ -8,6 +8,7 @@ package ssss
import (
"context"
"errors"
"fmt"
"maunium.net/go/mautrix"
@@ -34,7 +35,7 @@ func (mach *Machine) GetDefaultKeyID(ctx context.Context) (string, error) {
var data DefaultSecretStorageKeyContent
err := mach.Client.GetAccountData(ctx, event.AccountDataSecretStorageDefaultKey.Type, &data)
if err != nil {
if httpErr, ok := err.(mautrix.HTTPError); ok && httpErr.RespError != nil && httpErr.RespError.ErrCode == "M_NOT_FOUND" {
if httpErr, ok := err.(mautrix.HTTPError); ok && errors.Is(httpErr.RespError, mautrix.MNotFound) {
return "", ErrNoDefaultKeyAccountDataEvent
}
return "", fmt.Errorf("failed to get default key account data from server: %w", err)

View File

@@ -67,12 +67,12 @@ func NewKey(passphrase string) (*Key, error) {
if _, err := rand.Read(ivBytes[:]); err != nil {
return nil, fmt.Errorf("failed to get random bytes for IV: %w", err)
}
keyData.IV = base64.StdEncoding.EncodeToString(ivBytes[:])
keyData.IV = base64.RawStdEncoding.EncodeToString(ivBytes[:])
keyData.MAC = keyData.calculateHash(ssssKey)
return &Key{
Key: ssssKey,
ID: base64.StdEncoding.EncodeToString(keyIDBytes),
ID: base64.RawStdEncoding.EncodeToString(keyIDBytes),
Metadata: &keyData,
}, nil
}
@@ -87,13 +87,18 @@ func (key *Key) Encrypt(eventType string, data []byte) EncryptedKeyData {
aesKey, hmacKey := utils.DeriveKeysSHA256(key.Key, eventType)
iv := utils.GenA256CTRIV()
payload := make([]byte, base64.StdEncoding.EncodedLen(len(data)))
base64.StdEncoding.Encode(payload, data)
// For some reason, keys in secret storage are base64 encoded before encrypting.
// Even more confusingly, it's a part of each key type's spec rather than the secrets spec.
// Key backup (`m.megolm_backup.v1`): https://spec.matrix.org/v1.9/client-server-api/#recovery-key
// Cross-signing (master, etc): https://spec.matrix.org/v1.9/client-server-api/#cross-signing (the very last paragraph)
// It's also not clear whether unpadded base64 is the right option, but assuming it is because everything else is unpadded.
payload := make([]byte, base64.RawStdEncoding.EncodedLen(len(data)))
base64.RawStdEncoding.Encode(payload, data)
utils.XorA256CTR(payload, aesKey, iv)
return EncryptedKeyData{
Ciphertext: base64.StdEncoding.EncodeToString(payload),
IV: base64.StdEncoding.EncodeToString(iv[:]),
Ciphertext: base64.RawStdEncoding.EncodeToString(payload),
IV: base64.RawStdEncoding.EncodeToString(iv[:]),
MAC: utils.HMACSHA256B64(payload, hmacKey),
}
}
@@ -101,10 +106,10 @@ func (key *Key) Encrypt(eventType string, data []byte) EncryptedKeyData {
// Decrypt decrypts the given encrypted data with this key.
func (key *Key) Decrypt(eventType string, data EncryptedKeyData) ([]byte, error) {
var ivBytes [utils.AESCTRIVLength]byte
decodedIV, _ := base64.StdEncoding.DecodeString(data.IV)
decodedIV, _ := base64.RawStdEncoding.DecodeString(strings.TrimRight(data.IV, "="))
copy(ivBytes[:], decodedIV)
payload, err := base64.StdEncoding.DecodeString(data.Ciphertext)
payload, err := base64.RawStdEncoding.DecodeString(strings.TrimRight(data.Ciphertext, "="))
if err != nil {
return nil, err
}
@@ -114,11 +119,11 @@ func (key *Key) Decrypt(eventType string, data EncryptedKeyData) ([]byte, error)
// compare the stored MAC with the one we calculated from the ciphertext
calcMac := utils.HMACSHA256B64(payload, hmacKey)
if strings.ReplaceAll(data.MAC, "=", "") != strings.ReplaceAll(calcMac, "=", "") {
if strings.TrimRight(data.MAC, "=") != calcMac {
return nil, ErrKeyDataMACMismatch
}
utils.XorA256CTR(payload, aesKey, ivBytes)
decryptedDecoded, err := base64.StdEncoding.DecodeString(string(payload))
decryptedDecoded, err := base64.RawStdEncoding.DecodeString(strings.TrimRight(string(payload), "="))
return decryptedDecoded, err
}

View File

@@ -19,9 +19,14 @@ import (
type KeyMetadata struct {
id string
Algorithm Algorithm `json:"algorithm"`
IV string `json:"iv"`
MAC string `json:"mac"`
Name string `json:"name"`
Algorithm Algorithm `json:"algorithm"`
// Note: as per https://spec.matrix.org/v1.9/client-server-api/#msecret_storagev1aes-hmac-sha2,
// these fields are "maybe padded" base64, so both unpadded and padded values must be supported.
IV string `json:"iv"`
MAC string `json:"mac"`
Passphrase *PassphraseMetadata `json:"passphrase,omitempty"`
}
@@ -59,7 +64,7 @@ func (kd *KeyMetadata) VerifyRecoveryKey(recoverKey string) (*Key, error) {
// VerifyKey verifies the SSSS key is valid by calculating and comparing its MAC.
func (kd *KeyMetadata) VerifyKey(key []byte) bool {
return strings.ReplaceAll(kd.MAC, "=", "") == strings.ReplaceAll(kd.calculateHash(key), "=", "")
return strings.TrimRight(kd.MAC, "=") == kd.calculateHash(key)
}
// calculateHash calculates the hash used for checking if the key is entered correctly as described
@@ -68,7 +73,7 @@ func (kd *KeyMetadata) calculateHash(key []byte) string {
aesKey, hmacKey := utils.DeriveKeysSHA256(key, "")
var ivBytes [utils.AESCTRIVLength]byte
_, _ = base64.StdEncoding.Decode(ivBytes[:], []byte(kd.IV))
_, _ = base64.RawStdEncoding.Decode(ivBytes[:], []byte(strings.TrimRight(kd.IV, "=")))
cipher := utils.XorA256CTR(make([]byte, utils.AESCTRKeyLength), aesKey, ivBytes)

View File

@@ -47,6 +47,8 @@ const (
)
type EncryptedKeyData struct {
// Note: as per https://spec.matrix.org/v1.9/client-server-api/#msecret_storagev1aes-hmac-sha2-1,
// these fields are "maybe padded" base64, so both unpadded and padded values must be supported.
Ciphertext string `json:"ciphertext"`
IV string `json:"iv"`
MAC string `json:"mac"`
@@ -72,4 +74,5 @@ func init() {
event.TypeMap[event.AccountDataCrossSigningUser] = encryptedContent
event.TypeMap[event.AccountDataSecretStorageDefaultKey] = reflect.TypeOf(&DefaultSecretStorageKeyContent{})
event.TypeMap[event.AccountDataSecretStorageKey] = reflect.TypeOf(&KeyMetadata{})
event.TypeMap[event.AccountDataMegolmBackupKey] = reflect.TypeOf(&EncryptedAccountDataEventContent{})
}