mirror of https://github.com/mautrix/go.git
crypto: refactor to remove need for Utility struct
This also removes all dependence on libolm for the functions that were provided by the Utility struct. The crypto/signatures package should be used for all signature verification operations, and for the occasional situation where a base64-encoded SHA-256 hash is required, the olm.SHA256B64 function should be used. Signed-off-by: Sumner Evans <sumner@beeper.com>pull/154/head
parent
c77d6fe1f9
commit
65be59bfed
|
@ -11,7 +11,7 @@ import (
|
|||
"context"
|
||||
|
||||
"maunium.net/go/mautrix"
|
||||
"maunium.net/go/mautrix/crypto/olm"
|
||||
"maunium.net/go/mautrix/crypto/signatures"
|
||||
"maunium.net/go/mautrix/id"
|
||||
)
|
||||
|
||||
|
@ -80,7 +80,7 @@ func (mach *OlmMachine) storeCrossSigningKeys(ctx context.Context, crossSigningK
|
|||
}
|
||||
|
||||
log.Debug().Msg("Verifying cross-signing key signature")
|
||||
if verified, err := olm.VerifySignatureJSON(userKeys, signUserID, signKeyName, signingKey); err != nil {
|
||||
if verified, err := signatures.VerifySignatureJSON(userKeys, signUserID, signKeyName, signingKey); err != nil {
|
||||
log.Warn().Err(err).Msg("Error verifying cross-signing key signature")
|
||||
} else {
|
||||
if verified {
|
||||
|
|
|
@ -14,7 +14,7 @@ import (
|
|||
"github.com/rs/zerolog"
|
||||
|
||||
"maunium.net/go/mautrix"
|
||||
"maunium.net/go/mautrix/crypto/olm"
|
||||
"maunium.net/go/mautrix/crypto/signatures"
|
||||
"maunium.net/go/mautrix/id"
|
||||
)
|
||||
|
||||
|
@ -52,7 +52,7 @@ func (mach *OlmMachine) storeDeviceSelfSignatures(ctx context.Context, userID id
|
|||
} else if _, ok := selfSigs[id.NewKeyID(id.KeyAlgorithmEd25519, pubKey.String())]; !ok {
|
||||
continue
|
||||
}
|
||||
if verified, err := olm.VerifySignatureJSON(deviceKeys, signerUserID, pubKey.String(), pubKey); verified {
|
||||
if verified, err := signatures.VerifySignatureJSON(deviceKeys, signerUserID, pubKey.String(), pubKey); verified {
|
||||
if signKey, ok := deviceKeys.Keys[id.DeviceKeyID(signerKey)]; ok {
|
||||
signature := deviceKeys.Signatures[signerUserID][id.NewKeyID(id.KeyAlgorithmEd25519, pubKey.String())]
|
||||
log.Trace().Err(err).
|
||||
|
@ -245,7 +245,7 @@ func (mach *OlmMachine) validateDevice(userID id.UserID, deviceID id.DeviceID, d
|
|||
return existing, fmt.Errorf("%w (expected %s, got %s)", MismatchingSigningKey, existing.SigningKey, signingKey)
|
||||
}
|
||||
|
||||
ok, err := olm.VerifySignatureJSON(deviceKeys, userID, deviceID.String(), signingKey)
|
||||
ok, err := signatures.VerifySignatureJSON(deviceKeys, userID, deviceID.String(), signingKey)
|
||||
if err != nil {
|
||||
return existing, fmt.Errorf("failed to verify signature: %w", err)
|
||||
} else if !ok {
|
||||
|
|
|
@ -12,7 +12,7 @@ import (
|
|||
"fmt"
|
||||
|
||||
"maunium.net/go/mautrix"
|
||||
"maunium.net/go/mautrix/crypto/olm"
|
||||
"maunium.net/go/mautrix/crypto/signatures"
|
||||
"maunium.net/go/mautrix/event"
|
||||
"maunium.net/go/mautrix/id"
|
||||
)
|
||||
|
@ -109,7 +109,7 @@ func (mach *OlmMachine) createOutboundSessions(ctx context.Context, input map[id
|
|||
continue
|
||||
}
|
||||
identity := input[userID][deviceID]
|
||||
if ok, err := olm.VerifySignatureJSON(oneTimeKey.RawData, userID, deviceID.String(), identity.SigningKey); err != nil {
|
||||
if ok, err := signatures.VerifySignatureJSON(oneTimeKey.RawData, userID, deviceID.String(), identity.SigningKey); err != nil {
|
||||
log.Error().Err(err).Msg("Failed to verify signature of one-time key")
|
||||
} else if !ok {
|
||||
log.Warn().Msg("One-time key has invalid signature from device")
|
||||
|
|
|
@ -110,12 +110,13 @@ func (a Account) IdentityKeys() (id.Ed25519, id.Curve25519) {
|
|||
return ed25519, curve25519
|
||||
}
|
||||
|
||||
// Sign returns the signature of a message using the Ed25519 key for this Account.
|
||||
// Sign returns the base64-encoded signature of a message using the Ed25519 key
|
||||
// for this Account.
|
||||
func (a Account) Sign(message []byte) ([]byte, error) {
|
||||
if len(message) == 0 {
|
||||
return nil, fmt.Errorf("sign: %w", goolm.ErrEmptyInput)
|
||||
}
|
||||
return goolm.Base64Encode(a.IdKeys.Ed25519.Sign(message)), nil
|
||||
return []byte(base64.RawStdEncoding.EncodeToString(a.IdKeys.Ed25519.Sign(message))), nil
|
||||
}
|
||||
|
||||
// OneTimeKeys returns the public parts of the unpublished one time keys of the Account.
|
||||
|
|
|
@ -2,14 +2,18 @@ package account_test
|
|||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/base64"
|
||||
"errors"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"maunium.net/go/mautrix/id"
|
||||
|
||||
"maunium.net/go/mautrix/crypto/goolm"
|
||||
"maunium.net/go/mautrix/crypto/goolm/account"
|
||||
"maunium.net/go/mautrix/crypto/goolm/utilities"
|
||||
"maunium.net/go/mautrix/crypto/signatures"
|
||||
)
|
||||
|
||||
func TestAccount(t *testing.T) {
|
||||
|
@ -599,19 +603,14 @@ func TestOldV3AccountPickle(t *testing.T) {
|
|||
|
||||
func TestAccountSign(t *testing.T) {
|
||||
accountA, err := account.NewAccount(nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
plainText := []byte("Hello, World")
|
||||
signature, err := accountA.Sign(plainText)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
verified, err := utilities.VerifySignature(plainText, accountA.IdKeys.Ed25519.B64Encoded(), signature)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !verified {
|
||||
t.Fatal("signature did not verify")
|
||||
}
|
||||
signatureB64, err := accountA.Sign(plainText)
|
||||
require.NoError(t, err)
|
||||
signature, err := base64.RawStdEncoding.DecodeString(string(signatureB64))
|
||||
require.NoError(t, err)
|
||||
|
||||
verified, err := signatures.VerifySignature(plainText, accountA.IdKeys.Ed25519.B64Encoded(), signature)
|
||||
assert.NoError(t, err)
|
||||
assert.True(t, verified)
|
||||
}
|
||||
|
|
|
@ -1,23 +0,0 @@
|
|||
package utilities
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
|
||||
"maunium.net/go/mautrix/crypto/goolm"
|
||||
"maunium.net/go/mautrix/crypto/goolm/crypto"
|
||||
"maunium.net/go/mautrix/id"
|
||||
)
|
||||
|
||||
// VerifySignature verifies an ed25519 signature.
|
||||
func VerifySignature(message []byte, key id.Ed25519, signature []byte) (ok bool, err error) {
|
||||
keyDecoded, err := base64.RawStdEncoding.DecodeString(string(key))
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
signatureDecoded, err := goolm.Base64Decode(signature)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
publicKey := crypto.Ed25519PublicKey(keyDecoded)
|
||||
return publicKey.Verify(message, signatureDecoded), nil
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
package olm
|
||||
|
||||
import (
|
||||
"crypto/sha256"
|
||||
"encoding/base64"
|
||||
)
|
||||
|
||||
// SHA256B64 calculates the SHA-256 hash of the input and encodes it as base64.
|
||||
func SHA256B64(input []byte) string {
|
||||
if len(input) == 0 {
|
||||
panic(EmptyInput)
|
||||
}
|
||||
hash := sha256.Sum256([]byte(input))
|
||||
return base64.RawStdEncoding.EncodeToString(hash[:])
|
||||
}
|
|
@ -1,146 +0,0 @@
|
|||
//go:build !goolm
|
||||
|
||||
package olm
|
||||
|
||||
// #cgo LDFLAGS: -lolm -lstdc++
|
||||
// #include <olm/olm.h>
|
||||
import "C"
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"unsafe"
|
||||
|
||||
"github.com/tidwall/gjson"
|
||||
"github.com/tidwall/sjson"
|
||||
"go.mau.fi/util/exgjson"
|
||||
|
||||
"maunium.net/go/mautrix/crypto/canonicaljson"
|
||||
"maunium.net/go/mautrix/id"
|
||||
)
|
||||
|
||||
// Utility stores the necessary state to perform hash and signature
|
||||
// verification operations.
|
||||
type Utility struct {
|
||||
int *C.OlmUtility
|
||||
mem []byte
|
||||
}
|
||||
|
||||
// utilitySize returns the size of a utility object in bytes.
|
||||
func utilitySize() uint {
|
||||
return uint(C.olm_utility_size())
|
||||
}
|
||||
|
||||
// sha256Len returns the length of the buffer needed to hold the SHA-256 hash.
|
||||
func (u *Utility) sha256Len() uint {
|
||||
return uint(C.olm_sha256_length((*C.OlmUtility)(u.int)))
|
||||
}
|
||||
|
||||
// lastError returns an error describing the most recent error to happen to a
|
||||
// utility.
|
||||
func (u *Utility) lastError() error {
|
||||
return convertError(C.GoString(C.olm_utility_last_error((*C.OlmUtility)(u.int))))
|
||||
}
|
||||
|
||||
// Clear clears the memory used to back this utility.
|
||||
func (u *Utility) Clear() error {
|
||||
r := C.olm_clear_utility((*C.OlmUtility)(u.int))
|
||||
if r == errorVal() {
|
||||
return u.lastError()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// NewUtility creates a new utility.
|
||||
func NewUtility() *Utility {
|
||||
memory := make([]byte, utilitySize())
|
||||
return &Utility{
|
||||
int: C.olm_utility(unsafe.Pointer(&memory[0])),
|
||||
mem: memory,
|
||||
}
|
||||
}
|
||||
|
||||
// Sha256 calculates the SHA-256 hash of the input and encodes it as base64.
|
||||
func (u *Utility) Sha256(input string) string {
|
||||
if len(input) == 0 {
|
||||
panic(EmptyInput)
|
||||
}
|
||||
output := make([]byte, u.sha256Len())
|
||||
r := C.olm_sha256(
|
||||
(*C.OlmUtility)(u.int),
|
||||
unsafe.Pointer(&([]byte(input)[0])),
|
||||
C.size_t(len(input)),
|
||||
unsafe.Pointer(&(output[0])),
|
||||
C.size_t(len(output)))
|
||||
if r == errorVal() {
|
||||
panic(u.lastError())
|
||||
}
|
||||
return string(output)
|
||||
}
|
||||
|
||||
// VerifySignature verifies an ed25519 signature. Returns true if the verification
|
||||
// suceeds or false otherwise. Returns error on failure. If the key was too
|
||||
// small then the error will be "INVALID_BASE64".
|
||||
func (u *Utility) VerifySignature(message string, key id.Ed25519, signature string) (ok bool, err error) {
|
||||
if len(message) == 0 || len(key) == 0 || len(signature) == 0 {
|
||||
return false, EmptyInput
|
||||
}
|
||||
r := C.olm_ed25519_verify(
|
||||
(*C.OlmUtility)(u.int),
|
||||
unsafe.Pointer(&([]byte(key)[0])),
|
||||
C.size_t(len(key)),
|
||||
unsafe.Pointer(&([]byte(message)[0])),
|
||||
C.size_t(len(message)),
|
||||
unsafe.Pointer(&([]byte(signature)[0])),
|
||||
C.size_t(len(signature)))
|
||||
if r == errorVal() {
|
||||
err = u.lastError()
|
||||
if err == BadMessageMAC {
|
||||
err = nil
|
||||
}
|
||||
} else {
|
||||
ok = true
|
||||
}
|
||||
return ok, err
|
||||
}
|
||||
|
||||
// VerifySignatureJSON verifies the signature in the JSON object _obj following
|
||||
// the Matrix specification:
|
||||
// https://matrix.org/speculator/spec/drafts%2Fe2e/appendices.html#signing-json
|
||||
// If the _obj is a struct, the `json` tags will be honored.
|
||||
func (u *Utility) VerifySignatureJSON(obj interface{}, userID id.UserID, keyName string, key id.Ed25519) (bool, error) {
|
||||
var err error
|
||||
objJSON, ok := obj.(json.RawMessage)
|
||||
if !ok {
|
||||
objJSON, err = json.Marshal(obj)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
}
|
||||
sig := gjson.GetBytes(objJSON, exgjson.Path("signatures", string(userID), fmt.Sprintf("ed25519:%s", keyName)))
|
||||
if !sig.Exists() || sig.Type != gjson.String {
|
||||
return false, SignatureNotFound
|
||||
}
|
||||
objJSON, err = sjson.DeleteBytes(objJSON, "unsigned")
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
objJSON, err = sjson.DeleteBytes(objJSON, "signatures")
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
objJSONString := string(canonicaljson.CanonicalJSONAssumeValid(objJSON))
|
||||
return u.VerifySignature(objJSONString, key, sig.Str)
|
||||
}
|
||||
|
||||
// VerifySignatureJSON verifies the signature in the JSON object _obj following
|
||||
// the Matrix specification:
|
||||
// https://matrix.org/speculator/spec/drafts%2Fe2e/appendices.html#signing-json
|
||||
// This function is a wrapper over Utility.VerifySignatureJSON that creates and
|
||||
// destroys the Utility object transparently.
|
||||
// If the _obj is a struct, the `json` tags will be honored.
|
||||
func VerifySignatureJSON(obj interface{}, userID id.UserID, keyName string, key id.Ed25519) (bool, error) {
|
||||
u := NewUtility()
|
||||
defer u.Clear()
|
||||
return u.VerifySignatureJSON(obj, userID, keyName, key)
|
||||
}
|
|
@ -1,92 +0,0 @@
|
|||
//go:build goolm
|
||||
|
||||
package olm
|
||||
|
||||
import (
|
||||
"crypto/sha256"
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"github.com/tidwall/gjson"
|
||||
"github.com/tidwall/sjson"
|
||||
"go.mau.fi/util/exgjson"
|
||||
|
||||
"maunium.net/go/mautrix/crypto/canonicaljson"
|
||||
"maunium.net/go/mautrix/crypto/goolm/utilities"
|
||||
"maunium.net/go/mautrix/id"
|
||||
)
|
||||
|
||||
// Utility stores the necessary state to perform hash and signature
|
||||
// verification operations.
|
||||
type Utility struct{}
|
||||
|
||||
// Clear clears the memory used to back this utility.
|
||||
func (u *Utility) Clear() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// NewUtility creates a new utility.
|
||||
func NewUtility() *Utility {
|
||||
return &Utility{}
|
||||
}
|
||||
|
||||
// Sha256 calculates the SHA-256 hash of the input and encodes it as base64.
|
||||
func (u *Utility) Sha256(input string) string {
|
||||
if len(input) == 0 {
|
||||
panic(EmptyInput)
|
||||
}
|
||||
hash := sha256.Sum256([]byte(input))
|
||||
return base64.RawStdEncoding.EncodeToString(hash[:])
|
||||
}
|
||||
|
||||
// VerifySignature verifies an ed25519 signature. Returns true if the verification
|
||||
// suceeds or false otherwise. Returns error on failure. If the key was too
|
||||
// small then the error will be "INVALID_BASE64".
|
||||
func (u *Utility) VerifySignature(message string, key id.Ed25519, signature string) (ok bool, err error) {
|
||||
if len(message) == 0 || len(key) == 0 || len(signature) == 0 {
|
||||
return false, EmptyInput
|
||||
}
|
||||
return utilities.VerifySignature([]byte(message), key, []byte(signature))
|
||||
}
|
||||
|
||||
// VerifySignatureJSON verifies the signature in the JSON object _obj following
|
||||
// the Matrix specification:
|
||||
// https://matrix.org/speculator/spec/drafts%2Fe2e/appendices.html#signing-json
|
||||
// If the _obj is a struct, the `json` tags will be honored.
|
||||
func (u *Utility) VerifySignatureJSON(obj interface{}, userID id.UserID, keyName string, key id.Ed25519) (bool, error) {
|
||||
var err error
|
||||
objJSON, ok := obj.(json.RawMessage)
|
||||
if !ok {
|
||||
objJSON, err = json.Marshal(obj)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
}
|
||||
sig := gjson.GetBytes(objJSON, exgjson.Path("signatures", string(userID), fmt.Sprintf("ed25519:%s", keyName)))
|
||||
if !sig.Exists() || sig.Type != gjson.String {
|
||||
return false, SignatureNotFound
|
||||
}
|
||||
objJSON, err = sjson.DeleteBytes(objJSON, "unsigned")
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
objJSON, err = sjson.DeleteBytes(objJSON, "signatures")
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
objJSONString := string(canonicaljson.CanonicalJSONAssumeValid(objJSON))
|
||||
return u.VerifySignature(objJSONString, key, sig.Str)
|
||||
}
|
||||
|
||||
// VerifySignatureJSON verifies the signature in the JSON object _obj following
|
||||
// the Matrix specification:
|
||||
// https://matrix.org/speculator/spec/drafts%2Fe2e/appendices.html#signing-json
|
||||
// This function is a wrapper over Utility.VerifySignatureJSON that creates and
|
||||
// destroys the Utility object transparently.
|
||||
// If the _obj is a struct, the `json` tags will be honored.
|
||||
func VerifySignatureJSON(obj interface{}, userID id.UserID, keyName string, key id.Ed25519) (bool, error) {
|
||||
u := NewUtility()
|
||||
defer u.Clear()
|
||||
return u.VerifySignatureJSON(obj, userID, keyName, key)
|
||||
}
|
|
@ -1,6 +1,24 @@
|
|||
package signatures
|
||||
|
||||
import "maunium.net/go/mautrix/id"
|
||||
import (
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/tidwall/gjson"
|
||||
"github.com/tidwall/sjson"
|
||||
"go.mau.fi/util/exgjson"
|
||||
|
||||
"maunium.net/go/mautrix/crypto/canonicaljson"
|
||||
"maunium.net/go/mautrix/crypto/goolm/crypto"
|
||||
"maunium.net/go/mautrix/id"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrEmptyInput = errors.New("empty input")
|
||||
ErrSignatureNotFound = errors.New("input JSON doesn't contain signature from specified device")
|
||||
)
|
||||
|
||||
// Signatures represents a set of signatures for some data from multiple users
|
||||
// and keys.
|
||||
|
@ -15,3 +33,56 @@ func NewSingleSignature(userID id.UserID, algorithm id.KeyAlgorithm, keyID strin
|
|||
},
|
||||
}
|
||||
}
|
||||
|
||||
// VerifySignature verifies an Ed25519 signature.
|
||||
func VerifySignature(message []byte, key id.Ed25519, signature []byte) (ok bool, err error) {
|
||||
if len(message) == 0 || len(key) == 0 || len(signature) == 0 {
|
||||
return false, ErrEmptyInput
|
||||
}
|
||||
keyDecoded, err := base64.RawStdEncoding.DecodeString(key.String())
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
publicKey := crypto.Ed25519PublicKey(keyDecoded)
|
||||
return publicKey.Verify(message, signature), nil
|
||||
}
|
||||
|
||||
// VerifySignatureJSON verifies the signature in the given JSON object "obj"
|
||||
// as described in [Appendix 3] of the Matrix Spec.
|
||||
//
|
||||
// This function is a wrapper over [Utility.VerifySignatureJSON] that creates
|
||||
// and destroys the [Utility] object transparently.
|
||||
//
|
||||
// If the "obj" is not already a [json.RawMessage], it will re-encoded as JSON
|
||||
// for the verification, so "json" tags will be honored.
|
||||
//
|
||||
// [Appendix 3]: https://spec.matrix.org/v1.9/appendices/#signing-json
|
||||
func VerifySignatureJSON(obj any, userID id.UserID, keyName string, key id.Ed25519) (bool, error) {
|
||||
var err error
|
||||
objJSON, ok := obj.(json.RawMessage)
|
||||
if !ok {
|
||||
objJSON, err = json.Marshal(obj)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
}
|
||||
|
||||
sig := gjson.GetBytes(objJSON, exgjson.Path("signatures", string(userID), fmt.Sprintf("ed25519:%s", keyName)))
|
||||
if !sig.Exists() || sig.Type != gjson.String {
|
||||
return false, ErrSignatureNotFound
|
||||
}
|
||||
objJSON, err = sjson.DeleteBytes(objJSON, "unsigned")
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
objJSON, err = sjson.DeleteBytes(objJSON, "signatures")
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
objJSONString := canonicaljson.CanonicalJSONAssumeValid(objJSON)
|
||||
sigBytes, err := base64.RawStdEncoding.DecodeString(sig.Str)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
return VerifySignature(objJSONString, key, sigBytes)
|
||||
}
|
||||
|
|
|
@ -367,7 +367,7 @@ func (mach *OlmMachine) handleVerificationKey(ctx context.Context, userID id.Use
|
|||
|
||||
if verState.initiatedByUs {
|
||||
// verify commitment string from accept message now
|
||||
expectedCommitment := olm.NewUtility().Sha256(content.Key + verState.startEventCanonical)
|
||||
expectedCommitment := olm.SHA256B64([]byte(content.Key + verState.startEventCanonical))
|
||||
mach.Log.Debug().Msgf("Received commitment: %v Expected: %v", verState.commitment, expectedCommitment)
|
||||
if expectedCommitment != verState.commitment {
|
||||
mach.Log.Warn().Msgf("Canceling verification transaction %v due to commitment mismatch", transactionID)
|
||||
|
@ -716,7 +716,7 @@ func (mach *OlmMachine) SendSASVerificationAccept(ctx context.Context, fromUser
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
hash := olm.NewUtility().Sha256(string(publicKey) + string(canonical))
|
||||
hash := olm.SHA256B64(append(publicKey, canonical...))
|
||||
sasMethods := make([]event.SASMethod, len(methods))
|
||||
for i, method := range methods {
|
||||
sasMethods[i] = method.Type()
|
||||
|
|
|
@ -168,7 +168,7 @@ func (mach *OlmMachine) SendInRoomSASVerificationAccept(ctx context.Context, roo
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
hash := olm.NewUtility().Sha256(string(publicKey) + string(canonical))
|
||||
hash := olm.SHA256B64(append(publicKey, canonical...))
|
||||
sasMethods := make([]event.SASMethod, len(methods))
|
||||
for i, method := range methods {
|
||||
sasMethods[i] = method.Type()
|
||||
|
|
Loading…
Reference in New Issue