github.com/shogo82148/std@v1.22.1-0.20240327122250-4e474527810c/crypto/cipher/example_test.go (about) 1 // Copyright 2012 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package cipher_test 6 7 import ( 8 "github.com/shogo82148/std/bytes" 9 "github.com/shogo82148/std/crypto/aes" 10 "github.com/shogo82148/std/crypto/cipher" 11 "github.com/shogo82148/std/crypto/rand" 12 "github.com/shogo82148/std/encoding/hex" 13 "github.com/shogo82148/std/fmt" 14 "github.com/shogo82148/std/io" 15 "github.com/shogo82148/std/os" 16 ) 17 18 func ExampleNewGCM_encrypt() { 19 20 // 安全な場所から秘密鍵を読み込み、複数のSeal/Open呼び出しで再利用します。 21 //(もちろん、実際の用途にはこの例の鍵を使用しないでください。) 22 // パスフレーズを鍵に変換したい場合は、bcryptやscryptのような適切な 23 // パッケージを使用してください。 24 // デコードされた鍵は16バイト(AES-128)または32バイト(AES-256)である必要があります。 25 key, _ := hex.DecodeString("6368616e676520746869732070617373776f726420746f206120736563726574") 26 plaintext := []byte("exampleplaintext") 27 28 block, err := aes.NewCipher(key) 29 if err != nil { 30 panic(err.Error()) 31 } 32 33 // 同じキーで2^32以上のランダムなノンスを使用しないでください。繰り返しのリスクがあるためです。 34 nonce := make([]byte, 12) 35 if _, err := io.ReadFull(rand.Reader, nonce); err != nil { 36 panic(err.Error()) 37 } 38 39 aesgcm, err := cipher.NewGCM(block) 40 if err != nil { 41 panic(err.Error()) 42 } 43 44 ciphertext := aesgcm.Seal(nil, nonce, plaintext, nil) 45 fmt.Printf("%x\n", ciphertext) 46 } 47 48 func ExampleNewGCM_decrypt() { 49 50 // 安全な場所から秘密のキーを読み込み、複数のSeal/Open呼び出し間で再利用してください。 51 // (もちろん、実際の用途にはこの例のキーを使用しないでください。) 52 // パスフレーズをキーに変換したい場合は、bcryptやscryptなどの適切なパッケージを使用してください。 53 // キーをデコードすると、16バイト(AES-128)または32バイト(AES-256)である必要があります。 54 key, _ := hex.DecodeString("6368616e676520746869732070617373776f726420746f206120736563726574") 55 ciphertext, _ := hex.DecodeString("c3aaa29f002ca75870806e44086700f62ce4d43e902b3888e23ceff797a7a471") 56 nonce, _ := hex.DecodeString("64a9433eae7ccceee2fc0eda") 57 58 block, err := aes.NewCipher(key) 59 if err != nil { 60 panic(err.Error()) 61 } 62 63 aesgcm, err := cipher.NewGCM(block) 64 if err != nil { 65 panic(err.Error()) 66 } 67 68 plaintext, err := aesgcm.Open(nil, nonce, ciphertext, nil) 69 if err != nil { 70 panic(err.Error()) 71 } 72 73 fmt.Printf("%s\n", plaintext) 74 // Output: exampleplaintext 75 } 76 77 func ExampleNewCBCDecrypter() { 78 79 // 安全な場所から秘密鍵を読み込んで、複数の NewCipher 呼び出し間で再利用してください。 80 // (もちろん、実際の用途にはこの例の鍵を使用しないでください。) 81 // パスフレーズを鍵に変換したい場合は、bcrypt や scrypt のような適切なパッケージを使用してください。 82 key, _ := hex.DecodeString("6368616e676520746869732070617373") 83 ciphertext, _ := hex.DecodeString("73c86d43a9d700a253a96c85b0f6b03ac9792e0e757f869cca306bd3cba1c62b") 84 85 block, err := aes.NewCipher(key) 86 if err != nil { 87 panic(err) 88 } 89 90 // IVは一意である必要がありますが、セキュリティは必要ありません。 91 // そのため、しばしば暗号文の先頭に含まれます。 92 if len(ciphertext) < aes.BlockSize { 93 panic("ciphertext too short") 94 } 95 iv := ciphertext[:aes.BlockSize] 96 ciphertext = ciphertext[aes.BlockSize:] 97 98 // CBCモードは常に完全なブロックで動作します。 99 if len(ciphertext)%aes.BlockSize != 0 { 100 panic("ciphertext is not a multiple of the block size") 101 } 102 103 mode := cipher.NewCBCDecrypter(block, iv) 104 105 // CryptBlocks は、引数が同じであればその場で処理されます。 106 mode.CryptBlocks(ciphertext, ciphertext) 107 108 // もし元の平文の長さがブロックの倍数でない場合、暗号化する際に追加する必要があるパディングがこの時点で削除されます。例としては、https://tools.ietf.org/html/rfc5246#section-6.2.3.2 を参照してください。ただし、パディングオラクルを作成しないために、暗号文を複合化する前に必ず認証すること(つまり、crypto/hmacを使用すること)が非常に重要です。 109 110 fmt.Printf("%s\n", ciphertext) 111 // Output: exampleplaintext 112 } 113 114 func ExampleNewCBCEncrypter() { 115 116 // 安全な場所から秘密の鍵をロードし、複数の NewCipher 呼び出しで再利用します。 117 // (もちろん、実際の目的にはこの例の鍵を使用しないでください。) 118 // もしパスフレーズを鍵に変換したい場合は、bcrypt や scrypt のような適切なパッケージを使用してください。 119 key, _ := hex.DecodeString("6368616e676520746869732070617373") 120 plaintext := []byte("exampleplaintext") 121 122 // CBCモードでは、平文はブロック単位で処理されるため、次の完全なブロックまでパディングする必要がある場合があります。このようなパディングの例については、次を参照してください:https://tools.ietf.org/html/rfc5246#section-6.2.3.2。ここでは、平文が既に正しい長さであると仮定します。 123 if len(plaintext)%aes.BlockSize != 0 { 124 panic("plaintext is not a multiple of the block size") 125 } 126 127 block, err := aes.NewCipher(key) 128 if err != nil { 129 panic(err) 130 } 131 132 // IVはユニークである必要がありますが、セキュリティは求められません。 133 // そのため、一般的には暗号文の先頭に含めることがあります。 134 ciphertext := make([]byte, aes.BlockSize+len(plaintext)) 135 iv := ciphertext[:aes.BlockSize] 136 if _, err := io.ReadFull(rand.Reader, iv); err != nil { 137 panic(err) 138 } 139 140 mode := cipher.NewCBCEncrypter(block, iv) 141 mode.CryptBlocks(ciphertext[aes.BlockSize:], plaintext) 142 143 // 暗号文は、安全にするために暗号化されるだけでなく、 144 // (つまり、crypto/hmacを使用することによって)認証されている必要があることを忘れないことが重要です。 145 146 fmt.Printf("%x\n", ciphertext) 147 } 148 149 func ExampleNewCFBDecrypter() { 150 151 // 安全な場所から秘密キーを読み込み、複数のNewCipher呼び出しで再利用してください。 152 // (もちろん、実際にはこの例のキーを使用しないでください。)パスフレーズをキーに変換したい場合は、bcryptやscryptなど適切なパッケージを使用してください。 153 key, _ := hex.DecodeString("6368616e676520746869732070617373") 154 ciphertext, _ := hex.DecodeString("7dd015f06bec7f1b8f6559dad89f4131da62261786845100056b353194ad") 155 156 block, err := aes.NewCipher(key) 157 if err != nil { 158 panic(err) 159 } 160 161 // IVは一意である必要がありますが、安全性は問われません。したがって、通常は暗号文の先頭に含まれます。 162 if len(ciphertext) < aes.BlockSize { 163 panic("ciphertext too short") 164 } 165 iv := ciphertext[:aes.BlockSize] 166 ciphertext = ciphertext[aes.BlockSize:] 167 168 stream := cipher.NewCFBDecrypter(block, iv) 169 170 // もし2つの引数が同じ場合、XORKeyStreamはインプレースで動作することができます。 171 stream.XORKeyStream(ciphertext, ciphertext) 172 fmt.Printf("%s", ciphertext) 173 // Output: some plaintext 174 } 175 176 func ExampleNewCFBEncrypter() { 177 178 // 安全な場所から秘密鍵を読み込み、複数の NewCipher 呼び出しで再利用してください。 (明らかに、実際の何かのためにこの例の鍵を使用しないでください)。 パスフレーズを鍵に変換したい場合は、bcrypt や scrypt のような適切なパッケージを使用してください。 179 key, _ := hex.DecodeString("6368616e676520746869732070617373") 180 plaintext := []byte("some plaintext") 181 182 block, err := aes.NewCipher(key) 183 if err != nil { 184 panic(err) 185 } 186 187 // IVは一意である必要がありますが、安全である必要はありません。したがって、一般的には、暗号文の先頭にIVを含めることがあります。 188 ciphertext := make([]byte, aes.BlockSize+len(plaintext)) 189 iv := ciphertext[:aes.BlockSize] 190 if _, err := io.ReadFull(rand.Reader, iv); err != nil { 191 panic(err) 192 } 193 194 stream := cipher.NewCFBEncrypter(block, iv) 195 stream.XORKeyStream(ciphertext[aes.BlockSize:], plaintext) 196 197 // 暗号文は、安全性を確保するために、暗号化だけでなく、認証(crypto/hmac の使用によって)も行われる必要があることを覚えておくことが重要です。 198 fmt.Printf("%x\n", ciphertext) 199 } 200 201 func ExampleNewCTR() { 202 203 // 安全な場所から秘密キーを読み込み、複数のNewCipher呼び出しで再利用します。 204 // (もちろん、実際の用途にはこの例のキーを使用しないでください。) 205 // パスフレーズをキーに変換したい場合は、bcryptやscryptのような適切なパッケージを使用してください。 206 key, _ := hex.DecodeString("6368616e676520746869732070617373") 207 plaintext := []byte("some plaintext") 208 209 block, err := aes.NewCipher(key) 210 if err != nil { 211 panic(err) 212 } 213 214 // IVは一意である必要がありますが、セキュリティは必要ありません。そのため、一般的には暗号文の先頭に含まれます。 215 ciphertext := make([]byte, aes.BlockSize+len(plaintext)) 216 iv := ciphertext[:aes.BlockSize] 217 if _, err := io.ReadFull(rand.Reader, iv); err != nil { 218 panic(err) 219 } 220 221 stream := cipher.NewCTR(block, iv) 222 stream.XORKeyStream(ciphertext[aes.BlockSize:], plaintext) 223 224 // 暗号文は安全にするために、暗号化するだけでなく、認証(つまりcrypto/hmacを使用すること)することも重要であることを忘れないようにする必要があります。 225 226 // CTR モードは暗号化と復号化の両方に同じですので、NewCTR を使ってその暗号文を復号化することもできます。 227 228 plaintext2 := make([]byte, len(plaintext)) 229 stream = cipher.NewCTR(block, iv) 230 stream.XORKeyStream(plaintext2, ciphertext[aes.BlockSize:]) 231 232 fmt.Printf("%s\n", plaintext2) 233 // Output: some plaintext 234 } 235 236 func ExampleNewOFB() { 237 238 // 安全な場所から秘密鍵を読み込み、複数の NewCipher 呼び出しで再利用します。 239 //(もちろん、実際の用途にはこの例の鍵を使用しないでください。)もしパスフレーズを鍵に変換したい場合は、bcrypt や scrypt のような適切なパッケージを使用してください。 240 key, _ := hex.DecodeString("6368616e676520746869732070617373") 241 plaintext := []byte("some plaintext") 242 243 block, err := aes.NewCipher(key) 244 if err != nil { 245 panic(err) 246 } 247 248 // IVは一意である必要がありますが、セキュリティは必要ありません。そのため、一般的には 249 // 暗号文の先頭に含まれています。 250 ciphertext := make([]byte, aes.BlockSize+len(plaintext)) 251 iv := ciphertext[:aes.BlockSize] 252 if _, err := io.ReadFull(rand.Reader, iv); err != nil { 253 panic(err) 254 } 255 256 stream := cipher.NewOFB(block, iv) 257 stream.XORKeyStream(ciphertext[aes.BlockSize:], plaintext) 258 259 // 暗号文だけでなく、(crypto/hmacを使用して)認証も行われる必要があることを覚えておくことは重要です。これによってセキュリティが確保されます。 260 261 // OFBモードは暗号化と復号化の両方において同じですので、NewOFBを使ってその暗号文を復号化することも可能です。 262 263 plaintext2 := make([]byte, len(plaintext)) 264 stream = cipher.NewOFB(block, iv) 265 stream.XORKeyStream(plaintext2, ciphertext[aes.BlockSize:]) 266 267 fmt.Printf("%s\n", plaintext2) 268 // Output: some plaintext 269 } 270 271 func ExampleStreamReader() { 272 273 // 安全な場所から秘密の鍵をロードし、複数の NewCipher 呼び出しで再利用してください。 274 // (もちろん、これは実際には使用しないでください。)パスフレーズを鍵に変換したい場合は、bcrypt や scrypt のような適切なパッケージを使用してください。 275 key, _ := hex.DecodeString("6368616e676520746869732070617373") 276 277 encrypted, _ := hex.DecodeString("cf0495cc6f75dafc23948538e79904a9") 278 bReader := bytes.NewReader(encrypted) 279 280 block, err := aes.NewCipher(key) 281 if err != nil { 282 panic(err) 283 } 284 285 // もしキーがそれぞれの暗号文ごとにユニークである場合、ゼロの初期化ベクトル(IV)を使用しても問題ありません。 286 var iv [aes.BlockSize]byte 287 stream := cipher.NewOFB(block, iv[:]) 288 289 reader := &cipher.StreamReader{S: stream, R: bReader} 290 // 入力を出力ストリームにコピーし、逐次復号化する。 291 if _, err := io.Copy(os.Stdout, reader); err != nil { 292 panic(err) 293 } 294 295 // この例では、暗号化されたデータの認証を省略しているため、単純化されています。実際にこのようにStreamReaderを使用する場合、攻撃者は出力の任意のビットを反転させることができます。 296 297 // Output: some secret text 298 } 299 300 func ExampleStreamWriter() { 301 302 // 安全な場所から秘密キーを読み込み、複数の NewCipher 呼び出しで再利用します。 303 // (もちろん、実際の用途でこの例のキーを使用しないでください。) 304 // もしパスフレーズをキーに変換したい場合は、bcrypt や scrypt のような 305 // 適切なパッケージを使用してください。 306 key, _ := hex.DecodeString("6368616e676520746869732070617373") 307 308 bReader := bytes.NewReader([]byte("some secret text")) 309 310 block, err := aes.NewCipher(key) 311 if err != nil { 312 panic(err) 313 } 314 315 // キーが各暗号文ごとにユニークな場合、ゼロのIVを使用することは問題ありません。 316 var iv [aes.BlockSize]byte 317 stream := cipher.NewOFB(block, iv[:]) 318 319 var out bytes.Buffer 320 321 writer := &cipher.StreamWriter{S: stream, W: &out} 322 // 入力を出力バッファにコピーし、進行中に暗号化します。 323 if _, err := io.Copy(writer, bReader); err != nil { 324 panic(err) 325 } 326 327 // この例は暗号化されたデータの認証を省略して簡略化しています。実際にStreamReaderをこのように使用する場合、攻撃者が復号化された結果内の任意のビットを反転させる可能性があります。 328 329 fmt.Printf("%x\n", out.Bytes()) 330 // Output: cf0495cc6f75dafc23948538e79904a9 331 }