111 lines
3.7 KiB
Go
111 lines
3.7 KiB
Go
package transcrypt
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/binary"
|
|
"encoding/hex"
|
|
"fmt"
|
|
"reflect"
|
|
"regexp"
|
|
"strings"
|
|
|
|
"github.com/minio/sio"
|
|
)
|
|
|
|
// Defines the default layout of a string representing encrypted data.
|
|
// The string is divided in sections delimited by a colon.
|
|
// 1. Cipher suite
|
|
// 2. Salt
|
|
// 3. Data
|
|
// 4. Original data type
|
|
var regexEncryptedString = regexp.MustCompile(`\d{2}:[\w\d]{24}:[\w\d]*:[\w\d]*`)
|
|
|
|
// convertBytesToValue converts a byte-array to a reflect.Value.
|
|
// It takes a byte-slice and a reflect.Kind and returns an error if the conversion fails.
|
|
func convertBytesToValue(d []byte, k reflect.Kind) (reflect.Value, error) {
|
|
switch k {
|
|
case reflect.Int:
|
|
v := reflect.New(reflect.TypeOf(0))
|
|
v.Elem().SetInt(int64(binary.BigEndian.Uint64(d)))
|
|
return reflect.ValueOf(v.Elem().Interface()), nil
|
|
case reflect.Uint64:
|
|
v := reflect.New(reflect.TypeOf(uint64(0)))
|
|
v.Elem().SetUint(binary.BigEndian.Uint64(d))
|
|
return reflect.ValueOf(v.Elem().Interface()), nil
|
|
case reflect.String:
|
|
return reflect.ValueOf(string(d)), nil
|
|
default:
|
|
return reflect.Value{}, fmt.Errorf("unknown type %v", k)
|
|
}
|
|
}
|
|
|
|
// convertValueToHexString converts a value to a hex-encoded string.
|
|
// It returns an empty string and an error if the value is a kind reflect.Int and cannot be converted.
|
|
func convertValueToHexString(v reflect.Value) (string, error) {
|
|
var err error
|
|
switch v.Kind() {
|
|
case reflect.Int:
|
|
bufWriter := bytes.NewBuffer(make([]byte, 0))
|
|
if err = binary.Write(bufWriter, binary.BigEndian, v.Int()); err != nil {
|
|
return "", err
|
|
}
|
|
return hex.EncodeToString(bufWriter.Bytes()), nil
|
|
case reflect.String:
|
|
return hex.EncodeToString([]byte(v.String())), nil
|
|
default:
|
|
return "", fmt.Errorf("unknown type %v", v.Kind())
|
|
}
|
|
}
|
|
|
|
// decodeHexString decodes data into the pieces that make up the encrypted data.
|
|
// It takes an encrypted key and data string and returns the actual encrypted data as a byte-slice, reflect.Kind and the encryption config.
|
|
// It returns an error if the data string is empty or invalid, or any of the steps to get the encrypted data fails.
|
|
func decodeHexString(key string, data string) ([]byte, reflect.Kind, sio.Config, error) {
|
|
if key == "" {
|
|
return nil, reflect.Invalid, sio.Config{}, fmt.Errorf("key is empty")
|
|
}
|
|
if data == "" {
|
|
return nil, reflect.Invalid, sio.Config{}, fmt.Errorf("value is empty")
|
|
}
|
|
|
|
if !regexEncryptedString.MatchString(data) {
|
|
return nil, reflect.Invalid, sio.Config{}, fmt.Errorf("value is not valid")
|
|
}
|
|
|
|
var split []string
|
|
split = strings.Split(data, ":")
|
|
|
|
var err error
|
|
var cipherSuiteBytes []byte
|
|
if cipherSuiteBytes, err = hex.DecodeString(split[0]); err != nil {
|
|
return nil, reflect.Invalid, sio.Config{}, fmt.Errorf("cannot decode cipersuite: %w", err)
|
|
}
|
|
|
|
var salt []byte
|
|
if salt, err = hex.DecodeString(split[1]); err != nil {
|
|
return nil, reflect.Invalid, sio.Config{}, fmt.Errorf("cannot decode salt: %w", err)
|
|
}
|
|
|
|
var encryptedBytes []byte
|
|
if encryptedBytes, err = hex.DecodeString(split[2]); err != nil {
|
|
return nil, reflect.Invalid, sio.Config{}, fmt.Errorf("cannot decode encrypted data: %w", err)
|
|
}
|
|
|
|
var kindBytes []byte
|
|
if kindBytes, err = hex.DecodeString(split[3]); err != nil {
|
|
return nil, reflect.Invalid, sio.Config{}, fmt.Errorf("cannot decode kindBytes: %w", err)
|
|
}
|
|
|
|
var kind reflect.Kind
|
|
if kind = getKindForString(string(kindBytes)); kind == reflect.Invalid {
|
|
return nil, reflect.Invalid, sio.Config{}, fmt.Errorf("cannot decode kind: %w", err)
|
|
}
|
|
|
|
var cryptoConfig sio.Config
|
|
if cryptoConfig, err = createCryptoConfig(key, cipherSuiteBytes, salt); err != nil {
|
|
return nil, reflect.Invalid, sio.Config{}, fmt.Errorf("cannot create crypto config: %w", err)
|
|
}
|
|
|
|
return encryptedBytes, kind, cryptoConfig, nil
|
|
}
|