github.com/emmansun/gmsm@v0.29.1/sm4/example_test.go (about) 1 package sm4_test 2 3 import ( 4 "bytes" 5 "crypto/cipher" 6 "crypto/rand" 7 "encoding/hex" 8 "fmt" 9 "io" 10 "os" 11 12 smcipher "github.com/emmansun/gmsm/cipher" 13 "github.com/emmansun/gmsm/padding" 14 "github.com/emmansun/gmsm/sm4" 15 ) 16 17 func Example_encryptCBC() { 18 // Load your secret key from a safe place and reuse it across multiple 19 // NewCipher calls. (Obviously don't use this example key for anything 20 // real.) If you want to convert a passphrase to a key, use a suitable 21 // package like bcrypt or scrypt. 22 key, _ := hex.DecodeString("6368616e676520746869732070617373") 23 plaintext := []byte("sm4 exampleplaintext") 24 25 block, err := sm4.NewCipher(key) 26 if err != nil { 27 panic(err) 28 } 29 30 // CBC mode works on blocks so plaintexts may need to be padded to the 31 // next whole block. For an example of such padding, see 32 // https://tools.ietf.org/html/rfc5246#section-6.2.3.2. 33 pkcs7 := padding.NewPKCS7Padding(sm4.BlockSize) 34 paddedPlainText := pkcs7.Pad(plaintext) 35 36 // The IV needs to be unique, but not secure. Therefore it's common to 37 // include it at the beginning of the ciphertext. 38 ciphertext := make([]byte, sm4.BlockSize+len(paddedPlainText)) 39 iv := ciphertext[:sm4.BlockSize] 40 if _, err := io.ReadFull(rand.Reader, iv); err != nil { 41 panic(err) 42 } 43 44 mode := cipher.NewCBCEncrypter(block, iv) 45 mode.CryptBlocks(ciphertext[sm4.BlockSize:], paddedPlainText) 46 47 fmt.Printf("%x\n", ciphertext) 48 } 49 50 func Example_decryptCBC() { 51 // Load your secret key from a safe place and reuse it across multiple 52 // NewCipher calls. (Obviously don't use this example key for anything 53 // real.) If you want to convert a passphrase to a key, use a suitable 54 // package like bcrypt or scrypt. 55 key, _ := hex.DecodeString("6368616e676520746869732070617373") 56 ciphertext, _ := hex.DecodeString("4d5a1486bfda1b34447afd5bb852e77a867cc6b726a8a0e0ef9b2c21fffc3a30b42acf504628f65cb3fba339101c98ff") 57 58 block, err := sm4.NewCipher(key) 59 if err != nil { 60 panic(err) 61 } 62 63 // The IV needs to be unique, but not secure. Therefore it's common to 64 // include it at the beginning of the ciphertext. 65 if len(ciphertext) < sm4.BlockSize { 66 panic("ciphertext too short") 67 } 68 iv := ciphertext[:sm4.BlockSize] 69 ciphertext = ciphertext[sm4.BlockSize:] 70 71 mode := cipher.NewCBCDecrypter(block, iv) 72 73 // CryptBlocks can work in-place if the two arguments are the same. 74 mode.CryptBlocks(ciphertext, ciphertext) 75 76 // Unpad plaintext 77 pkcs7 := padding.NewPKCS7Padding(sm4.BlockSize) 78 ciphertext, err = pkcs7.Unpad(ciphertext) 79 if err != nil { 80 panic(err) 81 } 82 83 fmt.Printf("%s\n", ciphertext) 84 // Output: sm4 exampleplaintext 85 } 86 87 func Example_encryptGCM() { 88 // Load your secret key from a safe place and reuse it across multiple 89 // Seal/Open calls. (Obviously don't use this example key for anything 90 // real.) If you want to convert a passphrase to a key, use a suitable 91 // package like bcrypt or scrypt. 92 key, _ := hex.DecodeString("6368616e676520746869732070617373") 93 plaintext := []byte("exampleplaintext") 94 95 block, err := sm4.NewCipher(key) 96 if err != nil { 97 panic(err.Error()) 98 } 99 100 // Never use more than 2^32 random nonces with a given key because of the risk of a repeat. 101 nonce := make([]byte, 12) 102 if _, err := io.ReadFull(rand.Reader, nonce); err != nil { 103 panic(err.Error()) 104 } 105 106 sm4gcm, err := cipher.NewGCM(block) 107 if err != nil { 108 panic(err.Error()) 109 } 110 111 // You can encode the nonce and ciphertext with your own scheme 112 ciphertext := sm4gcm.Seal(nil, nonce, plaintext, nil) 113 fmt.Printf("%x %x\n", nonce, ciphertext) 114 } 115 116 func Example_decryptGCM() { 117 // Load your secret key from a safe place and reuse it across multiple 118 // Seal/Open calls. (Obviously don't use this example key for anything 119 // real.) If you want to convert a passphrase to a key, use a suitable 120 // package like bcrypt or scrypt. 121 key, _ := hex.DecodeString("6368616e676520746869732070617373") 122 // You can decode the nonce and ciphertext with your encoding scheme 123 ciphertext, _ := hex.DecodeString("b7fdece1c6b3dce9cc386e8bc93df0ce496df789166229f14b973b694a4a23c3") 124 nonce, _ := hex.DecodeString("07d168e0517656ab7131f495") 125 126 block, err := sm4.NewCipher(key) 127 if err != nil { 128 panic(err.Error()) 129 } 130 131 sm4gcm, err := cipher.NewGCM(block) 132 if err != nil { 133 panic(err.Error()) 134 } 135 136 plaintext, err := sm4gcm.Open(nil, nonce, ciphertext, nil) 137 if err != nil { 138 panic(err.Error()) 139 } 140 141 fmt.Printf("%s\n", plaintext) 142 // Output: exampleplaintext 143 } 144 145 func Example_encryptCCM() { 146 // Load your secret key from a safe place and reuse it across multiple 147 // Seal/Open calls. (Obviously don't use this example key for anything 148 // real.) If you want to convert a passphrase to a key, use a suitable 149 // package like bcrypt or scrypt. 150 key, _ := hex.DecodeString("6368616e676520746869732070617373") 151 plaintext := []byte("exampleplaintext") 152 153 block, err := sm4.NewCipher(key) 154 if err != nil { 155 panic(err.Error()) 156 } 157 158 // Never use more than 2^32 random nonces with a given key because of the risk of a repeat. 159 nonce := make([]byte, 12) 160 if _, err := io.ReadFull(rand.Reader, nonce); err != nil { 161 panic(err.Error()) 162 } 163 164 sm4ccm, err := smcipher.NewCCM(block) 165 if err != nil { 166 panic(err.Error()) 167 } 168 169 // You can encode the nonce and ciphertext with your own scheme 170 ciphertext := sm4ccm.Seal(nil, nonce, plaintext, nil) 171 fmt.Printf("%x %x\n", nonce, ciphertext) 172 } 173 174 func Example_decryptCCM() { 175 // Load your secret key from a safe place and reuse it across multiple 176 // Seal/Open calls. (Obviously don't use this example key for anything 177 // real.) If you want to convert a passphrase to a key, use a suitable 178 // package like bcrypt or scrypt. 179 key, _ := hex.DecodeString("6368616e676520746869732070617373") 180 // You can decode the nonce and ciphertext with your encoding scheme 181 ciphertext, _ := hex.DecodeString("aa5da19754e98c3a39787e8f0f8f73808b38ba31c9196772125e737f8d636483") 182 nonce, _ := hex.DecodeString("8f227cf05ad8b5c2902844e4") 183 184 block, err := sm4.NewCipher(key) 185 if err != nil { 186 panic(err.Error()) 187 } 188 189 sm4ccm, err := smcipher.NewCCM(block) 190 if err != nil { 191 panic(err.Error()) 192 } 193 194 plaintext, err := sm4ccm.Open(nil, nonce, ciphertext, nil) 195 if err != nil { 196 panic(err.Error()) 197 } 198 199 fmt.Printf("%s\n", plaintext) 200 // Output: exampleplaintext 201 } 202 203 func Example_encryptCFB() { 204 // Load your secret key from a safe place and reuse it across multiple 205 // NewCipher calls. (Obviously don't use this example key for anything 206 // real.) If you want to convert a passphrase to a key, use a suitable 207 // package like bcrypt or scrypt. 208 key, _ := hex.DecodeString("6368616e676520746869732070617373") 209 plaintext := []byte("some plaintext") 210 211 block, err := sm4.NewCipher(key) 212 if err != nil { 213 panic(err) 214 } 215 216 // The IV needs to be unique, but not secure. Therefore it's common to 217 // include it at the beginning of the ciphertext. 218 ciphertext := make([]byte, sm4.BlockSize+len(plaintext)) 219 iv := ciphertext[:sm4.BlockSize] 220 if _, err := io.ReadFull(rand.Reader, iv); err != nil { 221 panic(err) 222 } 223 224 stream := cipher.NewCFBEncrypter(block, iv) 225 stream.XORKeyStream(ciphertext[sm4.BlockSize:], plaintext) 226 227 // It's important to remember that ciphertexts must be authenticated 228 // (i.e. by using crypto/hmac) as well as being encrypted in order to 229 // be secure. 230 fmt.Printf("%x\n", ciphertext) 231 } 232 233 func Example_decryptCFB() { 234 // Load your secret key from a safe place and reuse it across multiple 235 // NewCipher calls. (Obviously don't use this example key for anything 236 // real.) If you want to convert a passphrase to a key, use a suitable 237 // package like bcrypt or scrypt. 238 key, _ := hex.DecodeString("6368616e676520746869732070617373") 239 ciphertext, _ := hex.DecodeString("37386876330ac7a6fa9d22d5b5dba22a779e3ed0e88307121a9808e65894") 240 241 block, err := sm4.NewCipher(key) 242 if err != nil { 243 panic(err) 244 } 245 246 // The IV needs to be unique, but not secure. Therefore it's common to 247 // include it at the beginning of the ciphertext. 248 if len(ciphertext) < sm4.BlockSize { 249 panic("ciphertext too short") 250 } 251 iv := ciphertext[:sm4.BlockSize] 252 ciphertext = ciphertext[sm4.BlockSize:] 253 254 stream := cipher.NewCFBDecrypter(block, iv) 255 256 // XORKeyStream can work in-place if the two arguments are the same. 257 stream.XORKeyStream(ciphertext, ciphertext) 258 fmt.Printf("%s", ciphertext) 259 // Output: some plaintext 260 } 261 262 func Example_modeCTR() { 263 // Load your secret key from a safe place and reuse it across multiple 264 // NewCipher calls. (Obviously don't use this example key for anything 265 // real.) If you want to convert a passphrase to a key, use a suitable 266 // package like bcrypt or scrypt. 267 key, _ := hex.DecodeString("6368616e676520746869732070617373") 268 plaintext := []byte("some plaintext") 269 270 block, err := sm4.NewCipher(key) 271 if err != nil { 272 panic(err) 273 } 274 275 // The IV needs to be unique, but not secure. Therefore it's common to 276 // include it at the beginning of the ciphertext. 277 ciphertext := make([]byte, sm4.BlockSize+len(plaintext)) 278 iv := ciphertext[:sm4.BlockSize] 279 if _, err := io.ReadFull(rand.Reader, iv); err != nil { 280 panic(err) 281 } 282 283 stream := cipher.NewCTR(block, iv) 284 stream.XORKeyStream(ciphertext[sm4.BlockSize:], plaintext) 285 286 // It's important to remember that ciphertexts must be authenticated 287 // (i.e. by using crypto/hmac) as well as being encrypted in order to 288 // be secure. 289 290 // CTR mode is the same for both encryption and decryption, so we can 291 // also decrypt that ciphertext with NewCTR. 292 293 plaintext2 := make([]byte, len(plaintext)) 294 stream = cipher.NewCTR(block, iv) 295 stream.XORKeyStream(plaintext2, ciphertext[sm4.BlockSize:]) 296 297 fmt.Printf("%s\n", plaintext2) 298 // Output: some plaintext 299 } 300 301 func Example_modeOFB() { 302 // Load your secret key from a safe place and reuse it across multiple 303 // NewCipher calls. (Obviously don't use this example key for anything 304 // real.) If you want to convert a passphrase to a key, use a suitable 305 // package like bcrypt or scrypt. 306 key, _ := hex.DecodeString("6368616e676520746869732070617373") 307 plaintext := []byte("some plaintext") 308 309 block, err := sm4.NewCipher(key) 310 if err != nil { 311 panic(err) 312 } 313 314 // The IV needs to be unique, but not secure. Therefore it's common to 315 // include it at the beginning of the ciphertext. 316 ciphertext := make([]byte, sm4.BlockSize+len(plaintext)) 317 iv := ciphertext[:sm4.BlockSize] 318 if _, err := io.ReadFull(rand.Reader, iv); err != nil { 319 panic(err) 320 } 321 322 stream := cipher.NewOFB(block, iv) 323 stream.XORKeyStream(ciphertext[sm4.BlockSize:], plaintext) 324 325 // It's important to remember that ciphertexts must be authenticated 326 // (i.e. by using crypto/hmac) as well as being encrypted in order to 327 // be secure. 328 329 // OFB mode is the same for both encryption and decryption, so we can 330 // also decrypt that ciphertext with NewOFB. 331 332 plaintext2 := make([]byte, len(plaintext)) 333 stream = cipher.NewOFB(block, iv) 334 stream.XORKeyStream(plaintext2, ciphertext[sm4.BlockSize:]) 335 336 fmt.Printf("%s\n", plaintext2) 337 // Output: some plaintext 338 } 339 340 func Example_streamReader() { 341 // Load your secret key from a safe place and reuse it across multiple 342 // NewCipher calls. (Obviously don't use this example key for anything 343 // real.) If you want to convert a passphrase to a key, use a suitable 344 // package like bcrypt or scrypt. 345 key, _ := hex.DecodeString("6368616e676520746869732070617373") 346 347 encrypted, _ := hex.DecodeString("38d03b4b50b6154e7437150b93fb0ef0") 348 bReader := bytes.NewReader(encrypted) 349 350 block, err := sm4.NewCipher(key) 351 if err != nil { 352 panic(err) 353 } 354 355 // If the key is unique for each ciphertext, then it's ok to use a zero 356 // IV. 357 var iv [sm4.BlockSize]byte 358 stream := cipher.NewOFB(block, iv[:]) 359 360 reader := &cipher.StreamReader{S: stream, R: bReader} 361 // Copy the input to the output stream, decrypting as we go. 362 if _, err := io.Copy(os.Stdout, reader); err != nil { 363 panic(err) 364 } 365 366 // Note that this example is simplistic in that it omits any 367 // authentication of the encrypted data. If you were actually to use 368 // StreamReader in this manner, an attacker could flip arbitrary bits in 369 // the output. 370 371 // Output: some secret text 372 } 373 374 func Example_streamWriter() { 375 // Load your secret key from a safe place and reuse it across multiple 376 // NewCipher calls. (Obviously don't use this example key for anything 377 // real.) If you want to convert a passphrase to a key, use a suitable 378 // package like bcrypt or scrypt. 379 key, _ := hex.DecodeString("6368616e676520746869732070617373") 380 381 bReader := bytes.NewReader([]byte("some secret text")) 382 383 block, err := sm4.NewCipher(key) 384 if err != nil { 385 panic(err) 386 } 387 388 // If the key is unique for each ciphertext, then it's ok to use a zero 389 // IV. 390 var iv [sm4.BlockSize]byte 391 stream := cipher.NewOFB(block, iv[:]) 392 393 var out bytes.Buffer 394 395 writer := &cipher.StreamWriter{S: stream, W: &out} 396 // Copy the input to the output buffer, encrypting as we go. 397 if _, err := io.Copy(writer, bReader); err != nil { 398 panic(err) 399 } 400 401 // Note that this example is simplistic in that it omits any 402 // authentication of the encrypted data. If you were actually to use 403 // StreamReader in this manner, an attacker could flip arbitrary bits in 404 // the decrypted result. 405 406 fmt.Printf("%x\n", out.Bytes()) 407 // Output: 38d03b4b50b6154e7437150b93fb0ef0 408 }