Skip to content

Commit

Permalink
feat: encrypt password
Browse files Browse the repository at this point in the history
  • Loading branch information
YenchangChan committed Jun 14, 2024
1 parent 016f803 commit ab7f90b
Show file tree
Hide file tree
Showing 6 changed files with 236 additions and 1 deletion.
10 changes: 10 additions & 0 deletions cmd/clickhouse_sinker/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,10 +60,12 @@ func initCmdOptions() {
NacosGroup: "DEFAULT_GROUP",
NacosUsername: "nacos",
NacosPassword: "nacos",
Encrypt: "",
}

// 2. Replace options with the corresponding env variable if present.
util.EnvBoolVar(&cmdOps.ShowVer, "v")
util.EnvStringVar(&cmdOps.Encrypt, "e")
util.EnvStringVar(&cmdOps.LogLevel, "log-level")
util.EnvStringVar(&cmdOps.LogPaths, "log-paths")
util.EnvIntVar(&cmdOps.HTTPPort, "http-port")
Expand All @@ -89,6 +91,7 @@ func initCmdOptions() {

// 3. Replace options with the corresponding CLI parameter if present.
flag.BoolVar(&cmdOps.ShowVer, "v", cmdOps.ShowVer, "show build version and quit")
flag.StringVar(&cmdOps.Encrypt, "e", cmdOps.Encrypt, "encrypt password")
flag.StringVar(&cmdOps.LogLevel, "log-level", cmdOps.LogLevel, "one of debug, info, warn, error, dpanic, panic, fatal")
flag.StringVar(&cmdOps.LogPaths, "log-paths", cmdOps.LogPaths, "a list of comma-separated log file path. stdout means the console stdout")
flag.IntVar(&cmdOps.HTTPPort, "http-port", cmdOps.HTTPPort, "http listen port")
Expand All @@ -114,6 +117,9 @@ func initCmdOptions() {
flag.StringVar(&cmdOps.KafkaGSSAPIPassword, "kafka-gssapi-password", cmdOps.KafkaGSSAPIPassword, "kafka GSSAPI password")

flag.Parse()
if err := util.Gsypt.Unmarshal(&cmdOps); err != nil {
util.Logger.Fatal("failed to decrypt password", zap.Error(err))
}
}

func getVersion() string {
Expand All @@ -122,6 +128,10 @@ func getVersion() string {

func init() {
initCmdOptions()
if cmdOps.Encrypt != "" {
fmt.Println(util.AesEncryptECB(cmdOps.Encrypt))
os.Exit(0)
}
logPaths := strings.Split(cmdOps.LogPaths, ",")
util.InitLogger(logPaths)
util.SetLogLevel(cmdOps.LogLevel)
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ require (
github.com/jinzhu/copier v0.4.0
github.com/matoous/go-nanoid/v2 v2.0.0
github.com/nacos-group/nacos-sdk-go v1.1.4
github.com/pkg/errors v0.9.1
github.com/prometheus/client_golang v1.18.0
github.com/prometheus/common v0.45.0
github.com/shopspring/decimal v1.3.1
Expand Down Expand Up @@ -64,7 +65,6 @@ require (
github.com/opentracing/opentracing-go v1.2.1-0.20220228012449-10b1cf09e00b // indirect
github.com/paulmach/orb v0.11.1 // indirect
github.com/pierrec/lz4/v4 v4.1.21 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
github.com/prometheus/client_model v0.5.0 // indirect
github.com/prometheus/procfs v0.12.0 // indirect
Expand Down
4 changes: 4 additions & 0 deletions task/sinker.go
Original file line number Diff line number Diff line change
Expand Up @@ -285,6 +285,10 @@ func (s *Sinker) applyConfig(newCfg *config.Config) (err error) {
util.SetLogTrace(newCfg.LogTrace)
util.Rs.SetPoolSize(newCfg.RecordPoolSize)
util.Rs.Reset()
if err := util.Gsypt.Unmarshal(&newCfg.Clickhouse); err != nil {
util.Logger.Error("failed to decrypt config password", zap.Error(err))
return err
}
if s.curCfg == nil {
// The first time invoking of applyConfig
err = s.applyFirstConfig(newCfg)
Expand Down
71 changes: 71 additions & 0 deletions util/aes.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
package util

import (
"crypto/aes"
"encoding/hex"
"strings"
)

var salt = "656f6974656b"

// select hex(aes_encrypt("123456", unhex("656f6974656b"))); => E310E892E56801CED9ED98AA177F18E6
func AesEncryptECB(origData string) string {
if origData == "" {
return origData
}
var encrypted []byte
var o = []byte(origData)
s, _ := hex.DecodeString(salt)
cipher, _ := aes.NewCipher(generateKey(s))
length := (len(o) + aes.BlockSize) / aes.BlockSize
plain := make([]byte, length*aes.BlockSize)
copy(plain, o)
pad := byte(len(plain) - len(o))
for i := len(o); i < len(plain); i++ {
plain[i] = pad
}
encrypted = make([]byte, len(plain))
for bs, be := 0, cipher.BlockSize(); bs <= len(o); bs, be = bs+cipher.BlockSize(), be+cipher.BlockSize() {
cipher.Encrypt(encrypted[bs:be], plain[bs:be])
}
return strings.ToUpper(hex.EncodeToString(encrypted))
}

// select aes_decrypt(unhex("E310E892E56801CED9ED98AA177F18E6"), unhex("656f6974656b")); => 123456
func AesDecryptECB(encrypted string) string {
if encrypted == "" {
return encrypted
}
var decrypted []byte
h, _ := hex.DecodeString(encrypted)
s, _ := hex.DecodeString(salt)
cipher, _ := aes.NewCipher(generateKey(s))
decrypted = make([]byte, len(h))

for bs, be := 0, cipher.BlockSize(); bs < len(h); bs, be = bs+cipher.BlockSize(), be+cipher.BlockSize() {
cipher.Decrypt(decrypted[bs:be], h[bs:be])
}

bEnd := searchByteSliceIndex(decrypted, 32)
return string(decrypted[:bEnd])
}
func generateKey(key []byte) (genKey []byte) {
genKey = make([]byte, 16)
copy(genKey, key)
for i := 16; i < len(key); {
for j := 0; j < 16 && i < len(key); j, i = j+1, i+1 {
genKey[j] ^= key[i]
}
}
return genKey
}

func searchByteSliceIndex(bSrc []byte, b byte) int {
for i := 0; i < len(bSrc); i++ {
if bSrc[i] < b {
return i
}
}

return len(bSrc)
}
1 change: 1 addition & 0 deletions util/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ type CmdOptions struct {
NacosPassword string
NacosDataID string
NacosServiceName string // participate in assignment management if not empty
Encrypt string

Credentials
}
Expand Down
149 changes: 149 additions & 0 deletions util/gosypt.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
package util

import (
"reflect"
"strings"

"github.com/pkg/errors"
)

const (
GosyptPrefixDefault = "ENC("
GosyptSuffxiDefault = ")"
GosyptAlgorithm = "AESWITHHEXANDBASE64"
)

/* Golang Simple Encrypt, simulate jasypt */
type Gosypt struct {
prefix string
suffix string
algorithm string
}

var Gsypt = &Gosypt{
prefix: GosyptPrefixDefault,
suffix: GosyptSuffxiDefault,
algorithm: GosyptAlgorithm,
}

func (gsypt *Gosypt) ensurePassword(password string) string {
if !strings.HasPrefix(password, gsypt.prefix) || !strings.HasSuffix(password, gsypt.suffix) {
return password
}
passwd := strings.TrimSuffix(strings.TrimPrefix(password, gsypt.prefix), gsypt.suffix)
if gsypt.algorithm == GosyptAlgorithm {
return AesDecryptECB(passwd)
}
return password
}

func (gsypt *Gosypt) SetAttribution(prefix, suffix, algorithm string) {
gsypt.prefix = prefix
gsypt.suffix = suffix
gsypt.algorithm = algorithm
}

func (gsypt *Gosypt) Unmarshal(v interface{}) error {
rt := reflect.TypeOf(v)
rv := reflect.ValueOf(v)

if rt.Kind() != reflect.Ptr {
return errors.Wrap(nil, "invalid args, expect ptr")
}

for rt.Kind() == reflect.Ptr {
rt = rt.Elem()
rv = rv.Elem()
}

if rt.Kind() == reflect.Struct {
v, err := gsypt.structHandle(rt, rv)
if err != nil {
return err
}
rv.Set(v)
} else if rt.Kind() == reflect.Slice || rt.Kind() == reflect.Array {
v, err := gsypt.sliceHandle(rt, rv)
if err != nil {
return err
}
rv.Set(v)
} else if rt.Kind() == reflect.Map {
v, err := gsypt.mapHandle(rt, rv)
if err != nil {
return err
}
rv.Set(v)
} else if rt.Kind() == reflect.Interface {
v, err := gsypt.interfaceHandle(rt, rv)
if err != nil {
return err
}
rv.Set(v)
} else if rt.Kind() == reflect.String {
rv.Set(gsypt.stringHandle(rv))
}

return nil
}

func (gsypt *Gosypt) sliceHandle(rt reflect.Type, rv reflect.Value) (reflect.Value, error) {
for j := 0; j < rv.Len(); j++ {
if rt.Elem().Kind() == reflect.String {
rv.Index(j).Set(gsypt.stringHandle(rv.Index(j)))
} else {
if err := gsypt.Unmarshal(rv.Index(j).Addr().Interface()); err != nil {
return rv, err
}
}
}
return rv, nil
}

func (gsypt *Gosypt) mapHandle(rt reflect.Type, rv reflect.Value) (reflect.Value, error) {
for _, k := range rv.MapKeys() {
key := k.Convert(rv.Type().Key())
if rt.Elem().Kind() == reflect.String {
v := gsypt.ensurePassword(rv.MapIndex(key).String())
rv.SetMapIndex(key, reflect.ValueOf(v))
} else {
v := rv.MapIndex(key).Interface()
if err := gsypt.Unmarshal(&v); err != nil {
return rv, err
}
rv.SetMapIndex(key, reflect.ValueOf(v))
}
}
return rv, nil
}

func (gsypt *Gosypt) interfaceHandle(rt reflect.Type, rv reflect.Value) (reflect.Value, error) {
//todo
return rv, nil
}

func (gsypt *Gosypt) structHandle(rt reflect.Type, rv reflect.Value) (reflect.Value, error) {
for i := 0; i < rt.NumField(); i++ {
rtf := rt.Field(i)
rvf := rv.Field(i)

rtt := rtf.Type
for rtt.Kind() == reflect.Ptr {
rtt = rtt.Elem()
}

if rtt.Kind() == reflect.String {
rv.Field(i).Set(gsypt.stringHandle(rvf))
} else {
if err := gsypt.Unmarshal(rvf.Addr().Interface()); err != nil {
return rv, err
}
}
}
return rv, nil
}

func (gsypt *Gosypt) stringHandle(rv reflect.Value) reflect.Value {
rv.SetString(gsypt.ensurePassword(rv.String()))
return rv
}

0 comments on commit ab7f90b

Please sign in to comment.