seekia/internal/messaging/myChatKeys/myChatKeys.go

586 lines
23 KiB
Go
Raw Normal View History

// myChatKeys provides functions to manage a user's chat keys
// New keys are created after a set duration has passed
// Old keys are deleted after the user has downloaded all of the messages during the period when they were used
package myChatKeys
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/logger"
import "seekia/internal/messaging/readMessages"
import "seekia/internal/myDatastores/myMap"
import "seekia/internal/myDatastores/myMapList"
import "seekia/internal/myIdentity"
import "sync"
import "time"
import "strings"
import "errors"
//TODO: Add pruning function to get rid of old keys
// This mutex will be locked whenever we update the chat keys maplist
var updatingMyChatKeysMutex sync.Mutex
// This mutex will be locked whenever we update the chatKeysLatestUpdateTime map object
var updatingMyChatKeysLatestUpdateTimeMutex sync.Mutex
var myChatKeysMapListDatastore *myMapList.MyMapList
// Map Structure: Identity Hash + "@" + Network Type -> Latest update unix time
var myChatKeysLatestUpdateTimeMapDatastore *myMap.MyMap
// Map Structure: Identity Hash + "@" + Network Type -> Nacl Key + "+" + Kyber Key
var myNewestBroadcastPublicChatKeysMapDatastore *myMap.MyMap
// This function must be called whenever an app user signs in
func InitializeMyChatKeysDatastores()error{
updatingMyChatKeysMutex.Lock()
defer updatingMyChatKeysMutex.Unlock()
updatingMyChatKeysLatestUpdateTimeMutex.Lock()
defer updatingMyChatKeysLatestUpdateTimeMutex.Unlock()
newMyChatKeysLatestUpdateTimeMapDatastore, err := myMap.CreateNewMap("MyChatKeysLatestUpdateTime")
if (err != nil) { return err }
newMyChatKeysMapListDatastore, err := myMapList.CreateNewMapList("MyChatKeys")
if (err != nil) { return err }
newMyNewestBroadcastPublicChatKeysMapDatastore, err := myMap.CreateNewMap("MyNewestBroadcastPublicChatKeys")
if (err != nil) { return err }
myChatKeysLatestUpdateTimeMapDatastore = newMyChatKeysLatestUpdateTimeMapDatastore
myChatKeysMapListDatastore = newMyChatKeysMapListDatastore
myNewestBroadcastPublicChatKeysMapDatastore = newMyNewestBroadcastPublicChatKeysMapDatastore
return nil
}
// This function provides the decryption keys for a particular identity hash
//Outputs:
// -bool: My identity found
// -bool: Any chat keys found (will be false if user has never broadcasted their profile)
// -[]ChatKeySet: Chat keys list
// -error
func GetMyChatDecryptionKeySetsList(myIdentityHash [16]byte, networkType byte)(bool, bool, []readMessages.ChatKeySet, error){
isMine, myIdentityType, err := myIdentity.CheckIfIdentityHashIsMine(myIdentityHash)
if (err != nil) { return false, false, nil, err }
if (isMine == false) {
return false, false, nil, nil
}
if (myIdentityType != "Mate" && myIdentityType != "Moderator"){
return false, false, nil, errors.New("GetMyChatDecryptionKeysMapList called with Host identity.")
}
isValid := helpers.VerifyNetworkType(networkType)
if (isValid == false){
networkTypeString := helpers.ConvertByteToString(networkType)
return false, false, nil, errors.New("GetMyChatDecryptionKeySetsList called with invalid networkType: " + networkTypeString)
}
myIdentityHashString, _, err := identity.EncodeIdentityHashBytesToString(myIdentityHash)
if (err != nil) {
myIdentityHashHex := encoding.EncodeBytesToHexString(myIdentityHash[:])
return false, false, nil, errors.New("CheckIfIdentityHashIsMine not verifying identity hash: " + myIdentityHashHex)
}
networkTypeString := helpers.ConvertByteToString(networkType)
lookupMap := map[string]string{
"MyIdentityHash": myIdentityHashString,
"NetworkType": networkTypeString,
}
anyExist, myChatKeysMapList, err := myChatKeysMapListDatastore.GetMapListItems(lookupMap)
if (err != nil){ return false, false, nil, err }
if (anyExist == false){
return true, false, nil, nil
}
chatDecryptionKeySetsList := make([]readMessages.ChatKeySet, 0, len(myChatKeysMapList))
for _, keySetMap := range myChatKeysMapList{
myNaclPublicKey, exists := keySetMap["NaclPublicKey"]
if (exists == false){
return false, false, nil, errors.New("Malformed myChatKeys map list: Item missing NaclPublicKey")
}
myNaclPrivateKey, exists := keySetMap["NaclPrivateKey"]
if (exists == false){
return false, false, nil, errors.New("Malformed myChatKeys map list: Item missing NaclPrivateKey")
}
myKyberPrivateKey, exists := keySetMap["KyberPrivateKey"]
if (exists == false){
return false, false, nil, errors.New("Malformed myChatKeys map list: Item missing KyberPrivateKey")
}
myNaclPublicKeyBytes, err := encoding.DecodeBase64StringToBytes(myNaclPublicKey)
if (err != nil){
return false, false, nil, errors.New("Malformed myChatKeys map list: NaclPublicKey is not Base64.")
}
if (len(myNaclPublicKeyBytes) != 32){
return false, false, nil, errors.New("Malformed myChatKeys map list: NaclPublicKey is invalid length.")
}
myNaclPublicKeyArray := [32]byte(myNaclPublicKeyBytes)
myNaclPrivateKeyBytes, err := encoding.DecodeHexStringToBytes(myNaclPrivateKey)
if (err != nil){
return false, false, nil, errors.New("Malformed myChatKeys map list: NaclPrivateKey is not Hex.")
}
if (len(myNaclPrivateKeyBytes) != 32){
return false, false, nil, errors.New("Malformed myChatKeys map list: NaclPrivateKey is invalid length.")
}
myNaclPrivateKeyArray := [32]byte(myNaclPrivateKeyBytes)
myKyberPrivateKeyBytes, err := encoding.DecodeHexStringToBytes(myKyberPrivateKey)
if (err != nil){
return false, false, nil, errors.New("Malformed myChatKeys map list: KyberPrivateKey is not Hex.")
}
if (len(myKyberPrivateKeyBytes) != 1536){
return false, false, nil, errors.New("Malformed myChatKeys map list: KyberPrivateKey is invalid length.")
}
myKyberPrivateKeyArray := [1536]byte(myKyberPrivateKeyBytes)
newChatKeySetObject := readMessages.ChatKeySet{
NaclPublicKey: myNaclPublicKeyArray,
NaclPrivateKey: myNaclPrivateKeyArray,
KyberPrivateKey: myKyberPrivateKeyArray,
}
chatDecryptionKeySetsList = append(chatDecryptionKeySetsList, newChatKeySetObject)
}
return true, true, chatDecryptionKeySetsList, nil
}
// This function generates new chat keys for an identity.
func GenerateNewChatKeys(myIdentityHash [16]byte, networkType byte)error{
myIdentityHashString, _, err := identity.EncodeIdentityHashBytesToString(myIdentityHash)
if (err != nil) {
myIdentityHashHex := encoding.EncodeBytesToHexString(myIdentityHash[:])
return errors.New("GenerateNewChatKeys called with invalid identity hash: " + myIdentityHashHex)
}
isValid := helpers.VerifyNetworkType(networkType)
if (isValid == false){
networkTypeString := helpers.ConvertByteToString(networkType)
return errors.New("GenerateNewChatKeys called with invalid networkType: " + networkTypeString)
}
updatingMyChatKeysMutex.Lock()
defer updatingMyChatKeysMutex.Unlock()
currentTime := time.Now().Unix()
currentTimeString := helpers.ConvertInt64ToString(currentTime)
networkTypeString := helpers.ConvertByteToString(networkType)
newNaclPublicKey, newNaclPrivateKey, err := nacl.GetNewRandomPublicPrivateNaclKeys()
if (err != nil) { return err }
newKyberPublicKey, newKyberPrivateKey, err := kyber.GetNewRandomPublicPrivateKyberKeys()
if (err != nil) { return err }
newNaclPublicKeyString := encoding.EncodeBytesToBase64String(newNaclPublicKey[:])
newNaclPrivateKeyString := encoding.EncodeBytesToHexString(newNaclPrivateKey[:])
newKyberPublicKeyString := encoding.EncodeBytesToBase64String(newKyberPublicKey[:])
newKyberPrivateKeyString := encoding.EncodeBytesToHexString(newKyberPrivateKey[:])
newMapListItem := map[string]string{
"MyIdentityHash": myIdentityHashString,
"CreatedTime": currentTimeString,
"NetworkType": networkTypeString,
"NaclPublicKey": newNaclPublicKeyString,
"NaclPrivateKey": newNaclPrivateKeyString,
"KyberPublicKey": newKyberPublicKeyString,
"KyberPrivateKey": newKyberPrivateKeyString,
}
err = myChatKeysMapListDatastore.AddMapListItem(newMapListItem)
if (err != nil) { return err }
return nil
}
// This function will get a user's newest public chat keys
// It will create new chat keys for the provided identity if none exist
//Outputs:
// -bool: My identity exists
// -[32]byte: My Nacl Public key
// -[1568]byte: My Kyber Public key
// -error
func GetMyNewestPublicChatKeys(myIdentityHash [16]byte, networkType byte)(bool, [32]byte, [1568]byte, error){
isMine, myIdentityType, err := myIdentity.CheckIfIdentityHashIsMine(myIdentityHash)
if (err != nil) { return false, [32]byte{}, [1568]byte{}, err }
if (isMine == false){
return false, [32]byte{}, [1568]byte{}, nil
}
if (myIdentityType != "Mate" && myIdentityType != "Moderator"){
return false, [32]byte{}, [1568]byte{}, errors.New("GetMyNewestPublicChatKeys called with host identity.")
}
isValid := helpers.VerifyNetworkType(networkType)
if (isValid == false){
networkTypeString := helpers.ConvertByteToString(networkType)
return false, [32]byte{}, [1568]byte{}, errors.New("GetMyNewestPublicChatKeys called with invalid networkType: " + networkTypeString)
}
myIdentityHashString, _, err := identity.EncodeIdentityHashBytesToString(myIdentityHash)
if (err != nil){
myIdentityHashHex := encoding.EncodeBytesToHexString(myIdentityHash[:])
return false, [32]byte{}, [1568]byte{}, errors.New("CheckIfIdentityHashIsMine not verifying identity hash: " + myIdentityHashHex)
}
updatingMyChatKeysMutex.Lock()
defer updatingMyChatKeysMutex.Unlock()
networkTypeString := helpers.ConvertByteToString(networkType)
lookupMap := map[string]string{
"MyIdentityHash": myIdentityHashString,
"NetworkType": networkTypeString,
}
anyItemsFound, myChatKeysMapList, err := myChatKeysMapListDatastore.GetMapListItems(lookupMap)
if (err != nil){ return false, [32]byte{}, [1568]byte{}, err }
if (anyItemsFound == true){
if (len(myChatKeysMapList) == 0){
return false, [32]byte{}, [1568]byte{}, errors.New("GetMapListItems returning empty items list after claiming items were found.")
}
newestChatKeysCreatedTime := int64(0)
var newestNaclPublicKey [32]byte
var newestKyberPublicKey [1568]byte
for index, chatKeysSetMap := range myChatKeysMapList{
itemMyIdentityHash, exists := chatKeysSetMap["MyIdentityHash"]
if (exists == false) {
return false, [32]byte{}, [1568]byte{}, errors.New("myMapList lookup not working properly.")
}
if (itemMyIdentityHash != myIdentityHashString){
return false, [32]byte{}, [1568]byte{}, errors.New("myMapList lookup not working properly.")
}
timeKeysCreated, exists := chatKeysSetMap["CreatedTime"]
if (exists == false) {
return false, [32]byte{}, [1568]byte{}, errors.New("Malformed myChatKeys map list: Item missing CreatedTime")
}
naclPublicKey, exists := chatKeysSetMap["NaclPublicKey"]
if (exists == false) {
return false, [32]byte{}, [1568]byte{}, errors.New("Malformed myChatKeys map list: Item missing NaclPublicKey")
}
kyberPublicKey, exists := chatKeysSetMap["KyberPublicKey"]
if (exists == false) {
return false, [32]byte{}, [1568]byte{}, errors.New("Malformed myChatKeys map list: Item missing KyberPublicKey")
}
naclPublicKeyBytes, err := encoding.DecodeBase64StringToBytes(naclPublicKey)
if (err != nil){
return false, [32]byte{}, [1568]byte{}, errors.New("Malformed myChatKeys map list: Item contains invalid NaclPublicKey: Not hex.")
}
if (len(naclPublicKeyBytes) != 32){
return false, [32]byte{}, [1568]byte{}, errors.New("Malformed myChatKeys map list: Item contains invalid NaclPublicKey: Invalid length.")
}
naclPublicKeyArray := [32]byte(naclPublicKeyBytes)
kyberPublicKeyBytes, err := encoding.DecodeBase64StringToBytes(kyberPublicKey)
if (err != nil){
return false, [32]byte{}, [1568]byte{}, errors.New("Malformed myChatKeys map list: Item contains invalid KyberPublicKey: Not hex.")
}
if (len(kyberPublicKeyBytes) != 1568){
return false, [32]byte{}, [1568]byte{}, errors.New("Malformed myChatKeys map list: Item contains invalid KyberPublicKey: Invalid length.")
}
kyberPublicKeyArray := [1568]byte(kyberPublicKeyBytes)
timeKeysCreatedInt64, err := helpers.ConvertStringToInt64(timeKeysCreated)
if (err != nil) {
return false, [32]byte{}, [1568]byte{}, errors.New("Malformed myChatKeys map list: Item contains invalid CreatedTime: " + timeKeysCreated)
}
if (index == 0 || newestChatKeysCreatedTime < timeKeysCreatedInt64){
newestChatKeysCreatedTime = timeKeysCreatedInt64
newestNaclPublicKey = naclPublicKeyArray
newestKyberPublicKey = kyberPublicKeyArray
}
}
return true, newestNaclPublicKey, newestKyberPublicKey, nil
}
// We must create new chat keys
currentTime := time.Now().Unix()
currentTimeString := helpers.ConvertInt64ToString(currentTime)
newNaclPublicKey, newNaclPrivateKey, err := nacl.GetNewRandomPublicPrivateNaclKeys()
if (err != nil) { return false, [32]byte{}, [1568]byte{}, err }
newKyberPublicKey, newKyberPrivateKey, err := kyber.GetNewRandomPublicPrivateKyberKeys()
if (err != nil) { return false, [32]byte{}, [1568]byte{}, err }
newNaclPublicKeyString := encoding.EncodeBytesToBase64String(newNaclPublicKey[:])
newNaclPrivateKeyString := encoding.EncodeBytesToHexString(newNaclPrivateKey[:])
newKyberPublicKeyString := encoding.EncodeBytesToBase64String(newKyberPublicKey[:])
newKyberPrivateKeyString := encoding.EncodeBytesToHexString(newKyberPrivateKey[:])
newChatKeysSetMap := map[string]string{
"MyIdentityHash": myIdentityHashString,
"NetworkType": networkTypeString,
"CreatedTime": currentTimeString,
"NaclPublicKey": newNaclPublicKeyString,
"NaclPrivateKey": newNaclPrivateKeyString,
"KyberPublicKey": newKyberPublicKeyString,
"KyberPrivateKey": newKyberPrivateKeyString,
}
err = myChatKeysMapListDatastore.AddMapListItem(newChatKeysSetMap)
if (err != nil) { return false, [32]byte{}, [1568]byte{}, err }
return true, newNaclPublicKey, newKyberPublicKey, nil
}
// This function is only called when a new profile is added to myBroadcasts
func SetMyChatKeysLatestUpdateTime(myIdentityHash [16]byte, networkType byte, newLatestUpdateTime int64)error{
isMine, myIdentityType, err := myIdentity.CheckIfIdentityHashIsMine(myIdentityHash)
if (err != nil) { return err }
if (isMine == false){
return errors.New("SetMyChatKeysLatestUpdateTime called with identity that is not mine.")
}
if (myIdentityType != "Mate" && myIdentityType != "Moderator"){
return errors.New("SetMyChatKeysLatestUpdateTime called with Host identity.")
}
isValid := helpers.VerifyNetworkType(networkType)
if (isValid == false){
networkTypeString := helpers.ConvertByteToString(networkType)
return errors.New("SetMyChatKeysLatestUpdateTime called with invalid networkType: " + networkTypeString)
}
updatingMyChatKeysLatestUpdateTimeMutex.Lock()
defer updatingMyChatKeysLatestUpdateTimeMutex.Unlock()
exists, existingLatestUpdateTime, err := GetMyChatKeysLatestUpdateTime(myIdentityHash, networkType)
if (err != nil) { return err }
if (exists == true){
if (existingLatestUpdateTime > newLatestUpdateTime) {
// This would only happen if our system clock was invalid, and became valid
// We will log this, but allow our latestUpdateTime to be updated
err := logger.AddLogEntry("General", "Existing latest chat keys update time is later than new update time.")
if (err != nil) { return err }
} else if (existingLatestUpdateTime == newLatestUpdateTime){
// No update is needed.
return nil
}
}
myIdentityHashString, _, err := identity.EncodeIdentityHashBytesToString(myIdentityHash)
if (err != nil){
myIdentityHashHex := encoding.EncodeBytesToHexString(myIdentityHash[:])
return errors.New("CheckIfIdentityHashIsMine not verifying identity hash: " + myIdentityHashHex)
}
networkTypeString := helpers.ConvertByteToString(networkType)
mapEntryKey := myIdentityHashString + "@" + networkTypeString
newLatestUpdateTimeString := helpers.ConvertInt64ToString(newLatestUpdateTime)
err = myChatKeysLatestUpdateTimeMapDatastore.SetMapEntry(mapEntryKey, newLatestUpdateTimeString)
if (err != nil) { return err }
return nil
}
//Outputs:
// -bool: Update time exists (wont exist if profile has never been broadcast, or existing profile is not imported yet)
// -int64: Current latest update time
// -error
func GetMyChatKeysLatestUpdateTime(myIdentityHash [16]byte, networkType byte)(bool, int64, error){
isMine, myIdentityType, err := myIdentity.CheckIfIdentityHashIsMine(myIdentityHash)
if (err != nil) { return false, 0, err }
if (isMine == false){
return false, 0, errors.New("GetMyChatKeysLatestUpdateTime called with identity that is not mine.")
}
if (myIdentityType != "Mate" && myIdentityType != "Moderator"){
return false, 0, errors.New("GetMyChatKeysLatestUpdateTime called with Host identity.")
}
isValid := helpers.VerifyNetworkType(networkType)
if (isValid == false){
networkTypeString := helpers.ConvertByteToString(networkType)
return false, 0, errors.New("GetMyChatKeysLatestUpdateTime called with invalid networkType: " + networkTypeString)
}
myIdentityHashString, _, err := identity.EncodeIdentityHashBytesToString(myIdentityHash)
if (err != nil){
myIdentityHashHex := encoding.EncodeBytesToHexString(myIdentityHash[:])
return false, 0, errors.New("CheckIfIdentityHashIsMine not verifying my identity hash: " + myIdentityHashHex)
}
networkTypeString := helpers.ConvertByteToString(networkType)
mapEntryKey := myIdentityHashString + "@" + networkTypeString
exists, latestUpdateTimeString, err := myChatKeysLatestUpdateTimeMapDatastore.GetMapEntry(mapEntryKey)
if (err != nil) { return false, 0, err }
if (exists == false) {
return false, 0, nil
}
latestUpdateTimeInt64, err := helpers.ConvertStringToInt64(latestUpdateTimeString)
if (err != nil) {
return false, 0, errors.New("myChatKeysLatestUpdateTimeMapDatastore is corrupt: Contains invalid latestUpdateTime: " + latestUpdateTimeString)
}
return true, latestUpdateTimeInt64, nil
}
// This function is used to keep track of the user's newest broadcasted chat keys
// We need to do this because we need to be able to tell if the profile we are broadcasting contains new keys
// This is stored seperately from myBroadcasts
// This datastore can prevent users from having to update their latestChatKeysUpdateTime when moving to a new device, if they import their keys
func SetMyNewestBroadcastPublicChatKeys(myIdentityHash [16]byte, networkType byte, naclKey [32]byte, kyberKey [1568]byte)error{
isMine, myIdentityType, err := myIdentity.CheckIfIdentityHashIsMine(myIdentityHash)
if (err != nil) { return err }
if (isMine == false){
return errors.New("SetMyNewestBroadcastPublicChatKeys called with identity that is not mine.")
}
if (myIdentityType != "Mate" && myIdentityType != "Moderator"){
return errors.New("SetMyNewestBroadcastPublicChatKeys called with Host identity.")
}
isValid := helpers.VerifyNetworkType(networkType)
if (isValid == false){
networkTypeString := helpers.ConvertByteToString(networkType)
return errors.New("SetMyNewestBroadcastPublicChatKeys called with invalid networkType: " + networkTypeString)
}
myIdentityHashString, _, err := identity.EncodeIdentityHashBytesToString(myIdentityHash)
if (err != nil){
myIdentityHashHex := encoding.EncodeBytesToHexString(myIdentityHash[:])
return errors.New("CheckIfIdentityHashIsMine not verifying my identity hash: " + myIdentityHashHex)
}
networkTypeString := helpers.ConvertByteToString(networkType)
mapEntryKey := myIdentityHashString + "@" + networkTypeString
naclKeyEncoded := encoding.EncodeBytesToBase64String(naclKey[:])
kyberKeyEncoded := encoding.EncodeBytesToBase64String(kyberKey[:])
newEntryValue := naclKeyEncoded + "+" + kyberKeyEncoded
err = myNewestBroadcastPublicChatKeysMapDatastore.SetMapEntry(mapEntryKey, newEntryValue)
if (err != nil) { return err }
return nil
}
//Outputs:
// -bool: My identity found
// -bool: Any keys found
// -[32]byte: Newest broadcast Nacl key (Encoded base64)
// -[1568]byte: Newest broadcast Kyber key (Encoded base64)
// -error
func GetMyNewestBroadcastPublicChatKeys(myIdentityHash [16]byte, networkType byte)(bool, bool, [32]byte, [1568]byte, error){
isMine, myIdentityType, err := myIdentity.CheckIfIdentityHashIsMine(myIdentityHash)
if (err != nil) { return false, false, [32]byte{}, [1568]byte{}, err }
if (isMine == false){
return false, false, [32]byte{}, [1568]byte{}, nil
}
if (myIdentityType != "Mate" && myIdentityType != "Moderator"){
return false, false, [32]byte{}, [1568]byte{}, errors.New("GetMyNewestBroadcastPublicChatKeys called with Host identity.")
}
isValid := helpers.VerifyNetworkType(networkType)
if (isValid == false){
networkTypeString := helpers.ConvertByteToString(networkType)
return false, false, [32]byte{}, [1568]byte{}, errors.New("GetMyNewestBroadcastPublicChatKeys called with invalid networkType: " + networkTypeString)
}
myIdentityHashString, _, err := identity.EncodeIdentityHashBytesToString(myIdentityHash)
if (err != nil){
myIdentityHashHex := encoding.EncodeBytesToHexString(myIdentityHash[:])
return false, false, [32]byte{}, [1568]byte{}, errors.New("CheckIfIdentityHashIsMine not verifying my identity hash: " + myIdentityHashHex)
}
networkTypeString := helpers.ConvertByteToString(networkType)
mapEntryKey := myIdentityHashString + "@" + networkTypeString
exists, mapItemValue, err := myNewestBroadcastPublicChatKeysMapDatastore.GetMapEntry(mapEntryKey)
if (err != nil) { return false, false, [32]byte{}, [1568]byte{}, err }
if (exists == false){
return true, false, [32]byte{}, [1568]byte{}, nil
}
naclKeyString, kyberKeyString, delimiterFound := strings.Cut(mapItemValue, "+")
if (delimiterFound == false){
return false, false, [32]byte{}, [1568]byte{}, errors.New("Malformed myNewestBroadcastPublicChatKeysMapDatastore item value: " + mapItemValue)
}
naclKeyBytes, err := encoding.DecodeBase64StringToBytes(naclKeyString)
if (err != nil){
return false, false, [32]byte{}, [1568]byte{}, errors.New("Malformed myNewestBroadcastPublicChatKeysMapDatastore item value: Invalid NaclKey: Not Base64: " + naclKeyString)
}
if (len(naclKeyBytes) != 32){
return false, false, [32]byte{}, [1568]byte{}, errors.New("Malformed myNewestBroadcastPublicChatKeysMapDatastore item value: Invalid NaclKey: Invalid length: " + naclKeyString)
}
naclKey := [32]byte(naclKeyBytes)
kyberKeyBytes, err := encoding.DecodeBase64StringToBytes(kyberKeyString)
if (err != nil){
return false, false, [32]byte{}, [1568]byte{}, errors.New("Malformed myNewestBroadcastPublicChatKeysMapDatastore item value: Invalid KyberKey: Not Base64: " + kyberKeyString)
}
if (len(kyberKeyBytes) != 1568){
return false, false, [32]byte{}, [1568]byte{}, errors.New("Malformed myNewestBroadcastPublicChatKeysMapDatastore item value: Invalid KyberKey: Invalid length: " + kyberKeyString)
}
kyberKey := [1568]byte(kyberKeyBytes)
return true, true, naclKey, kyberKey, nil
}