Skip to content

Commit

Permalink
feat: crypto/aesutil/aesecb: add DecryptBase64(), EncryptBase64()
Browse files Browse the repository at this point in the history
  • Loading branch information
grokify committed Jan 12, 2025
1 parent 700499f commit 8b4825f
Show file tree
Hide file tree
Showing 2 changed files with 119 additions and 0 deletions.
87 changes: 87 additions & 0 deletions crypto/aesutil/aesecb/aesecb.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
package aesecb

import (
"bytes"
"crypto/aes"
"crypto/cipher"
"encoding/base64"
"errors"
)

func DecryptBase64(v, key string) (string, error) {
if decoded, err := base64.StdEncoding.DecodeString(v); err != nil {
return "", err
} else if block, err := aes.NewCipher([]byte(key)); err != nil {
return "", err
} else if len(decoded)%aes.BlockSize != 0 {
return "", errors.New("ciphertext is not a multiple of the block size")
} else {
decrypted := make([]byte, len(decoded))
decryptECB(block, decrypted, decoded)

decrypted, err = removePKCS7Padding(decrypted, aes.BlockSize)
if err != nil {
return "", err
} else {
return string(decrypted), nil
}
}
}

// decryptECB performs the ECB mode decryption
func decryptECB(block cipher.Block, dst, src []byte) {
bs := block.BlockSize()
for len(src) > 0 {
block.Decrypt(dst, src[:bs])
src = src[bs:]
dst = dst[bs:]
}
}

// removePKCS7Padding removes padding from the decrypted data.
func removePKCS7Padding(data []byte, blockSize int) ([]byte, error) {
if len(data) == 0 || len(data)%blockSize != 0 {
return nil, errors.New("invalid padding size")
}

paddingLen := int(data[len(data)-1])
if paddingLen == 0 || paddingLen > blockSize {
return nil, errors.New("invalid padding")
}

for _, padByte := range data[len(data)-paddingLen:] {
if int(padByte) != paddingLen {
return nil, errors.New("invalid padding")
}
}

return data[:len(data)-paddingLen], nil
}

func EncryptBase64(v, key string) (string, error) {
paddedInput := addPKCS5Padding([]byte(v), aes.BlockSize)

if block, err := aes.NewCipher([]byte(key)); err != nil {
return "", err
} else {
encrypted := make([]byte, len(paddedInput))
encryptECB(block, encrypted, paddedInput)
return base64.StdEncoding.EncodeToString(encrypted), nil
}
}

// encryptECB performs the ECB mode encryption.
func encryptECB(block cipher.Block, dst, src []byte) {
bs := block.BlockSize()
for len(src) > 0 {
block.Encrypt(dst, src[:bs])
src = src[bs:]
dst = dst[bs:]
}
}

func addPKCS5Padding(data []byte, blockSize int) []byte {
padding := blockSize - len(data)%blockSize
padText := bytes.Repeat([]byte{byte(padding)}, padding)
return append(data, padText...)
}
32 changes: 32 additions & 0 deletions crypto/aesutil/aesecb/aesecb_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package aesecb

import (
"fmt"
"testing"
)

var aesecbTests = []struct {
plaintext string
key string
}{
{"My Secret Password", "0123456789abcdef"},
{"My Secret Password", "1234567890123456"},
}

func TestEncryptDecrypt(t *testing.T) {
for _, tt := range aesecbTests {
enc, err := EncryptBase64(tt.plaintext, tt.key)
if err != nil {
t.Errorf("aesecb.EncryptBase64 error(%s)", err.Error())
}
dec, err := DecryptBase64(enc, tt.key)
if err != nil {
t.Errorf("aesecb.DecryptBase64 error(%s)", err.Error())
}
if dec != tt.plaintext {
fmt.Printf("[%v]\n", []byte(dec))
fmt.Printf("[%v]\n", []byte(tt.plaintext))
t.Errorf("encrypt/decrypt AES ECB error: want decrypted (%s), got (%s)", tt.plaintext, dec)
}
}
}

0 comments on commit 8b4825f

Please sign in to comment.