// serverResponse provides functions to create and read server responses package serverResponse // See a description of each response and its purpose in Specification.md //TODO: Verify all received 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 "seekia/internal/messaging/readMessages" import "seekia/internal/moderation/readReports" import "seekia/internal/moderation/readReviews" import "seekia/internal/parameters/readParameters" import "seekia/internal/profiles/readProfiles" import messagepack "github.com/vmihailenco/msgpack/v5" import "slices" import "crypto/rand" import "errors" // The variables below specify the maximum number of items that can fit into a response // They are used when making requests to know when to break up the request so it does not exceed the maximum size //TODO: Make these numbers accurate const MaximumProfilesInResponse_GetProfilesInfo int = 100000 const MaximumMessageHashesInResponse_GetMessageHashesList int = 100000 const MaximumMessagesInResponse_GetMessages int = 100000 const MaximumReviewHashesInResponse_GetReviewHashesList int = 100000 const MaximumReviewsInResponse_GetIdentityReviewsInfo int = 100000 const MaximumReviewsInResponse_GetMessageReviewsInfo int = 100000 const MaximumReviewsInResponse_GetReviews int = 100000 const MaximumReportsInResponse_GetIdentityReportsInfo int = 100000 const MaximumReportsInResponse_GetMessageReportsInfo int = 100000 const MaximumReportsInResponse_GetReports int = 100000 const MaximumBalancesInResponse_GetAddressDeposits int = 100000 const MaximumProfilesInResponse_GetProfileViewableStatuses int = 10000 const MaximumIdentitiesInResponse_GetIdentityViewableStatuses int = 1000 func GetMaximumProfilesInResponse_GetProfiles(profileType string)(int, error){ if (profileType == "Mate"){ return 1000, nil } if (profileType == "Host"){ return 10000, nil } if (profileType == "Moderator"){ return 10000, nil } return 0, errors.New("GetMaximumProfilesInResponse_GetProfiles called with invalid profile type: " + profileType) } //Outputs: // -[]byte: Response bytes // -[32]byte: Connection Key // -error func CreateServerResponse_EstablishConnectionKey(hostPublicIdentityKey [32]byte, hostPrivateIdentityKey [64]byte, requestIdentifier [16]byte, requestorNaclPublicKey [32]byte, requestorKyberPublicKey [1568]byte)([]byte, [32]byte, error){ var connectionKey [32]byte _, err := rand.Read(connectionKey[:]) if (err != nil) { return nil, [32]byte{}, err } type responseStruct struct{ HostIdentityKey [32]byte RequestIdentifier [16]byte ResponseType string ConnectionKey [32]byte } responseObject := responseStruct{ HostIdentityKey: hostPublicIdentityKey, RequestIdentifier: requestIdentifier, ResponseType: "EstablishConnectionKey", ConnectionKey: connectionKey, } responseContentBytes, err := encoding.EncodeMessagePackBytes(responseObject) if (err != nil) { return nil, [32]byte{}, err } responseSignedBytes, err := createResponseSignedContent(hostPrivateIdentityKey, responseContentBytes) if (err != nil) { return nil, [32]byte{}, err } chaPolyKey, err := helpers.GetNewRandom32ByteArray() if (err != nil) { return nil, [32]byte{}, err } chaPolyNonce, err := helpers.GetNewRandom24ByteArray() if (err != nil) { return nil, [32]byte{}, err } cipheredContent, err := chaPolyShrink.EncryptChaPolyShrink(responseSignedBytes, chaPolyKey, chaPolyNonce, true, 50, false, [32]byte{}) if (err != nil) { return nil, [32]byte{}, err } keyPieceA, err := helpers.GetNewRandom32ByteArray() if (err != nil) { return nil, [32]byte{}, err } keyPieceB := helpers.XORTwo32ByteArrays(keyPieceA, chaPolyKey) naclEncryptedKeyPieceA, err := nacl.EncryptKeyWithNacl(requestorNaclPublicKey, keyPieceA) if (err != nil) { return nil, [32]byte{}, err } kyberEncryptedKeyPieceB, err := kyber.EncryptKeyWithKyber(requestorKyberPublicKey, keyPieceB) if (err != nil) { return nil, [32]byte{}, err } keyPiecesList := slices.Concat(naclEncryptedKeyPieceA[:], kyberEncryptedKeyPieceB[:]) type encryptedResponseStruct struct{ KeyPieces []byte ChaPolyNonce [24]byte CipheredContent []byte } encryptedResponseObject := encryptedResponseStruct{ KeyPieces: keyPiecesList, ChaPolyNonce: chaPolyNonce, CipheredContent: cipheredContent, } encryptedResponseBytes, err := encoding.EncodeMessagePackBytes(encryptedResponseObject) if (err != nil) { return nil, [32]byte{}, err } return encryptedResponseBytes, connectionKey, nil } //Outputs: // -bool: Able to read // -[16]byte: Request identifier // -[16]byte: Host Identity Hash // -[32]byte: Connection key // -error (if inputs to function are invalid) func ReadServerResponse_EstablishConnectionKey(responseBytes []byte, requestorNaclPublicKey [32]byte, requestorNaclPrivateKey [32]byte, requestorKyberPrivateKey [1536]byte)(bool, [16]byte, [16]byte, [32]byte, error){ type encryptedResponseStruct struct{ KeyPieces [1648]byte ChaPolyNonce [24]byte CipheredContent []byte } var encryptedResponseObject encryptedResponseStruct err := encoding.DecodeMessagePackBytes(false, responseBytes, &encryptedResponseObject) if (err != nil) { return false, [16]byte{}, [16]byte{}, [32]byte{}, nil } keyPiecesListArray := encryptedResponseObject.KeyPieces chaPolyNonce := encryptedResponseObject.ChaPolyNonce cipheredContent := encryptedResponseObject.CipheredContent naclEncryptedKeyPieceA := [80]byte(keyPiecesListArray[:80]) kyberEncryptedKeyPieceB := [1568]byte(keyPiecesListArray[80:]) ableToDecrypt, keyPieceA, err := nacl.DecryptNaclEncryptedKey(naclEncryptedKeyPieceA, requestorNaclPublicKey, requestorNaclPrivateKey) if (err != nil) { return false, [16]byte{}, [16]byte{}, [32]byte{}, err } if (ableToDecrypt == false){ return false, [16]byte{}, [16]byte{}, [32]byte{}, nil } keyPieceB, err := kyber.DecryptKyberEncryptedKey(kyberEncryptedKeyPieceB, requestorKyberPrivateKey) if (err != nil) { return false, [16]byte{}, [16]byte{}, [32]byte{}, nil } contentChaPolyKey := helpers.XORTwo32ByteArrays(keyPieceA, keyPieceB) ableToDecrypt, decryptedResponseBytes, err := chaPolyShrink.DecryptChaPolyShrink(cipheredContent, contentChaPolyKey, chaPolyNonce, false, [32]byte{}) if (err != nil) { return false, [16]byte{}, [16]byte{}, [32]byte{}, nil } if (ableToDecrypt == false){ return false, [16]byte{}, [16]byte{}, [32]byte{}, nil } ableToRead, requestIdentifier, hostIdentityHash, contentBytes, err := readResponseSignedContent(decryptedResponseBytes, "EstablishConnectionKey") if (err != nil) { return false, [16]byte{}, [16]byte{}, [32]byte{}, err } if (ableToRead == false){ return false, [16]byte{}, [16]byte{}, [32]byte{}, nil } type responseContentStruct struct{ ConnectionKey [32]byte } var responseContentObject responseContentStruct err = encoding.DecodeMessagePackBytes(true, contentBytes, &responseContentObject) if (err != nil) { return false, [16]byte{}, [16]byte{}, [32]byte{}, nil } connectionKey := responseContentObject.ConnectionKey return true, requestIdentifier, hostIdentityHash, connectionKey, nil } //Outputs: // -[]byte: Response bytes // -error func CreateServerResponse_GetParametersInfo(hostPublicIdentityKey [32]byte, hostPrivateIdentityKey [64]byte, connectionKey [32]byte, requestIdentifier [16]byte, parametersInfoMap map[string]int64)([]byte, error){ if (len(parametersInfoMap) == 0){ return nil, errors.New("CreateServerResponse_GetParametersInfo called with empty ParametersInfoMap") } type responseContentStruct struct{ HostIdentityKey [32]byte RequestIdentifier [16]byte ResponseType string ParametersInfo map[string]int64 // Parameters Type -> Parameters broadcast time } responseContentObject := responseContentStruct{ HostIdentityKey: hostPublicIdentityKey, RequestIdentifier: requestIdentifier, ResponseType: "GetParametersInfo", ParametersInfo: parametersInfoMap, } innerResponseBytes, err := encoding.EncodeMessagePackBytes(responseContentObject) if (err != nil) { return nil, err } encryptedResponse, err := createEncryptedAndSignedResponse(connectionKey, hostPrivateIdentityKey, innerResponseBytes) if (err != nil) { return nil, err } return encryptedResponse, nil } //Outputs: // -bool: Able to read server response // -[16]byte: Request Identifier // -[16]byte: Host Identity Hash // -map[string]int64: Parameters Info map (Parameters Type -> Parameters broadcast time) // -error (returns err if input keys are invalid) func ReadServerResponse_GetParametersInfo(responseBytes []byte, connectionKey [32]byte)(bool, [16]byte, [16]byte, map[string]int64, error){ ableToRead, requestIdentifier, hostIdentityHash, decryptedContentBytes, err := readEncryptedAndSignedResponse(responseBytes, connectionKey, "GetParametersInfo") if (err != nil) { return false, [16]byte{}, [16]byte{}, nil, err } if (ableToRead == false){ //Response is malformed return false, [16]byte{}, [16]byte{}, nil, nil } type responseContentStruct struct{ ParametersInfo map[string]int64 } var responseContentObject responseContentStruct err = encoding.DecodeMessagePackBytes(true, decryptedContentBytes, &responseContentObject) if (err != nil) { // Response malformed return false, [16]byte{}, [16]byte{}, nil, nil } parametersInfoMap := responseContentObject.ParametersInfo //TODO: Verify parameters return true, requestIdentifier, hostIdentityHash, parametersInfoMap, nil } //Outputs: // -[]byte: Response bytes // -error func CreateServerResponse_GetParameters(hostPublicIdentityKey [32]byte, hostPrivateIdentityKey [64]byte, connectionKey [32]byte, requestIdentifier [16]byte, parametersList [][]byte)([]byte, error){ //TODO: Verify inputs messagepackParametersList := make([]messagepack.RawMessage, 0, len(parametersList)) for _, parametersBytes := range parametersList{ messagepackParametersList = append(messagepackParametersList, parametersBytes) } type responseContentStruct struct{ HostIdentityKey [32]byte RequestIdentifier [16]byte ResponseType string ParametersList []messagepack.RawMessage } responseContentObject := responseContentStruct{ HostIdentityKey: hostPublicIdentityKey, RequestIdentifier: requestIdentifier, ResponseType: "GetParameters", ParametersList: messagepackParametersList, } innerResponseBytes, err := encoding.EncodeMessagePackBytes(responseContentObject) if (err != nil) { return nil, err } encryptedResponse, err := createEncryptedAndSignedResponse(connectionKey, hostPrivateIdentityKey, innerResponseBytes) if (err != nil) { return nil, err } return encryptedResponse, nil } //Outputs: // -bool: Able to read server response // -[16]byte: Request Identifier // -[16]byte: Host Identity Hash // -[][]byte: Parameters list // -error (returns err if input keys are invalid) func ReadServerResponse_GetParameters(responseBytes []byte, connectionKey [32]byte)(bool, [16]byte, [16]byte, [][]byte, error){ //TODO: Verify inputs ableToRead, requestIdentifier, hostIdentityHash, decryptedContentBytes, err := readEncryptedAndSignedResponse(responseBytes, connectionKey, "GetParameters") if (err != nil) { return false, [16]byte{}, [16]byte{}, nil, err } if (ableToRead == false){ //Response is malformed return false, [16]byte{}, [16]byte{}, nil, nil } type responseContentStruct struct{ ParametersList []messagepack.RawMessage } var responseContentObject responseContentStruct err = encoding.DecodeMessagePackBytes(true, decryptedContentBytes, &responseContentObject) if (err != nil) { // Response is malformed return false, [16]byte{}, [16]byte{}, nil, nil } parametersListRawMessagepack := responseContentObject.ParametersList // We use the map below to ensure we only received each parameter type once receivedParametersTypesMap := make(map[string]struct{}) // We use this to ensure that all parameters network types are the same parametersNetworkType := byte(0) parametersList := make([][]byte, 0, len(parametersListRawMessagepack)) for index, parametersBytes := range parametersListRawMessagepack{ ableToRead, _, currentNetworkType, _, parametersType, _, _, err := readParameters.ReadParameters(true, parametersBytes) if (err != nil) { return false, [16]byte{}, [16]byte{}, nil, err } if (ableToRead == false){ // Response is malformed return false, [16]byte{}, [16]byte{}, nil, nil } if (index == 0){ parametersNetworkType = currentNetworkType } else if (parametersNetworkType != currentNetworkType){ // We received two parameters with different network types. // Response is malformed. return false, [16]byte{}, [16]byte{}, nil, nil } _, exists := receivedParametersTypesMap[parametersType] if (exists == true){ // We received a duplicate parameters type. Response is malformed. return false, [16]byte{}, [16]byte{}, nil, nil } receivedParametersTypesMap[parametersType] = struct{}{} parametersList = append(parametersList, parametersBytes) } return true, requestIdentifier, hostIdentityHash, parametersList, nil } // This is used for the GetProfilesInfo request type ProfileInfoStruct struct{ ProfileHash [28]byte ProfileAuthor [16]byte ProfileBroadcastTime int64 } //Outputs: // -[]byte: Response bytes // -error func CreateServerResponse_GetProfilesInfo(hostPublicIdentityKey [32]byte, hostPrivateIdentityKey [64]byte, connectionKey [32]byte, requestIdentifier [16]byte, profileInfoObjectsList []ProfileInfoStruct)([]byte, error){ //TODO: Verify inputs for _, profileInfoObject := range profileInfoObjectsList{ profileHash := profileInfoObject.ProfileHash profileAuthor := profileInfoObject.ProfileAuthor profileBroadcastTime := profileInfoObject.ProfileBroadcastTime profileType, _, err := readProfiles.ReadProfileHashMetadata(profileHash) if (err != nil){ profileHashHex := encoding.EncodeBytesToHexString(profileHash[:]) return nil, errors.New("Cannot create response: Invalid profileInfoObjectsList: Invalid ProfileHash: " + profileHashHex + ". Reason: " + err.Error()) } authorIdentityType, err := identity.GetIdentityTypeFromIdentityHash(profileAuthor) if (err != nil){ profileAuthorHex := encoding.EncodeBytesToHexString(profileAuthor[:]) return nil, errors.New("Cannot create response: invalid profileInfoObjectsList: Invalid profileAuthor: " + profileAuthorHex) } if (authorIdentityType != profileType){ return nil, errors.New("Cannot create response: Invalid profileInfoObjectsList: ProfileHash profile type does not match profileAuthor identity type.") } isValid := helpers.VerifyBroadcastTime(profileBroadcastTime) if (isValid == false){ broadcastTimeString := helpers.ConvertInt64ToString(profileBroadcastTime) return nil, errors.New("Cannot create response: Invalid profileInfoObjectsList: Invalid broadcastTime: " + broadcastTimeString) } } type responseContentStruct struct{ HostIdentityKey [32]byte RequestIdentifier [16]byte ResponseType string ProfilesInfo []ProfileInfoStruct } responseContentObject := responseContentStruct{ HostIdentityKey: hostPublicIdentityKey, RequestIdentifier: requestIdentifier, ResponseType: "GetProfilesInfo", ProfilesInfo: profileInfoObjectsList, } innerResponseBytes, err := encoding.EncodeMessagePackBytes(responseContentObject) if (err != nil) { return nil, err } encryptedResponse, err := createEncryptedAndSignedResponse(connectionKey, hostPrivateIdentityKey, innerResponseBytes) if (err != nil) { return nil, err } return encryptedResponse, nil } //Outputs: // -bool: Able to read server response // -[16]byte: Request Identifier // -[16]byte: Host Identity Hash // -[]ProfileInfoStruct: Profiles Info map list // -error (returns err if input keys are invalid) func ReadServerResponse_GetProfilesInfo(responseBytes []byte, connectionKey [32]byte)(bool, [16]byte, [16]byte, []ProfileInfoStruct, error){ //TODO: Verify inputs ableToRead, requestIdentifier, hostIdentityHash, decryptedContentBytes, err := readEncryptedAndSignedResponse(responseBytes, connectionKey, "GetProfilesInfo") if (err != nil) { return false, [16]byte{}, [16]byte{}, nil, err } if (ableToRead == false){ //Response is malformed return false, [16]byte{}, [16]byte{}, nil, nil } type responseContentStruct struct{ ProfilesInfo []ProfileInfoStruct } var responseContentObject responseContentStruct err = encoding.DecodeMessagePackBytes(true, decryptedContentBytes, &responseContentObject) if (err != nil) { // Response malformed return false, [16]byte{}, [16]byte{}, nil, nil } //TODO: Validate info profileInfoObjectsList := responseContentObject.ProfilesInfo return true, requestIdentifier, hostIdentityHash, profileInfoObjectsList, nil } //Outputs: // -[]byte: Response bytes // -error func CreateServerResponse_GetProfiles(hostPublicIdentityKey [32]byte, hostPrivateIdentityKey [64]byte, connectionKey [32]byte, requestIdentifier [16]byte, profilesList [][]byte)([]byte, error){ //TODO: Verify inputs messagepackProfilesList := make([]messagepack.RawMessage, 0, len(profilesList)) for _, profileBytes := range profilesList{ messagepackProfilesList = append(messagepackProfilesList, profileBytes) } type responseContentStruct struct{ HostIdentityKey [32]byte RequestIdentifier [16]byte ResponseType string ProfilesList []messagepack.RawMessage } responseContentObject := responseContentStruct{ HostIdentityKey: hostPublicIdentityKey, RequestIdentifier: requestIdentifier, ResponseType: "GetProfiles", ProfilesList: messagepackProfilesList, } innerResponseBytes, err := encoding.EncodeMessagePackBytes(responseContentObject) if (err != nil) { return nil, err } encryptedResponse, err := createEncryptedAndSignedResponse(connectionKey, hostPrivateIdentityKey, innerResponseBytes) if (err != nil) { return nil, err } return encryptedResponse, nil } //Outputs: // -bool: Able to read server response // -[16]byte: Request Identifier // -[16]byte: Host Identity Hash // -[][]byte: Profiles list // -error (returns err if input keys are invalid) func ReadServerResponse_GetProfiles(responseBytes []byte, connectionKey [32]byte)(bool, [16]byte, [16]byte, [][]byte, error){ //TODO: Verify inputs ableToRead, requestIdentifier, hostIdentityHash, decryptedContentBytes, err := readEncryptedAndSignedResponse(responseBytes, connectionKey, "GetProfiles") if (err != nil) { return false, [16]byte{}, [16]byte{}, nil, err } if (ableToRead == false){ //Response is malformed return false, [16]byte{}, [16]byte{}, nil, nil } type responseContentStruct struct{ ProfilesList []messagepack.RawMessage } var responseContentObject responseContentStruct err = encoding.DecodeMessagePackBytes(true, decryptedContentBytes, &responseContentObject) if (err != nil) { // Response is malformed return false, [16]byte{}, [16]byte{}, nil, nil } messagepackProfilesList := responseContentObject.ProfilesList // We use the map below to ensure we only received each profile once receivedProfileHashesMap := make(map[[28]byte]struct{}) profilesList := make([][]byte, 0, len(messagepackProfilesList)) // We use this variable to make sure the network type of each profile is the same profilesNetworkType := byte(0) for index, profileBytes := range messagepackProfilesList{ ableToRead, profileHash, _, profileNetworkType, _, _, _, _, err := readProfiles.ReadProfileAndHash(true, profileBytes) if (err != nil) { return false, [16]byte{}, [16]byte{}, nil, err } if (ableToRead == false){ // Profile is malformed. Host is malicious. return false, [16]byte{}, [16]byte{}, nil, nil } _, exists := receivedProfileHashesMap[profileHash] if (exists == true){ // We received a duplicate profile. Host is malicious. return false, [16]byte{}, [16]byte{}, nil, nil } receivedProfileHashesMap[profileHash] = struct{}{} if (index == 0){ profilesNetworkType = profileNetworkType } else if (profilesNetworkType != profileNetworkType){ // Profiles of differing network type cannot be sent in the same response // Response is malformed return false, [16]byte{}, [16]byte{}, nil, nil } profilesList = append(profilesList, profileBytes) } return true, requestIdentifier, hostIdentityHash, profilesList, nil } //Outputs: // -[]byte: Response bytes // -error func CreateServerResponse_GetMessageHashesList(hostPublicIdentityKey [32]byte, hostPrivateIdentityKey [64]byte, connectionKey [32]byte, requestIdentifier [16]byte, messageHashesList [][26]byte)([]byte, error){ type responseContentStruct struct{ HostIdentityKey [32]byte RequestIdentifier [16]byte ResponseType string MessageHashesList [][26]byte } responseContentObject := responseContentStruct{ HostIdentityKey: hostPublicIdentityKey, RequestIdentifier: requestIdentifier, ResponseType: "GetMessageHashesList", MessageHashesList: messageHashesList, } innerResponseBytes, err := encoding.EncodeMessagePackBytes(responseContentObject) if (err != nil) { return nil, err } encryptedResponse, err := createEncryptedAndSignedResponse(connectionKey, hostPrivateIdentityKey, innerResponseBytes) if (err != nil) { return nil, err } return encryptedResponse, nil } //Outputs: // -bool: Able to read server response // -[16]byte: Request Identifier // -[16]byte: Host Identity Hash // -[][26]byte: Message Hashes List // -error (returns err if input keys are invalid) func ReadServerResponse_GetMessageHashesList(responseBytes []byte, connectionKey [32]byte)(bool, [16]byte, [16]byte, [][26]byte, error){ //TODO: Verify inputs ableToRead, requestIdentifier, hostIdentityHash, decryptedContentBytes, err := readEncryptedAndSignedResponse(responseBytes, connectionKey, "GetMessageHashesList") if (err != nil) { return false, [16]byte{}, [16]byte{}, nil, err } if (ableToRead == false){ //Response is malformed return false, [16]byte{}, [16]byte{}, nil, nil } type responseContentStruct struct{ MessageHashesList [][26]byte } var responseContentObject responseContentStruct err = encoding.DecodeMessagePackBytes(true, decryptedContentBytes, &responseContentObject) if (err != nil) { // Response malformed return false, [16]byte{}, [16]byte{}, nil, nil } messageHashesList := responseContentObject.MessageHashesList return true, requestIdentifier, hostIdentityHash, messageHashesList, nil } //Outputs: // -[]byte: Response bytes // -error func CreateServerResponse_GetMessages(hostPublicIdentityKey [32]byte, hostPrivateIdentityKey [64]byte, connectionKey [32]byte, requestIdentifier [16]byte, messagesList [][]byte)([]byte, error){ //TODO: Verify inputs messagepackMessagesList := make([]messagepack.RawMessage, 0, len(messagesList)) for _, messageBytes := range messagesList{ messagepackMessagesList = append(messagepackMessagesList, messageBytes) } type responseContentStruct struct{ HostIdentityKey [32]byte RequestIdentifier [16]byte ResponseType string MessagesList []messagepack.RawMessage } responseContentObject := responseContentStruct{ HostIdentityKey: hostPublicIdentityKey, RequestIdentifier: requestIdentifier, ResponseType: "GetMessages", MessagesList: messagepackMessagesList, } innerResponseBytes, err := encoding.EncodeMessagePackBytes(responseContentObject) if (err != nil) { return nil, err } encryptedResponse, err := createEncryptedAndSignedResponse(connectionKey, hostPrivateIdentityKey, innerResponseBytes) if (err != nil) { return nil, err } return encryptedResponse, nil } //Outputs: // -bool: Able to read server response // -[16]byte: Request Identifier // -[16]byte: Host Identity Hash // -[][]byte: Messages list // -error (returns err if input keys are invalid) func ReadServerResponse_GetMessages(responseBytes []byte, connectionKey [32]byte)(bool, [16]byte, [16]byte, [][]byte, error){ //TODO: Verify inputs ableToRead, requestIdentifier, hostIdentityHash, decryptedContentBytes, err := readEncryptedAndSignedResponse(responseBytes, connectionKey, "GetMessages") if (err != nil) { return false, [16]byte{}, [16]byte{}, nil, err } if (ableToRead == false){ //Response is malformed return false, [16]byte{}, [16]byte{}, nil, nil } type responseContentStruct struct{ MessagesList []messagepack.RawMessage } var responseContentObject responseContentStruct err = encoding.DecodeMessagePackBytes(true, decryptedContentBytes, &responseContentObject) if (err != nil) { // Response is malformed return false, [16]byte{}, [16]byte{}, nil, nil } messagepackMessagesList := responseContentObject.MessagesList // We use this map to detect duplicates messageHashesMap := make(map[[26]byte]struct{}) messagesList := make([][]byte, 0, len(messagepackMessagesList)) // We use this variable to make sure the network type of all messages in the response is the same messagesNetworkType := byte(0) for index, messageBytes := range messagepackMessagesList{ ableToRead, messageHash, _, messageNetworkType, _, _, _, _, _, _, _, err := readMessages.ReadChatMessagePublicDataAndHash(true, messageBytes) if (err != nil) { return false, [16]byte{}, [16]byte{}, nil, err } if (ableToRead == false){ // Message is invalid, host must be malicious. return false, [16]byte{}, [16]byte{}, nil, nil } _, exists := messageHashesMap[messageHash] if (exists == true){ // Host sent duplicate message. return false, [16]byte{}, [16]byte{}, nil, nil } messageHashesMap[messageHash] = struct{}{} if (index == 0){ messagesNetworkType = messageNetworkType } else if (messagesNetworkType != messageNetworkType){ // All messages in the response must contain the same networkType return false, [16]byte{}, [16]byte{}, nil, nil } messagesList = append(messagesList, messageBytes) } return true, requestIdentifier, hostIdentityHash, messagesList, nil } //Outputs: // -[]byte: Response bytes // -error func CreateServerResponse_GetIdentityReviewsInfo(hostPublicIdentityKey [32]byte, hostPrivateIdentityKey [64]byte, connectionKey [32]byte, requestIdentifier [16]byte, reviewsInfoMap map[[29]byte][]byte)([]byte, error){ //TODO: Verify inputs type responseContentStruct struct{ HostIdentityKey [32]byte RequestIdentifier [16]byte ResponseType string ReviewsInfo map[[29]byte][]byte // ReviewHash -> ReviewedHash } responseContentObject := responseContentStruct{ HostIdentityKey: hostPublicIdentityKey, RequestIdentifier: requestIdentifier, ResponseType: "GetIdentityReviewsInfo", ReviewsInfo: reviewsInfoMap, } innerResponseBytes, err := encoding.EncodeMessagePackBytes(responseContentObject) if (err != nil) { return nil, err } encryptedResponse, err := createEncryptedAndSignedResponse(connectionKey, hostPrivateIdentityKey, innerResponseBytes) if (err != nil) { return nil, err } return encryptedResponse, nil } //Outputs: // -bool: Able to read server response // -[16]byte: Request Identifier // -[16]byte: Host Identity Hash // -map[[29]byte][]byte: Reviews Info map (Review Hash -> Reviewed Hash) // -error (returns err if input keys are invalid) func ReadServerResponse_GetIdentityReviewsInfo(responseBytes []byte, connectionKey [32]byte)(bool, [16]byte, [16]byte, map[[29]byte][]byte, error){ //TODO: Verify inputs ableToRead, requestIdentifier, hostIdentityHash, decryptedContentBytes, err := readEncryptedAndSignedResponse(responseBytes, connectionKey, "GetIdentityReviewsInfo") if (err != nil) { return false, [16]byte{}, [16]byte{}, nil, err } if (ableToRead == false){ //Response is malformed return false, [16]byte{}, [16]byte{}, nil, nil } type responseContentStruct struct{ ReviewsInfo map[[29]byte][]byte } var responseContentObject responseContentStruct err = encoding.DecodeMessagePackBytes(true, decryptedContentBytes, &responseContentObject) if (err != nil) { // Response malformed return false, [16]byte{}, [16]byte{}, nil, nil } reviewsInfoMap := responseContentObject.ReviewsInfo for reviewHash, reviewedHash := range reviewsInfoMap{ reviewedType, err := helpers.GetReviewedTypeFromReviewedHash(reviewedHash) if (err != nil) { // Response is malformed return false, [16]byte{}, [16]byte{}, nil, nil } if (reviewedType != "Identity" && reviewedType != "Profile" && reviewedType != "Attribute"){ // Response is malformed return false, [16]byte{}, [16]byte{}, nil, nil } isValid, err := readReviews.VerifyReviewHash(reviewHash, true, reviewedType) if (err != nil) { return false, [16]byte{}, [16]byte{}, nil, err } if (isValid == false){ // Received reviewsInfoMap contains invalid reviewHash // Response is malformed return false, [16]byte{}, [16]byte{}, nil, nil } } return true, requestIdentifier, hostIdentityHash, reviewsInfoMap, nil } //Outputs: // -[]byte: Response bytes // -error func CreateServerResponse_GetMessageReviewsInfo(hostPublicIdentityKey [32]byte, hostPrivateIdentityKey [64]byte, connectionKey [32]byte, requestIdentifier [16]byte, reviewsInfoMap map[[29]byte][26]byte)([]byte, error){ //TODO: Verify inputs type responseContentStruct struct{ HostIdentityKey [32]byte RequestIdentifier [16]byte ResponseType string ReviewsInfo map[[29]byte][26]byte // Review Hash -> Reviewed Message Hash } responseContentObject := responseContentStruct{ HostIdentityKey: hostPublicIdentityKey, RequestIdentifier: requestIdentifier, ResponseType: "GetMessageReviewsInfo", ReviewsInfo: reviewsInfoMap, } innerResponseBytes, err := encoding.EncodeMessagePackBytes(responseContentObject) if (err != nil) { return nil, err } encryptedResponse, err := createEncryptedAndSignedResponse(connectionKey, hostPrivateIdentityKey, innerResponseBytes) if (err != nil) { return nil, err } return encryptedResponse, nil } //Outputs: // -bool: Able to read server response // -[16]byte: Request Identifier // -[16]byte: Host Identity Hash // -map[[29]byte][26]byte: Reviews Info map (Review Hash -> Reviewed Message Hash) // -error (returns err if input keys are invalid) func ReadServerResponse_GetMessageReviewsInfo(responseBytes []byte, connectionKey [32]byte)(bool, [16]byte, [16]byte, map[[29]byte][26]byte, error){ //TODO: Verify inputs ableToRead, requestIdentifier, hostIdentityHash, decryptedContentBytes, err := readEncryptedAndSignedResponse(responseBytes, connectionKey, "GetMessageReviewsInfo") if (err != nil) { return false, [16]byte{}, [16]byte{}, nil, err } if (ableToRead == false){ //Response is malformed return false, [16]byte{}, [16]byte{}, nil, nil } type responseContentStruct struct{ ReviewsInfo map[[29]byte][26]byte } var responseContentObject responseContentStruct err = encoding.DecodeMessagePackBytes(true, decryptedContentBytes, &responseContentObject) if (err != nil) { // Response malformed return false, [16]byte{}, [16]byte{}, nil, nil } reviewsInfoMap := responseContentObject.ReviewsInfo for reviewHash, _ := range reviewsInfoMap{ isValid, err := readReviews.VerifyReviewHash(reviewHash, true, "Message") if (err != nil) { return false, [16]byte{}, [16]byte{}, nil, err } if (isValid == false){ // Received reviewsInfoMap contains invalid reviewHash // Response is malformed return false, [16]byte{}, [16]byte{}, nil, nil } } return true, requestIdentifier, hostIdentityHash, reviewsInfoMap, nil } //Outputs: // -[]byte: Response bytes // -error func CreateServerResponse_GetReviews(hostPublicIdentityKey [32]byte, hostPrivateIdentityKey [64]byte, connectionKey [32]byte, requestIdentifier [16]byte, reviewsList [][]byte)([]byte, error){ //TODO: Verify inputs messagepackReviewsList := make([]messagepack.RawMessage, 0, len(reviewsList)) for _, reviewBytes := range reviewsList{ messagepackReviewsList = append(messagepackReviewsList, reviewBytes) } type responseContentStruct struct{ HostIdentityKey [32]byte RequestIdentifier [16]byte ResponseType string ReviewsList []messagepack.RawMessage } responseContentObject := responseContentStruct{ HostIdentityKey: hostPublicIdentityKey, RequestIdentifier: requestIdentifier, ResponseType: "GetReviews", ReviewsList: messagepackReviewsList, } innerResponseBytes, err := encoding.EncodeMessagePackBytes(responseContentObject) if (err != nil) { return nil, err } encryptedResponse, err := createEncryptedAndSignedResponse(connectionKey, hostPrivateIdentityKey, innerResponseBytes) if (err != nil) { return nil, err } return encryptedResponse, nil } //Outputs: // -bool: Able to read server response // -[16]byte: Request Identifier // -[16]byte: Host Identity Hash // -[][]byte: Reviews list // -error (returns err if input keys are invalid) func ReadServerResponse_GetReviews(responseBytes []byte, connectionKey [32]byte)(bool, [16]byte, [16]byte, [][]byte, error){ //TODO: Verify inputs ableToRead, requestIdentifier, hostIdentityHash, decryptedContentBytes, err := readEncryptedAndSignedResponse(responseBytes, connectionKey, "GetReviews") if (err != nil) { return false, [16]byte{}, [16]byte{}, nil, err } if (ableToRead == false){ //Response is malformed return false, [16]byte{}, [16]byte{}, nil, nil } type responseContentStruct struct{ ReviewsList []messagepack.RawMessage } var responseContentObject responseContentStruct err = encoding.DecodeMessagePackBytes(true, decryptedContentBytes, &responseContentObject) if (err != nil) { // Response is malformed return false, [16]byte{}, [16]byte{}, nil, nil } messagepackReviewsList := responseContentObject.ReviewsList // We use a map to detect duplicates reviewHashesMap := make(map[[29]byte]struct{}) reviewsList := make([][]byte, 0, len(messagepackReviewsList)) // We use this variable to ensure that all reviews in the response belong to the same networkType reviewsNetworkType := byte(0) for index, reviewBytes := range messagepackReviewsList{ ableToRead, reviewHash, _, reviewNetworkType, _, _, _, _, _, _, err := readReviews.ReadReviewAndHash(true, reviewBytes) if (err != nil) { return false, [16]byte{}, [16]byte{}, nil, err } if (ableToRead == false){ // Review is invalid, host must be malicious. return false, [16]byte{}, [16]byte{}, nil, nil } _, exists := reviewHashesMap[reviewHash] if (exists == true){ // Duplicate review exists // Response is malformed return false, [16]byte{}, [16]byte{}, nil, nil } reviewHashesMap[reviewHash] = struct{}{} if (index == 0){ reviewsNetworkType = reviewNetworkType } else if (reviewsNetworkType != reviewNetworkType){ // Response contains two reviews with differing networkType // Response is malformed return false, [16]byte{}, [16]byte{}, nil, nil } reviewsList = append(reviewsList, reviewBytes) } return true, requestIdentifier, hostIdentityHash, reviewsList, nil } //Outputs: // -[]byte: Response bytes // -error func CreateServerResponse_GetIdentityReportsInfo(hostPublicIdentityKey [32]byte, hostPrivateIdentityKey [64]byte, connectionKey [32]byte, requestIdentifier [16]byte, reportsInfoMap map[[30]byte][]byte)([]byte, error){ //TODO: Verify inputs type responseContentStruct struct{ HostIdentityKey [32]byte RequestIdentifier [16]byte ResponseType string ReportsInfo map[[30]byte][]byte // Report hash -> Reported hash } responseContentObject := responseContentStruct{ HostIdentityKey: hostPublicIdentityKey, RequestIdentifier: requestIdentifier, ResponseType: "GetIdentityReportsInfo", ReportsInfo: reportsInfoMap, } innerResponseBytes, err := encoding.EncodeMessagePackBytes(responseContentObject) if (err != nil) { return nil, err } encryptedResponse, err := createEncryptedAndSignedResponse(connectionKey, hostPrivateIdentityKey, innerResponseBytes) if (err != nil) { return nil, err } return encryptedResponse, nil } //Outputs: // -bool: Able to read server response // -[16]byte: Request Identifier // -[16]byte: Host Identity Hash // -map[[30]byte][]byte: Reports Info map (Report Hash -> Reported hash) // -error (returns err if input keys are invalid) func ReadServerResponse_GetIdentityReportsInfo(responseBytes []byte, connectionKey [32]byte)(bool, [16]byte, [16]byte, map[[30]byte][]byte, error){ //TODO: Verify inputs ableToRead, requestIdentifier, hostIdentityHash, decryptedContentBytes, err := readEncryptedAndSignedResponse(responseBytes, connectionKey, "GetIdentityReportsInfo") if (err != nil) { return false, [16]byte{}, [16]byte{}, nil, err } if (ableToRead == false){ //Response is malformed return false, [16]byte{}, [16]byte{}, nil, nil } type responseContentStruct struct{ ReportsInfo map[[30]byte][]byte } var responseContentObject responseContentStruct err = encoding.DecodeMessagePackBytes(true, decryptedContentBytes, &responseContentObject) if (err != nil) { // Response malformed return false, [16]byte{}, [16]byte{}, nil, nil } reportsInfoMap := responseContentObject.ReportsInfo for reportHash, reportedHash := range reportsInfoMap{ reportedType, err := helpers.GetReportedTypeFromReportedHash(reportedHash) if (err != nil) { // Response is malformed return false, [16]byte{}, [16]byte{}, nil, nil } if (reportedType != "Identity" && reportedType != "Profile" && reportedType != "Attribute"){ // Response is malformed return false, [16]byte{}, [16]byte{}, nil, nil } isValid, err := readReports.VerifyReportHash(reportHash, true, reportedType) if (err != nil){ return false, [16]byte{}, [16]byte{}, nil, err } if (isValid == false){ //Response contains invalid reportHash // Response is malformed return false, [16]byte{}, [16]byte{}, nil, nil } } return true, requestIdentifier, hostIdentityHash, reportsInfoMap, nil } //Outputs: // -[]byte: Response bytes // -error func CreateServerResponse_GetMessageReportsInfo(hostPublicIdentityKey [32]byte, hostPrivateIdentityKey [64]byte, connectionKey [32]byte, requestIdentifier [16]byte, reportsInfoMap map[[30]byte][26]byte)([]byte, error){ //TODO: Verify inputs type responseContentStruct struct{ HostIdentityKey [32]byte RequestIdentifier [16]byte ResponseType string ReportsInfo map[[30]byte][26]byte // Report Hash -> Reported message hash } responseContentObject := responseContentStruct{ HostIdentityKey: hostPublicIdentityKey, RequestIdentifier: requestIdentifier, ResponseType: "GetMessageReportsInfo", ReportsInfo: reportsInfoMap, } innerResponseBytes, err := encoding.EncodeMessagePackBytes(responseContentObject) if (err != nil) { return nil, err } encryptedResponse, err := createEncryptedAndSignedResponse(connectionKey, hostPrivateIdentityKey, innerResponseBytes) if (err != nil) { return nil, err } return encryptedResponse, nil } //Outputs: // -bool: Able to read server response // -[16]byte: Request Identifier // -[16]byte: Host Identity Hash // -map[[30]byte][26]byte: Reports Info map (Report hash -> Reported message hash) // -error (returns err if input keys are invalid) func ReadServerResponse_GetMessageReportsInfo(responseBytes []byte, connectionKey [32]byte)(bool, [16]byte, [16]byte, map[[30]byte][26]byte, error){ //TODO: Verify inputs ableToRead, requestIdentifier, hostIdentityHash, decryptedContentBytes, err := readEncryptedAndSignedResponse(responseBytes, connectionKey, "GetMessageReportsInfo") if (err != nil) { return false, [16]byte{}, [16]byte{}, nil, err } if (ableToRead == false){ //Response is malformed return false, [16]byte{}, [16]byte{}, nil, nil } type responseContentStruct struct{ ReportsInfo map[[30]byte][26]byte } var responseContentObject responseContentStruct err = encoding.DecodeMessagePackBytes(true, decryptedContentBytes, &responseContentObject) if (err != nil) { // Response malformed return false, [16]byte{}, [16]byte{}, nil, nil } reportsInfoMap := responseContentObject.ReportsInfo for reportHash, _ := range reportsInfoMap{ isValid, err := readReports.VerifyReportHash(reportHash, true, "Message") if (err != nil) { return false, [16]byte{}, [16]byte{}, nil, err } if (isValid == false){ // Response contains invalid reportHash // Response is malformed return false, [16]byte{}, [16]byte{}, nil, nil } } return true, requestIdentifier, hostIdentityHash, reportsInfoMap, nil } //Outputs: // -[]byte: Response bytes // -error func CreateServerResponse_GetReports(hostPublicIdentityKey [32]byte, hostPrivateIdentityKey [64]byte, connectionKey [32]byte, requestIdentifier [16]byte, reportsList [][]byte)([]byte, error){ //TODO: Verify inputs messagepackReportsList := make([]messagepack.RawMessage, 0, len(reportsList)) for _, reportBytes := range reportsList{ messagepackReportsList = append(messagepackReportsList, reportBytes) } type responseContentStruct struct{ HostIdentityKey [32]byte RequestIdentifier [16]byte ResponseType string ReportsList []messagepack.RawMessage } responseContentObject := responseContentStruct{ HostIdentityKey: hostPublicIdentityKey, RequestIdentifier: requestIdentifier, ResponseType: "GetReports", ReportsList: messagepackReportsList, } innerResponseBytes, err := encoding.EncodeMessagePackBytes(responseContentObject) if (err != nil) { return nil, err } encryptedResponse, err := createEncryptedAndSignedResponse(connectionKey, hostPrivateIdentityKey, innerResponseBytes) if (err != nil) { return nil, err } return encryptedResponse, nil } //Outputs: // -bool: Able to read server response // -[16]byte: Request Identifier // -[16]byte: Host Identity Hash // -[][]byte: Reports list // -error (returns err if input keys are invalid) func ReadServerResponse_GetReports(responseBytes []byte, connectionKey [32]byte)(bool, [16]byte, [16]byte, [][]byte, error){ //TODO: Verify inputs ableToRead, requestIdentifier, hostIdentityHash, decryptedContentBytes, err := readEncryptedAndSignedResponse(responseBytes, connectionKey, "GetReports") if (err != nil) { return false, [16]byte{}, [16]byte{}, nil, err } if (ableToRead == false){ //Response is malformed return false, [16]byte{}, [16]byte{}, nil, nil } type responseContentStruct struct{ ReportsList []messagepack.RawMessage } var responseContentObject responseContentStruct err = encoding.DecodeMessagePackBytes(true, decryptedContentBytes, &responseContentObject) if (err != nil) { // Response is malformed return false, [16]byte{}, [16]byte{}, nil, nil } messagepackReportsList := responseContentObject.ReportsList // We use this map to detect duplicates reportHashesMap := make(map[[30]byte]struct{}) reportsList := make([][]byte, 0, len(messagepackReportsList)) // We use this variable to ensure all reports in response belong to the same network type reportsNetworkType := byte(0) for index, reportBytes := range messagepackReportsList{ ableToRead, reportHash, _, reportNetworkType, _, _, _, _, err := readReports.ReadReportAndHash(true, reportBytes) if (err != nil) { return false, [16]byte{}, [16]byte{}, nil, err } if (ableToRead == false){ // Response is malformed return false, [16]byte{}, [16]byte{}, nil, nil } _, exists := reportHashesMap[reportHash] if (exists == true){ // A duplicate report exists // Response is malformed return false, [16]byte{}, [16]byte{}, nil, nil } reportHashesMap[reportHash] = struct{}{} if (index == 0){ reportsNetworkType = reportNetworkType } else if (reportsNetworkType != reportNetworkType){ // All reports in response must belong to the same network type // Response is malformed return false, [16]byte{}, [16]byte{}, nil, nil } reportsList = append(reportsList, reportBytes) } return true, requestIdentifier, hostIdentityHash, reportsList, nil } // This object type is used to represent a deposit to an address type DepositStruct struct{ // The cryptocurrency address where funds were deposited Address string // The unix time of the block when deposit(s) were made DepositTime int64 // The sum of all deposit amounts in the block to the specified address, in crypto atomic units (example: wei) //TODO: Change this to big.Int DepositAmount int64 } //Outputs: // -[]byte: Response bytes // -error func CreateServerResponse_GetAddressDeposits(hostPublicIdentityKey [32]byte, hostPrivateIdentityKey [64]byte, connectionKey [32]byte, requestIdentifier [16]byte, depositObjectsList []DepositStruct)([]byte, error){ //TODO: Verify inputs type responseContentStruct struct{ HostIdentityKey [32]byte RequestIdentifier [16]byte ResponseType string AddressDepositsList []DepositStruct } responseContentObject := responseContentStruct{ HostIdentityKey: hostPublicIdentityKey, RequestIdentifier: requestIdentifier, ResponseType: "GetAddressDeposits", AddressDepositsList: depositObjectsList, } innerResponseBytes, err := encoding.EncodeMessagePackBytes(responseContentObject) if (err != nil) { return nil, err } encryptedResponse, err := createEncryptedAndSignedResponse(connectionKey, hostPrivateIdentityKey, innerResponseBytes) if (err != nil) { return nil, err } return encryptedResponse, nil } //Outputs: // -bool: Able to read server response // -[16]byte: Request Identifier // -[16]byte: Host Identity Hash // -[]DepositStruct: Deposit objects list // -error (returns err if input keys are invalid) func ReadServerResponse_GetAddressDeposits(responseBytes []byte, connectionKey [32]byte)(bool, [16]byte, [16]byte, []DepositStruct, error){ //TODO: Verify inputs ableToRead, requestIdentifier, hostIdentityHash, decryptedContentBytes, err := readEncryptedAndSignedResponse(responseBytes, connectionKey, "GetAddressDeposits") if (err != nil) { return false, [16]byte{}, [16]byte{}, nil, err } if (ableToRead == false){ //Response is malformed return false, [16]byte{}, [16]byte{}, nil, nil } type responseContentStruct struct{ AddressDepositsList []DepositStruct } var responseContentObject responseContentStruct err = encoding.DecodeMessagePackBytes(true, decryptedContentBytes, &responseContentObject) if (err != nil) { // Response malformed return false, [16]byte{}, [16]byte{}, nil, nil } addressDepositsList := responseContentObject.AddressDepositsList //TODO: validate info return true, requestIdentifier, hostIdentityHash, addressDepositsList, nil } //Outputs: // -[]byte: Response bytes // -error func CreateServerResponse_GetViewableStatuses(hostPublicIdentityKey [32]byte, hostPrivateIdentityKey [64]byte, connectionKey [32]byte, requestIdentifier [16]byte, identityHashStatusesMap map[[16]byte]bool, profileHashStatusesMap map[[28]byte]bool)([]byte, error){ //TODO: Verify inputs type responseContentStruct struct{ HostIdentityKey [32]byte RequestIdentifier [16]byte ResponseType string IdentityHashStatuses map[[16]byte]bool ProfileHashStatuses map[[28]byte]bool } responseContentObject := responseContentStruct{ HostIdentityKey: hostPublicIdentityKey, RequestIdentifier: requestIdentifier, ResponseType: "GetViewableStatuses", IdentityHashStatuses: identityHashStatusesMap, ProfileHashStatuses: profileHashStatusesMap, } innerResponseBytes, err := encoding.EncodeMessagePackBytes(responseContentObject) if (err != nil) { return nil, err } encryptedResponse, err := createEncryptedAndSignedResponse(connectionKey, hostPrivateIdentityKey, innerResponseBytes) if (err != nil) { return nil, err } return encryptedResponse, nil } //Outputs: // -bool: Able to read server response // -[16]byte: Request Identifier // -[16]byte: Host Identity Hash // -map[[16]byte]bool: Identity Hash Statuses Map (Identity Hash -> true/false)( true = viewable, false = unviewable) // -map[[28]byte]bool: Profile hash statuses map (Profile Hash -> true/false)( true = viewable, false = unviewable) // -error (returns err if input keys are invalid) func ReadServerResponse_GetViewableStatuses(responseBytes []byte, connectionKey [32]byte)(bool, [16]byte, [16]byte, map[[16]byte]bool, map[[28]byte]bool, error){ ableToRead, requestIdentifier, hostIdentityHash, decryptedContentBytes, err := readEncryptedAndSignedResponse(responseBytes, connectionKey, "GetViewableStatuses") if (err != nil) { return false, [16]byte{}, [16]byte{}, nil, nil, err } if (ableToRead == false){ //Response is malformed return false, [16]byte{}, [16]byte{}, nil, nil, nil } type responseContentStruct struct{ IdentityHashStatuses map[[16]byte]bool ProfileHashStatuses map[[28]byte]bool } var responseContentObject responseContentStruct err = encoding.DecodeMessagePackBytes(true, decryptedContentBytes, &responseContentObject) if (err != nil) { // Response malformed return false, [16]byte{}, [16]byte{}, nil, nil, nil } identityHashStatusesMap := responseContentObject.IdentityHashStatuses profileHashStatusesMap := responseContentObject.ProfileHashStatuses //TODO: Verify maps return true, requestIdentifier, hostIdentityHash, identityHashStatusesMap, profileHashStatusesMap, nil } //Outputs: // -[]byte: Response bytes // -error func CreateServerResponse_BroadcastContent(hostPublicIdentityKey [32]byte, hostPrivateIdentityKey [64]byte, connectionKey [32]byte, requestIdentifier [16]byte, contentAcceptedInfoMap map[string]bool)([]byte, error){ //TODO: Verify inputs type responseContentStruct struct{ HostIdentityKey [32]byte RequestIdentifier [16]byte ResponseType string ContentAcceptedInfo map[string]bool //Content Hash -> true/false } responseContentObject := responseContentStruct{ HostIdentityKey: hostPublicIdentityKey, RequestIdentifier: requestIdentifier, ResponseType: "BroadcastContent", ContentAcceptedInfo: contentAcceptedInfoMap, } innerResponseBytes, err := encoding.EncodeMessagePackBytes(responseContentObject) if (err != nil) { return nil, err } encryptedResponse, err := createEncryptedAndSignedResponse(connectionKey, hostPrivateIdentityKey, innerResponseBytes) if (err != nil) { return nil, err } return encryptedResponse, nil } //Outputs: // -bool: Able to read server response // -[16]byte: Request Identifier // -[16]byte: Host Identity Hash // -map[string]bool: Content Accepted Info Map (Content Hash -> true/false) // -error (returns err if input keys are invalid) func ReadServerResponse_BroadcastContent(responseBytes []byte, connectionKey [32]byte)(bool, [16]byte, [16]byte, map[string]bool, error){ //TODO: Verify stuff ableToRead, requestIdentifier, hostIdentityHash, decryptedContentBytes, err := readEncryptedAndSignedResponse(responseBytes, connectionKey, "BroadcastContent") if (err != nil) { return false, [16]byte{}, [16]byte{}, nil, err } if (ableToRead == false){ //Response is malformed return false, [16]byte{}, [16]byte{}, nil, nil } type responseContentStruct struct{ ContentAcceptedInfo map[string]bool } var responseContentObject responseContentStruct err = encoding.DecodeMessagePackBytes(true, decryptedContentBytes, &responseContentObject) if (err != nil) { // Response is malformed return false, [16]byte{}, [16]byte{}, nil, nil } contentAcceptedInfoMap := responseContentObject.ContentAcceptedInfo for contentHash, _ := range contentAcceptedInfoMap{ _, err := helpers.GetContentTypeFromContentHash([]byte(contentHash)) if (err != nil){ // Invalid content hash return false, [16]byte{}, [16]byte{}, nil, nil } } return true, requestIdentifier, hostIdentityHash, contentAcceptedInfoMap, nil } func createEncryptedAndSignedResponse(connectionKey [32]byte, hostPrivateIdentityKey [64]byte, innerResponseBytes []byte)([]byte, error){ responseSignedBytes, err := createResponseSignedContent(hostPrivateIdentityKey, innerResponseBytes) if (err != nil) { return nil, err } encryptedResponse, err := createEncryptedResponse(responseSignedBytes, connectionKey) if (err != nil) { return nil, err } return encryptedResponse, nil } //Outputs: // -bool: Able to read (response is valid) // -[16]byte: Request identifier // -[16]byte: Host identity hash // -[]byte: Content Bytes // -error (return err if there is a bug in the function) func readEncryptedAndSignedResponse(inputResponse []byte, connectionKey [32]byte, expectedResponseType string)(bool, [16]byte, [16]byte, []byte, error){ ableToDecrypt, decryptedResponseBytes, err := readEncryptedResponse(inputResponse, connectionKey) if (err != nil) { return false, [16]byte{}, [16]byte{}, nil, err } if (ableToDecrypt == false){ return false, [16]byte{}, [16]byte{}, nil, nil } ableToRead, requestIdentifier, hostIdentityHash, contentBytes, err := readResponseSignedContent(decryptedResponseBytes, expectedResponseType) if (err != nil) { return false, [16]byte{}, [16]byte{}, nil, err } if (ableToRead == false){ //Response is malformed return false, [16]byte{}, [16]byte{}, nil, nil } return true, requestIdentifier, hostIdentityHash, contentBytes, nil } func createEncryptedResponse(contentToEncrypt []byte, connectionKey [32]byte)([]byte, error){ chaPolyNonce, err := helpers.GetNewRandom24ByteArray() if (err != nil) { return nil, err } cipheredContent, err := chaPolyShrink.EncryptChaPolyShrink(contentToEncrypt, connectionKey, chaPolyNonce, true, 100, false, [32]byte{}) if (err != nil) { return nil, err } type encryptedResponseStruct struct{ ChaPolyNonce [24]byte CipheredContent []byte } encryptedResponseObject := encryptedResponseStruct{ ChaPolyNonce: chaPolyNonce, CipheredContent: cipheredContent, } encryptedResponseBytes, err := encoding.EncodeMessagePackBytes(encryptedResponseObject) if (err != nil) { return nil, err } return encryptedResponseBytes, nil } //Outputs: // -bool: Response well formed and able to decrypt // -[]byte: Decrypted response // -error (decryption key inputs are malformed) func readEncryptedResponse(inputResponse []byte, connectionKey [32]byte)(bool, []byte, error){ type encryptedResponseStruct struct{ ChaPolyNonce [24]byte CipheredContent []byte } var encryptedResponseObject encryptedResponseStruct err := encoding.DecodeMessagePackBytes(true, inputResponse, &encryptedResponseObject) if (err != nil) { return false, nil, nil } chaPolyNonce := encryptedResponseObject.ChaPolyNonce cipheredContent := encryptedResponseObject.CipheredContent ableToDecrypt, decryptedBytes, err := chaPolyShrink.DecryptChaPolyShrink(cipheredContent, connectionKey, chaPolyNonce, false, [32]byte{}) if (err != nil) { return false, nil, nil } if (ableToDecrypt == false){ return false, nil, nil } return true, decryptedBytes, nil } func createResponseSignedContent(hostIdentityPrivateKey [64]byte, responseContent messagepack.RawMessage)([]byte, error){ contentHash, err := blake3.Get32ByteBlake3Hash(responseContent) if (err != nil) { return nil, err } responseSignature := edwardsKeys.CreateSignature(hostIdentityPrivateKey, contentHash) type finalResponseStruct struct { Signature [64]byte Content messagepack.RawMessage } finalResponseObject := finalResponseStruct{ Signature: responseSignature, Content: responseContent, } finalResponseBytes, err := encoding.EncodeMessagePackBytes(finalResponseObject) if (err != nil) { return nil, err } return finalResponseBytes, nil } //Outputs: // -bool: Able to read (response is valid) // -[16]byte: Request identifier // -[16]byte: Host identity hash // -[]byte: Content bytes // -error (return err if there is a bug in the function) func readResponseSignedContent(inputBytes []byte, expectedResponseType string)(bool, [16]byte, [16]byte, []byte, error){ type outerResponseStruct struct{ Signature [64]byte Content messagepack.RawMessage } var outerResponseObject outerResponseStruct err := encoding.DecodeMessagePackBytes(true, inputBytes, &outerResponseObject) if (err != nil) { return false, [16]byte{}, [16]byte{}, nil, nil } responseSignature := outerResponseObject.Signature responseContentBytes := outerResponseObject.Content if (len(responseContentBytes) == 0){ return false, [16]byte{}, [16]byte{}, nil, nil } responseContentHashed, err := blake3.Get32ByteBlake3Hash(responseContentBytes) if (err != nil) { return false, [16]byte{}, [16]byte{}, nil, err } type partialResponseStruct struct { HostIdentityKey [32]byte RequestIdentifier [16]byte ResponseType string } var partialResponseObject partialResponseStruct err = encoding.DecodeMessagePackBytes(true, responseContentBytes, &partialResponseObject) if (err != nil) { return false, [16]byte{}, [16]byte{}, nil, nil } requestIdentifier := partialResponseObject.RequestIdentifier hostIdentityKey := partialResponseObject.HostIdentityKey responseType := partialResponseObject.ResponseType isValid := edwardsKeys.VerifySignature(hostIdentityKey, responseSignature, responseContentHashed) if (isValid == false){ return false, [16]byte{}, [16]byte{}, nil, nil } hostIdentityHash, err := identity.ConvertIdentityKeyToIdentityHash(hostIdentityKey, "Host") if (err != nil) { return false, [16]byte{}, [16]byte{}, nil, err } if (responseType != expectedResponseType){ return false, [16]byte{}, [16]byte{}, nil, nil } return true, requestIdentifier, hostIdentityHash, responseContentBytes, nil }