From e05304b0e35fa70149e79f431cb86b3c86efca38 Mon Sep 17 00:00:00 2001 From: w-mj Date: Thu, 23 Feb 2023 17:36:19 +0800 Subject: [PATCH] aes and jwt --- install.yaml | 8 ++- main.go | 122 +++++++++++++++++++++++++++++++++++++- test/test_aes.go | 151 +++++++++++++++++++++++++++++++++++++++++++++++ test/test_jwt.go | 28 +++++++++ 4 files changed, 306 insertions(+), 3 deletions(-) create mode 100644 test/test_aes.go create mode 100644 test/test_jwt.go diff --git a/install.yaml b/install.yaml index e0e7d05..e4200c9 100644 --- a/install.yaml +++ b/install.yaml @@ -21,12 +21,18 @@ spec: ports: - containerPort: 8080 env: + - name: URL_PREFIX + value: admin - name: DB_HOST value: 192.168.131.195 - name: DB_USER value: app - name: DB_PASS - value: ??????? + value: 1PQlNf9*9Ulo + - name: JWT_KEY + value: !bd832W0@CG + - name: ASE_KEY + value: A5es$&!0GeoEast --- apiVersion: v1 kind: Service diff --git a/main.go b/main.go index 671750a..4fad8c9 100644 --- a/main.go +++ b/main.go @@ -1,20 +1,41 @@ package main import ( + "crypto/aes" + "crypto/cipher" + "crypto/sha1" "embed" + "encoding/base64" + "errors" + "fmt" "github.com/gin-gonic/gin" + "github.com/golang-jwt/jwt/v4" log "github.com/sirupsen/logrus" "io/fs" m "k8s-manager/src" "net/http" + "os" + "strings" ) //go:embed template/* static/* var f embed.FS +var jwtKey string +var aseKey string + func main() { m.InitClient() + jwtKey = os.Getenv("JWT_KEY") + aseKey = os.Getenv("ASE_KEY") + if jwtKey == "" { + panic("No jwt key") + } + if aseKey == "" { + panic("No ase key") + } + r := gin.Default() fp, _ := fs.Sub(f, "static") @@ -32,6 +53,7 @@ func main() { r.DELETE("/dep", m.JWTAuthMiddleware, m.CreateDeleteDeployment) r.GET("/login/:username", Test) + r.Any("/test_token", TestToken) r.GET("/username", m.JWTAuthMiddleware, m.GetUsername) err := r.Run(":8000") if err != nil { @@ -39,8 +61,89 @@ func main() { } } +type CGJWTClaim struct { + jwt.RegisteredClaims + Userid string +} + +func ParseCGToken(token string) (string, error) { + token = strings.ReplaceAll(token, "-", "+") + token = strings.ReplaceAll(token, "_", "/") + token = token + []string{"", "===", "==", "="}[len(token)%4] + fmt.Println(token) + aesEncrypt, err := base64.StdEncoding.DecodeString(token) + if err != nil { + log.WithError(err).Error("Parse CG Token 1") + return "", err + } + + jwtString := AesDecryptECB(aesEncrypt, []byte(aseKey)) + + jwtResult, err := jwt.ParseWithClaims(string(jwtString), &CGJWTClaim{}, func(token *jwt.Token) (i interface{}, err error) { + return jwtKey, nil + // return hmac.New(sha256.New, []byte(jwtKey)), nil + }) + if err != nil { + log.WithError(err).Error("Parse CG Token 2") + return "", err + } + if claims, ok := jwtResult.Claims.(*CGJWTClaim); ok && jwtResult.Valid { // 校验token + return claims.Userid, nil + } + return "", errors.New("jwt parse error") +} + +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 AesDecryptECB(encrypted []byte, key []byte) (decrypted []byte) { + cipher, _ := aes.NewCipher(generateKey(key)) + decrypted = make([]byte, len(encrypted)) + // + for bs, be := 0, cipher.BlockSize(); bs < len(encrypted); bs, be = bs+cipher.BlockSize(), be+cipher.BlockSize() { + cipher.Decrypt(decrypted[bs:be], encrypted[bs:be]) + } + + trim := 0 + if len(decrypted) > 0 { + trim = len(decrypted) - int(decrypted[len(decrypted)-1]) + } + + return decrypted[:trim] +} + +func AesDecrypt(data []byte, key []byte) ([]byte, error) { + sh := sha1.New() + sh.Write(key) + realKey := sh.Sum(nil) + + fmt.Println(string(realKey)) + block, err := aes.NewCipher(realKey[:16]) + if err != nil { + log.WithError(err).Error("AesDecrypt 1") + return nil, err + } + blockSize := block.BlockSize() + blockMode := cipher.NewCBCDecrypter(block, key[:blockSize]) + crypted := make([]byte, len(data)) + blockMode.CryptBlocks(crypted, data) + if err != nil { + log.WithError(err).Error("AesDecrypt 2") + return nil, err + } + return crypted, nil +} + func Test(c *gin.Context) { - username := c.Param("username") + //username := c.Param("username") + username, _ := ParseCGToken(c.Request.URL.Query().Get("cgtoken")) if username == "" { c.JSON(http.StatusNotFound, gin.H{ "code": http.StatusNotFound, @@ -56,6 +159,21 @@ func Test(c *gin.Context) { c.SetCookie("Authorization", "Bearer "+token, 0, "", "", false, false) c.Header("Authorization", "Bearer "+token) c.Header("Cache-Control", "no-store") - c.Redirect(http.StatusTemporaryRedirect, "../index") + redirectUrl := fmt.Sprintf("/%s/index", os.Getenv("URL_PREFIX")) + c.Redirect(http.StatusTemporaryRedirect, redirectUrl) } } + +func TestToken(c *gin.Context) { + token := c.Request.URL.Query().Get("cgtoken") + if token == "" { + c.JSON(http.StatusForbidden, gin.H{"msg": "No token"}) + return + } + username, err := ParseCGToken(token) + if err != nil { + c.JSON(http.StatusForbidden, gin.H{"msg": "token error"}) + return + } + c.JSON(http.StatusOK, gin.H{"msg": "ok", "username": username}) +} diff --git a/test/test_aes.go b/test/test_aes.go new file mode 100644 index 0000000..afe7a53 --- /dev/null +++ b/test/test_aes.go @@ -0,0 +1,151 @@ +package main + +import ( + "bytes" + "crypto/aes" + "crypto/cipher" + "crypto/rand" + "crypto/sha1" + "encoding/base64" + "encoding/hex" + "io" + "log" +) + +func RealKey(key string) []byte { + sh := sha1.New() + sh.Write([]byte(key)) + realKey := sh.Sum(nil) + return realKey +} + +func main() { + origData := []byte("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzY2hvb2xpZCI6Ijk5OSIsImV4cCI6MTY3MDcxMzk3OSwidXNlcm5hbWUiOiLllJDlrociLCJjb3Vyc2VzIjoiLDMyLDQsMzgsMzcsNDIsNDMsOSw0MCw0MSwxMSwxMiwxMyw0NCwxNCwxOSwyNiwyOSIsInNjaG9vbG5hbWUiOiLluIzlhoDlnKjnur8iLCJ1c2VyaWQiOiJjZ190YW5neXUiLCJjb2xsZWdlbmFtZSI6IuWtpuefpeahpSIsImhvbWVwYWdlIjoiaHR0cHM6Ly85OTkuYmQuZWR1Y2cubmV0LyJ9.fB3-L-gEOXVlyjjZqphkORtGCRK4ZWI9RNxO4-FULhw") // 待加密的数据 + key := RealKey("A5es$&!0GeoEast") + log.Println("原文:", string(origData)) + + // log.Println("------------------ CBC模式 --------------------") + // encrypted := AesEncryptCBC(origData, key) + // log.Println("密文(hex):", hex.EncodeToString(encrypted)) + // log.Println("密文(base64):", base64.StdEncoding.EncodeToString(encrypted)) + // decrypted := AesDecryptCBC(encrypted, key) + // log.Println("解密结果:", string(decrypted)) + + log.Println("------------------ ECB模式 --------------------") + encrypted := AesEncryptECB(origData, key) + log.Println("密文(hex):", hex.EncodeToString(encrypted)) + log.Println("密文(base64):", base64.StdEncoding.EncodeToString(encrypted)) + decrypted := AesDecryptECB(encrypted, key) + log.Println("解密结果:", string(decrypted)) + + // log.Println("------------------ CFB模式 --------------------") + // encrypted = AesEncryptCFB(origData, key) + // log.Println("密文(hex):", hex.EncodeToString(encrypted)) + // log.Println("密文(base64):", base64.StdEncoding.EncodeToString(encrypted)) + // decrypted = AesDecryptCFB(encrypted, key) + // log.Println("解密结果:", string(decrypted)) +} + +// =================== CBC ====================== +func AesEncryptCBC(origData []byte, key []byte) (encrypted []byte) { + // 分组秘钥 + // NewCipher该函数限制了输入k的长度必须为16, 24或者32 + block, _ := aes.NewCipher(key) + blockSize := block.BlockSize() // 获取秘钥块的长度 + origData = pkcs5Padding(origData, blockSize) // 补全码 + blockMode := cipher.NewCBCEncrypter(block, key[:blockSize]) // 加密模式 + encrypted = make([]byte, len(origData)) // 创建数组 + blockMode.CryptBlocks(encrypted, origData) // 加密 + return encrypted +} +func AesDecryptCBC(encrypted []byte, key []byte) (decrypted []byte) { + block, _ := aes.NewCipher(key) // 分组秘钥 + blockSize := block.BlockSize() // 获取秘钥块的长度 + blockMode := cipher.NewCBCDecrypter(block, key[:blockSize]) // 加密模式 + decrypted = make([]byte, len(encrypted)) // 创建数组 + blockMode.CryptBlocks(decrypted, encrypted) // 解密 + decrypted = pkcs5UnPadding(decrypted) // 去除补全码 + return decrypted +} +func pkcs5Padding(ciphertext []byte, blockSize int) []byte { + padding := blockSize - len(ciphertext)%blockSize + padtext := bytes.Repeat([]byte{byte(padding)}, padding) + return append(ciphertext, padtext...) +} +func pkcs5UnPadding(origData []byte) []byte { + length := len(origData) + unpadding := int(origData[length-1]) + return origData[:(length - unpadding)] +} + +// =================== ECB ====================== +func AesEncryptECB(origData []byte, key []byte) (encrypted []byte) { + cipher, _ := aes.NewCipher(generateKey(key)) + length := (len(origData) + aes.BlockSize) / aes.BlockSize + plain := make([]byte, length*aes.BlockSize) + copy(plain, origData) + pad := byte(len(plain) - len(origData)) + for i := len(origData); i < len(plain); i++ { + plain[i] = pad + } + encrypted = make([]byte, len(plain)) + // 分组分块加密 + for bs, be := 0, cipher.BlockSize(); bs <= len(origData); bs, be = bs+cipher.BlockSize(), be+cipher.BlockSize() { + cipher.Encrypt(encrypted[bs:be], plain[bs:be]) + } + + return encrypted +} +func AesDecryptECB(encrypted []byte, key []byte) (decrypted []byte) { + cipher, _ := aes.NewCipher(generateKey(key)) + decrypted = make([]byte, len(encrypted)) + // + for bs, be := 0, cipher.BlockSize(); bs < len(encrypted); bs, be = bs+cipher.BlockSize(), be+cipher.BlockSize() { + cipher.Decrypt(decrypted[bs:be], encrypted[bs:be]) + } + + trim := 0 + if len(decrypted) > 0 { + trim = len(decrypted) - int(decrypted[len(decrypted)-1]) + } + + return decrypted[:trim] +} +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 +} + +// =================== CFB ====================== +func AesEncryptCFB(origData []byte, key []byte) (encrypted []byte) { + block, err := aes.NewCipher(key) + if err != nil { + panic(err) + } + encrypted = make([]byte, aes.BlockSize+len(origData)) + iv := encrypted[:aes.BlockSize] + if _, err := io.ReadFull(rand.Reader, iv); err != nil { + panic(err) + } + stream := cipher.NewCFBEncrypter(block, iv) + stream.XORKeyStream(encrypted[aes.BlockSize:], origData) + return encrypted +} +func AesDecryptCFB(encrypted []byte, key []byte) (decrypted []byte) { + block, _ := aes.NewCipher(key) + if len(encrypted) < aes.BlockSize { + panic("ciphertext too short") + } + iv := encrypted[:aes.BlockSize] + encrypted = encrypted[aes.BlockSize:] + + stream := cipher.NewCFBDecrypter(block, iv) + stream.XORKeyStream(encrypted, encrypted) + return encrypted +} diff --git a/test/test_jwt.go b/test/test_jwt.go new file mode 100644 index 0000000..b0c1398 --- /dev/null +++ b/test/test_jwt.go @@ -0,0 +1,28 @@ +package main + +import ( + "github.com/golang-jwt/jwt/v4" + log "github.com/sirupsen/logrus" +) + +var data = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzY2hvb2xpZCI6Ijk5OSIsImV4cCI6MTY3MDcxMzk3OSwidXNlcm5hbWUiOiLllJDlrociLCJjb3Vyc2VzIjoiLDMyLDQsMzgsMzcsNDIsNDMsOSw0MCw0MSwxMSwxMiwxMyw0NCwxNCwxOSwyNiwyOSIsInNjaG9vbG5hbWUiOiLluIzlhoDlnKjnur8iLCJ1c2VyaWQiOiJjZ190YW5neXUiLCJjb2xsZWdlbmFtZSI6IuWtpuefpeahpSIsImhvbWVwYWdlIjoiaHR0cHM6Ly85OTkuYmQuZWR1Y2cubmV0LyJ9.fB3-L-gEOXVlyjjZqphkORtGCRK4ZWI9RNxO4-FULhw" +var key = "!bd832W0@CG" + +type CGJWTClaim struct { + jwt.RegisteredClaims + Userid string +} + +func main() { + jwtResult, err := jwt.ParseWithClaims(data, &CGJWTClaim{}, func(token *jwt.Token) (i interface{}, err error) { + return []byte(key), nil + }) + if err != nil { + log.WithError(err).Error("err1") + } + if claims, ok := jwtResult.Claims.(*CGJWTClaim); ok && jwtResult.Valid { // 校验token + log.Println("user id", claims.Userid) + } else { + log.Error("err 2") + } +}