205 lines
5.6 KiB
Go
205 lines
5.6 KiB
Go
|
// Copyright (c) 2020 Nikos Filippakis
|
||
|
//
|
||
|
// 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/.
|
||
|
|
||
|
//go:build !nosas
|
||
|
// +build !nosas
|
||
|
|
||
|
package crypto
|
||
|
|
||
|
import (
|
||
|
"fmt"
|
||
|
|
||
|
"maunium.net/go/mautrix/crypto/olm"
|
||
|
"maunium.net/go/mautrix/event"
|
||
|
"maunium.net/go/mautrix/id"
|
||
|
)
|
||
|
|
||
|
// SASData contains the data that users need to verify.
|
||
|
type SASData interface {
|
||
|
Type() event.SASMethod
|
||
|
}
|
||
|
|
||
|
// VerificationMethod describes a method for generating a SAS.
|
||
|
type VerificationMethod interface {
|
||
|
// GetVerificationSAS uses the user, device ID and key of the user who initiated the verification transaction,
|
||
|
// the user, device ID and key of the user who accepted, the transaction ID and the SAS object to generate a SAS.
|
||
|
// The SAS can be any type, such as an array of numbers or emojis.
|
||
|
GetVerificationSAS(initUserID id.UserID, initDeviceID id.DeviceID, initKey string,
|
||
|
acceptUserID id.UserID, acceptDeviceID id.DeviceID, acceptKey string,
|
||
|
transactionID string, sas *olm.SAS) (SASData, error)
|
||
|
// Type returns the type of this SAS method
|
||
|
Type() event.SASMethod
|
||
|
}
|
||
|
|
||
|
const sasInfoFormat = "MATRIX_KEY_VERIFICATION_SAS|%s|%s|%s|%s|%s|%s|%s"
|
||
|
|
||
|
// VerificationMethodDecimal describes the decimal SAS method.
|
||
|
type VerificationMethodDecimal struct{}
|
||
|
|
||
|
// DecimalSASData contains the verification numbers for the decimal SAS method.
|
||
|
type DecimalSASData [3]uint
|
||
|
|
||
|
// Type returns the decimal SAS method type.
|
||
|
func (DecimalSASData) Type() event.SASMethod {
|
||
|
return event.SASDecimal
|
||
|
}
|
||
|
|
||
|
// GetVerificationSAS generates the three numbers that need to match with the other device for a verification to be valid.
|
||
|
func (VerificationMethodDecimal) GetVerificationSAS(initUserID id.UserID, initDeviceID id.DeviceID, initKey string,
|
||
|
acceptUserID id.UserID, acceptDeviceID id.DeviceID, acceptKey string,
|
||
|
transactionID string, sas *olm.SAS) (SASData, error) {
|
||
|
|
||
|
sasInfo := fmt.Sprintf(sasInfoFormat,
|
||
|
initUserID, initDeviceID, initKey,
|
||
|
acceptUserID, acceptDeviceID, acceptKey,
|
||
|
transactionID)
|
||
|
|
||
|
sasBytes, err := sas.GenerateBytes([]byte(sasInfo), 5)
|
||
|
if err != nil {
|
||
|
return DecimalSASData{0, 0, 0}, err
|
||
|
}
|
||
|
|
||
|
numbers := DecimalSASData{
|
||
|
(uint(sasBytes[0])<<5 | uint(sasBytes[1])>>3) + 1000,
|
||
|
(uint(sasBytes[1]&0x7)<<10 | uint(sasBytes[2])<<2 | uint(sasBytes[3]>>6)) + 1000,
|
||
|
(uint(sasBytes[3]&0x3F)<<7 | uint(sasBytes[4])>>1) + 1000,
|
||
|
}
|
||
|
|
||
|
return numbers, nil
|
||
|
}
|
||
|
|
||
|
// Type returns the decimal SAS method type.
|
||
|
func (VerificationMethodDecimal) Type() event.SASMethod {
|
||
|
return event.SASDecimal
|
||
|
}
|
||
|
|
||
|
var allEmojis = [...]VerificationEmoji{
|
||
|
{'🐶', "Dog"},
|
||
|
{'🐱', "Cat"},
|
||
|
{'🦁', "Lion"},
|
||
|
{'🐎', "Horse"},
|
||
|
{'🦄', "Unicorn"},
|
||
|
{'🐷', "Pig"},
|
||
|
{'🐘', "Elephant"},
|
||
|
{'🐰', "Rabbit"},
|
||
|
{'🐼', "Panda"},
|
||
|
{'🐓', "Rooster"},
|
||
|
{'🐧', "Penguin"},
|
||
|
{'🐢', "Turtle"},
|
||
|
{'🐟', "Fish"},
|
||
|
{'🐙', "Octopus"},
|
||
|
{'🦋', "Butterfly"},
|
||
|
{'🌷', "Flower"},
|
||
|
{'🌳', "Tree"},
|
||
|
{'🌵', "Cactus"},
|
||
|
{'🍄', "Mushroom"},
|
||
|
{'🌏', "Globe"},
|
||
|
{'🌙', "Moon"},
|
||
|
{'☁', "Cloud"},
|
||
|
{'🔥', "Fire"},
|
||
|
{'🍌', "Banana"},
|
||
|
{'🍎', "Apple"},
|
||
|
{'🍓', "Strawberry"},
|
||
|
{'🌽', "Corn"},
|
||
|
{'🍕', "Pizza"},
|
||
|
{'🎂', "Cake"},
|
||
|
{'❤', "Heart"},
|
||
|
{'😀', "Smiley"},
|
||
|
{'🤖', "Robot"},
|
||
|
{'🎩', "Hat"},
|
||
|
{'👓', "Glasses"},
|
||
|
{'🔧', "Spanner"},
|
||
|
{'🎅', "Santa"},
|
||
|
{'👍', "Thumbs Up"},
|
||
|
{'☂', "Umbrella"},
|
||
|
{'⌛', "Hourglass"},
|
||
|
{'⏰', "Clock"},
|
||
|
{'🎁', "Gift"},
|
||
|
{'💡', "Light Bulb"},
|
||
|
{'📕', "Book"},
|
||
|
{'✏', "Pencil"},
|
||
|
{'📎', "Paperclip"},
|
||
|
{'✂', "Scissors"},
|
||
|
{'🔒', "Lock"},
|
||
|
{'🔑', "Key"},
|
||
|
{'🔨', "Hammer"},
|
||
|
{'☎', "Telephone"},
|
||
|
{'🏁', "Flag"},
|
||
|
{'🚂', "Train"},
|
||
|
{'🚲', "Bicycle"},
|
||
|
{'✈', "Aeroplane"},
|
||
|
{'🚀', "Rocket"},
|
||
|
{'🏆', "Trophy"},
|
||
|
{'⚽', "Ball"},
|
||
|
{'🎸', "Guitar"},
|
||
|
{'🎺', "Trumpet"},
|
||
|
{'🔔', "Bell"},
|
||
|
{'⚓', "Anchor"},
|
||
|
{'🎧', "Headphones"},
|
||
|
{'📁', "Folder"},
|
||
|
{'📌', "Pin"},
|
||
|
}
|
||
|
|
||
|
// VerificationEmoji describes an emoji that might be sent for verifying devices.
|
||
|
type VerificationEmoji struct {
|
||
|
Emoji rune
|
||
|
Description string
|
||
|
}
|
||
|
|
||
|
func (vm VerificationEmoji) GetEmoji() rune {
|
||
|
return vm.Emoji
|
||
|
}
|
||
|
|
||
|
func (vm VerificationEmoji) GetDescription() string {
|
||
|
return vm.Description
|
||
|
}
|
||
|
|
||
|
// EmojiSASData contains the verification emojis for the emoji SAS method.
|
||
|
type EmojiSASData [7]VerificationEmoji
|
||
|
|
||
|
// Type returns the emoji SAS method type.
|
||
|
func (EmojiSASData) Type() event.SASMethod {
|
||
|
return event.SASEmoji
|
||
|
}
|
||
|
|
||
|
// VerificationMethodEmoji describes the emoji SAS method.
|
||
|
type VerificationMethodEmoji struct{}
|
||
|
|
||
|
// GetVerificationSAS generates the three numbers that need to match with the other device for a verification to be valid.
|
||
|
func (VerificationMethodEmoji) GetVerificationSAS(initUserID id.UserID, initDeviceID id.DeviceID, initKey string,
|
||
|
acceptUserID id.UserID, acceptDeviceID id.DeviceID, acceptKey string,
|
||
|
transactionID string, sas *olm.SAS) (SASData, error) {
|
||
|
|
||
|
sasInfo := fmt.Sprintf(sasInfoFormat,
|
||
|
initUserID, initDeviceID, initKey,
|
||
|
acceptUserID, acceptDeviceID, acceptKey,
|
||
|
transactionID)
|
||
|
|
||
|
var emojis EmojiSASData
|
||
|
sasBytes, err := sas.GenerateBytes([]byte(sasInfo), 6)
|
||
|
|
||
|
if err != nil {
|
||
|
return emojis, err
|
||
|
}
|
||
|
|
||
|
sasNum := uint64(sasBytes[0])<<40 | uint64(sasBytes[1])<<32 | uint64(sasBytes[2])<<24 |
|
||
|
uint64(sasBytes[3])<<16 | uint64(sasBytes[4])<<8 | uint64(sasBytes[5])
|
||
|
|
||
|
for i := 0; i < len(emojis); i++ {
|
||
|
// take nth group of 6 bits
|
||
|
emojiIdx := (sasNum >> uint(48-(i+1)*6)) & 0x3F
|
||
|
emoji := allEmojis[emojiIdx]
|
||
|
emojis[i] = emoji
|
||
|
}
|
||
|
|
||
|
return emojis, nil
|
||
|
}
|
||
|
|
||
|
// Type returns the emoji SAS method type.
|
||
|
func (VerificationMethodEmoji) Type() event.SASMethod {
|
||
|
return event.SASEmoji
|
||
|
}
|