fix: critical security fixes in core/codec (S0) (#5479)

This commit is contained in:
Kevin Wan
2026-03-15 16:40:15 +08:00
committed by GitHub
parent ec802e25a6
commit d1a014955c
6 changed files with 291 additions and 42 deletions

View File

@@ -6,8 +6,6 @@ import (
"crypto/cipher"
"encoding/base64"
"errors"
"github.com/zeromicro/go-zero/core/logx"
)
// ErrPaddingSize indicates bad padding size.
@@ -27,7 +25,8 @@ func newECB(b cipher.Block) *ecb {
type ecbEncrypter ecb
// NewECBEncrypter returns an ECB encrypter.
// Deprecated: NewECBEncrypter returns an ECB encrypter.
// ECB mode is insecure for multi-block data. Use AES-GCM instead.
func NewECBEncrypter(b cipher.Block) cipher.BlockMode {
return (*ecbEncrypter)(newECB(b))
}
@@ -39,12 +38,10 @@ func (x *ecbEncrypter) BlockSize() int { return x.blockSize }
// the block size. Dst and src must overlap entirely or not at all.
func (x *ecbEncrypter) CryptBlocks(dst, src []byte) {
if len(src)%x.blockSize != 0 {
logx.Error("crypto/cipher: input not full blocks")
return
panic("crypto/cipher: input not full blocks")
}
if len(dst) < len(src) {
logx.Error("crypto/cipher: output smaller than input")
return
panic("crypto/cipher: output smaller than input")
}
for len(src) > 0 {
@@ -56,7 +53,8 @@ func (x *ecbEncrypter) CryptBlocks(dst, src []byte) {
type ecbDecrypter ecb
// NewECBDecrypter returns an ECB decrypter.
// Deprecated: NewECBDecrypter returns an ECB decrypter.
// ECB mode is insecure for multi-block data. Use AES-GCM instead.
func NewECBDecrypter(b cipher.Block) cipher.BlockMode {
return (*ecbDecrypter)(newECB(b))
}
@@ -70,12 +68,10 @@ func (x *ecbDecrypter) BlockSize() int {
// the block size. Dst and src must overlap entirely or not at all.
func (x *ecbDecrypter) CryptBlocks(dst, src []byte) {
if len(src)%x.blockSize != 0 {
logx.Error("crypto/cipher: input not full blocks")
return
panic("crypto/cipher: input not full blocks")
}
if len(dst) < len(src) {
logx.Error("crypto/cipher: output smaller than input")
return
panic("crypto/cipher: output smaller than input")
}
for len(src) > 0 {
@@ -85,14 +81,18 @@ func (x *ecbDecrypter) CryptBlocks(dst, src []byte) {
}
}
// EcbDecrypt decrypts src with the given key.
// Deprecated: EcbDecrypt decrypts src with the given key.
// ECB mode is insecure for multi-block data. Use AES-GCM instead.
func EcbDecrypt(key, src []byte) ([]byte, error) {
block, err := aes.NewCipher(key)
if err != nil {
logx.Errorf("Decrypt key error: % x", key)
return nil, err
}
if len(src)%block.BlockSize() != 0 {
return nil, ErrPaddingSize
}
decrypter := NewECBDecrypter(block)
decrypted := make([]byte, len(src))
decrypter.CryptBlocks(decrypted, src)
@@ -100,8 +100,9 @@ func EcbDecrypt(key, src []byte) ([]byte, error) {
return pkcs5Unpadding(decrypted, decrypter.BlockSize())
}
// EcbDecryptBase64 decrypts base64 encoded src with the given base64 encoded key.
// Deprecated: EcbDecryptBase64 decrypts base64 encoded src with the given base64 encoded key.
// The returned string is also base64 encoded.
// ECB mode is insecure for multi-block data. Use AES-GCM instead.
func EcbDecryptBase64(key, src string) (string, error) {
keyBytes, err := getKeyBytes(key)
if err != nil {
@@ -121,11 +122,11 @@ func EcbDecryptBase64(key, src string) (string, error) {
return base64.StdEncoding.EncodeToString(decryptedBytes), nil
}
// EcbEncrypt encrypts src with the given key.
// Deprecated: EcbEncrypt encrypts src with the given key.
// ECB mode is insecure for multi-block data. Use AES-GCM instead.
func EcbEncrypt(key, src []byte) ([]byte, error) {
block, err := aes.NewCipher(key)
if err != nil {
logx.Errorf("Encrypt key error: % x", key)
return nil, err
}
@@ -137,8 +138,9 @@ func EcbEncrypt(key, src []byte) ([]byte, error) {
return crypted, nil
}
// EcbEncryptBase64 encrypts base64 encoded src with the given base64 encoded key.
// Deprecated: EcbEncryptBase64 encrypts base64 encoded src with the given base64 encoded key.
// The returned string is also base64 encoded.
// ECB mode is insecure for multi-block data. Use AES-GCM instead.
func EcbEncryptBase64(key, src string) (string, error) {
keyBytes, err := getKeyBytes(key)
if err != nil {
@@ -179,10 +181,20 @@ func pkcs5Padding(ciphertext []byte, blockSize int) []byte {
func pkcs5Unpadding(src []byte, blockSize int) ([]byte, error) {
length := len(src)
unpadding := int(src[length-1])
if unpadding >= length || unpadding > blockSize {
if length == 0 {
return nil, ErrPaddingSize
}
unpadding := int(src[length-1])
if unpadding < 1 || unpadding > blockSize || unpadding > length {
return nil, ErrPaddingSize
}
for _, b := range src[length-unpadding:] {
if int(b) != unpadding {
return nil, ErrPaddingSize
}
}
return src[:length-unpadding], nil
}