add vendoring

This commit is contained in:
Aine
2022-11-16 12:08:51 +02:00
parent 14751cbf3a
commit c1d33fe3cb
1104 changed files with 759066 additions and 0 deletions

108
vendor/maunium.net/go/mautrix/crypto/ssss/client.go generated vendored Normal file
View File

@@ -0,0 +1,108 @@
// Copyright (c) 2020 Tulir Asokan
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
package ssss
import (
"fmt"
"maunium.net/go/mautrix"
"maunium.net/go/mautrix/event"
)
// Machine contains utility methods for interacting with SSSS data on the server.
type Machine struct {
Client *mautrix.Client
}
func NewSSSSMachine(client *mautrix.Client) *Machine {
return &Machine{
Client: client,
}
}
type DefaultSecretStorageKeyContent struct {
KeyID string `json:"key"`
}
// GetDefaultKeyID retrieves the default key ID for this account from SSSS.
func (mach *Machine) GetDefaultKeyID() (string, error) {
var data DefaultSecretStorageKeyContent
err := mach.Client.GetAccountData(event.AccountDataSecretStorageDefaultKey.Type, &data)
if err != nil {
if httpErr, ok := err.(mautrix.HTTPError); ok && httpErr.RespError != nil && httpErr.RespError.ErrCode == "M_NOT_FOUND" {
return "", ErrNoDefaultKeyAccountDataEvent
}
return "", fmt.Errorf("failed to get default key account data from server: %w", err)
}
if len(data.KeyID) == 0 {
return "", ErrNoKeyFieldInAccountDataEvent
}
return data.KeyID, nil
}
// SetDefaultKeyID sets the default key ID for this account on the server.
func (mach *Machine) SetDefaultKeyID(keyID string) error {
return mach.Client.SetAccountData(event.AccountDataSecretStorageDefaultKey.Type, &DefaultSecretStorageKeyContent{keyID})
}
// GetKeyData gets the details about the given key ID.
func (mach *Machine) GetKeyData(keyID string) (keyData *KeyMetadata, err error) {
keyData = &KeyMetadata{id: keyID}
err = mach.Client.GetAccountData(fmt.Sprintf("%s.%s", event.AccountDataSecretStorageKey.Type, keyID), keyData)
return
}
// SetKeyData stores SSSS key metadata on the server.
func (mach *Machine) SetKeyData(keyID string, keyData *KeyMetadata) error {
return mach.Client.SetAccountData(fmt.Sprintf("%s.%s", event.AccountDataSecretStorageKey.Type, keyID), keyData)
}
// GetDefaultKeyData gets the details about the default key ID (see GetDefaultKeyID).
func (mach *Machine) GetDefaultKeyData() (keyID string, keyData *KeyMetadata, err error) {
keyID, err = mach.GetDefaultKeyID()
if err != nil {
return
}
keyData, err = mach.GetKeyData(keyID)
return
}
// GetDecryptedAccountData gets the account data event with the given event type and decrypts it using the given key.
func (mach *Machine) GetDecryptedAccountData(eventType event.Type, key *Key) ([]byte, error) {
var encData EncryptedAccountDataEventContent
err := mach.Client.GetAccountData(eventType.Type, &encData)
if err != nil {
return nil, err
}
return encData.Decrypt(eventType.Type, key)
}
// SetEncryptedAccountData encrypts the given data with the given keys and stores it on the server.
func (mach *Machine) SetEncryptedAccountData(eventType event.Type, data []byte, keys ...*Key) error {
if len(keys) == 0 {
return ErrNoKeyGiven
}
encrypted := make(map[string]EncryptedKeyData, len(keys))
for _, key := range keys {
encrypted[key.ID] = key.Encrypt(eventType.Type, data)
}
return mach.Client.SetAccountData(eventType.Type, &EncryptedAccountDataEventContent{Encrypted: encrypted})
}
// GenerateAndUploadKey generates a new SSSS key and stores the metadata on the server.
func (mach *Machine) GenerateAndUploadKey(passphrase string) (key *Key, err error) {
key, err = NewKey(passphrase)
if err != nil {
return nil, fmt.Errorf("failed to generate new key: %w", err)
}
err = mach.SetKeyData(key.ID, key.Metadata)
if err != nil {
err = fmt.Errorf("failed to upload key: %w", err)
}
return key, err
}

124
vendor/maunium.net/go/mautrix/crypto/ssss/key.go generated vendored Normal file
View File

@@ -0,0 +1,124 @@
// Copyright (c) 2020 Tulir Asokan
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
package ssss
import (
"crypto/rand"
"encoding/base64"
"fmt"
"strings"
"maunium.net/go/mautrix/crypto/utils"
)
// Key represents a SSSS private key and related metadata.
type Key struct {
ID string `json:"-"`
Key []byte `json:"-"`
Metadata *KeyMetadata `json:"-"`
}
// NewKey generates a new SSSS key, optionally based on the given passphrase.
//
// Errors are only returned if crypto/rand runs out of randomness.
func NewKey(passphrase string) (*Key, error) {
// We don't support any other algorithms currently.
keyData := KeyMetadata{Algorithm: AlgorithmAESHMACSHA2}
var ssssKey []byte
if len(passphrase) > 0 {
// There's a passphrase. We need to generate a salt for it, set the metadata
// and then compute the key using the passphrase and the metadata.
saltBytes := make([]byte, 24)
if _, err := rand.Read(saltBytes); err != nil {
return nil, fmt.Errorf("failed to get random bytes for salt: %w", err)
}
keyData.Passphrase = &PassphraseMetadata{
Algorithm: PassphraseAlgorithmPBKDF2,
Iterations: 500000,
Salt: base64.StdEncoding.EncodeToString(saltBytes),
Bits: 256,
}
var err error
ssssKey, err = keyData.Passphrase.GetKey(passphrase)
if err != nil {
return nil, fmt.Errorf("failed to get key from passphrase: %w", err)
}
} else {
// No passphrase, just generate a random key
ssssKey = make([]byte, 32)
if _, err := rand.Read(ssssKey); err != nil {
return nil, fmt.Errorf("failed to get random bytes for key: %w", err)
}
}
// Generate a random ID for the key. It's what identifies the key in account data.
keyIDBytes := make([]byte, 24)
if _, err := rand.Read(keyIDBytes); err != nil {
return nil, fmt.Errorf("failed to get random bytes for key ID: %w", err)
}
// We store a certain hash in the key metadata so that clients can check if the user entered the correct key.
var ivBytes [utils.AESCTRIVLength]byte
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.MAC = keyData.calculateHash(ssssKey)
return &Key{
Key: ssssKey,
ID: base64.StdEncoding.EncodeToString(keyIDBytes),
Metadata: &keyData,
}, nil
}
// RecoveryKey gets the recovery key for this SSSS key.
func (key *Key) RecoveryKey() string {
return utils.EncodeBase58RecoveryKey(key.Key)
}
// Encrypt encrypts the given data with this key.
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)
utils.XorA256CTR(payload, aesKey, iv)
return EncryptedKeyData{
Ciphertext: base64.StdEncoding.EncodeToString(payload),
IV: base64.StdEncoding.EncodeToString(iv[:]),
MAC: utils.HMACSHA256B64(payload, hmacKey),
}
}
// 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)
copy(ivBytes[:], decodedIV)
payload, err := base64.StdEncoding.DecodeString(data.Ciphertext)
if err != nil {
return nil, err
}
// derive the AES and HMAC keys for the requested event type using the SSSS key
aesKey, hmacKey := utils.DeriveKeysSHA256(key.Key, eventType)
// 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, "=", "") {
return nil, ErrKeyDataMACMismatch
}
utils.XorA256CTR(payload, aesKey, ivBytes)
decryptedDecoded, err := base64.StdEncoding.DecodeString(string(payload))
return decryptedDecoded, err
}

102
vendor/maunium.net/go/mautrix/crypto/ssss/meta.go generated vendored Normal file
View File

@@ -0,0 +1,102 @@
// Copyright (c) 2020 Tulir Asokan
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
package ssss
import (
"encoding/base64"
"fmt"
"strings"
"maunium.net/go/mautrix/crypto/utils"
)
// KeyMetadata represents server-side metadata about a SSSS key. The metadata can be used to get
// the actual SSSS key from a passphrase or recovery key.
type KeyMetadata struct {
id string
Algorithm Algorithm `json:"algorithm"`
IV string `json:"iv"`
MAC string `json:"mac"`
Passphrase *PassphraseMetadata `json:"passphrase,omitempty"`
}
// VerifyRecoveryKey verifies that the given passphrase is valid and returns the computed SSSS key.
func (kd *KeyMetadata) VerifyPassphrase(passphrase string) (*Key, error) {
ssssKey, err := kd.Passphrase.GetKey(passphrase)
if err != nil {
return nil, err
} else if !kd.VerifyKey(ssssKey) {
return nil, ErrIncorrectSSSSKey
}
return &Key{
ID: kd.id,
Key: ssssKey,
Metadata: kd,
}, nil
}
// VerifyRecoveryKey verifies that the given recovery key is valid and returns the decoded SSSS key.
func (kd *KeyMetadata) VerifyRecoveryKey(recoverKey string) (*Key, error) {
ssssKey := utils.DecodeBase58RecoveryKey(recoverKey)
if ssssKey == nil {
return nil, ErrInvalidRecoveryKey
} else if !kd.VerifyKey(ssssKey) {
return nil, ErrIncorrectSSSSKey
}
return &Key{
ID: kd.id,
Key: ssssKey,
Metadata: kd,
}, nil
}
// 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), "=", "")
}
// calculateHash calculates the hash used for checking if the key is entered correctly as described
// in the spec: https://matrix.org/docs/spec/client_server/unstable#m-secret-storage-v1-aes-hmac-sha2
func (kd *KeyMetadata) calculateHash(key []byte) string {
aesKey, hmacKey := utils.DeriveKeysSHA256(key, "")
var ivBytes [utils.AESCTRIVLength]byte
_, _ = base64.StdEncoding.Decode(ivBytes[:], []byte(kd.IV))
cipher := utils.XorA256CTR(make([]byte, utils.AESCTRKeyLength), aesKey, ivBytes)
return utils.HMACSHA256B64(cipher, hmacKey)
}
// PassphraseMetadata represents server-side metadata about a SSSS key passphrase.
type PassphraseMetadata struct {
Algorithm PassphraseAlgorithm `json:"algorithm"`
Iterations int `json:"iterations"`
Salt string `json:"salt"`
Bits int `json:"bits"`
}
// GetKey gets the SSSS key from the passphrase.
func (pd *PassphraseMetadata) GetKey(passphrase string) ([]byte, error) {
if pd == nil {
return nil, ErrNoPassphrase
}
if pd.Algorithm != PassphraseAlgorithmPBKDF2 {
return nil, fmt.Errorf("%w: %s", ErrUnsupportedPassphraseAlgorithm, pd.Algorithm)
}
bits := 256
if pd.Bits != 0 {
bits = pd.Bits
}
return utils.PBKDF2SHA512([]byte(passphrase), []byte(pd.Salt), pd.Iterations, bits), nil
}

75
vendor/maunium.net/go/mautrix/crypto/ssss/types.go generated vendored Normal file
View File

@@ -0,0 +1,75 @@
// Copyright (c) 2020 Tulir Asokan
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
package ssss
import (
"errors"
"fmt"
"reflect"
"maunium.net/go/mautrix/event"
)
var (
ErrNoDefaultKeyID = errors.New("could not find default key ID")
ErrNoDefaultKeyAccountDataEvent = fmt.Errorf("%w: no %s event in account data", ErrNoDefaultKeyID, event.AccountDataSecretStorageDefaultKey.Type)
ErrNoKeyFieldInAccountDataEvent = fmt.Errorf("%w: missing key field in account data event", ErrNoDefaultKeyID)
ErrNoKeyGiven = errors.New("must provide at least one key to encrypt for")
ErrNotEncryptedForKey = errors.New("data is not encrypted for given key ID")
ErrKeyDataMACMismatch = errors.New("key data MAC mismatch")
ErrNoPassphrase = errors.New("no passphrase data has been set for the default key")
ErrUnsupportedPassphraseAlgorithm = errors.New("unsupported passphrase KDF algorithm")
ErrIncorrectSSSSKey = errors.New("incorrect SSSS key")
ErrInvalidRecoveryKey = errors.New("invalid recovery key")
)
// Algorithm is the identifier for an SSSS encryption algorithm.
type Algorithm string
const (
// AlgorithmAESHMACSHA2 is the current main algorithm.
AlgorithmAESHMACSHA2 Algorithm = "m.secret_storage.v1.aes-hmac-sha2"
// AlgorithmCurve25519AESSHA2 is the old algorithm
AlgorithmCurve25519AESSHA2 Algorithm = "m.secret_storage.v1.curve25519-aes-sha2"
)
// PassphraseAlgorithm is the identifier for an algorithm used to derive a key from a passphrase for SSSS.
type PassphraseAlgorithm string
const (
// PassphraseAlgorithmPBKDF2 is the current main algorithm
PassphraseAlgorithmPBKDF2 PassphraseAlgorithm = "m.pbkdf2"
)
type EncryptedKeyData struct {
Ciphertext string `json:"ciphertext"`
IV string `json:"iv"`
MAC string `json:"mac"`
}
type EncryptedAccountDataEventContent struct {
Encrypted map[string]EncryptedKeyData `json:"encrypted"`
}
func (ed *EncryptedAccountDataEventContent) Decrypt(eventType string, key *Key) ([]byte, error) {
keyEncData, ok := ed.Encrypted[key.ID]
if !ok {
return nil, ErrNotEncryptedForKey
}
return key.Decrypt(eventType, keyEncData)
}
func init() {
encryptedContent := reflect.TypeOf(&EncryptedAccountDataEventContent{})
event.TypeMap[event.AccountDataCrossSigningMaster] = encryptedContent
event.TypeMap[event.AccountDataCrossSigningSelf] = encryptedContent
event.TypeMap[event.AccountDataCrossSigningUser] = encryptedContent
event.TypeMap[event.AccountDataSecretStorageDefaultKey] = reflect.TypeOf(&DefaultSecretStorageKeyContent{})
event.TypeMap[event.AccountDataSecretStorageKey] = reflect.TypeOf(&KeyMetadata{})
}