restruc my codebase
This commit is contained in:
parent
c577c396f4
commit
3869d24200
4
.env
4
.env
|
|
@ -1,5 +1,5 @@
|
||||||
MONGO_URI="mongodb://adminLinh:linhporo1@localhost:27017/linhporo1?authSource=admin"
|
MONGO_URI="mongodb://adminLinh:linhporo1@10.10.0.216:27017/linhporo1?authSource=admin"
|
||||||
API_TEST_PORT=":8080"
|
API_TEST_PORT=":8080"
|
||||||
REDIS_URI="redis://localhost:6379/0"
|
REDIS_URI="redis://10.10.0.216:6379/0"
|
||||||
STMP_PASS="btmp judz ebys pfxw"
|
STMP_PASS="btmp judz ebys pfxw"
|
||||||
EMAIL_VERIFY_SECRET="WDc&4+&vYP(n'}?LHNE#5M?IE|g(c812"
|
EMAIL_VERIFY_SECRET="WDc&4+&vYP(n'}?LHNE#5M?IE|g(c812"
|
||||||
|
|
@ -83,3 +83,8 @@ type EmailTemplate struct {
|
||||||
Otp string `json:"otp"`
|
Otp string `json:"otp"`
|
||||||
AlternativeLink string `json:"alternativeLink"`
|
AlternativeLink string `json:"alternativeLink"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type OtpGenerate struct {
|
||||||
|
PureOTP string
|
||||||
|
HashOTP string
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,28 +1,16 @@
|
||||||
package rest_api
|
package rest_api
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
"context"
|
"context"
|
||||||
"crypto/aes"
|
|
||||||
"crypto/cipher"
|
|
||||||
"crypto/rand"
|
|
||||||
"encoding/base32"
|
|
||||||
"encoding/base64"
|
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/go-playground/validator/v10"
|
|
||||||
"github.com/gorilla/mux"
|
"github.com/gorilla/mux"
|
||||||
"github.com/pquerna/otp"
|
|
||||||
"github.com/pquerna/otp/hotp"
|
|
||||||
"go.mongodb.org/mongo-driver/bson"
|
|
||||||
"go.mongodb.org/mongo-driver/mongo"
|
|
||||||
"golang.org/x/crypto/bcrypt"
|
|
||||||
"linhdevtran99/rest-api/models"
|
"linhdevtran99/rest-api/models"
|
||||||
|
"linhdevtran99/rest-api/rest-api/services"
|
||||||
"linhdevtran99/rest-api/utils"
|
"linhdevtran99/rest-api/utils"
|
||||||
"log"
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type APIServer struct {
|
type APIServer struct {
|
||||||
|
|
@ -108,24 +96,24 @@ func (s *APIServer) testCheckUserAndPass(w http.ResponseWriter, r *http.Request)
|
||||||
// panic(err)
|
// panic(err)
|
||||||
//}
|
//}
|
||||||
|
|
||||||
serect := os.Getenv("EMAIL_VERIFY_SECRET")
|
//serect := os.Getenv("EMAIL_VERIFY_SECRET")
|
||||||
//isPass, _ := generatorOtp("hello", "nhocdl.poro1@gmail.com", 12, serect)
|
//isPass, _ := generatorOtp("hello", "nhocdl.poro1@gmail.com", 12, serect)
|
||||||
//fmt.Println(isPass)
|
//fmt.Println(isPass)
|
||||||
cipherBase64 := createLinkVerify(&models.CreateUser{
|
//cipherBase64 := createLinkVerify(&models.CreateUser{
|
||||||
Username: "thewind121212",
|
// Username: "thewind121212",
|
||||||
Email: "nhocdl.poro1@gmail.com",
|
// Email: "nhocdl.poro1@gmail.com",
|
||||||
Password: "linhporoQ1@",
|
// Password: "linhporoQ1@",
|
||||||
ConfirmPassword: "linhporoQ1@",
|
// ConfirmPassword: "linhporoQ1@",
|
||||||
}, serect)
|
//}, serect)
|
||||||
|
//
|
||||||
key := []byte(serect)
|
//key := []byte(serect)
|
||||||
|
//
|
||||||
i, err := decrypt(cipherBase64, key)
|
//i, err := utils.DecryptAES(cipherBase64, key)
|
||||||
if err != nil {
|
//if err != nil {
|
||||||
return err
|
// return err
|
||||||
}
|
//}
|
||||||
|
//
|
||||||
fmt.Println(string(i))
|
//fmt.Println(string(i))
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -134,9 +122,9 @@ func (s *APIServer) testCheckUserAndPass(w http.ResponseWriter, r *http.Request)
|
||||||
|
|
||||||
_ = json.NewDecoder(r.Body).Decode(®isterInfo)
|
_ = json.NewDecoder(r.Body).Decode(®isterInfo)
|
||||||
//call function check info user type in
|
//call function check info user type in
|
||||||
validRegisterInfo := checkAndValidDataFiled(®isterInfo, w)
|
validRegisterInfo := services.CheckAndValidRegisterFiled(®isterInfo, w)
|
||||||
//call function check data user use in past or not
|
//call function check data user use in past or not
|
||||||
isValidData := checkAccountExist(client, registerInfo.Username, registerInfo.Email, w)
|
isValidData := services.CheckAccountExist(client, registerInfo.Username, registerInfo.Email, w)
|
||||||
|
|
||||||
if isValidData == false || validRegisterInfo == false {
|
if isValidData == false || validRegisterInfo == false {
|
||||||
return errors.New("USER DON'T HAVE VALID INFO FOR REGISTER ACCOUNT")
|
return errors.New("USER DON'T HAVE VALID INFO FOR REGISTER ACCOUNT")
|
||||||
|
|
@ -175,206 +163,3 @@ func (s *APIServer) handleAccount(w http.ResponseWriter, r *http.Request) error
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
//register group-func
|
|
||||||
|
|
||||||
//checking is user create that have account before
|
|
||||||
|
|
||||||
func checkAndValidDataFiled(registerData *models.CreateUser, w http.ResponseWriter) bool {
|
|
||||||
_ = models.Validate.RegisterValidation("customPassword", models.PasswordValidator)
|
|
||||||
errs := models.Validate.Struct(registerData)
|
|
||||||
var errStack []string
|
|
||||||
if errs != nil {
|
|
||||||
for _, err := range errs.(validator.ValidationErrors) {
|
|
||||||
switch err.Field() {
|
|
||||||
case "Email":
|
|
||||||
{
|
|
||||||
fmt.Println("Email không hợp lệ")
|
|
||||||
errStack = append(errStack, "Email")
|
|
||||||
}
|
|
||||||
case "Username":
|
|
||||||
{
|
|
||||||
fmt.Println("User không hợp lệ")
|
|
||||||
errStack = append(errStack, "User")
|
|
||||||
}
|
|
||||||
case "Password":
|
|
||||||
{
|
|
||||||
fmt.Println("Password không hợp lệ")
|
|
||||||
errStack = append(errStack, "Password")
|
|
||||||
}
|
|
||||||
case "ConfirmPassword":
|
|
||||||
{
|
|
||||||
fmt.Println("Nhập lại mật khẩu sai")
|
|
||||||
errStack = append(errStack, "ConfirmPassword")
|
|
||||||
}
|
|
||||||
case "PhoneNumber":
|
|
||||||
{
|
|
||||||
fmt.Println("SĐT không hợp lệ")
|
|
||||||
errStack = append(errStack, "PhoneNumber")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//handle repose error
|
|
||||||
w.WriteHeader(http.StatusBadRequest)
|
|
||||||
err := json.NewEncoder(w).Encode(errStack)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
fmt.Println("There is error in write reponse at checking info user")
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
return true
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func checkAccountExist(mongoClient *mongo.Client, userName string, email string, w http.ResponseWriter) bool {
|
|
||||||
//filter in mongodb
|
|
||||||
var isValid bool
|
|
||||||
|
|
||||||
filter := bson.D{
|
|
||||||
{"$or", bson.A{
|
|
||||||
bson.D{{"username", userName}},
|
|
||||||
bson.D{{"email", email}},
|
|
||||||
}},
|
|
||||||
}
|
|
||||||
|
|
||||||
userData := mongoClient.Database("Totoday-shop").Collection("users")
|
|
||||||
|
|
||||||
var result models.UsersMongo
|
|
||||||
err := userData.FindOne(context.TODO(), filter).Decode(&result)
|
|
||||||
if err != nil {
|
|
||||||
isValid = true
|
|
||||||
}
|
|
||||||
if err == nil {
|
|
||||||
fmt.Println("Email or username already had register")
|
|
||||||
w.WriteHeader(http.StatusBadRequest)
|
|
||||||
err := json.NewEncoder(w).Encode("Your username or email had been register before")
|
|
||||||
if err != nil {
|
|
||||||
fmt.Println("There is error in write reponse at checking data user register")
|
|
||||||
}
|
|
||||||
isValid = false
|
|
||||||
}
|
|
||||||
|
|
||||||
return isValid
|
|
||||||
}
|
|
||||||
|
|
||||||
//after cheking register data generate otp and send email write valid time to confirm in redis
|
|
||||||
// noice this will do concurency for speed reason
|
|
||||||
|
|
||||||
type otpGenerate struct {
|
|
||||||
pureOTP string
|
|
||||||
hashOTP string
|
|
||||||
}
|
|
||||||
|
|
||||||
func generatorOtp(userName string, email string, counter uint64, serect string) (bool, *otpGenerate) {
|
|
||||||
|
|
||||||
serectBase32 := base32.StdEncoding.EncodeToString([]byte(serect + userName + email))
|
|
||||||
passCode, err := hotp.GenerateCodeCustom(serectBase32, counter, hotp.ValidateOpts{
|
|
||||||
Digits: 6,
|
|
||||||
Algorithm: otp.AlgorithmSHA256,
|
|
||||||
})
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
fmt.Println("Fail to create OTP")
|
|
||||||
return false, &otpGenerate{
|
|
||||||
pureOTP: "none",
|
|
||||||
hashOTP: "none",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
hashed, err := bcrypt.GenerateFromPassword([]byte(passCode), 5)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Println("Fail to create OTP")
|
|
||||||
return false, &otpGenerate{
|
|
||||||
pureOTP: "none",
|
|
||||||
hashOTP: "none",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true, &otpGenerate{
|
|
||||||
pureOTP: passCode,
|
|
||||||
hashOTP: string(hashed),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func createLinkVerify(registerInfo *models.CreateUser, secrect string) string {
|
|
||||||
|
|
||||||
data, _ := json.Marshal(registerInfo)
|
|
||||||
key := []byte(secrect)
|
|
||||||
|
|
||||||
ciphertext, _ := encrypt(data, key)
|
|
||||||
|
|
||||||
cipherTextBase64 := base64.StdEncoding.EncodeToString(ciphertext)
|
|
||||||
|
|
||||||
return cipherTextBase64
|
|
||||||
}
|
|
||||||
|
|
||||||
func encrypt(data []byte, key []byte) ([]byte, error) {
|
|
||||||
block, err := aes.NewCipher(key)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Generate a random IV (Initialization Vector)
|
|
||||||
iv := make([]byte, aes.BlockSize)
|
|
||||||
if _, err := rand.Read(iv); err != nil {
|
|
||||||
fmt.Println("error generating IV:", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Pad the data to a multiple of the block size
|
|
||||||
data = pkcs7Pad(data, aes.BlockSize)
|
|
||||||
|
|
||||||
// Create a CBC mode cipher block
|
|
||||||
mode := cipher.NewCBCEncrypter(block, iv)
|
|
||||||
|
|
||||||
// Encrypt the data
|
|
||||||
ciphertext := make([]byte, len(data))
|
|
||||||
mode.CryptBlocks(ciphertext, data)
|
|
||||||
|
|
||||||
// Prepend the IV to the ciphertext
|
|
||||||
ciphertext = append(iv, ciphertext...)
|
|
||||||
|
|
||||||
return ciphertext, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func decrypt(base64Ciphertext string, key []byte) ([]byte, error) {
|
|
||||||
block, err := aes.NewCipher(key)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Decode base64
|
|
||||||
ciphertext, err := base64.StdEncoding.DecodeString(base64Ciphertext)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Println("error decoding base64:", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Extract the IV from the ciphertext
|
|
||||||
iv := ciphertext[:aes.BlockSize]
|
|
||||||
ciphertext = ciphertext[aes.BlockSize:]
|
|
||||||
|
|
||||||
// Create a CBC mode cipher block
|
|
||||||
mode := cipher.NewCBCDecrypter(block, iv)
|
|
||||||
|
|
||||||
// Decrypt the data
|
|
||||||
mode.CryptBlocks(ciphertext, ciphertext)
|
|
||||||
|
|
||||||
// Remove padding
|
|
||||||
ciphertext = pkcs7Unpad(ciphertext)
|
|
||||||
|
|
||||||
return ciphertext, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// pkcs7Pad pads the input to a multiple of blockSize using PKCS#7 padding
|
|
||||||
func pkcs7Pad(data []byte, blockSize int) []byte {
|
|
||||||
padding := blockSize - len(data)%blockSize
|
|
||||||
padText := bytes.Repeat([]byte{byte(padding)}, padding)
|
|
||||||
return append(data, padText...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// pkcs7Unpad removes PKCS#7 padding from the input
|
|
||||||
func pkcs7Unpad(data []byte) []byte {
|
|
||||||
padding := int(data[len(data)-1])
|
|
||||||
return data[:len(data)-padding]
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -1 +1,144 @@
|
||||||
package services
|
package services
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/base32"
|
||||||
|
"encoding/base64"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"github.com/go-playground/validator/v10"
|
||||||
|
"github.com/pquerna/otp"
|
||||||
|
"github.com/pquerna/otp/hotp"
|
||||||
|
"go.mongodb.org/mongo-driver/bson"
|
||||||
|
"go.mongodb.org/mongo-driver/mongo"
|
||||||
|
"golang.org/x/crypto/bcrypt"
|
||||||
|
"linhdevtran99/rest-api/models"
|
||||||
|
"linhdevtran99/rest-api/utils"
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Check the user register field is valid or not
|
||||||
|
func CheckAndValidRegisterFiled(registerData *models.CreateUser, w http.ResponseWriter) bool {
|
||||||
|
_ = models.Validate.RegisterValidation("customPassword", models.PasswordValidator)
|
||||||
|
errs := models.Validate.Struct(registerData)
|
||||||
|
var errStack []string
|
||||||
|
if errs != nil {
|
||||||
|
for _, err := range errs.(validator.ValidationErrors) {
|
||||||
|
switch err.Field() {
|
||||||
|
case "Email":
|
||||||
|
{
|
||||||
|
fmt.Println("Email không hợp lệ")
|
||||||
|
errStack = append(errStack, "Email")
|
||||||
|
}
|
||||||
|
case "Username":
|
||||||
|
{
|
||||||
|
fmt.Println("User không hợp lệ")
|
||||||
|
errStack = append(errStack, "User")
|
||||||
|
}
|
||||||
|
case "Password":
|
||||||
|
{
|
||||||
|
fmt.Println("Password không hợp lệ")
|
||||||
|
errStack = append(errStack, "Password")
|
||||||
|
}
|
||||||
|
case "ConfirmPassword":
|
||||||
|
{
|
||||||
|
fmt.Println("Nhập lại mật khẩu sai")
|
||||||
|
errStack = append(errStack, "ConfirmPassword")
|
||||||
|
}
|
||||||
|
case "PhoneNumber":
|
||||||
|
{
|
||||||
|
fmt.Println("SĐT không hợp lệ")
|
||||||
|
errStack = append(errStack, "PhoneNumber")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//handle repose error
|
||||||
|
w.WriteHeader(http.StatusBadRequest)
|
||||||
|
err := json.NewEncoder(w).Encode(errStack)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("There is error in write reponse at checking info user")
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Checking in db is user input same data in
|
||||||
|
func CheckAccountExist(mongoClient *mongo.Client, userName string, email string, w http.ResponseWriter) bool {
|
||||||
|
//filter in mongodb
|
||||||
|
var isValid bool
|
||||||
|
|
||||||
|
filter := bson.D{
|
||||||
|
{"$or", bson.A{
|
||||||
|
bson.D{{"username", userName}},
|
||||||
|
bson.D{{"email", email}},
|
||||||
|
}},
|
||||||
|
}
|
||||||
|
|
||||||
|
userData := mongoClient.Database("Totoday-shop").Collection("users")
|
||||||
|
|
||||||
|
var result models.UsersMongo
|
||||||
|
err := userData.FindOne(context.TODO(), filter).Decode(&result)
|
||||||
|
if err != nil {
|
||||||
|
isValid = true
|
||||||
|
}
|
||||||
|
if err == nil {
|
||||||
|
fmt.Println("Email or username already had register")
|
||||||
|
w.WriteHeader(http.StatusBadRequest)
|
||||||
|
err := json.NewEncoder(w).Encode("Your username or email had been register before")
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("There is error in write reponse at checking data user register")
|
||||||
|
}
|
||||||
|
isValid = false
|
||||||
|
}
|
||||||
|
|
||||||
|
return isValid
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate HOtp for confirm infomation
|
||||||
|
func GeneratorOtp(userName string, email string, counter uint64, serect string) (bool, *models.OtpGenerate) {
|
||||||
|
|
||||||
|
serectBase32 := base32.StdEncoding.EncodeToString([]byte(serect + userName + email))
|
||||||
|
passCode, err := hotp.GenerateCodeCustom(serectBase32, counter, hotp.ValidateOpts{
|
||||||
|
Digits: 6,
|
||||||
|
Algorithm: otp.AlgorithmSHA256,
|
||||||
|
})
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("Fail to create OTP")
|
||||||
|
return false, &models.OtpGenerate{
|
||||||
|
PureOTP: "none",
|
||||||
|
HashOTP: "none",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
hashed, err := bcrypt.GenerateFromPassword([]byte(passCode), 5)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("Fail to create OTP")
|
||||||
|
return false, &models.OtpGenerate{
|
||||||
|
PureOTP: "none",
|
||||||
|
HashOTP: "none",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true, &models.OtpGenerate{
|
||||||
|
PureOTP: passCode,
|
||||||
|
HashOTP: string(hashed),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a alternative verify link
|
||||||
|
func CreateLinkVerify(registerInfo *models.CreateUser, secrect string) string {
|
||||||
|
|
||||||
|
data, _ := json.Marshal(registerInfo)
|
||||||
|
key := []byte(secrect)
|
||||||
|
|
||||||
|
ciphertext, _ := utils.EncryptAES(data, key)
|
||||||
|
|
||||||
|
cipherTextBase64 := base64.StdEncoding.EncodeToString(ciphertext)
|
||||||
|
|
||||||
|
return cipherTextBase64
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1 +1,79 @@
|
||||||
package utils
|
package utils
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"crypto/aes"
|
||||||
|
"crypto/cipher"
|
||||||
|
"crypto/rand"
|
||||||
|
"encoding/base64"
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
func EncryptAES(data []byte, key []byte) ([]byte, error) {
|
||||||
|
block, err := aes.NewCipher(key)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate a random IV (Initialization Vector)
|
||||||
|
iv := make([]byte, aes.BlockSize)
|
||||||
|
if _, err := rand.Read(iv); err != nil {
|
||||||
|
fmt.Println("error generating IV:", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pad the data to a multiple of the block size
|
||||||
|
data = pkcs7Pad(data, aes.BlockSize)
|
||||||
|
|
||||||
|
// Create a CBC mode cipher block
|
||||||
|
mode := cipher.NewCBCEncrypter(block, iv)
|
||||||
|
|
||||||
|
// Encrypt the data
|
||||||
|
ciphertext := make([]byte, len(data))
|
||||||
|
mode.CryptBlocks(ciphertext, data)
|
||||||
|
|
||||||
|
// Prepend the IV to the ciphertext
|
||||||
|
ciphertext = append(iv, ciphertext...)
|
||||||
|
|
||||||
|
return ciphertext, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func DecryptAES(base64Ciphertext string, key []byte) ([]byte, error) {
|
||||||
|
block, err := aes.NewCipher(key)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decode base64
|
||||||
|
ciphertext, err := base64.StdEncoding.DecodeString(base64Ciphertext)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("error decoding base64:", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extract the IV from the ciphertext
|
||||||
|
iv := ciphertext[:aes.BlockSize]
|
||||||
|
ciphertext = ciphertext[aes.BlockSize:]
|
||||||
|
|
||||||
|
// Create a CBC mode cipher block
|
||||||
|
mode := cipher.NewCBCDecrypter(block, iv)
|
||||||
|
|
||||||
|
// Decrypt the data
|
||||||
|
mode.CryptBlocks(ciphertext, ciphertext)
|
||||||
|
|
||||||
|
// Remove padding
|
||||||
|
ciphertext = pkcs7Unpad(ciphertext)
|
||||||
|
|
||||||
|
return ciphertext, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// pkcs7Pad pads the input to a multiple of blockSize using PKCS#7 padding
|
||||||
|
func pkcs7Pad(data []byte, blockSize int) []byte {
|
||||||
|
padding := blockSize - len(data)%blockSize
|
||||||
|
padText := bytes.Repeat([]byte{byte(padding)}, padding)
|
||||||
|
return append(data, padText...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// pkcs7Unpad removes PKCS#7 padding from the input
|
||||||
|
func pkcs7Unpad(data []byte) []byte {
|
||||||
|
padding := int(data[len(data)-1])
|
||||||
|
return data[:len(data)-padding]
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue