// 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 broadcast 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 sent 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 broadcast 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] messageSentTimeUnixEncoded := 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 } messageSentTimeUnix, err := encoding.DecodeRawMessagePackToInt64(messageSentTimeUnixEncoded) if (err != nil) { // Malformed message basaldata: Invalid SentTime 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.VerifyBroadcastTime(messageSentTimeUnix) if (isValid == false){ // Malformed message basaldata: Contains invalid unixSentTime 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, messageSentTimeUnix, 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 }