seekia/internal/messaging/readMessages/readMessages.go

613 lines
26 KiB
Go

// readMessages provides functions to read Seekia chat messages
// The chat message structure will eventually be documented in /documentation/Specification.md
package readMessages
//TODO: Add an upper limit on bytes, and an upper limit for size of communication.
//TODO: Verify all message values and function inputs.
import "seekia/internal/cryptography/blake3"
import "seekia/internal/cryptography/chaPolyShrink"
import "seekia/internal/cryptography/edwardsKeys"
import "seekia/internal/cryptography/kyber"
import "seekia/internal/cryptography/nacl"
import "seekia/internal/encoding"
import "seekia/internal/helpers"
import "seekia/internal/identity"
import messagepack "github.com/vmihailenco/msgpack/v5"
import "bytes"
import "errors"
func VerifyMessageHashHex(inputHash string)bool{
isValid := helpers.VerifyHexString(26, inputHash)
return isValid
}
func VerifyMessageCipherKeyHex(inputCipherKey string)bool{
isValid := helpers.VerifyHexString(32, inputCipherKey)
return isValid
}
func ReadMessageHashHex(inputMessageHash string)([26]byte, error){
messageHashBytes, err := encoding.DecodeHexStringToBytes(inputMessageHash)
if (err != nil){
return [26]byte{}, errors.New("ReadMessageHashHex called with invalid MessageHash: Not Hex: " + inputMessageHash)
}
if (len(messageHashBytes) != 26){
return [26]byte{}, errors.New("ReadMessageHashHex called with invalid MessageHash: Invalid length: " + inputMessageHash)
}
messageHashArray := [26]byte(messageHashBytes)
return messageHashArray, nil
}
func ReadMessageCipherKeyHex(inputCipherKey string)([32]byte, error){
cipherKeyBytes, err := encoding.DecodeHexStringToBytes(inputCipherKey)
if (err != nil){
return [32]byte{}, errors.New("ReadMessageCipherKeyHex called with invalid inputCipherKey: Not Hex: " + inputCipherKey)
}
if (len(cipherKeyBytes) != 32){
return [32]byte{}, errors.New("ReadMessageCipherKeyHex called with invalid inputCipherKey: Invalid length: " + inputCipherKey)
}
cipherKeyArray := [32]byte(cipherKeyBytes)
return cipherKeyArray, nil
}
func VerifyMessageCipherKeyHashHex(inputCipherKeyHash string)bool{
isValid := helpers.VerifyHexString(25, inputCipherKeyHash)
return isValid
}
func ConvertMessageCipherKeyToCipherKeyHash(inputMessageCipherKey [32]byte)([25]byte, error){
cipherKeyHash, err := blake3.GetBlake3HashAsBytes(25, inputMessageCipherKey[:])
if (err != nil) { return [25]byte{}, err }
cipherKeyHashArray := [25]byte(cipherKeyHash)
return cipherKeyHashArray, nil
}
// This function reads a chat message's public data
// It also computes and returns the message hash
// It does not decrypt the message.
// Outputs:
// -bool: Able to read
// -[26]byte: Message Hash
// -int: Message version
// -byte: Network type (1 == Mainnet, 2 == Testnet)
// -[10]byte: Message Inbox
// -messagepack.RawMessage: Message noncipheredSection bytes (needed to decrypt the cipheredMessage)
// -[24]byte: DoubleSealedKeysNonce
// -[]byte: DoubleSealedKeys
// -[25]byte: CipherKeyHash
// -[24]byte: CipheredMessageNonce
// -[]byte: CipheredMessage
// -error (will return err if there is a bug)
func ReadChatMessagePublicDataAndHash(verifyData bool, inputMessage []byte)(bool, [26]byte, int, byte, [10]byte, messagepack.RawMessage, [24]byte, []byte, [25]byte, [24]byte, []byte, error){
ableToRead, messageVersion, messageNetworkType, messageInbox, messageNoncipheredSectionBytes, messageDoubleSealedKeysNonce, messageDoubleSealedKeys, messageCipherKeyHash, messageCipheredMessageNonce, messageCipheredMessage, err := ReadChatMessagePublicData(verifyData, inputMessage)
if (err != nil) { return false, [26]byte{}, 0, 0, [10]byte{}, nil, [24]byte{}, nil, [25]byte{}, [24]byte{}, nil, err }
if (ableToRead == false){
return false, [26]byte{}, 0, 0, [10]byte{}, nil, [24]byte{}, nil, [25]byte{}, [24]byte{}, nil, nil
}
messageHashSlice, err := blake3.GetBlake3HashAsBytes(26, inputMessage)
if (err != nil) { return false, [26]byte{}, 0, 0, [10]byte{}, nil, [24]byte{}, nil, [25]byte{}, [24]byte{}, nil, err }
messageHash := [26]byte(messageHashSlice)
return true, messageHash, messageVersion, messageNetworkType, messageInbox, messageNoncipheredSectionBytes, messageDoubleSealedKeysNonce, messageDoubleSealedKeys, messageCipherKeyHash, messageCipheredMessageNonce, messageCipheredMessage, nil
}
// This function reads a chat message's public data, and optionally verifies the message's public data.
// It does not compute the message hash, thus it is faster
// It does not decrypt the message.
// Outputs:
// -bool: Able to read
// -int: Message version
// -byte: Network type (1 == Mainnet, 2 == Testnet)
// -[10]byte: Message Inbox
// -messagepack.RawMessage: Message noncipheredSection bytes (needed to decrypt the cipheredMessage)
// -[24]byte: DoubleSealedKeysNonce
// -[]byte: DoubleSealedKeys
// -[25]byte: CipherKeyHash
// -[24]byte: CipheredMessageNonce
// -[]byte: CipheredMessage
// -error (will return err if there is a bug)
func ReadChatMessagePublicData(verifyData bool, inputMessage []byte)(bool, int, byte, [10]byte, messagepack.RawMessage, [24]byte, []byte, [25]byte, [24]byte, []byte, error){
var messageSlice []messagepack.RawMessage
err := encoding.DecodeMessagePackBytes(false, inputMessage, &messageSlice)
if (err != nil){
// Cannot read message: Invalid messagepack
return false, 0, 0, [10]byte{}, nil, [24]byte{}, nil, [25]byte{}, [24]byte{}, nil, nil
}
if (len(messageSlice) != 2){
// Cannot read message: Invalid messagepack
return false, 0, 0, [10]byte{}, nil, [24]byte{}, nil, [25]byte{}, [24]byte{}, nil, nil
}
messageNoncipheredSectionEncoded := messageSlice[0]
cipheredMessageEncoded := messageSlice[1]
var noncipheredSectionSlice []messagepack.RawMessage
err = encoding.DecodeMessagePackBytes(false, messageNoncipheredSectionEncoded, &noncipheredSectionSlice)
if (err != nil){
// Malformed message: Invalid message content
return false, 0, 0, [10]byte{}, nil, [24]byte{}, nil, [25]byte{}, [24]byte{}, nil, nil
}
if (len(noncipheredSectionSlice) != 7){
// Malformed message: Invalid message noncipheredSection
return false, 0, 0, [10]byte{}, nil, [24]byte{}, nil, [25]byte{}, [24]byte{}, nil, nil
}
messageVersionEncoded := noncipheredSectionSlice[0]
networkTypeEncoded := noncipheredSectionSlice[1]
recipientInboxEncoded := noncipheredSectionSlice[2]
doubleSealedKeysNonceEncoded := noncipheredSectionSlice[3]
doubleSealedKeysEncoded := noncipheredSectionSlice[4]
cipherKeyHashEncoded := noncipheredSectionSlice[5]
cipheredMessageNonceEncoded := noncipheredSectionSlice[6]
messageVersion, err := encoding.DecodeRawMessagePackToInt(messageVersionEncoded)
if (err != nil){
// Malformed message: Invalid message version
return false, 0, 0, [10]byte{}, nil, [24]byte{}, nil, [25]byte{}, [24]byte{}, nil, nil
}
if (messageVersion != 1){
// We cannot read the message. It is created for a newer version of Seekia
return false, 0, 0, [10]byte{}, nil, [24]byte{}, nil, [25]byte{}, [24]byte{}, nil, nil
}
messageNetworkType, err := encoding.DecodeRawMessagePackToByte(networkTypeEncoded)
if (err != nil){
// Malformed message: Invalid networkType
return false, 0, 0, [10]byte{}, nil, [24]byte{}, nil, [25]byte{}, [24]byte{}, nil, nil
}
isValid := helpers.VerifyNetworkType(messageNetworkType)
if (isValid == false){
// Malformed message: Invalid networkType
return false, 0, 0, [10]byte{}, nil, [24]byte{}, nil, [25]byte{}, [24]byte{}, nil, nil
}
recipientInbox, err := encoding.DecodeRawMessagePackTo10ByteArray(recipientInboxEncoded)
if (err != nil){
// Malformed message: Invalid recipient inbox
return false, 0, 0, [10]byte{}, nil, [24]byte{}, nil, [25]byte{}, [24]byte{}, nil, nil
}
doubleSealedKeysNonce, err := encoding.DecodeRawMessagePackTo24ByteArray(doubleSealedKeysNonceEncoded)
if (err != nil){
// Malformed message: Invalid doubleSealedKeysNonce
return false, 0, 0, [10]byte{}, nil, [24]byte{}, nil, [25]byte{}, [24]byte{}, nil, nil
}
doubleSealedKeys, err := encoding.DecodeRawMessagePackToBytes(doubleSealedKeysEncoded)
if (err != nil){
// Malformed message: Invalid doubleSealedKeys
return false, 0, 0, [10]byte{}, nil, [24]byte{}, nil, [25]byte{}, [24]byte{}, nil, nil
}
cipherKeyHash, err := encoding.DecodeRawMessagePackTo25ByteArray(cipherKeyHashEncoded)
if (err != nil){
// Malformed message: Invalid cipherKeyHash
return false, 0, 0, [10]byte{}, nil, [24]byte{}, nil, [25]byte{}, [24]byte{}, nil, nil
}
cipheredMessageNonce, err := encoding.DecodeRawMessagePackTo24ByteArray(cipheredMessageNonceEncoded)
if (err != nil){
// Malformed message: Invalid cipheredMessageNonce
return false, 0, 0, [10]byte{}, nil, [24]byte{}, nil, [25]byte{}, [24]byte{}, nil, nil
}
cipheredMessage, err := encoding.DecodeRawMessagePackToBytes(cipheredMessageEncoded)
if (err != nil){
// Malformed message: Invalid cipheredMessage
return false, 0, 0, [10]byte{}, nil, [24]byte{}, nil, [25]byte{}, [24]byte{}, nil, nil
}
if (verifyData == true){
if (len(doubleSealedKeys) != 1684){
// Invalid doubleSealedKeys: Invalid length
return false, 0, 0, [10]byte{}, nil, [24]byte{}, nil, [25]byte{}, [24]byte{}, nil, nil
}
if (len(cipheredMessage) < 3){
// Invalid Message: Invalid cipheredMessage
return false, 0, 0, [10]byte{}, nil, [24]byte{}, nil, [25]byte{}, [24]byte{}, nil, nil
}
}
return true, messageVersion, messageNetworkType, recipientInbox, messageNoncipheredSectionEncoded, doubleSealedKeysNonce, doubleSealedKeys, cipherKeyHash, cipheredMessageNonce, cipheredMessage, nil
}
// This struct defines a chat key set which is used to decrypt a chat message
// Each user may have multiple key sets, if they have shared newer keys more recently.
// They keep their old keys so they can decrypt messages sent to their older keys.
type ChatKeySet struct{
NaclPublicKey [32]byte
NaclPrivateKey [32]byte
KyberPrivateKey [1536]byte
}
// This function will decrypt a chat message with a recipient device chat keys list
// This is used by users who are decrypting messages sent to them
//Inputs:
// -[]byte: InputMessage
// -[32]byte: Double Sealed Keys decryption key
// -[]ChatKeySet: RecipientChatDecryptionKeysList (contains decryption keys for each recipient chat key set)
//Outputs:
// -bool: Able to read message (could be false if message is malformed or unable to decrypt)
// -[26]byte: Message Hash
// -int: Message Version
// -byte: Message network type (1 == Mainnet, 2 == Testnet1)
// -[32]byte: Message Cipher Key
// -[16]byte: Sender Identity Hash
// -[16]byte: Recipient Identity Hash
// -int64: Message creation time (unix)
// -string: Communication
// -[22]byte: Sender Current secret inbox seed
// -[22]byte: Sender Next secret inbox seed
// -[11]byte: Sender Device Identifier
// -int64: Sender Latest chat keys update time
// -error (will return err if non-message inputs are malformed, or there is a bug)
func ReadChatMessage(inputMessage []byte, doubleSealedKeysDecryptionKey [32]byte, recipientDecryptionKeySetsList []ChatKeySet)(bool, [26]byte, int, byte, [32]byte, [16]byte, [16]byte, int64, string, [22]byte, [22]byte, [11]byte, int64, error){
ableToRead, messageHash, messageVersion, messageNetworkType, _, messageNoncipheredSectionBytes, doubleSealedKeysNonce, doubleSealedKeys, expectedCipherKeyHash, cipheredMessageNonce, cipheredMessage, err := ReadChatMessagePublicDataAndHash(true, inputMessage)
if (err != nil) { return false, [26]byte{}, 0, 0, [32]byte{}, [16]byte{}, [16]byte{}, 0, "", [22]byte{}, [22]byte{}, [11]byte{}, 0, err }
if (ableToRead == false){
// Invalid message format
return false, [26]byte{}, 0, 0, [32]byte{}, [16]byte{}, [16]byte{}, 0, "", [22]byte{}, [22]byte{}, [11]byte{}, 0, nil
}
ableToDecrypt, decryptedBytes, err := chaPolyShrink.DecryptChaPolyShrink(doubleSealedKeys, doubleSealedKeysDecryptionKey, doubleSealedKeysNonce, false, [32]byte{})
if (err != nil) { return false, [26]byte{}, 0, 0, [32]byte{}, [16]byte{}, [16]byte{}, 0, "", [22]byte{}, [22]byte{}, [11]byte{}, 0, err }
if (ableToDecrypt == false){
// doubleSealedKeys cannot be decrypted
// Sender must be malicious
return false, [26]byte{}, 0, 0, [32]byte{}, [16]byte{}, [16]byte{}, 0, "", [22]byte{}, [22]byte{}, [11]byte{}, 0, nil
}
if (len(decryptedBytes) != 1648){
// Sender must be malicious.
return false, [26]byte{}, 0, 0, [32]byte{}, [16]byte{}, [16]byte{}, 0, "", [22]byte{}, [22]byte{}, [11]byte{}, 0, nil
}
naclEncryptedKeyPieceA := [80]byte(decryptedBytes[:80])
kyberEncryptedKeyPieceB := [1568]byte(decryptedBytes[80:])
//Outputs:
// -bool: Able to decrypt
// -[32]byte: Basaldata decryption key
// -error (will be error if inputs are invalid)
getBasaldataDecryptionKey := func()(bool, [32]byte, error){
// This cycles through all chat decryption keys the user has
// They share new keys on their profile, and delete old keys after a certain time period
for _, keySetObject := range recipientDecryptionKeySetsList{
recipientNaclPublicKey := keySetObject.NaclPublicKey
recipientNaclPrivateKey := keySetObject.NaclPrivateKey
recipientKyberPrivateKey := keySetObject.KyberPrivateKey
ableToDecrypt, keyPieceA, err := nacl.DecryptNaclEncryptedKey(naclEncryptedKeyPieceA, recipientNaclPublicKey, recipientNaclPrivateKey)
if (err != nil) { return false, [32]byte{}, err }
if (ableToDecrypt == false){
// Keys are not the correct decryption keys
// Skip to next keys
continue
}
keyPieceB, err := kyber.DecryptKyberEncryptedKey(kyberEncryptedKeyPieceB, recipientKyberPrivateKey)
if (err != nil) { return false, [32]byte{}, err }
basaldataDecryptionKey := helpers.XORTwo32ByteArrays(keyPieceA, keyPieceB)
return true, basaldataDecryptionKey, nil
}
// We don't have the keys needed to decrypt the message.
return false, [32]byte{}, nil
}
ableToDecrypt, basaldataDecryptionKey, err := getBasaldataDecryptionKey()
if (err != nil) { return false, [26]byte{}, 0, 0, [32]byte{}, [16]byte{}, [16]byte{}, 0, "", [22]byte{}, [22]byte{}, [11]byte{}, 0, err }
if (ableToDecrypt == false){
// We don't have the keys to decrypt, or message is invalid
return false, [26]byte{}, 0, 0, [32]byte{}, [16]byte{}, [16]byte{}, 0, "", [22]byte{}, [22]byte{}, [11]byte{}, 0, nil
}
// CipheredMessageKey is a hash of the Basaldata decryption key
// This allows users to report messages and reveal only the cipheredMessage
// This way, only the innerMessage contents are revealed, and the basaldata remains encrypted
messageCipherKey, err := blake3.GetBlake3HashAsBytes(32, basaldataDecryptionKey[:])
if (err != nil) { return false, [26]byte{}, 0, 0, [32]byte{}, [16]byte{}, [16]byte{}, 0, "", [22]byte{}, [22]byte{}, [11]byte{}, 0, err }
messageCipherKeyArray := [32]byte(messageCipherKey)
messageCipherKeyHash, err := blake3.GetBlake3HashAsBytes(25, messageCipherKey)
if (err != nil) { return false, [26]byte{}, 0, 0, [32]byte{}, [16]byte{}, [16]byte{}, 0, "", [22]byte{}, [22]byte{}, [11]byte{}, 0, err }
areEqual := bytes.Equal(messageCipherKeyHash, expectedCipherKeyHash[:])
if (areEqual == false){
// Cipher key hash does not match expected cipher key hash
return false, [26]byte{}, 0, 0, [32]byte{}, [16]byte{}, [16]byte{}, 0, "", [22]byte{}, [22]byte{}, [11]byte{}, 0, nil
}
ableToRead, senderIdentityHash, senderIdentityType, encryptedBasaldata, basaldataNonce, messageCommunication, err := readCipheredMessage(1, cipheredMessage, messageCipherKeyArray, cipheredMessageNonce, messageNoncipheredSectionBytes)
if (ableToRead == false){
// Invalid ciphered message
return false, [26]byte{}, 0, 0, [32]byte{}, [16]byte{}, [16]byte{}, 0, "", [22]byte{}, [22]byte{}, [11]byte{}, 0, nil
}
// Now we decrypt basaldata
ableToDecrypt, decryptedBasaldataBytes, err := chaPolyShrink.DecryptChaPolyShrink(encryptedBasaldata, basaldataDecryptionKey, basaldataNonce, false, [32]byte{})
if (err != nil) { return false, [26]byte{}, 0, 0, [32]byte{}, [16]byte{}, [16]byte{}, 0, "", [22]byte{}, [22]byte{}, [11]byte{}, 0, err }
if (ableToDecrypt == false) {
// Unable to decrypt. Sender is malicious.
return false, [26]byte{}, 0, 0, [32]byte{}, [16]byte{}, [16]byte{}, 0, "", [22]byte{}, [22]byte{}, [11]byte{}, 0, nil
}
var basaldataSlice []messagepack.RawMessage
err = encoding.DecodeMessagePackBytes(false, decryptedBasaldataBytes, &basaldataSlice)
if (err != nil) {
// Message basaldata messagepack is invalid
return false, [26]byte{}, 0, 0, [32]byte{}, [16]byte{}, [16]byte{}, 0, "", [22]byte{}, [22]byte{}, [11]byte{}, 0, nil
}
if (len(basaldataSlice) != 6){
// Message basaldata is invalid
return false, [26]byte{}, 0, 0, [32]byte{}, [16]byte{}, [16]byte{}, 0, "", [22]byte{}, [22]byte{}, [11]byte{}, 0, nil
}
recipientIdentityHashEncoded := basaldataSlice[0]
messageCreationTimeUnixEncoded := basaldataSlice[1]
senderCurrentSecretInboxSeedEncoded := basaldataSlice[2]
senderNextSecretInboxSeedEncoded := basaldataSlice[3]
senderDeviceIdentifierEncoded := basaldataSlice[4]
senderLatestChatKeysUpdateTimeEncoded := basaldataSlice[5]
recipientIdentityHash, err := encoding.DecodeRawMessagePackTo16ByteArray(recipientIdentityHashEncoded)
if (err != nil) {
// Malformed message basaldata: Invalid RecipientIdentityHash
return false, [26]byte{}, 0, 0, [32]byte{}, [16]byte{}, [16]byte{}, 0, "", [22]byte{}, [22]byte{}, [11]byte{}, 0, nil
}
messageCreationTimeUnix, err := encoding.DecodeRawMessagePackToInt64(messageCreationTimeUnixEncoded)
if (err != nil) {
// Malformed message basaldata: Invalid CreationTime
return false, [26]byte{}, 0, 0, [32]byte{}, [16]byte{}, [16]byte{}, 0, "", [22]byte{}, [22]byte{}, [11]byte{}, 0, nil
}
senderCurrentSecretInboxSeed, err := encoding.DecodeRawMessagePackTo22ByteArray(senderCurrentSecretInboxSeedEncoded)
if (err != nil) {
// Malformed message basaldata: Invalid SenderCurrentSecretInboxSeed
return false, [26]byte{}, 0, 0, [32]byte{}, [16]byte{}, [16]byte{}, 0, "", [22]byte{}, [22]byte{}, [11]byte{}, 0, nil
}
senderNextSecretInboxSeed, err := encoding.DecodeRawMessagePackTo22ByteArray(senderNextSecretInboxSeedEncoded)
if (err != nil) {
// Malformed message basaldata: Invalid SenderNextSecretInboxSeed
return false, [26]byte{}, 0, 0, [32]byte{}, [16]byte{}, [16]byte{}, 0, "", [22]byte{}, [22]byte{}, [11]byte{}, 0, nil
}
senderDeviceIdentifier, err := encoding.DecodeRawMessagePackTo11ByteArray(senderDeviceIdentifierEncoded)
if (err != nil) {
// Malformed message basaldata: Invalid SenderDeviceIdentifier
return false, [26]byte{}, 0, 0, [32]byte{}, [16]byte{}, [16]byte{}, 0, "", [22]byte{}, [22]byte{}, [11]byte{}, 0, nil
}
senderLatestChatKeysUpdateTime, err := encoding.DecodeRawMessagePackToInt64(senderLatestChatKeysUpdateTimeEncoded)
if (err != nil) {
// Malformed message basaldata: Invalid SenderLatestChatKeysUpdateTime
return false, [26]byte{}, 0, 0, [32]byte{}, [16]byte{}, [16]byte{}, 0, "", [22]byte{}, [22]byte{}, [11]byte{}, 0, nil
}
recipientIdentityType, err := identity.GetIdentityTypeFromIdentityHash(recipientIdentityHash)
if (err != nil) {
// Malformed message basaldata: Invalid RecipientIdentityHash
return false, [26]byte{}, 0, 0, [32]byte{}, [16]byte{}, [16]byte{}, 0, "", [22]byte{}, [22]byte{}, [11]byte{}, 0, nil
}
if (senderIdentityType != recipientIdentityType){
// Malformed message basaldata: Recipient and sender identity types do not match.
return false, [26]byte{}, 0, 0, [32]byte{}, [16]byte{}, [16]byte{}, 0, "", [22]byte{}, [22]byte{}, [11]byte{}, 0, nil
}
isValid := helpers.VerifyCreationTime(messageCreationTimeUnix)
if (isValid == false){
// Malformed message basaldata: Contains invalid messageCreationTime
return false, [26]byte{}, 0, 0, [32]byte{}, [16]byte{}, [16]byte{}, 0, "", [22]byte{}, [22]byte{}, [11]byte{}, 0, nil
}
return true, messageHash, messageVersion, messageNetworkType, messageCipherKeyArray, senderIdentityHash, recipientIdentityHash, messageCreationTimeUnix, messageCommunication, senderCurrentSecretInboxSeed, senderNextSecretInboxSeed, senderDeviceIdentifier, senderLatestChatKeysUpdateTime, nil
}
// This is used by moderators to decrypt a chat message
// This does not decrypt the basaldata
//Outputs:
// -bool: Able to read message (could be false if message is malformed or unable to decrypt)
// -[26]byte: Message Hash
// -int: Message Version
// -byte: Message network type (1 == Mainnet, 2 == Testnet1)
// -[16]byte: Sender Identity Hash
// -string: Communication
// -error (will return err if non-message inputs are malformed, or there is a bug)
func ReadChatMessageWithCipherKey(inputMessage []byte, messageCipherKey [32]byte)(bool, [26]byte, int, byte, [16]byte, string, error){
ableToRead, messageHash, messageVersion, messageNetworkType, _, messageNoncipheredSectionBytes, _, _, expectedCipherKeyHash, cipheredMessageNonce, cipheredMessage, err := ReadChatMessagePublicDataAndHash(true, inputMessage)
if (err != nil) { return false, [26]byte{}, 0, 0, [16]byte{}, "", err }
if (ableToRead == false){
// Invalid message format
return false, [26]byte{}, 0, 0, [16]byte{}, "", nil
}
cipherKeyHash, err := blake3.GetBlake3HashAsBytes(25, messageCipherKey[:])
if (err != nil) { return false, [26]byte{}, 0, 0, [16]byte{}, "", err }
areEqual := bytes.Equal(cipherKeyHash, expectedCipherKeyHash[:])
if (areEqual == false){
// Invalid message: Cipher key hash does not match
return false, [26]byte{}, 0, 0, [16]byte{}, "", nil
}
ableToRead, senderIdentityHash, _, _, _, messageCommunication, err := readCipheredMessage(messageVersion, cipheredMessage, messageCipherKey, cipheredMessageNonce, messageNoncipheredSectionBytes)
if (err != nil) { return false, [26]byte{}, 0, 0, [16]byte{}, "", err }
if (ableToRead == false){
return false, [26]byte{}, 0, 0, [16]byte{}, "", nil
}
return true, messageHash, messageVersion, messageNetworkType, senderIdentityHash, messageCommunication, nil
}
//Outputs:
// -bool: Able to read (message is decryptable and well formed)
// -[16]byte: Sender Identity Hash
// -string: Sender Identity Type
// -[]byte: Encrypted Basaldata
// -[24]byte: Basaldata nonce
// -string: Communication
// -error (this will return err if there is a bug in the function)
func readCipheredMessage(messageVersion int, cipheredMessage []byte, cipheredMessageKey [32]byte, cipheredMessageNonce [24]byte, noncipheredSectionBytes messagepack.RawMessage)(bool, [16]byte, string, []byte, [24]byte, string, error){
if (messageVersion != 1){
return false, [16]byte{}, "", nil, [24]byte{}, "", errors.New("readCipheredMessage called with invalid messageVersion")
}
noncipheredSectionHash, err := blake3.Get32ByteBlake3Hash(noncipheredSectionBytes)
if (err != nil) { return false, [16]byte{}, "", nil, [24]byte{}, "", err }
ableToDecrypt, decryptedBytes, err := chaPolyShrink.DecryptChaPolyShrink(cipheredMessage, cipheredMessageKey, cipheredMessageNonce, true, noncipheredSectionHash)
if (err != nil) { return false, [16]byte{}, "", nil, [24]byte{}, "", err }
if (ableToDecrypt == false) {
// Unable to decrypt. Sender is malicious.
return false, [16]byte{}, "", nil, [24]byte{}, "", nil
}
// Now we read inner message
var innerMessageSlice []messagepack.RawMessage
err = encoding.DecodeMessagePackBytes(false, decryptedBytes, &innerMessageSlice)
if (err != nil) {
// Inner message messagepack is invalid
return false, [16]byte{}, "", nil, [24]byte{}, "", nil
}
if (len(innerMessageSlice) != 2){
// Inner message messagepack is invalid
return false, [16]byte{}, "", nil, [24]byte{}, "", nil
}
innerMessageSignatureEncoded := innerMessageSlice[0]
innerMessageRawMessagepack := innerMessageSlice[1]
innerMessageSignature, err := encoding.DecodeRawMessagePackTo64ByteArray(innerMessageSignatureEncoded)
if (err != nil){
// Malformed inner message: Invalid innerMessageSignature
return false, [16]byte{}, "", nil, [24]byte{}, "", nil
}
var innerMessageContentSlice []messagepack.RawMessage
err = encoding.DecodeMessagePackBytes(false, innerMessageRawMessagepack, &innerMessageContentSlice)
if (err != nil) {
// Message Inner plaintext messagepack is invalid
return false, [16]byte{}, "", nil, [24]byte{}, "", nil
}
if (len(innerMessageContentSlice) != 5){
// Malformed inner message: Invalid inner message content
return false, [16]byte{}, "", nil, [24]byte{}, "", nil
}
senderIdentityKeyEncoded := innerMessageContentSlice[0]
senderIdentityTypeEncoded := innerMessageContentSlice[1]
basaldataNonceEncoded := innerMessageContentSlice[2]
encryptedBasaldataEncoded := innerMessageContentSlice[3]
communicationEncoded := innerMessageContentSlice[4]
senderIdentityKey, err := encoding.DecodeRawMessagePackTo32ByteArray(senderIdentityKeyEncoded)
if (err != nil){
// Malformed inner message: Sender identity key is invalid.
return false, [16]byte{}, "", nil, [24]byte{}, "", nil
}
senderIdentityType, err := encoding.DecodeRawMessagePackToString(senderIdentityTypeEncoded)
if (err != nil){
// Malformed inner message: Sender identity type is invalid.
return false, [16]byte{}, "", nil, [24]byte{}, "", nil
}
basaldataNonce, err := encoding.DecodeRawMessagePackTo24ByteArray(basaldataNonceEncoded)
if (err != nil){
// Malformed inner message: Basaldata nonce is invalid.
return false, [16]byte{}, "", nil, [24]byte{}, "", nil
}
encryptedBasaldata, err := encoding.DecodeRawMessagePackToBytes(encryptedBasaldataEncoded)
if (err != nil){
// Malformed inner message: Encrypted basaldata is invalid.
return false, [16]byte{}, "", nil, [24]byte{}, "", nil
}
messageCommunication, err := encoding.DecodeRawMessagePackToString(communicationEncoded)
if (err != nil){
// Malformed inner message: Message communication is invalid.
return false, [16]byte{}, "", nil, [24]byte{}, "", nil
}
//TODO: Verify communication is valid
if (senderIdentityType != "Mate" && senderIdentityType != "Moderator"){
// Malformed inner message: Invalid senderIdentityType.
return false, [16]byte{}, "", nil, [24]byte{}, "", nil
}
innerContentHash, err := blake3.Get32ByteBlake3Hash(innerMessageRawMessagepack)
if (err != nil) { return false, [16]byte{}, "", nil, [24]byte{}, "", err }
isValid := edwardsKeys.VerifySignature(senderIdentityKey, innerMessageSignature, innerContentHash)
if (isValid == false) {
// Malformed inner message: signature is invalid.
return false, [16]byte{}, "", nil, [24]byte{}, "", nil
}
senderIdentityHash, err := identity.ConvertIdentityKeyToIdentityHash(senderIdentityKey, senderIdentityType)
if (err != nil) { return false, [16]byte{}, "", nil, [24]byte{}, "", err }
return true, senderIdentityHash, senderIdentityType, encryptedBasaldata, basaldataNonce, messageCommunication, nil
}