277 lines
7.7 KiB
Go
277 lines
7.7 KiB
Go
|
|
package symm
|
||
|
|
|
||
|
|
import (
|
||
|
|
"crypto/cipher"
|
||
|
|
"crypto/rand"
|
||
|
|
"errors"
|
||
|
|
"io"
|
||
|
|
|
||
|
|
"github.com/emmansun/gmsm/sm4"
|
||
|
|
)
|
||
|
|
|
||
|
|
func EncryptSM4(data, key, iv []byte, mode, paddingType string) ([]byte, error) {
|
||
|
|
normalizedMode := normalizeCipherMode(mode)
|
||
|
|
if normalizedMode == MODEGCM {
|
||
|
|
return EncryptSM4GCM(data, key, iv, nil)
|
||
|
|
}
|
||
|
|
|
||
|
|
block, err := sm4.NewCipher(key)
|
||
|
|
if err != nil {
|
||
|
|
return nil, err
|
||
|
|
}
|
||
|
|
return encryptWithBlockMode(block, data, iv, normalizedMode, paddingType, PKCS7PADDING)
|
||
|
|
}
|
||
|
|
|
||
|
|
func DecryptSM4(src, key, iv []byte, mode, paddingType string) ([]byte, error) {
|
||
|
|
normalizedMode := normalizeCipherMode(mode)
|
||
|
|
if normalizedMode == MODEGCM {
|
||
|
|
return DecryptSM4GCM(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 {
|
||
|
|
normalizedMode := normalizeCipherMode(mode)
|
||
|
|
if normalizedMode == MODEGCM {
|
||
|
|
return EncryptSM4GCMStream(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 {
|
||
|
|
normalizedMode := normalizeCipherMode(mode)
|
||
|
|
if normalizedMode == MODEGCM {
|
||
|
|
return DecryptSM4GCMStream(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) {
|
||
|
|
cfg := normalizeCipherOptions(opts)
|
||
|
|
mode := normalizeCipherMode(cfg.Mode)
|
||
|
|
if mode == "" {
|
||
|
|
mode = MODEGCM
|
||
|
|
}
|
||
|
|
if mode == MODEGCM {
|
||
|
|
return EncryptSM4GCM(data, key, nonceFromOptions(cfg), cfg.AAD)
|
||
|
|
}
|
||
|
|
return EncryptSM4(data, key, cfg.IV, mode, cfg.Padding)
|
||
|
|
}
|
||
|
|
|
||
|
|
func DecryptSM4WithOptions(src, key []byte, opts *CipherOptions) ([]byte, error) {
|
||
|
|
cfg := normalizeCipherOptions(opts)
|
||
|
|
mode := normalizeCipherMode(cfg.Mode)
|
||
|
|
if mode == "" {
|
||
|
|
mode = MODEGCM
|
||
|
|
}
|
||
|
|
if mode == MODEGCM {
|
||
|
|
return DecryptSM4GCM(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 {
|
||
|
|
cfg := normalizeCipherOptions(opts)
|
||
|
|
mode := normalizeCipherMode(cfg.Mode)
|
||
|
|
if mode == "" {
|
||
|
|
mode = MODEGCM
|
||
|
|
}
|
||
|
|
if mode == MODEGCM {
|
||
|
|
return EncryptSM4GCMStream(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 {
|
||
|
|
cfg := normalizeCipherOptions(opts)
|
||
|
|
mode := normalizeCipherMode(cfg.Mode)
|
||
|
|
if mode == "" {
|
||
|
|
mode = MODEGCM
|
||
|
|
}
|
||
|
|
if mode == MODEGCM {
|
||
|
|
return DecryptSM4GCMStream(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) {
|
||
|
|
block, err := sm4.NewCipher(key)
|
||
|
|
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) {
|
||
|
|
block, err := sm4.NewCipher(key)
|
||
|
|
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 EncryptSM4GCMStream(dst io.Writer, src io.Reader, key, nonce, aad []byte) error {
|
||
|
|
plain, err := io.ReadAll(src)
|
||
|
|
if err != nil {
|
||
|
|
return err
|
||
|
|
}
|
||
|
|
out, err := EncryptSM4GCM(plain, key, nonce, aad)
|
||
|
|
if err != nil {
|
||
|
|
return err
|
||
|
|
}
|
||
|
|
_, err = dst.Write(out)
|
||
|
|
return err
|
||
|
|
}
|
||
|
|
|
||
|
|
func DecryptSM4GCMStream(dst io.Writer, src io.Reader, key, nonce, aad []byte) error {
|
||
|
|
enc, err := io.ReadAll(src)
|
||
|
|
if err != nil {
|
||
|
|
return err
|
||
|
|
}
|
||
|
|
out, err := DecryptSM4GCM(enc, key, nonce, aad)
|
||
|
|
if err != nil {
|
||
|
|
return err
|
||
|
|
}
|
||
|
|
_, err = dst.Write(out)
|
||
|
|
return err
|
||
|
|
}
|
||
|
|
|
||
|
|
func EncryptSM4CFB(origData, key []byte) ([]byte, error) {
|
||
|
|
block, err := sm4.NewCipher(key)
|
||
|
|
if err != nil {
|
||
|
|
return nil, err
|
||
|
|
}
|
||
|
|
out := make([]byte, block.BlockSize()+len(origData))
|
||
|
|
iv := out[:block.BlockSize()]
|
||
|
|
if _, err := io.ReadFull(rand.Reader, iv); err != nil {
|
||
|
|
return nil, err
|
||
|
|
}
|
||
|
|
body, err := EncryptSM4CFBNoBlock(origData, key, iv)
|
||
|
|
if err != nil {
|
||
|
|
return nil, err
|
||
|
|
}
|
||
|
|
copy(out[block.BlockSize():], body)
|
||
|
|
return out, nil
|
||
|
|
}
|
||
|
|
|
||
|
|
func DecryptSM4CFB(encrypted, key []byte) ([]byte, error) {
|
||
|
|
block, err := sm4.NewCipher(key)
|
||
|
|
if err != nil {
|
||
|
|
return nil, err
|
||
|
|
}
|
||
|
|
if len(encrypted) < block.BlockSize() {
|
||
|
|
return nil, errors.New("ciphertext too short")
|
||
|
|
}
|
||
|
|
iv := encrypted[:block.BlockSize()]
|
||
|
|
return DecryptSM4CFBNoBlock(encrypted[block.BlockSize():], key, iv)
|
||
|
|
}
|
||
|
|
|
||
|
|
func EncryptSM4CFBNoBlock(origData, key, iv []byte) ([]byte, error) {
|
||
|
|
return EncryptSM4(origData, key, iv, MODECFB, "")
|
||
|
|
}
|
||
|
|
|
||
|
|
func DecryptSM4CFBNoBlock(encrypted, key, iv []byte) ([]byte, error) {
|
||
|
|
return DecryptSM4(encrypted, key, iv, MODECFB, "")
|
||
|
|
}
|
||
|
|
|
||
|
|
func EncryptSM4ECB(data, key []byte, paddingType string) ([]byte, error) {
|
||
|
|
return EncryptSM4(data, key, nil, MODEECB, paddingType)
|
||
|
|
}
|
||
|
|
|
||
|
|
func DecryptSM4ECB(src, key []byte, paddingType string) ([]byte, error) {
|
||
|
|
return DecryptSM4(src, key, nil, MODEECB, paddingType)
|
||
|
|
}
|
||
|
|
|
||
|
|
func EncryptSM4CBC(data, key, iv []byte, paddingType string) ([]byte, error) {
|
||
|
|
return EncryptSM4(data, key, iv, MODECBC, paddingType)
|
||
|
|
}
|
||
|
|
|
||
|
|
func DecryptSM4CBC(src, key, iv []byte, paddingType string) ([]byte, error) {
|
||
|
|
return DecryptSM4(src, key, iv, MODECBC, paddingType)
|
||
|
|
}
|
||
|
|
|
||
|
|
func EncryptSM4OFB(data, key, iv []byte) ([]byte, error) {
|
||
|
|
return EncryptSM4(data, key, iv, MODEOFB, "")
|
||
|
|
}
|
||
|
|
|
||
|
|
func DecryptSM4OFB(src, key, iv []byte) ([]byte, error) {
|
||
|
|
return DecryptSM4(src, key, iv, MODEOFB, "")
|
||
|
|
}
|
||
|
|
|
||
|
|
func EncryptSM4CTR(data, key, iv []byte) ([]byte, error) {
|
||
|
|
return EncryptSM4(data, key, iv, MODECTR, "")
|
||
|
|
}
|
||
|
|
|
||
|
|
func DecryptSM4CTR(src, key, iv []byte) ([]byte, error) {
|
||
|
|
return DecryptSM4(src, key, iv, MODECTR, "")
|
||
|
|
}
|
||
|
|
|
||
|
|
func EncryptSM4ECBStream(dst io.Writer, src io.Reader, key []byte, paddingType string) error {
|
||
|
|
return EncryptSM4Stream(dst, src, key, nil, MODEECB, paddingType)
|
||
|
|
}
|
||
|
|
|
||
|
|
func DecryptSM4ECBStream(dst io.Writer, src io.Reader, key []byte, paddingType string) error {
|
||
|
|
return DecryptSM4Stream(dst, src, key, nil, MODEECB, paddingType)
|
||
|
|
}
|
||
|
|
|
||
|
|
func EncryptSM4CBCStream(dst io.Writer, src io.Reader, key, iv []byte, paddingType string) error {
|
||
|
|
return EncryptSM4Stream(dst, src, key, iv, MODECBC, paddingType)
|
||
|
|
}
|
||
|
|
|
||
|
|
func DecryptSM4CBCStream(dst io.Writer, src io.Reader, key, iv []byte, paddingType string) error {
|
||
|
|
return DecryptSM4Stream(dst, src, key, iv, MODECBC, paddingType)
|
||
|
|
}
|
||
|
|
|
||
|
|
func EncryptSM4CFBStream(dst io.Writer, src io.Reader, key, iv []byte) error {
|
||
|
|
return EncryptSM4Stream(dst, src, key, iv, MODECFB, "")
|
||
|
|
}
|
||
|
|
|
||
|
|
func DecryptSM4CFBStream(dst io.Writer, src io.Reader, key, iv []byte) error {
|
||
|
|
return DecryptSM4Stream(dst, src, key, iv, MODECFB, "")
|
||
|
|
}
|
||
|
|
|
||
|
|
func EncryptSM4OFBStream(dst io.Writer, src io.Reader, key, iv []byte) error {
|
||
|
|
return EncryptSM4Stream(dst, src, key, iv, MODEOFB, "")
|
||
|
|
}
|
||
|
|
|
||
|
|
func DecryptSM4OFBStream(dst io.Writer, src io.Reader, key, iv []byte) error {
|
||
|
|
return DecryptSM4Stream(dst, src, key, iv, MODEOFB, "")
|
||
|
|
}
|
||
|
|
|
||
|
|
func EncryptSM4CTRStream(dst io.Writer, src io.Reader, key, iv []byte) error {
|
||
|
|
return EncryptSM4Stream(dst, src, key, iv, MODECTR, "")
|
||
|
|
}
|
||
|
|
|
||
|
|
func DecryptSM4CTRStream(dst io.Writer, src io.Reader, key, iv []byte) error {
|
||
|
|
return DecryptSM4Stream(dst, src, key, iv, MODECTR, "")
|
||
|
|
}
|