summary refs log tree commit diff
path: root/vendor/maunium.net/go/mautrix/crypto/utils/utils.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/maunium.net/go/mautrix/crypto/utils/utils.go')
-rw-r--r--vendor/maunium.net/go/mautrix/crypto/utils/utils.go132
1 files changed, 132 insertions, 0 deletions
diff --git a/vendor/maunium.net/go/mautrix/crypto/utils/utils.go b/vendor/maunium.net/go/mautrix/crypto/utils/utils.go
new file mode 100644
index 0000000..e2f8a19
--- /dev/null
+++ b/vendor/maunium.net/go/mautrix/crypto/utils/utils.go
@@ -0,0 +1,132 @@
+// 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/.
+
+package utils
+
+import (
+	"crypto/aes"
+	"crypto/cipher"
+	"crypto/hmac"
+	"crypto/rand"
+	"crypto/sha256"
+	"crypto/sha512"
+	"encoding/base64"
+	"strings"
+
+	"go.mau.fi/util/base58"
+	"golang.org/x/crypto/hkdf"
+	"golang.org/x/crypto/pbkdf2"
+)
+
+const (
+	// AESCTRKeyLength is the length of the AES256-CTR key used.
+	AESCTRKeyLength = 32
+	// AESCTRIVLength is the length of the AES256-CTR IV used.
+	AESCTRIVLength = 16
+	// HMACKeyLength is the length of the HMAC key used.
+	HMACKeyLength = 32
+	// SHAHashLength is the length of the SHA hash used.
+	SHAHashLength = 32
+)
+
+// XorA256CTR encrypts the input with the keystream generated by the AES256-CTR algorithm with the given arguments.
+func XorA256CTR(source []byte, key [AESCTRKeyLength]byte, iv [AESCTRIVLength]byte) []byte {
+	block, _ := aes.NewCipher(key[:])
+	cipher.NewCTR(block, iv[:]).XORKeyStream(source, source)
+	return source
+}
+
+// GenAttachmentA256CTR generates a new random AES256-CTR key and IV suitable for encrypting attachments.
+func GenAttachmentA256CTR() (key [AESCTRKeyLength]byte, iv [AESCTRIVLength]byte) {
+	_, err := rand.Read(key[:])
+	if err != nil {
+		panic(err)
+	}
+
+	// The last 8 bytes of the IV act as the counter in AES-CTR, which means they're left empty here
+	_, err = rand.Read(iv[:8])
+	if err != nil {
+		panic(err)
+	}
+	return
+}
+
+// GenA256CTRIV generates a random IV for AES256-CTR with the last bit set to zero.
+func GenA256CTRIV() (iv [AESCTRIVLength]byte) {
+	_, err := rand.Read(iv[:])
+	if err != nil {
+		panic(err)
+	}
+	iv[8] &= 0x7F
+	return
+}
+
+// DeriveKeysSHA256 derives an AES and a HMAC key from the given recovery key.
+func DeriveKeysSHA256(key []byte, name string) ([AESCTRKeyLength]byte, [HMACKeyLength]byte) {
+	var zeroBytes [32]byte
+
+	derivedHkdf := hkdf.New(sha256.New, key[:], zeroBytes[:], []byte(name))
+
+	var aesKey [AESCTRKeyLength]byte
+	var hmacKey [HMACKeyLength]byte
+	derivedHkdf.Read(aesKey[:])
+	derivedHkdf.Read(hmacKey[:])
+
+	return aesKey, hmacKey
+}
+
+// PBKDF2SHA512 generates a key of the given bit-length using the given passphrase, salt and iteration count.
+func PBKDF2SHA512(password []byte, salt []byte, iters int, keyLenBits int) []byte {
+	return pbkdf2.Key(password, salt, iters, keyLenBits/8, sha512.New)
+}
+
+// DecodeBase58RecoveryKey recovers the secret storage from a recovery key.
+func DecodeBase58RecoveryKey(recoveryKey string) []byte {
+	noSpaces := strings.ReplaceAll(recoveryKey, " ", "")
+	decoded := base58.Decode(noSpaces)
+	if len(decoded) != AESCTRKeyLength+3 { // AESCTRKeyLength bytes key and 3 bytes prefix / parity
+		return nil
+	}
+	var parity byte
+	for _, b := range decoded[:34] {
+		parity ^= b
+	}
+	if parity != decoded[34] || decoded[0] != 0x8B || decoded[1] != 1 {
+		return nil
+	}
+	return decoded[2:34]
+}
+
+// EncodeBase58RecoveryKey recovers the secret storage from a recovery key.
+func EncodeBase58RecoveryKey(key []byte) string {
+	var inputBytes [35]byte
+	copy(inputBytes[2:34], key[:])
+	inputBytes[0] = 0x8B
+	inputBytes[1] = 1
+
+	var parity byte
+	for _, b := range inputBytes[:34] {
+		parity ^= b
+	}
+	inputBytes[34] = parity
+	recoveryKey := base58.Encode(inputBytes[:])
+
+	var spacedKey string
+	for i, c := range recoveryKey {
+		if i > 0 && i%4 == 0 {
+			spacedKey += " "
+		}
+		spacedKey += string(c)
+	}
+	return spacedKey
+}
+
+// HMACSHA256B64 calculates the unpadded base64 of the SHA256 hmac of the input with the given key.
+func HMACSHA256B64(input []byte, hmacKey [HMACKeyLength]byte) string {
+	h := hmac.New(sha256.New, hmacKey[:])
+	h.Write(input)
+	return base64.RawStdEncoding.EncodeToString(h.Sum(nil))
+}