github.com/hxx258456/ccgo@v0.0.5-0.20230213014102-48b35f46f66f/sm4/sm4.go (about) 1 // Copyright 2022 s1ren@github.com/hxx258456. 2 3 package sm4 4 5 import ( 6 "bytes" 7 "crypto/cipher" 8 "crypto/rand" 9 "errors" 10 "fmt" 11 "io" 12 ) 13 14 // PKCS7Padding 根据pkcs7标准填充明文 15 func PKCS7Padding(src []byte) []byte { 16 padding := BlockSize - len(src)%BlockSize 17 padtext := bytes.Repeat([]byte{byte(padding)}, padding) 18 return append(src, padtext...) 19 } 20 21 // PKCS7UnPadding 根据pkcs7标准去除填充 22 func PKCS7UnPadding(src []byte) ([]byte, error) { 23 length := len(src) 24 if length == 0 { 25 return nil, errors.New("invalid pkcs7 padding (len(padtext) == 0)") 26 } 27 unpadding := int(src[length-1]) 28 if unpadding > BlockSize || unpadding == 0 { 29 return nil, fmt.Errorf("invalid pkcs7 padding (unpadding > BlockSize || unpadding == 0). unpadding: %d, BlockSize: %d", unpadding, BlockSize) 30 } 31 32 pad := src[len(src)-unpadding:] 33 for i := 0; i < unpadding; i++ { 34 if pad[i] != byte(unpadding) { 35 return nil, errors.New("invalid pkcs7 padding (pad[i] != unpadding)") 36 } 37 } 38 39 return src[:(length - unpadding)], nil 40 } 41 42 // Sm4EncryptCbc sm4加密,CBC模式 43 // 44 //goland:noinspection GoNameStartsWithPackageName 45 func Sm4EncryptCbc(plainData, key []byte) (iv, encryptData []byte, err error) { 46 block, err := NewCipher(key) 47 if err != nil { 48 return nil, nil, err 49 } 50 paddedData := PKCS7Padding(plainData) 51 encryptData = make([]byte, len(paddedData)) 52 iv = make([]byte, BlockSize) 53 if _, err = io.ReadFull(rand.Reader, iv); err != nil { 54 return nil, nil, err 55 } 56 mode := cipher.NewCBCEncrypter(block, iv) 57 mode.CryptBlocks(encryptData, paddedData) 58 return 59 } 60 61 // Sm4DecryptCbc sm4解密,CBC模式 62 // 63 //goland:noinspection GoNameStartsWithPackageName 64 func Sm4DecryptCbc(encryptData, key, iv []byte) (plainData []byte, err error) { 65 block, err := NewCipher(key) 66 if err != nil { 67 return nil, err 68 } 69 // 长度检查 70 length := len(encryptData) 71 if length < BlockSize || length%BlockSize != 0 { 72 return nil, fmt.Errorf("sm4.Sm4DecryptCbc: 密文长度不正确,不是Block字节数的整数倍. Block字节数: [%d]", BlockSize) 73 } 74 paddedData := make([]byte, len(encryptData)) 75 mode := cipher.NewCBCDecrypter(block, iv) 76 mode.CryptBlocks(paddedData, encryptData) 77 plainData, err = PKCS7UnPadding(paddedData) 78 if err != nil { 79 return nil, err 80 } 81 return 82 } 83 84 // Sm4EncryptCfb sm4加密,CFB模式 85 // 86 //goland:noinspection GoNameStartsWithPackageName 87 func Sm4EncryptCfb(plainData, key []byte) (iv, encryptData []byte, err error) { 88 block, err := NewCipher(key) 89 if err != nil { 90 return nil, nil, err 91 } 92 encryptData = make([]byte, len(plainData)) 93 iv = make([]byte, BlockSize) 94 if _, err = io.ReadFull(rand.Reader, iv); err != nil { 95 return nil, nil, err 96 } 97 mode := cipher.NewCFBEncrypter(block, iv) 98 mode.XORKeyStream(encryptData, plainData) 99 return 100 } 101 102 // Sm4DecryptCfb sm4解密,CFB模式 103 // 104 //goland:noinspection GoNameStartsWithPackageName 105 func Sm4DecryptCfb(encryptData, key, iv []byte) (plainData []byte, err error) { 106 block, err := NewCipher(key) 107 if err != nil { 108 return nil, err 109 } 110 plainData = make([]byte, len(encryptData)) 111 mode := cipher.NewCFBDecrypter(block, iv) 112 mode.XORKeyStream(plainData, encryptData) 113 return 114 } 115 116 // Sm4EncryptOfb sm4加密,OFB模式 117 // 118 //goland:noinspection GoNameStartsWithPackageName 119 func Sm4EncryptOfb(plainData, key []byte) (iv, encryptData []byte, err error) { 120 block, err := NewCipher(key) 121 if err != nil { 122 return nil, nil, err 123 } 124 encryptData = make([]byte, len(plainData)) 125 iv = make([]byte, BlockSize) 126 if _, err = io.ReadFull(rand.Reader, iv); err != nil { 127 return nil, nil, err 128 } 129 mode := cipher.NewOFB(block, iv) 130 mode.XORKeyStream(encryptData, plainData) 131 return 132 } 133 134 // Sm4DecryptOfb sm4解密,OFB模式 135 // 136 //goland:noinspection GoNameStartsWithPackageName 137 func Sm4DecryptOfb(encryptData, key, iv []byte) (plainData []byte, err error) { 138 block, err := NewCipher(key) 139 if err != nil { 140 return nil, err 141 } 142 plainData = make([]byte, len(encryptData)) 143 mode := cipher.NewOFB(block, iv) 144 mode.XORKeyStream(plainData, encryptData) 145 return 146 } 147 148 // Sm4EncryptGcm sm4加密,GCM模式 149 // 150 //goland:noinspection GoNameStartsWithPackageName 151 func Sm4EncryptGcm(plainData, key []byte) (nonce, encryptData []byte, err error) { 152 block, err := NewCipher(key) 153 if err != nil { 154 return nil, nil, err 155 } 156 sm4gcm, err := cipher.NewGCM(block) 157 if err != nil { 158 return nil, nil, err 159 } 160 nonce = make([]byte, sm4gcm.NonceSize()) 161 _, err = io.ReadFull(rand.Reader, nonce) 162 if err != nil { 163 return nil, nil, err 164 } 165 out := sm4gcm.Seal(nonce, nonce, plainData, nil) 166 encryptData = out[sm4gcm.NonceSize():] 167 return 168 } 169 170 // Sm4DecryptGcm sm4解密,GCM模式 171 // 172 //goland:noinspection GoNameStartsWithPackageName 173 func Sm4DecryptGcm(encryptData, key, nonce []byte) ([]byte, error) { 174 block, err := NewCipher(key) 175 if err != nil { 176 return nil, err 177 } 178 sm4gcm, err := cipher.NewGCM(block) 179 if err != nil { 180 return nil, err 181 } 182 // nonce, ciphertext := data[:sm4gcm.NonceSize()], data[sm4gcm.NonceSize():] 183 out, err := sm4gcm.Open(nil, nonce, encryptData, nil) 184 if err != nil { 185 return nil, err 186 } 187 return out, nil 188 } 189 190 // Sm4EncryptGcmWithNonce sm4加密,GCM模式 191 // 192 //goland:noinspection GoNameStartsWithPackageName 193 func Sm4EncryptGcmWithNonce(plainData, key, nonce, dst []byte) (encryptData []byte, err error) { 194 block, err := NewCipher(key) 195 if err != nil { 196 return nil, err 197 } 198 sm4gcm, err := cipher.NewGCM(block) 199 if err != nil { 200 return nil, err 201 } 202 out := sm4gcm.Seal(dst, nonce, plainData, dst) 203 encryptData = out[len(dst):] 204 return 205 } 206 207 // Sm4DecryptGcmWithNonce sm4解密,GCM模式 208 // 209 //goland:noinspection GoNameStartsWithPackageName 210 func Sm4DecryptGcmWithNonce(encryptData, key, nonce, dst []byte) ([]byte, error) { 211 block, err := NewCipher(key) 212 if err != nil { 213 return nil, err 214 } 215 sm4gcm, err := cipher.NewGCM(block) 216 if err != nil { 217 return nil, err 218 } 219 out, err := sm4gcm.Open(encryptData[:0], nonce, encryptData, dst) 220 if err != nil { 221 return nil, err 222 } 223 return out, nil 224 }