refactor: 抽取symm通用加解密分发并统一hashx未知算法错误语义

This commit is contained in:
兔子 2026-03-18 14:32:55 +08:00
parent 4fa79744e8
commit 8d0f32015c
Signed by: b612
GPG Key ID: 99DD2222B612B612
7 changed files with 341 additions and 564 deletions

View File

@ -71,6 +71,9 @@
- Stream APIs expanded across AES/SM4/DES/3DES and ChaCha20. - Stream APIs expanded across AES/SM4/DES/3DES and ChaCha20.
- Updated docs to include a security-first recommendation and algorithm capability matrix. - Updated docs to include a security-first recommendation and algorithm capability matrix.
- Updated dependencies and modules for current code paths (`gmsm`, `x/crypto`). - Updated dependencies and modules for current code paths (`gmsm`, `x/crypto`).
- Refactored duplicated AES/SM4 symmetric code paths by extracting shared dispatch/helpers in `symm`.
- Unified hash method validation semantics: `hashx.SumAll` and `hashx.FileSumAll` now return errors for unknown methods (aligned with `FileSum`).
- Updated `hashx` tests for unsupported-method behavior.
### Fixed ### Fixed
- Fixed Base128 encode/decode round-trip bug in `encodingx`. - Fixed Base128 encode/decode round-trip bug in `encodingx`.

View File

@ -133,6 +133,7 @@ func main() {
## 兼容性说明 ## 兼容性说明
库中保留了部分历史/兼容用途算法与接口(例如 `ECB``DES/3DES`)。如无兼容要求,建议优先使用 AEAD 方案。 库中保留了部分历史/兼容用途算法与接口(例如 `ECB``DES/3DES`)。如无兼容要求,建议优先使用 AEAD 方案。
- `hashx``SumAll` / `FileSumAll` / `FileSum` 对未知算法名会返回错误(不再静默忽略)。
## 许可证 ## 许可证

View File

@ -8,6 +8,7 @@ import (
"encoding/binary" "encoding/binary"
"encoding/hex" "encoding/hex"
"errors" "errors"
"fmt"
"hash" "hash"
"hash/crc32" "hash/crc32"
"io" "io"
@ -146,6 +147,27 @@ func Crc32AStr(data []byte) string {
return hex.EncodeToString(crc32aDigest(data)) return hex.EncodeToString(crc32aDigest(data))
} }
func buildHasher(method string) (hash.Hash, hash.Hash32, error) {
switch method {
case "md5":
return md5.New(), nil, nil
case "sha1":
return sha1.New(), nil, nil
case "sha224":
return sha256.New224(), nil, nil
case "sha256":
return sha256.New(), nil, nil
case "sha384":
return sha512.New384(), nil, nil
case "sha512":
return sha512.New(), nil, nil
case "crc32":
return nil, crc32.NewIEEE(), nil
default:
return nil, nil, fmt.Errorf("%w: %s", ErrUnsupportedMethod, method)
}
}
func SumAll(data []byte, methods []string) (map[string][]byte, error) { func SumAll(data []byte, methods []string) (map[string][]byte, error) {
if len(methods) == 0 { if len(methods) == 0 {
methods = []string{"sha512", "sha256", "sha384", "sha224", "sha1", "crc32", "md5"} methods = []string{"sha512", "sha256", "sha384", "sha224", "sha1", "crc32", "md5"}
@ -156,25 +178,15 @@ func SumAll(data []byte, methods []string) (map[string][]byte, error) {
var crc hash.Hash32 var crc hash.Hash32
for _, method := range methods { for _, method := range methods {
switch method { h, h32, err := buildHasher(method)
case "md5": if err != nil {
hashers[method] = md5.New() return nil, err
case "sha1":
hashers[method] = sha1.New()
case "sha224":
hashers[method] = sha256.New224()
case "sha256":
hashers[method] = sha256.New()
case "sha384":
hashers[method] = sha512.New384()
case "sha512":
hashers[method] = sha512.New()
case "crc32":
if crc == nil {
crc = crc32.NewIEEE()
} }
default: if h != nil {
// Keep compatibility with previous behavior: unknown methods are ignored. hashers[method] = h
}
if h32 != nil && crc == nil {
crc = h32
} }
} }
@ -206,40 +218,22 @@ func FileSum(filePath, method string, progress func(float64)) (string, error) {
return "", err return "", err
} }
h, h32, err := buildHasher(method)
if err != nil {
return "", err
}
var ( var (
h hash.Hash
h32 hash.Hash32
is32 bool
total int64 total int64
size = stat.Size() size = stat.Size()
) )
switch method {
case "sha512":
h = sha512.New()
case "sha384":
h = sha512.New384()
case "sha256":
h = sha256.New()
case "sha224":
h = sha256.New224()
case "sha1":
h = sha1.New()
case "md5":
h = md5.New()
case "crc32":
h32 = crc32.NewIEEE()
is32 = true
default:
return "", errors.New(ErrUnsupportedMethod.Error() + ": " + method)
}
buf := make([]byte, 1024*1024) buf := make([]byte, 1024*1024)
for { for {
n, readErr := fp.Read(buf) n, readErr := fp.Read(buf)
if n > 0 { if n > 0 {
total += int64(n) total += int64(n)
if is32 { if h32 != nil {
_, _ = h32.Write(buf[:n]) _, _ = h32.Write(buf[:n])
} else { } else {
_, _ = h.Write(buf[:n]) _, _ = h.Write(buf[:n])
@ -254,7 +248,7 @@ func FileSum(filePath, method string, progress func(float64)) (string, error) {
} }
} }
if is32 { if h32 != nil {
return hex.EncodeToString(h32.Sum(nil)), nil return hex.EncodeToString(h32.Sum(nil)), nil
} }
return hex.EncodeToString(h.Sum(nil)), nil return hex.EncodeToString(h.Sum(nil)), nil
@ -279,25 +273,15 @@ func FileSumAll(filePath string, methods []string, progress func(float64)) (map[
hashers := make(map[string]hash.Hash, len(methods)) hashers := make(map[string]hash.Hash, len(methods))
var crc hash.Hash32 var crc hash.Hash32
for _, method := range methods { for _, method := range methods {
switch method { h, h32, err := buildHasher(method)
case "md5": if err != nil {
hashers[method] = md5.New() return nil, err
case "sha1":
hashers[method] = sha1.New()
case "sha224":
hashers[method] = sha256.New224()
case "sha256":
hashers[method] = sha256.New()
case "sha384":
hashers[method] = sha512.New384()
case "sha512":
hashers[method] = sha512.New()
case "crc32":
if crc == nil {
crc = crc32.NewIEEE()
} }
default: if h != nil {
// Keep compatibility with previous behavior: unknown methods are ignored. hashers[method] = h
}
if h32 != nil && crc == nil {
crc = h32
} }
} }
@ -335,7 +319,6 @@ func FileSumAll(filePath string, methods []string, progress func(float64)) (map[
} }
return result, nil return result, nil
} }
func reportProgress(progress func(float64), current, total int64) { func reportProgress(progress func(float64), current, total int64) {
if progress == nil { if progress == nil {
return return

View File

@ -29,16 +29,10 @@ func TestSM3AndCRC32A(t *testing.T) {
} }
} }
func TestSumAllUnknownMethodIgnored(t *testing.T) { func TestSumAllUnsupportedMethod(t *testing.T) {
res, err := SumAll([]byte("abc"), []string{"sha1", "unknown"}) _, err := SumAll([]byte("abc"), []string{"sha1", "unknown"})
if err != nil { if err == nil {
t.Fatalf("SumAll returned error: %v", err) t.Fatalf("expected unsupported method error")
}
if _, ok := res["sha1"]; !ok {
t.Fatalf("expected sha1 in result")
}
if _, ok := res["unknown"]; ok {
t.Fatalf("unknown method should be ignored")
} }
} }
@ -63,7 +57,7 @@ func TestFileSumAndFileSumAll(t *testing.T) {
t.Fatalf("progress callback should be called") t.Fatalf("progress callback should be called")
} }
all, err := FileSumAll(path, []string{"sha1", "crc32", "unknown"}, nil) all, err := FileSumAll(path, []string{"sha1", "crc32"}, nil)
if err != nil { if err != nil {
t.Fatalf("FileSumAll failed: %v", err) t.Fatalf("FileSumAll failed: %v", err)
} }
@ -73,9 +67,6 @@ func TestFileSumAndFileSumAll(t *testing.T) {
if _, ok := all["crc32"]; !ok { if _, ok := all["crc32"]; !ok {
t.Fatalf("expected crc32 in FileSumAll") t.Fatalf("expected crc32 in FileSumAll")
} }
if _, ok := all["unknown"]; ok {
t.Fatalf("unknown method should not appear")
}
} }
func TestFileSumUnsupportedMethod(t *testing.T) { func TestFileSumUnsupportedMethod(t *testing.T) {
@ -88,6 +79,18 @@ func TestFileSumUnsupportedMethod(t *testing.T) {
t.Fatalf("expected unsupported method error") t.Fatalf("expected unsupported method error")
} }
} }
func TestFileSumAllUnsupportedMethod(t *testing.T) {
dir := t.TempDir()
path := filepath.Join(dir, "sum.txt")
if err := os.WriteFile(path, []byte("x"), 0o644); err != nil {
t.Fatalf("WriteFile failed: %v", err)
}
if _, err := FileSumAll(path, []string{"sha256", "not-support"}, nil); err == nil {
t.Fatalf("expected unsupported method error")
}
}
func TestPBKDF2SHA256Vector(t *testing.T) { func TestPBKDF2SHA256Vector(t *testing.T) {
got, err := DerivePBKDF2SHA256Key("password", []byte("salt"), 1, 32) got, err := DerivePBKDF2SHA256Key("password", []byte("salt"), 1, 32)
if err != nil { if err != nil {

View File

@ -2,12 +2,10 @@ package symm
import ( import (
"crypto/aes" "crypto/aes"
"crypto/cipher"
"crypto/rand" "crypto/rand"
"errors" "errors"
"io" "io"
"b612.me/starcrypto/ccm"
"b612.me/starcrypto/paddingx" "b612.me/starcrypto/paddingx"
) )
@ -28,306 +26,90 @@ const (
aeadCCMNonceSize = 12 aeadCCMNonceSize = 12
) )
func EncryptAes(data, key, iv []byte, mode, paddingType string) ([]byte, error) { var (
normalizedMode := normalizeCipherMode(mode) aesGCMFactory = newGCMFactory(aes.NewCipher)
if normalizedMode == "" { aesCCMFactory = newCCMFactory(aes.NewCipher)
normalizedMode = MODEGCM )
}
if normalizedMode == MODEGCM {
return EncryptAesGCM(data, key, iv, nil)
}
if normalizedMode == MODECCM {
return EncryptAesCCM(data, key, iv, nil)
}
block, err := aes.NewCipher(key) func EncryptAes(data, key, iv []byte, mode, paddingType string) ([]byte, error) {
if err != nil { return encryptBlockCipher(data, key, iv, mode, paddingType, PKCS7PADDING, aes.NewCipher, EncryptAesGCM, EncryptAesCCM)
return nil, err
}
return encryptWithBlockMode(block, data, iv, normalizedMode, paddingType, PKCS7PADDING)
} }
func DecryptAes(src, key, iv []byte, mode, paddingType string) ([]byte, error) { func DecryptAes(src, key, iv []byte, mode, paddingType string) ([]byte, error) {
normalizedMode := normalizeCipherMode(mode) return decryptBlockCipher(src, key, iv, mode, paddingType, PKCS7PADDING, aes.NewCipher, DecryptAesGCM, DecryptAesCCM)
if normalizedMode == "" {
normalizedMode = MODEGCM
}
if normalizedMode == MODEGCM {
return DecryptAesGCM(src, key, iv, nil)
}
if normalizedMode == MODECCM {
return DecryptAesCCM(src, key, iv, nil)
}
block, err := aes.NewCipher(key)
if err != nil {
return nil, err
}
return decryptWithBlockMode(block, src, iv, normalizedMode, paddingType, PKCS7PADDING)
} }
func EncryptAesStream(dst io.Writer, src io.Reader, key, iv []byte, mode, paddingType string) error { func EncryptAesStream(dst io.Writer, src io.Reader, key, iv []byte, mode, paddingType string) error {
normalizedMode := normalizeCipherMode(mode) return encryptBlockCipherStream(dst, src, key, iv, mode, paddingType, PKCS7PADDING, aes.NewCipher, EncryptAesGCMStream, EncryptAesCCMStream)
if normalizedMode == "" {
normalizedMode = MODEGCM
}
if normalizedMode == MODEGCM {
return EncryptAesGCMStream(dst, src, key, iv, nil)
}
if normalizedMode == MODECCM {
return EncryptAesCCMStream(dst, src, key, iv, nil)
}
block, err := aes.NewCipher(key)
if err != nil {
return err
}
return encryptWithBlockModeStream(block, dst, src, iv, normalizedMode, paddingType, PKCS7PADDING)
} }
func DecryptAesStream(dst io.Writer, src io.Reader, key, iv []byte, mode, paddingType string) error { func DecryptAesStream(dst io.Writer, src io.Reader, key, iv []byte, mode, paddingType string) error {
normalizedMode := normalizeCipherMode(mode) return decryptBlockCipherStream(dst, src, key, iv, mode, paddingType, PKCS7PADDING, aes.NewCipher, DecryptAesGCMStream, DecryptAesCCMStream)
if normalizedMode == "" {
normalizedMode = MODEGCM
}
if normalizedMode == MODEGCM {
return DecryptAesGCMStream(dst, src, key, iv, nil)
}
if normalizedMode == MODECCM {
return DecryptAesCCMStream(dst, src, key, iv, nil)
}
block, err := aes.NewCipher(key)
if err != nil {
return err
}
return decryptWithBlockModeStream(block, dst, src, iv, normalizedMode, paddingType, PKCS7PADDING)
} }
func EncryptAesWithOptions(data, key []byte, opts *CipherOptions) ([]byte, error) { func EncryptAesWithOptions(data, key []byte, opts *CipherOptions) ([]byte, error) {
cfg := normalizeCipherOptions(opts) return encryptBlockWithOptions(data, key, opts, EncryptAesGCM, EncryptAesCCM, EncryptAes)
mode := normalizeCipherMode(cfg.Mode)
if mode == "" {
mode = MODEGCM
}
if mode == MODEGCM {
return EncryptAesGCM(data, key, nonceFromOptions(cfg), cfg.AAD)
}
if mode == MODECCM {
return EncryptAesCCM(data, key, nonceFromOptions(cfg), cfg.AAD)
}
return EncryptAes(data, key, cfg.IV, mode, cfg.Padding)
} }
func DecryptAesWithOptions(src, key []byte, opts *CipherOptions) ([]byte, error) { func DecryptAesWithOptions(src, key []byte, opts *CipherOptions) ([]byte, error) {
cfg := normalizeCipherOptions(opts) return decryptBlockWithOptions(src, key, opts, DecryptAesGCM, DecryptAesCCM, DecryptAes)
mode := normalizeCipherMode(cfg.Mode)
if mode == "" {
mode = MODEGCM
}
if mode == MODEGCM {
return DecryptAesGCM(src, key, nonceFromOptions(cfg), cfg.AAD)
}
if mode == MODECCM {
return DecryptAesCCM(src, key, nonceFromOptions(cfg), cfg.AAD)
}
return DecryptAes(src, key, cfg.IV, mode, cfg.Padding)
} }
func EncryptAesStreamWithOptions(dst io.Writer, src io.Reader, key []byte, opts *CipherOptions) error { func EncryptAesStreamWithOptions(dst io.Writer, src io.Reader, key []byte, opts *CipherOptions) error {
cfg := normalizeCipherOptions(opts) return encryptBlockStreamWithOptions(dst, src, key, opts, EncryptAesGCMStream, EncryptAesCCMStream, EncryptAesStream)
mode := normalizeCipherMode(cfg.Mode)
if mode == "" {
mode = MODEGCM
}
if mode == MODEGCM {
return EncryptAesGCMStream(dst, src, key, nonceFromOptions(cfg), cfg.AAD)
}
if mode == MODECCM {
return EncryptAesCCMStream(dst, src, key, nonceFromOptions(cfg), cfg.AAD)
}
return EncryptAesStream(dst, src, key, cfg.IV, mode, cfg.Padding)
} }
func DecryptAesStreamWithOptions(dst io.Writer, src io.Reader, key []byte, opts *CipherOptions) error { func DecryptAesStreamWithOptions(dst io.Writer, src io.Reader, key []byte, opts *CipherOptions) error {
cfg := normalizeCipherOptions(opts) return decryptBlockStreamWithOptions(dst, src, key, opts, DecryptAesGCMStream, DecryptAesCCMStream, DecryptAesStream)
mode := normalizeCipherMode(cfg.Mode)
if mode == "" {
mode = MODEGCM
}
if mode == MODEGCM {
return DecryptAesGCMStream(dst, src, key, nonceFromOptions(cfg), cfg.AAD)
}
if mode == MODECCM {
return DecryptAesCCMStream(dst, src, key, nonceFromOptions(cfg), cfg.AAD)
}
return DecryptAesStream(dst, src, key, cfg.IV, mode, cfg.Padding)
} }
func EncryptAesGCM(plain, key, nonce, aad []byte) ([]byte, error) { func EncryptAesGCM(plain, key, nonce, aad []byte) ([]byte, error) {
block, err := aes.NewCipher(key) return encryptAEAD(aesGCMFactory, plain, key, nonce, aad, ErrInvalidGCMNonceLength)
if err != nil {
return nil, err
}
gcm, err := cipher.NewGCM(block)
if err != nil {
return nil, err
}
if len(nonce) != gcm.NonceSize() {
return nil, ErrInvalidGCMNonceLength
}
return gcm.Seal(nil, nonce, plain, aad), nil
} }
func DecryptAesGCM(ciphertext, key, nonce, aad []byte) ([]byte, error) { func DecryptAesGCM(ciphertext, key, nonce, aad []byte) ([]byte, error) {
block, err := aes.NewCipher(key) return decryptAEAD(aesGCMFactory, ciphertext, key, nonce, aad, ErrInvalidGCMNonceLength)
if err != nil {
return nil, err
}
gcm, err := cipher.NewGCM(block)
if err != nil {
return nil, err
}
if len(nonce) != gcm.NonceSize() {
return nil, ErrInvalidGCMNonceLength
}
return gcm.Open(nil, nonce, ciphertext, aad)
}
func newAesCCM(key []byte) (cipher.AEAD, error) {
block, err := aes.NewCipher(key)
if err != nil {
return nil, err
}
return ccm.NewCCM(block, aeadCCMTagSize, aeadCCMNonceSize)
} }
func EncryptAesCCM(plain, key, nonce, aad []byte) ([]byte, error) { func EncryptAesCCM(plain, key, nonce, aad []byte) ([]byte, error) {
aead, err := newAesCCM(key) return encryptAEAD(aesCCMFactory, plain, key, nonce, aad, ErrInvalidCCMNonceLength)
if err != nil {
return nil, err
}
if len(nonce) != aead.NonceSize() {
return nil, ErrInvalidCCMNonceLength
}
return aead.Seal(nil, nonce, plain, aad), nil
} }
func DecryptAesCCM(ciphertext, key, nonce, aad []byte) ([]byte, error) { func DecryptAesCCM(ciphertext, key, nonce, aad []byte) ([]byte, error) {
aead, err := newAesCCM(key) return decryptAEAD(aesCCMFactory, ciphertext, key, nonce, aad, ErrInvalidCCMNonceLength)
if err != nil {
return nil, err
}
if len(nonce) != aead.NonceSize() {
return nil, ErrInvalidCCMNonceLength
}
return aead.Open(nil, nonce, ciphertext, aad)
} }
func EncryptAesCCMChunk(plain, key, nonce, aad []byte, chunkIndex uint64) ([]byte, error) { func EncryptAesCCMChunk(plain, key, nonce, aad []byte, chunkIndex uint64) ([]byte, error) {
aead, err := newAesCCM(key) return encryptAEADChunk(aesCCMFactory, plain, key, nonce, aad, chunkIndex, ErrInvalidCCMNonceLength, encryptCCMChunk)
if err != nil {
return nil, err
}
if len(nonce) != aead.NonceSize() {
return nil, ErrInvalidCCMNonceLength
}
return encryptCCMChunk(aead, plain, nonce, aad, chunkIndex), nil
} }
func DecryptAesCCMChunk(ciphertext, key, nonce, aad []byte, chunkIndex uint64) ([]byte, error) { func DecryptAesCCMChunk(ciphertext, key, nonce, aad []byte, chunkIndex uint64) ([]byte, error) {
aead, err := newAesCCM(key) return decryptAEADChunk(aesCCMFactory, ciphertext, key, nonce, aad, chunkIndex, ErrInvalidCCMNonceLength, decryptCCMChunk)
if err != nil {
return nil, err
}
if len(nonce) != aead.NonceSize() {
return nil, ErrInvalidCCMNonceLength
}
return decryptCCMChunk(aead, ciphertext, nonce, aad, chunkIndex)
} }
func EncryptAesCCMStream(dst io.Writer, src io.Reader, key, nonce, aad []byte) error { func EncryptAesCCMStream(dst io.Writer, src io.Reader, key, nonce, aad []byte) error {
aead, err := newAesCCM(key) return encryptAEADStream(aesCCMFactory, dst, src, key, nonce, aad, ErrInvalidCCMNonceLength, encryptCCMChunkedStream)
if err != nil {
return err
}
if len(nonce) != aead.NonceSize() {
return ErrInvalidCCMNonceLength
}
return encryptCCMChunkedStream(dst, src, aead, nonce, aad)
} }
func DecryptAesCCMStream(dst io.Writer, src io.Reader, key, nonce, aad []byte) error { func DecryptAesCCMStream(dst io.Writer, src io.Reader, key, nonce, aad []byte) error {
aead, err := newAesCCM(key) return decryptAEADStream(aesCCMFactory, dst, src, key, nonce, aad, ErrInvalidCCMNonceLength, decryptCCMChunkedOrLegacyStream)
if err != nil {
return err
}
if len(nonce) != aead.NonceSize() {
return ErrInvalidCCMNonceLength
}
return decryptCCMChunkedOrLegacyStream(dst, src, aead, nonce, aad)
} }
func EncryptAesGCMChunk(plain, key, nonce, aad []byte, chunkIndex uint64) ([]byte, error) { func EncryptAesGCMChunk(plain, key, nonce, aad []byte, chunkIndex uint64) ([]byte, error) {
block, err := aes.NewCipher(key) return encryptAEADChunk(aesGCMFactory, plain, key, nonce, aad, chunkIndex, ErrInvalidGCMNonceLength, encryptGCMChunk)
if err != nil {
return nil, err
}
gcm, err := cipher.NewGCM(block)
if err != nil {
return nil, err
}
if len(nonce) != gcm.NonceSize() {
return nil, ErrInvalidGCMNonceLength
}
return encryptGCMChunk(gcm, plain, nonce, aad, chunkIndex), nil
} }
func DecryptAesGCMChunk(ciphertext, key, nonce, aad []byte, chunkIndex uint64) ([]byte, error) { func DecryptAesGCMChunk(ciphertext, key, nonce, aad []byte, chunkIndex uint64) ([]byte, error) {
block, err := aes.NewCipher(key) return decryptAEADChunk(aesGCMFactory, ciphertext, key, nonce, aad, chunkIndex, ErrInvalidGCMNonceLength, decryptGCMChunk)
if err != nil {
return nil, err
}
gcm, err := cipher.NewGCM(block)
if err != nil {
return nil, err
}
if len(nonce) != gcm.NonceSize() {
return nil, ErrInvalidGCMNonceLength
}
return decryptGCMChunk(gcm, ciphertext, nonce, aad, chunkIndex)
} }
func EncryptAesGCMStream(dst io.Writer, src io.Reader, key, nonce, aad []byte) error { func EncryptAesGCMStream(dst io.Writer, src io.Reader, key, nonce, aad []byte) error {
block, err := aes.NewCipher(key) return encryptAEADStream(aesGCMFactory, dst, src, key, nonce, aad, ErrInvalidGCMNonceLength, encryptGCMChunkedStream)
if err != nil {
return err
}
gcm, err := cipher.NewGCM(block)
if err != nil {
return err
}
if len(nonce) != gcm.NonceSize() {
return ErrInvalidGCMNonceLength
}
return encryptGCMChunkedStream(dst, src, gcm, nonce, aad)
} }
func DecryptAesGCMStream(dst io.Writer, src io.Reader, key, nonce, aad []byte) error { func DecryptAesGCMStream(dst io.Writer, src io.Reader, key, nonce, aad []byte) error {
block, err := aes.NewCipher(key) return decryptAEADStream(aesGCMFactory, dst, src, key, nonce, aad, ErrInvalidGCMNonceLength, decryptGCMChunkedOrLegacyStream)
if err != nil {
return err
} }
gcm, err := cipher.NewGCM(block)
if err != nil {
return err
}
if len(nonce) != gcm.NonceSize() {
return ErrInvalidGCMNonceLength
}
return decryptGCMChunkedOrLegacyStream(dst, src, gcm, nonce, aad)
}
func EncryptAesECB(data, key []byte, paddingType string) ([]byte, error) { func EncryptAesECB(data, key []byte, paddingType string) ([]byte, error) {
return EncryptAes(data, key, nil, MODEECB, paddingType) return EncryptAes(data, key, nil, MODEECB, paddingType)
} }

223
symm/cipher_common.go Normal file
View File

@ -0,0 +1,223 @@
package symm
import (
"crypto/cipher"
"io"
"b612.me/starcrypto/ccm"
)
type blockCipherFactory func(key []byte) (cipher.Block, error)
type aeadFactory func(key []byte) (cipher.AEAD, error)
type aeadBytesFunc func(data, key, nonce, aad []byte) ([]byte, error)
type aeadStreamFunc func(dst io.Writer, src io.Reader, key, nonce, aad []byte) error
type blockModeBytesFunc func(data, key, iv []byte, mode, paddingType string) ([]byte, error)
type blockModeStreamFunc func(dst io.Writer, src io.Reader, key, iv []byte, mode, paddingType string) error
type aeadChunkEncryptFunc func(aead cipher.AEAD, plain, nonce, aad []byte, chunkIndex uint64) []byte
type aeadChunkDecryptFunc func(aead cipher.AEAD, ciphertext, nonce, aad []byte, chunkIndex uint64) ([]byte, error)
type aeadStreamCodec func(dst io.Writer, src io.Reader, aead cipher.AEAD, nonce, aad []byte) error
func newGCMFactory(newBlock blockCipherFactory) aeadFactory {
return func(key []byte) (cipher.AEAD, error) {
block, err := newBlock(key)
if err != nil {
return nil, err
}
return cipher.NewGCM(block)
}
}
func newCCMFactory(newBlock blockCipherFactory) aeadFactory {
return func(key []byte) (cipher.AEAD, error) {
block, err := newBlock(key)
if err != nil {
return nil, err
}
return ccm.NewCCM(block, aeadCCMTagSize, aeadCCMNonceSize)
}
}
func normalizeModeOrDefaultAEAD(mode string) string {
mode = normalizeCipherMode(mode)
if mode == "" {
mode = MODEGCM
}
return mode
}
func encryptBlockCipher(data, key, iv []byte, mode, paddingType, defaultPadding string, newBlock blockCipherFactory, encryptGCM, encryptCCM aeadBytesFunc) ([]byte, error) {
mode = normalizeModeOrDefaultAEAD(mode)
switch mode {
case MODEGCM:
return encryptGCM(data, key, iv, nil)
case MODECCM:
return encryptCCM(data, key, iv, nil)
default:
block, err := newBlock(key)
if err != nil {
return nil, err
}
return encryptWithBlockMode(block, data, iv, mode, paddingType, defaultPadding)
}
}
func decryptBlockCipher(src, key, iv []byte, mode, paddingType, defaultPadding string, newBlock blockCipherFactory, decryptGCM, decryptCCM aeadBytesFunc) ([]byte, error) {
mode = normalizeModeOrDefaultAEAD(mode)
switch mode {
case MODEGCM:
return decryptGCM(src, key, iv, nil)
case MODECCM:
return decryptCCM(src, key, iv, nil)
default:
block, err := newBlock(key)
if err != nil {
return nil, err
}
return decryptWithBlockMode(block, src, iv, mode, paddingType, defaultPadding)
}
}
func encryptBlockCipherStream(dst io.Writer, src io.Reader, key, iv []byte, mode, paddingType, defaultPadding string, newBlock blockCipherFactory, encryptGCMStream, encryptCCMStream aeadStreamFunc) error {
mode = normalizeModeOrDefaultAEAD(mode)
switch mode {
case MODEGCM:
return encryptGCMStream(dst, src, key, iv, nil)
case MODECCM:
return encryptCCMStream(dst, src, key, iv, nil)
default:
block, err := newBlock(key)
if err != nil {
return err
}
return encryptWithBlockModeStream(block, dst, src, iv, mode, paddingType, defaultPadding)
}
}
func decryptBlockCipherStream(dst io.Writer, src io.Reader, key, iv []byte, mode, paddingType, defaultPadding string, newBlock blockCipherFactory, decryptGCMStream, decryptCCMStream aeadStreamFunc) error {
mode = normalizeModeOrDefaultAEAD(mode)
switch mode {
case MODEGCM:
return decryptGCMStream(dst, src, key, iv, nil)
case MODECCM:
return decryptCCMStream(dst, src, key, iv, nil)
default:
block, err := newBlock(key)
if err != nil {
return err
}
return decryptWithBlockModeStream(block, dst, src, iv, mode, paddingType, defaultPadding)
}
}
func encryptBlockWithOptions(data, key []byte, opts *CipherOptions, encryptGCM, encryptCCM aeadBytesFunc, encryptBlock blockModeBytesFunc) ([]byte, error) {
cfg := normalizeCipherOptions(opts)
mode := normalizeModeOrDefaultAEAD(cfg.Mode)
switch mode {
case MODEGCM:
return encryptGCM(data, key, nonceFromOptions(cfg), cfg.AAD)
case MODECCM:
return encryptCCM(data, key, nonceFromOptions(cfg), cfg.AAD)
default:
return encryptBlock(data, key, cfg.IV, mode, cfg.Padding)
}
}
func decryptBlockWithOptions(data, key []byte, opts *CipherOptions, decryptGCM, decryptCCM aeadBytesFunc, decryptBlock blockModeBytesFunc) ([]byte, error) {
cfg := normalizeCipherOptions(opts)
mode := normalizeModeOrDefaultAEAD(cfg.Mode)
switch mode {
case MODEGCM:
return decryptGCM(data, key, nonceFromOptions(cfg), cfg.AAD)
case MODECCM:
return decryptCCM(data, key, nonceFromOptions(cfg), cfg.AAD)
default:
return decryptBlock(data, key, cfg.IV, mode, cfg.Padding)
}
}
func encryptBlockStreamWithOptions(dst io.Writer, src io.Reader, key []byte, opts *CipherOptions, encryptGCM, encryptCCM aeadStreamFunc, encryptBlockStream blockModeStreamFunc) error {
cfg := normalizeCipherOptions(opts)
mode := normalizeModeOrDefaultAEAD(cfg.Mode)
switch mode {
case MODEGCM:
return encryptGCM(dst, src, key, nonceFromOptions(cfg), cfg.AAD)
case MODECCM:
return encryptCCM(dst, src, key, nonceFromOptions(cfg), cfg.AAD)
default:
return encryptBlockStream(dst, src, key, cfg.IV, mode, cfg.Padding)
}
}
func decryptBlockStreamWithOptions(dst io.Writer, src io.Reader, key []byte, opts *CipherOptions, decryptGCM, decryptCCM aeadStreamFunc, decryptBlockStream blockModeStreamFunc) error {
cfg := normalizeCipherOptions(opts)
mode := normalizeModeOrDefaultAEAD(cfg.Mode)
switch mode {
case MODEGCM:
return decryptGCM(dst, src, key, nonceFromOptions(cfg), cfg.AAD)
case MODECCM:
return decryptCCM(dst, src, key, nonceFromOptions(cfg), cfg.AAD)
default:
return decryptBlockStream(dst, src, key, cfg.IV, mode, cfg.Padding)
}
}
func buildAEAD(factory aeadFactory, key, nonce []byte, errInvalidNonce error) (cipher.AEAD, error) {
aead, err := factory(key)
if err != nil {
return nil, err
}
if len(nonce) != aead.NonceSize() {
return nil, errInvalidNonce
}
return aead, nil
}
func encryptAEAD(factory aeadFactory, plain, key, nonce, aad []byte, errInvalidNonce error) ([]byte, error) {
aead, err := buildAEAD(factory, key, nonce, errInvalidNonce)
if err != nil {
return nil, err
}
return aead.Seal(nil, nonce, plain, aad), nil
}
func decryptAEAD(factory aeadFactory, ciphertext, key, nonce, aad []byte, errInvalidNonce error) ([]byte, error) {
aead, err := buildAEAD(factory, key, nonce, errInvalidNonce)
if err != nil {
return nil, err
}
return aead.Open(nil, nonce, ciphertext, aad)
}
func encryptAEADChunk(factory aeadFactory, plain, key, nonce, aad []byte, chunkIndex uint64, errInvalidNonce error, encryptChunk aeadChunkEncryptFunc) ([]byte, error) {
aead, err := buildAEAD(factory, key, nonce, errInvalidNonce)
if err != nil {
return nil, err
}
return encryptChunk(aead, plain, nonce, aad, chunkIndex), nil
}
func decryptAEADChunk(factory aeadFactory, ciphertext, key, nonce, aad []byte, chunkIndex uint64, errInvalidNonce error, decryptChunk aeadChunkDecryptFunc) ([]byte, error) {
aead, err := buildAEAD(factory, key, nonce, errInvalidNonce)
if err != nil {
return nil, err
}
return decryptChunk(aead, ciphertext, nonce, aad, chunkIndex)
}
func encryptAEADStream(factory aeadFactory, dst io.Writer, src io.Reader, key, nonce, aad []byte, errInvalidNonce error, encryptStream aeadStreamCodec) error {
aead, err := buildAEAD(factory, key, nonce, errInvalidNonce)
if err != nil {
return err
}
return encryptStream(dst, src, aead, nonce, aad)
}
func decryptAEADStream(factory aeadFactory, dst io.Writer, src io.Reader, key, nonce, aad []byte, errInvalidNonce error, decryptStream aeadStreamCodec) error {
aead, err := buildAEAD(factory, key, nonce, errInvalidNonce)
if err != nil {
return err
}
return decryptStream(dst, src, aead, nonce, aad)
}

View File

@ -1,315 +1,97 @@
package symm package symm
import ( import (
"crypto/cipher"
"crypto/rand" "crypto/rand"
"errors" "errors"
"io" "io"
"b612.me/starcrypto/ccm"
"github.com/emmansun/gmsm/sm4" "github.com/emmansun/gmsm/sm4"
) )
func EncryptSM4(data, key, iv []byte, mode, paddingType string) ([]byte, error) { var (
normalizedMode := normalizeCipherMode(mode) sm4GCMFactory = newGCMFactory(sm4.NewCipher)
if normalizedMode == "" { sm4CCMFactory = newCCMFactory(sm4.NewCipher)
normalizedMode = MODEGCM )
}
if normalizedMode == MODEGCM {
return EncryptSM4GCM(data, key, iv, nil)
}
if normalizedMode == MODECCM {
return EncryptSM4CCM(data, key, iv, nil)
}
block, err := sm4.NewCipher(key) func EncryptSM4(data, key, iv []byte, mode, paddingType string) ([]byte, error) {
if err != nil { return encryptBlockCipher(data, key, iv, mode, paddingType, PKCS7PADDING, sm4.NewCipher, EncryptSM4GCM, EncryptSM4CCM)
return nil, err
}
return encryptWithBlockMode(block, data, iv, normalizedMode, paddingType, PKCS7PADDING)
} }
func DecryptSM4(src, key, iv []byte, mode, paddingType string) ([]byte, error) { func DecryptSM4(src, key, iv []byte, mode, paddingType string) ([]byte, error) {
normalizedMode := normalizeCipherMode(mode) return decryptBlockCipher(src, key, iv, mode, paddingType, PKCS7PADDING, sm4.NewCipher, DecryptSM4GCM, DecryptSM4CCM)
if normalizedMode == "" {
normalizedMode = MODEGCM
}
if normalizedMode == MODEGCM {
return DecryptSM4GCM(src, key, iv, nil)
}
if normalizedMode == MODECCM {
return DecryptSM4CCM(src, key, iv, nil)
}
block, err := sm4.NewCipher(key)
if err != nil {
return nil, err
}
return decryptWithBlockMode(block, src, iv, normalizedMode, paddingType, PKCS7PADDING)
} }
func EncryptSM4Stream(dst io.Writer, src io.Reader, key, iv []byte, mode, paddingType string) error { func EncryptSM4Stream(dst io.Writer, src io.Reader, key, iv []byte, mode, paddingType string) error {
normalizedMode := normalizeCipherMode(mode) return encryptBlockCipherStream(dst, src, key, iv, mode, paddingType, PKCS7PADDING, sm4.NewCipher, EncryptSM4GCMStream, EncryptSM4CCMStream)
if normalizedMode == "" {
normalizedMode = MODEGCM
}
if normalizedMode == MODEGCM {
return EncryptSM4GCMStream(dst, src, key, iv, nil)
}
if normalizedMode == MODECCM {
return EncryptSM4CCMStream(dst, src, key, iv, nil)
}
block, err := sm4.NewCipher(key)
if err != nil {
return err
}
return encryptWithBlockModeStream(block, dst, src, iv, normalizedMode, paddingType, PKCS7PADDING)
} }
func DecryptSM4Stream(dst io.Writer, src io.Reader, key, iv []byte, mode, paddingType string) error { func DecryptSM4Stream(dst io.Writer, src io.Reader, key, iv []byte, mode, paddingType string) error {
normalizedMode := normalizeCipherMode(mode) return decryptBlockCipherStream(dst, src, key, iv, mode, paddingType, PKCS7PADDING, sm4.NewCipher, DecryptSM4GCMStream, DecryptSM4CCMStream)
if normalizedMode == "" {
normalizedMode = MODEGCM
}
if normalizedMode == MODEGCM {
return DecryptSM4GCMStream(dst, src, key, iv, nil)
}
if normalizedMode == MODECCM {
return DecryptSM4CCMStream(dst, src, key, iv, nil)
}
block, err := sm4.NewCipher(key)
if err != nil {
return err
}
return decryptWithBlockModeStream(block, dst, src, iv, normalizedMode, paddingType, PKCS7PADDING)
} }
func EncryptSM4WithOptions(data, key []byte, opts *CipherOptions) ([]byte, error) { func EncryptSM4WithOptions(data, key []byte, opts *CipherOptions) ([]byte, error) {
cfg := normalizeCipherOptions(opts) return encryptBlockWithOptions(data, key, opts, EncryptSM4GCM, EncryptSM4CCM, EncryptSM4)
mode := normalizeCipherMode(cfg.Mode)
if mode == "" {
mode = MODEGCM
}
if mode == MODEGCM {
return EncryptSM4GCM(data, key, nonceFromOptions(cfg), cfg.AAD)
}
if mode == MODECCM {
return EncryptSM4CCM(data, key, nonceFromOptions(cfg), cfg.AAD)
}
return EncryptSM4(data, key, cfg.IV, mode, cfg.Padding)
} }
func DecryptSM4WithOptions(src, key []byte, opts *CipherOptions) ([]byte, error) { func DecryptSM4WithOptions(src, key []byte, opts *CipherOptions) ([]byte, error) {
cfg := normalizeCipherOptions(opts) return decryptBlockWithOptions(src, key, opts, DecryptSM4GCM, DecryptSM4CCM, DecryptSM4)
mode := normalizeCipherMode(cfg.Mode)
if mode == "" {
mode = MODEGCM
}
if mode == MODEGCM {
return DecryptSM4GCM(src, key, nonceFromOptions(cfg), cfg.AAD)
}
if mode == MODECCM {
return DecryptSM4CCM(src, key, nonceFromOptions(cfg), cfg.AAD)
}
return DecryptSM4(src, key, cfg.IV, mode, cfg.Padding)
} }
func EncryptSM4StreamWithOptions(dst io.Writer, src io.Reader, key []byte, opts *CipherOptions) error { func EncryptSM4StreamWithOptions(dst io.Writer, src io.Reader, key []byte, opts *CipherOptions) error {
cfg := normalizeCipherOptions(opts) return encryptBlockStreamWithOptions(dst, src, key, opts, EncryptSM4GCMStream, EncryptSM4CCMStream, EncryptSM4Stream)
mode := normalizeCipherMode(cfg.Mode)
if mode == "" {
mode = MODEGCM
}
if mode == MODEGCM {
return EncryptSM4GCMStream(dst, src, key, nonceFromOptions(cfg), cfg.AAD)
}
if mode == MODECCM {
return EncryptSM4CCMStream(dst, src, key, nonceFromOptions(cfg), cfg.AAD)
}
return EncryptSM4Stream(dst, src, key, cfg.IV, mode, cfg.Padding)
} }
func DecryptSM4StreamWithOptions(dst io.Writer, src io.Reader, key []byte, opts *CipherOptions) error { func DecryptSM4StreamWithOptions(dst io.Writer, src io.Reader, key []byte, opts *CipherOptions) error {
cfg := normalizeCipherOptions(opts) return decryptBlockStreamWithOptions(dst, src, key, opts, DecryptSM4GCMStream, DecryptSM4CCMStream, DecryptSM4Stream)
mode := normalizeCipherMode(cfg.Mode)
if mode == "" {
mode = MODEGCM
}
if mode == MODEGCM {
return DecryptSM4GCMStream(dst, src, key, nonceFromOptions(cfg), cfg.AAD)
}
if mode == MODECCM {
return DecryptSM4CCMStream(dst, src, key, nonceFromOptions(cfg), cfg.AAD)
}
return DecryptSM4Stream(dst, src, key, cfg.IV, mode, cfg.Padding)
} }
func EncryptSM4GCM(plain, key, nonce, aad []byte) ([]byte, error) { func EncryptSM4GCM(plain, key, nonce, aad []byte) ([]byte, error) {
block, err := sm4.NewCipher(key) return encryptAEAD(sm4GCMFactory, plain, key, nonce, aad, ErrInvalidGCMNonceLength)
if err != nil {
return nil, err
}
gcm, err := cipher.NewGCM(block)
if err != nil {
return nil, err
}
if len(nonce) != gcm.NonceSize() {
return nil, ErrInvalidGCMNonceLength
}
return gcm.Seal(nil, nonce, plain, aad), nil
} }
func DecryptSM4GCM(ciphertext, key, nonce, aad []byte) ([]byte, error) { func DecryptSM4GCM(ciphertext, key, nonce, aad []byte) ([]byte, error) {
block, err := sm4.NewCipher(key) return decryptAEAD(sm4GCMFactory, ciphertext, key, nonce, aad, ErrInvalidGCMNonceLength)
if err != nil {
return nil, err
}
gcm, err := cipher.NewGCM(block)
if err != nil {
return nil, err
}
if len(nonce) != gcm.NonceSize() {
return nil, ErrInvalidGCMNonceLength
}
return gcm.Open(nil, nonce, ciphertext, aad)
} }
func EncryptSM4GCMChunk(plain, key, nonce, aad []byte, chunkIndex uint64) ([]byte, error) { func EncryptSM4GCMChunk(plain, key, nonce, aad []byte, chunkIndex uint64) ([]byte, error) {
block, err := sm4.NewCipher(key) return encryptAEADChunk(sm4GCMFactory, plain, key, nonce, aad, chunkIndex, ErrInvalidGCMNonceLength, encryptGCMChunk)
if err != nil {
return nil, err
}
gcm, err := cipher.NewGCM(block)
if err != nil {
return nil, err
}
if len(nonce) != gcm.NonceSize() {
return nil, ErrInvalidGCMNonceLength
}
return encryptGCMChunk(gcm, plain, nonce, aad, chunkIndex), nil
} }
func DecryptSM4GCMChunk(ciphertext, key, nonce, aad []byte, chunkIndex uint64) ([]byte, error) { func DecryptSM4GCMChunk(ciphertext, key, nonce, aad []byte, chunkIndex uint64) ([]byte, error) {
block, err := sm4.NewCipher(key) return decryptAEADChunk(sm4GCMFactory, ciphertext, key, nonce, aad, chunkIndex, ErrInvalidGCMNonceLength, decryptGCMChunk)
if err != nil {
return nil, err
}
gcm, err := cipher.NewGCM(block)
if err != nil {
return nil, err
}
if len(nonce) != gcm.NonceSize() {
return nil, ErrInvalidGCMNonceLength
}
return decryptGCMChunk(gcm, ciphertext, nonce, aad, chunkIndex)
} }
func EncryptSM4GCMStream(dst io.Writer, src io.Reader, key, nonce, aad []byte) error { func EncryptSM4GCMStream(dst io.Writer, src io.Reader, key, nonce, aad []byte) error {
block, err := sm4.NewCipher(key) return encryptAEADStream(sm4GCMFactory, dst, src, key, nonce, aad, ErrInvalidGCMNonceLength, encryptGCMChunkedStream)
if err != nil {
return err
}
gcm, err := cipher.NewGCM(block)
if err != nil {
return err
}
if len(nonce) != gcm.NonceSize() {
return ErrInvalidGCMNonceLength
}
return encryptGCMChunkedStream(dst, src, gcm, nonce, aad)
} }
func DecryptSM4GCMStream(dst io.Writer, src io.Reader, key, nonce, aad []byte) error { func DecryptSM4GCMStream(dst io.Writer, src io.Reader, key, nonce, aad []byte) error {
block, err := sm4.NewCipher(key) return decryptAEADStream(sm4GCMFactory, dst, src, key, nonce, aad, ErrInvalidGCMNonceLength, decryptGCMChunkedOrLegacyStream)
if err != nil {
return err
}
gcm, err := cipher.NewGCM(block)
if err != nil {
return err
}
if len(nonce) != gcm.NonceSize() {
return ErrInvalidGCMNonceLength
}
return decryptGCMChunkedOrLegacyStream(dst, src, gcm, nonce, aad)
}
func newSM4CCM(key []byte) (cipher.AEAD, error) {
block, err := sm4.NewCipher(key)
if err != nil {
return nil, err
}
return ccm.NewCCM(block, aeadCCMTagSize, aeadCCMNonceSize)
} }
func EncryptSM4CCM(plain, key, nonce, aad []byte) ([]byte, error) { func EncryptSM4CCM(plain, key, nonce, aad []byte) ([]byte, error) {
aead, err := newSM4CCM(key) return encryptAEAD(sm4CCMFactory, plain, key, nonce, aad, ErrInvalidCCMNonceLength)
if err != nil {
return nil, err
}
if len(nonce) != aead.NonceSize() {
return nil, ErrInvalidCCMNonceLength
}
return aead.Seal(nil, nonce, plain, aad), nil
} }
func DecryptSM4CCM(ciphertext, key, nonce, aad []byte) ([]byte, error) { func DecryptSM4CCM(ciphertext, key, nonce, aad []byte) ([]byte, error) {
aead, err := newSM4CCM(key) return decryptAEAD(sm4CCMFactory, ciphertext, key, nonce, aad, ErrInvalidCCMNonceLength)
if err != nil {
return nil, err
}
if len(nonce) != aead.NonceSize() {
return nil, ErrInvalidCCMNonceLength
}
return aead.Open(nil, nonce, ciphertext, aad)
} }
func EncryptSM4CCMChunk(plain, key, nonce, aad []byte, chunkIndex uint64) ([]byte, error) { func EncryptSM4CCMChunk(plain, key, nonce, aad []byte, chunkIndex uint64) ([]byte, error) {
aead, err := newSM4CCM(key) return encryptAEADChunk(sm4CCMFactory, plain, key, nonce, aad, chunkIndex, ErrInvalidCCMNonceLength, encryptCCMChunk)
if err != nil {
return nil, err
}
if len(nonce) != aead.NonceSize() {
return nil, ErrInvalidCCMNonceLength
}
return encryptCCMChunk(aead, plain, nonce, aad, chunkIndex), nil
} }
func DecryptSM4CCMChunk(ciphertext, key, nonce, aad []byte, chunkIndex uint64) ([]byte, error) { func DecryptSM4CCMChunk(ciphertext, key, nonce, aad []byte, chunkIndex uint64) ([]byte, error) {
aead, err := newSM4CCM(key) return decryptAEADChunk(sm4CCMFactory, ciphertext, key, nonce, aad, chunkIndex, ErrInvalidCCMNonceLength, decryptCCMChunk)
if err != nil {
return nil, err
}
if len(nonce) != aead.NonceSize() {
return nil, ErrInvalidCCMNonceLength
}
return decryptCCMChunk(aead, ciphertext, nonce, aad, chunkIndex)
} }
func EncryptSM4CCMStream(dst io.Writer, src io.Reader, key, nonce, aad []byte) error { func EncryptSM4CCMStream(dst io.Writer, src io.Reader, key, nonce, aad []byte) error {
aead, err := newSM4CCM(key) return encryptAEADStream(sm4CCMFactory, dst, src, key, nonce, aad, ErrInvalidCCMNonceLength, encryptCCMChunkedStream)
if err != nil {
return err
}
if len(nonce) != aead.NonceSize() {
return ErrInvalidCCMNonceLength
}
return encryptCCMChunkedStream(dst, src, aead, nonce, aad)
} }
func DecryptSM4CCMStream(dst io.Writer, src io.Reader, key, nonce, aad []byte) error { func DecryptSM4CCMStream(dst io.Writer, src io.Reader, key, nonce, aad []byte) error {
aead, err := newSM4CCM(key) return decryptAEADStream(sm4CCMFactory, dst, src, key, nonce, aad, ErrInvalidCCMNonceLength, decryptCCMChunkedOrLegacyStream)
if err != nil {
return err
} }
if len(nonce) != aead.NonceSize() {
return ErrInvalidCCMNonceLength
}
return decryptCCMChunkedOrLegacyStream(dst, src, aead, nonce, aad)
}
func EncryptSM4CFB(origData, key []byte) ([]byte, error) { func EncryptSM4CFB(origData, key []byte) ([]byte, error) {
block, err := sm4.NewCipher(key) block, err := sm4.NewCipher(key)
if err != nil { if err != nil {