// encoding provides functions to encode and decode data in hex, base32, base64, and MessagePack package encoding // See what encodings are used for which types of data in Specification.md import "bytes" import "encoding/hex" import "encoding/base64" import "encoding/base32" import "strings" import "errors" import messagepack "github.com/vmihailenco/msgpack/v5" func DecodeHexStringToBytes(hexInput string)([]byte, error){ decodedBytes, err := hex.DecodeString(hexInput) if (err != nil) { return nil, err } return decodedBytes, nil } func DecodeHexStringTo3ByteArray(hexInput string)([3]byte, error){ decodedBytes, err := hex.DecodeString(hexInput) if (err != nil) { return [3]byte{}, err } if (len(decodedBytes) != 3){ return [3]byte{}, errors.New("DecodeHexStringTo3ByteArray called with invalid length hex string: " + hexInput) } result := [3]byte(decodedBytes) return result, nil } func DecodeHexStringTo16ByteArray(hexInput string)([16]byte, error){ decodedBytes, err := hex.DecodeString(hexInput) if (err != nil) { return [16]byte{}, err } if (len(decodedBytes) != 16){ return [16]byte{}, errors.New("DecodeHexStringTo16ByteArray called with invalid length hex string: " + hexInput) } result := [16]byte(decodedBytes) return result, nil } func EncodeBytesToHexString(input []byte)string{ result := hex.EncodeToString(input) return result } const base32Charset = "abcdefghijklmnopqrstuvwxyz234567" func EncodeBytesToBase32String(input []byte)string{ newEncodingObject := base32.NewEncoding(base32Charset) result := newEncodingObject.EncodeToString(input) return result } func DecodeBase32StringToBytes(input string)([]byte, error){ // We have to check for newlines because golang's base32 allows them for _, element := range input{ if (element == '\r' || element == '\n') { return nil, errors.New("Invalid base32 input: contains newline.") } } newEncodingObject := base32.NewEncoding(base32Charset) decodedBytes, err := newEncodingObject.DecodeString(input) if (err != nil) { return nil, err } return decodedBytes, nil } // Verifies string is a base32 string // Outputs: // -bool: String is base32 charset only // -string: Character that is not base32 func VerifyStringContainsOnlyBase32Charset(input string)(bool, string){ // This iterates through the string's runes for _, element := range input { characterString := string(element) isBase32Character := strings.ContainsAny(characterString, base32Charset) if (isBase32Character == false) { return false, characterString } } return true, "" } func EncodeBytesToBase64String(input []byte) string { result := base64.URLEncoding.EncodeToString(input) return result } func DecodeBase64StringToBytes(base64Input string) ([]byte, error) { decodedBytes, err := base64.URLEncoding.DecodeString(base64Input) if (err != nil) { return nil, err } return decodedBytes, nil } func DecodeBase64StringToUnicodeString(base64Input string)(string, error){ decodedBytes, err := DecodeBase64StringToBytes(base64Input) if (err != nil) { return "", err } decodedString := string(decodedBytes) return decodedString, nil } // This will omit empty values func EncodeMessagePackBytes(input interface{}) ([]byte, error) { encoder := messagepack.GetEncoder() encoder.SetOmitEmpty(true) encoder.UseCompactInts(true) var buffer bytes.Buffer encoder.Reset(&buffer) err := encoder.Encode(input) bytes := buffer.Bytes() messagepack.PutEncoder(encoder) if (err != nil) { return nil, err } return bytes, nil } func DecodeRawMessagePackToString(data messagepack.RawMessage)(string, error){ var outputString string err := DecodeMessagePackBytes(false, data, &outputString) if (err != nil) { return "", err } return outputString, nil } func DecodeRawMessagePackToByte(data messagepack.RawMessage)(byte, error){ var outputByte byte err := DecodeMessagePackBytes(false, data, &outputByte) if (err != nil) { return 0, err } return outputByte, nil } func DecodeRawMessagePackToBytes(data messagepack.RawMessage)([]byte, error){ var outputBytes []byte err := DecodeMessagePackBytes(false, data, &outputBytes) if (err != nil) { return nil, err } return outputBytes, nil } // This is used to decode inboxes func DecodeRawMessagePackTo10ByteArray(data messagepack.RawMessage)([10]byte, error){ var outputArray [10]byte err := DecodeMessagePackBytes(false, data, &outputArray) if (err != nil) { return [10]byte{}, err } return outputArray, nil } // This is used to decode device identifiers func DecodeRawMessagePackTo11ByteArray(data messagepack.RawMessage)([11]byte, error){ var outputArray [11]byte err := DecodeMessagePackBytes(false, data, &outputArray) if (err != nil) { return [11]byte{}, err } return outputArray, nil } // This is used to decode identity hashes func DecodeRawMessagePackTo16ByteArray(data messagepack.RawMessage)([16]byte, error){ var outputArray [16]byte err := DecodeMessagePackBytes(false, data, &outputArray) if (err != nil) { return [16]byte{}, err } return outputArray, nil } func DecodeRawMessagePackTo22ByteArray(data messagepack.RawMessage)([22]byte, error){ var outputArray [22]byte err := DecodeMessagePackBytes(false, data, &outputArray) if (err != nil) { return [22]byte{}, err } return outputArray, nil } func DecodeRawMessagePackTo24ByteArray(data messagepack.RawMessage)([24]byte, error){ var outputArray [24]byte err := DecodeMessagePackBytes(false, data, &outputArray) if (err != nil) { return [24]byte{}, err } return outputArray, nil } // This is used to decode message cipher key hashes func DecodeRawMessagePackTo25ByteArray(data messagepack.RawMessage)([25]byte, error){ var outputArray [25]byte err := DecodeMessagePackBytes(false, data, &outputArray) if (err != nil) { return [25]byte{}, err } return outputArray, nil } func DecodeRawMessagePackTo32ByteArray(data messagepack.RawMessage)([32]byte, error){ var outputArray [32]byte err := DecodeMessagePackBytes(false, data, &outputArray) if (err != nil) { return [32]byte{}, err } return outputArray, nil } func DecodeRawMessagePackTo64ByteArray(data messagepack.RawMessage)([64]byte, error){ var outputArray [64]byte err := DecodeMessagePackBytes(false, data, &outputArray) if (err != nil) { return [64]byte{}, err } return outputArray, nil } func DecodeRawMessagePackToBool(data messagepack.RawMessage)(bool, error){ var outputBool bool err := DecodeMessagePackBytes(false, data, &outputBool) if (err != nil) { return false, err } return outputBool, nil } func DecodeRawMessagePackToInt(data messagepack.RawMessage)(int, error){ var outputInt int err := DecodeMessagePackBytes(false, data, &outputInt) if (err != nil) { return 0, err } return outputInt, nil } func DecodeRawMessagePackToInt64(data messagepack.RawMessage)(int64, error){ var outputInt int64 err := DecodeMessagePackBytes(false, data, &outputInt) if (err != nil) { return 0, err } return outputInt, nil } func DecodeRawMessagePackToFloat64(data messagepack.RawMessage)(float64, error){ var outputFloat float64 err := DecodeMessagePackBytes(false, data, &outputFloat) if (err != nil) { return 0, err } return outputFloat, nil } func DecodeMessagePackBytes(allowUnknownFields bool, data []byte, output interface{}) error { decoder := messagepack.GetDecoder() //TODO: Make allowUnknownFields also reject ignored fields decoder.DisallowUnknownFields(!allowUnknownFields) newReader := bytes.NewReader(data) decoder.Reset(newReader) err := decoder.Decode(output) messagepack.PutDecoder(decoder) return err }