github.com/emmansun/gmsm@v0.29.1/docs/zuc.md (about) 1 # 祖冲之序列密码算法应用指南 2 3 ## 参考标准 4 * 《GB/T 33133.1-2016 信息安全技术 祖冲之序列密码算法 第1部分:算法描述》 5 * 《GB/T 33133.2-2021 信息安全技术 祖冲之序列密码算法 第2部分:保密性算法》 6 * 《GB/T 33133.3-2021 信息安全技术 祖冲之序列密码算法 第2部分:完整性算法》 7 * [《祖冲之算法:ZUC-256算法草案(中文)》](https://github.com/guanzhi/GM-Standards/blob/master/%E5%85%AC%E5%BC%80%E6%96%87%E6%A1%A3/%E7%A5%96%E5%86%B2%E4%B9%8B%E7%AE%97%E6%B3%95%EF%BC%9AZUC-256%E7%AE%97%E6%B3%95%E8%8D%89%E6%A1%88(%E4%B8%AD%E6%96%87).pdf) 8 9 您可以从[国家标准全文公开系统](https://openstd.samr.gov.cn/)在线阅读这些标准。 10 11 ## 保密性算法 12 保密性算法EEA实现了```cipher.Stream```接口,所以和其它流密码算法使用类似,只是创建方法不同而已。 13 14 | | ZUC-128 | ZUC-256 | 15 | :--- | :--- | :--- | 16 | Key字节数 | 16 | 32 | 17 | IV字节数 | 16 | 23 | 18 19 ```go 20 func ExampleNewCipher() { 21 // Load your secret key from a safe place and reuse it across multiple 22 // NewCipher calls. (Obviously don't use this example key for anything 23 // real.) If you want to convert a passphrase to a key, use a suitable 24 // package like bcrypt or scrypt. 25 key, _ := hex.DecodeString("6368616e676520746869732070617373") 26 plaintext := []byte("some plaintext") 27 28 const ivSize = zuc.IVSize128 29 // The IV needs to be unique, but not secure. Therefore it's common to 30 // include it at the beginning of the ciphertext. 31 ciphertext := make([]byte, ivSize+len(plaintext)) 32 iv := ciphertext[:ivSize] 33 if _, err := io.ReadFull(rand.Reader, iv); err != nil { 34 panic(err) 35 } 36 37 stream, err := zuc.NewCipher(key, iv) 38 if err != nil { 39 panic(err) 40 } 41 stream.XORKeyStream(ciphertext[ivSize:], plaintext) 42 43 // It's important to remember that ciphertexts must be authenticated 44 // (i.e. by using crypto/hmac) as well as being encrypted in order to 45 // be secure. 46 47 // Stream cipher is the same for both encryption and decryption, so we can 48 // also decrypt that ciphertext with NewCTR. 49 50 plaintext2 := make([]byte, len(plaintext)) 51 stream, err = zuc.NewCipher(key, iv) 52 if err != nil { 53 panic(err) 54 } 55 stream.XORKeyStream(plaintext2, ciphertext[ivSize:]) 56 57 fmt.Printf("%s\n", plaintext2) 58 // Output: some plaintext 59 } 60 61 func ExampleNewCipher_zuc256() { 62 // Load your secret key from a safe place and reuse it across multiple 63 // NewCipher calls. (Obviously don't use this example key for anything 64 // real.) If you want to convert a passphrase to a key, use a suitable 65 // package like bcrypt or scrypt. 66 key, _ := hex.DecodeString("6368616e6765207468697320706173736368616e676520746869732070617373") 67 plaintext := []byte("some plaintext") 68 69 const ivSize = zuc.IVSize256 70 // The IV needs to be unique, but not secure. Therefore it's common to 71 // include it at the beginning of the ciphertext. 72 ciphertext := make([]byte, ivSize+len(plaintext)) 73 iv := ciphertext[:ivSize] 74 if _, err := io.ReadFull(rand.Reader, iv); err != nil { 75 panic(err) 76 } 77 78 stream, err := zuc.NewCipher(key, iv) 79 if err != nil { 80 panic(err) 81 } 82 stream.XORKeyStream(ciphertext[ivSize:], plaintext) 83 84 // It's important to remember that ciphertexts must be authenticated 85 // (i.e. by using crypto/hmac) as well as being encrypted in order to 86 // be secure. 87 88 // Stream cipher is the same for both encryption and decryption, so we can 89 // also decrypt that ciphertext with NewCTR. 90 91 plaintext2 := make([]byte, len(plaintext)) 92 stream, err = zuc.NewCipher(key, iv) 93 if err != nil { 94 panic(err) 95 } 96 stream.XORKeyStream(plaintext2, ciphertext[ivSize:]) 97 98 fmt.Printf("%s\n", plaintext2) 99 // Output: some plaintext 100 } 101 ``` 102 103 ## 完整性算法 104 完整性算法实现了```hash.Hash```接口,所以其使用方法和其它哈希算法类似。 105 106 | | ZUC-128 | ZUC-256 | 107 | :--- | :--- | :--- | 108 | Key字节数 | 16 | 32 | 109 | IV字节数 | 16 | 23 | 110 | MAC字节数 | 4 | 4/8/16 | 111 112 ```go 113 func ExampleNewHash() { 114 // Load your secret key from a safe place and reuse it across multiple 115 // NewCipher calls. (Obviously don't use this example key for anything 116 // real.) If you want to convert a passphrase to a key, use a suitable 117 // package like bcrypt or scrypt. 118 key, _ := hex.DecodeString("6368616e676520746869732070617373") 119 120 // iv should be generated randomly 121 iv, _ := hex.DecodeString("6368616e676520746869732070617373") 122 123 h, err := zuc.NewHash(key, iv) 124 if err != nil { 125 panic(err) 126 } 127 h.Write([]byte("hello world\n")) 128 fmt.Printf("%x", h.Sum(nil)) 129 // Output: c43cd26a 130 } 131 132 func ExampleNewHash256_tagSize4() { 133 // Load your secret key from a safe place and reuse it across multiple 134 // NewCipher calls. (Obviously don't use this example key for anything 135 // real.) If you want to convert a passphrase to a key, use a suitable 136 // package like bcrypt or scrypt. 137 key, _ := hex.DecodeString("6368616e6765207468697320706173736368616e676520746869732070617373") 138 139 // iv should be generated randomly 140 iv, _ := hex.DecodeString("6368616e6765207468697320706173736368616e676520") 141 142 h, err := zuc.NewHash256(key, iv, 4) 143 if err != nil { 144 panic(err) 145 } 146 h.Write([]byte("hello world\n")) 147 fmt.Printf("%x", h.Sum(nil)) 148 // Output: b76f96ed 149 } 150 151 func ExampleNewHash256_tagSize8() { 152 // Load your secret key from a safe place and reuse it across multiple 153 // NewCipher calls. (Obviously don't use this example key for anything 154 // real.) If you want to convert a passphrase to a key, use a suitable 155 // package like bcrypt or scrypt. 156 key, _ := hex.DecodeString("6368616e6765207468697320706173736368616e676520746869732070617373") 157 158 // iv should be generated randomly 159 iv, _ := hex.DecodeString("6368616e6765207468697320706173736368616e676520") 160 161 h, err := zuc.NewHash256(key, iv, 8) 162 if err != nil { 163 panic(err) 164 } 165 h.Write([]byte("hello world\n")) 166 fmt.Printf("%x", h.Sum(nil)) 167 // Output: f28aea6c9db3dc69 168 } 169 170 func ExampleNewHash256_tagSize16() { 171 // Load your secret key from a safe place and reuse it across multiple 172 // NewCipher calls. (Obviously don't use this example key for anything 173 // real.) If you want to convert a passphrase to a key, use a suitable 174 // package like bcrypt or scrypt. 175 key, _ := hex.DecodeString("6368616e6765207468697320706173736368616e676520746869732070617373") 176 177 // iv should be generated randomly 178 iv, _ := hex.DecodeString("6368616e6765207468697320706173736368616e676520") 179 180 h, err := zuc.NewHash256(key, iv, 16) 181 if err != nil { 182 panic(err) 183 } 184 h.Write([]byte("hello world\n")) 185 fmt.Printf("%x", h.Sum(nil)) 186 // Output: fd8d10ea65b6369cccc07d50b4657d84 187 } 188 ``` 189 190 要支持位为单位的话,可以调用```Finish```方法。 191 ```go 192 func ExampleZUC128Mac_Finish() { 193 key := make([]byte, 16) 194 iv := make([]byte, 16) 195 h, err := zuc.NewHash(key, iv) 196 if err != nil { 197 panic(err) 198 } 199 fmt.Printf("%x", h.Finish([]byte{0}, 1)) 200 // Output: c8a9595e 201 } 202 203 func ExampleZUC128Mac_Finish_mixed() { 204 key := []byte{ 205 0xc9, 0xe6, 0xce, 0xc4, 0x60, 0x7c, 0x72, 0xdb, 206 0x00, 0x0a, 0xef, 0xa8, 0x83, 0x85, 0xab, 0x0a, 207 } 208 209 // iv should be generated randomly 210 iv, _ := hex.DecodeString("a94059da50000000294059da50008000") 211 212 h, err := zuc.NewHash(key, iv) 213 if err != nil { 214 panic(err) 215 } 216 217 in, _ := hex.DecodeString("983b41d47d780c9e1ad11d7eb70391b1de0b35da2dc62f83e7b78d6306ca0ea07e941b7be91348f9fcb170e2217fecd97f9f68adb16e5d7d21e569d280ed775cebde3f4093c53881") 218 h.Write(in) 219 fmt.Printf("%x", h.Finish([]byte{0}, 1)) 220 // Output: fae8ff0b 221 } 222 ```