github.com/emmansun/gmsm@v0.29.1/sm9/enc_mode.go (about) 1 package sm9 2 3 import ( 4 "crypto/cipher" 5 "io" 6 7 _cipher "github.com/emmansun/gmsm/cipher" 8 "github.com/emmansun/gmsm/internal/subtle" 9 "github.com/emmansun/gmsm/padding" 10 "github.com/emmansun/gmsm/sm4" 11 ) 12 13 // EncrypterOpts is an interface implemented by detail encrypt/decrypt mode. 14 type EncrypterOpts interface { 15 // GetEncryptType returns the encrypt type/mode. 16 GetEncryptType() encryptType 17 // GetKeySize returns key size used by this encrypt mode. 18 GetKeySize(plaintext []byte) int 19 // Encrypt encrypts the plaintext with the key, returns ciphertext. 20 Encrypt(rand io.Reader, key, plaintext []byte) ([]byte, error) 21 // Decrypt decrypts the ciphertext with the key, returns plaintext. 22 Decrypt(key, ciphertext []byte) ([]byte, error) 23 } 24 25 // XOREncrypterOpts represents XOR mode. 26 type XOREncrypterOpts struct{} 27 28 func (opts *XOREncrypterOpts) GetEncryptType() encryptType { 29 return ENC_TYPE_XOR 30 } 31 32 func (opts *XOREncrypterOpts) GetKeySize(plaintext []byte) int { 33 return len(plaintext) 34 } 35 36 func (opts *XOREncrypterOpts) Encrypt(rand io.Reader, key, plaintext []byte) ([]byte, error) { 37 subtle.XORBytes(key, key, plaintext) 38 return key, nil 39 } 40 41 func (opts *XOREncrypterOpts) Decrypt(key, ciphertext []byte) ([]byte, error) { 42 if len(ciphertext) == 0 { 43 return nil, ErrDecryption 44 } 45 subtle.XORBytes(key, ciphertext, key) 46 return key, nil 47 } 48 49 type newCipher func(key []byte) (cipher.Block, error) 50 51 type baseBlockEncrypterOpts struct { 52 encryptType encryptType 53 newCipher newCipher 54 cipherKeySize int 55 } 56 57 func (opts *baseBlockEncrypterOpts) GetEncryptType() encryptType { 58 return opts.encryptType 59 } 60 61 func (opts *baseBlockEncrypterOpts) GetKeySize(plaintext []byte) int { 62 return opts.cipherKeySize 63 } 64 65 // CBCEncrypterOpts represents CBC (Cipher block chaining) mode. 66 type CBCEncrypterOpts struct { 67 baseBlockEncrypterOpts 68 padding padding.Padding 69 } 70 71 func NewCBCEncrypterOpts(padding padding.Padding, newCipher newCipher, keySize int) EncrypterOpts { 72 opts := new(CBCEncrypterOpts) 73 opts.encryptType = ENC_TYPE_CBC 74 opts.padding = padding 75 opts.newCipher = newCipher 76 opts.cipherKeySize = keySize 77 return opts 78 } 79 80 // Encrypt encrypts the plaintext with the key, includes generated IV at the beginning of the ciphertext. 81 func (opts *CBCEncrypterOpts) Encrypt(rand io.Reader, key, plaintext []byte) ([]byte, error) { 82 block, err := opts.newCipher(key) 83 if err != nil { 84 return nil, err 85 } 86 paddedPlainText := opts.padding.Pad(plaintext) 87 blockSize := block.BlockSize() 88 ciphertext := make([]byte, blockSize+len(paddedPlainText)) 89 iv := ciphertext[:blockSize] 90 if _, err := io.ReadFull(rand, iv); err != nil { 91 return nil, err 92 } 93 mode := cipher.NewCBCEncrypter(block, iv) 94 mode.CryptBlocks(ciphertext[blockSize:], paddedPlainText) 95 return ciphertext, nil 96 } 97 98 func (opts *CBCEncrypterOpts) Decrypt(key, ciphertext []byte) ([]byte, error) { 99 block, err := opts.newCipher(key) 100 if err != nil { 101 return nil, err 102 } 103 blockSize := block.BlockSize() 104 if len(ciphertext) <= blockSize { 105 return nil, ErrDecryption 106 } 107 iv := ciphertext[:blockSize] 108 ciphertext = ciphertext[blockSize:] 109 plaintext := make([]byte, len(ciphertext)) 110 mode := cipher.NewCBCDecrypter(block, iv) 111 mode.CryptBlocks(plaintext, ciphertext) 112 return opts.padding.Unpad(plaintext) 113 } 114 115 // ECBEncrypterOpts represents ECB (Electronic Code Book) mode. 116 type ECBEncrypterOpts struct { 117 baseBlockEncrypterOpts 118 padding padding.Padding 119 } 120 121 func NewECBEncrypterOpts(padding padding.Padding, newCipher newCipher, keySize int) EncrypterOpts { 122 opts := new(ECBEncrypterOpts) 123 opts.encryptType = ENC_TYPE_ECB 124 opts.padding = padding 125 opts.newCipher = newCipher 126 opts.cipherKeySize = keySize 127 return opts 128 } 129 130 func (opts *ECBEncrypterOpts) Encrypt(rand io.Reader, key, plaintext []byte) ([]byte, error) { 131 block, err := opts.newCipher(key) 132 if err != nil { 133 return nil, err 134 } 135 paddedPlainText := opts.padding.Pad(plaintext) 136 ciphertext := make([]byte, len(paddedPlainText)) 137 mode := _cipher.NewECBEncrypter(block) 138 mode.CryptBlocks(ciphertext, paddedPlainText) 139 return ciphertext, nil 140 } 141 142 func (opts *ECBEncrypterOpts) Decrypt(key, ciphertext []byte) ([]byte, error) { 143 block, err := opts.newCipher(key) 144 if err != nil { 145 return nil, err 146 } 147 if len(ciphertext) == 0 { 148 return nil, ErrDecryption 149 } 150 plaintext := make([]byte, len(ciphertext)) 151 mode := _cipher.NewECBDecrypter(block) 152 mode.CryptBlocks(plaintext, ciphertext) 153 return opts.padding.Unpad(plaintext) 154 } 155 156 // CFBEncrypterOpts represents CFB (Cipher Feedback) mode. 157 type CFBEncrypterOpts struct { 158 baseBlockEncrypterOpts 159 } 160 161 func NewCFBEncrypterOpts(newCipher newCipher, keySize int) EncrypterOpts { 162 opts := new(CFBEncrypterOpts) 163 opts.encryptType = ENC_TYPE_CFB 164 opts.newCipher = newCipher 165 opts.cipherKeySize = keySize 166 return opts 167 } 168 169 // Encrypt encrypts the plaintext with the key, includes generated IV at the beginning of the ciphertext. 170 func (opts *CFBEncrypterOpts) Encrypt(rand io.Reader, key, plaintext []byte) ([]byte, error) { 171 block, err := opts.newCipher(key) 172 if err != nil { 173 return nil, err 174 } 175 blockSize := block.BlockSize() 176 ciphertext := make([]byte, blockSize+len(plaintext)) 177 iv := ciphertext[:blockSize] 178 if _, err := io.ReadFull(rand, iv); err != nil { 179 return nil, err 180 } 181 stream := cipher.NewCFBEncrypter(block, iv) 182 stream.XORKeyStream(ciphertext[blockSize:], plaintext) 183 return ciphertext, nil 184 } 185 186 func (opts *CFBEncrypterOpts) Decrypt(key, ciphertext []byte) ([]byte, error) { 187 block, err := opts.newCipher(key) 188 if err != nil { 189 return nil, err 190 } 191 blockSize := block.BlockSize() 192 if len(ciphertext) <= blockSize { 193 return nil, ErrDecryption 194 } 195 iv := ciphertext[:blockSize] 196 ciphertext = ciphertext[blockSize:] 197 plaintext := make([]byte, len(ciphertext)) 198 stream := cipher.NewCFBDecrypter(block, iv) 199 stream.XORKeyStream(plaintext, ciphertext) 200 return plaintext, nil 201 } 202 203 // OFBEncrypterOpts represents OFB (Output Feedback) mode. 204 type OFBEncrypterOpts struct { 205 baseBlockEncrypterOpts 206 } 207 208 func NewOFBEncrypterOpts(newCipher newCipher, keySize int) EncrypterOpts { 209 opts := new(OFBEncrypterOpts) 210 opts.encryptType = ENC_TYPE_OFB 211 opts.newCipher = newCipher 212 opts.cipherKeySize = keySize 213 return opts 214 } 215 216 // Encrypt encrypts the plaintext with the key, includes generated IV at the beginning of the ciphertext. 217 func (opts *OFBEncrypterOpts) Encrypt(rand io.Reader, key, plaintext []byte) ([]byte, error) { 218 block, err := opts.newCipher(key) 219 if err != nil { 220 return nil, err 221 } 222 blockSize := block.BlockSize() 223 ciphertext := make([]byte, blockSize+len(plaintext)) 224 iv := ciphertext[:blockSize] 225 if _, err := io.ReadFull(rand, iv); err != nil { 226 return nil, err 227 } 228 stream := cipher.NewOFB(block, iv) 229 stream.XORKeyStream(ciphertext[blockSize:], plaintext) 230 return ciphertext, nil 231 } 232 233 func (opts *OFBEncrypterOpts) Decrypt(key, ciphertext []byte) ([]byte, error) { 234 block, err := opts.newCipher(key) 235 if err != nil { 236 return nil, err 237 } 238 blockSize := block.BlockSize() 239 if len(ciphertext) <= blockSize { 240 return nil, ErrDecryption 241 } 242 iv := ciphertext[:blockSize] 243 ciphertext = ciphertext[blockSize:] 244 plaintext := make([]byte, len(ciphertext)) 245 stream := cipher.NewOFB(block, iv) 246 stream.XORKeyStream(plaintext, ciphertext) 247 return plaintext, nil 248 } 249 250 // DefaultEncrypterOpts default option represents XOR mode 251 var DefaultEncrypterOpts = new(XOREncrypterOpts) 252 253 // SM4ECBEncrypterOpts option represents SM4 ECB mode 254 var SM4ECBEncrypterOpts = NewECBEncrypterOpts(padding.NewPKCS7Padding(sm4.BlockSize), sm4.NewCipher, sm4.BlockSize) 255 256 // SM4CBCEncrypterOpts option represents SM4 CBC mode 257 var SM4CBCEncrypterOpts = NewCBCEncrypterOpts(padding.NewPKCS7Padding(sm4.BlockSize), sm4.NewCipher, sm4.BlockSize) 258 259 // SM4CFBEncrypterOpts option represents SM4 CFB mode 260 var SM4CFBEncrypterOpts = NewCFBEncrypterOpts(sm4.NewCipher, sm4.BlockSize) 261 262 // SM4OFBEncrypterOpts option represents SM4 OFB mode 263 var SM4OFBEncrypterOpts = NewOFBEncrypterOpts(sm4.NewCipher, sm4.BlockSize) 264 265 func shangMiEncrypterOpts(encType encryptType) EncrypterOpts { 266 switch encType { 267 case ENC_TYPE_XOR: 268 return DefaultEncrypterOpts 269 case ENC_TYPE_CBC: 270 return SM4CBCEncrypterOpts 271 case ENC_TYPE_ECB: 272 return SM4ECBEncrypterOpts 273 case ENC_TYPE_CFB: 274 return SM4CFBEncrypterOpts 275 case ENC_TYPE_OFB: 276 return SM4OFBEncrypterOpts 277 } 278 return nil 279 }