diff options
Diffstat (limited to '')
-rw-r--r-- | src/crypto/cipher/example_test.go | 363 |
1 files changed, 363 insertions, 0 deletions
diff --git a/src/crypto/cipher/example_test.go b/src/crypto/cipher/example_test.go new file mode 100644 index 0000000..9c32d6a --- /dev/null +++ b/src/crypto/cipher/example_test.go @@ -0,0 +1,363 @@ +// Copyright 2012 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package cipher_test + +import ( + "bytes" + "crypto/aes" + "crypto/cipher" + "crypto/rand" + "encoding/hex" + "fmt" + "io" + "os" +) + +func ExampleNewGCM_encrypt() { + // Load your secret key from a safe place and reuse it across multiple + // Seal/Open calls. (Obviously don't use this example key for anything + // real.) If you want to convert a passphrase to a key, use a suitable + // package like bcrypt or scrypt. + // When decoded the key should be 16 bytes (AES-128) or 32 (AES-256). + key, _ := hex.DecodeString("6368616e676520746869732070617373776f726420746f206120736563726574") + plaintext := []byte("exampleplaintext") + + block, err := aes.NewCipher(key) + if err != nil { + panic(err.Error()) + } + + // Never use more than 2^32 random nonces with a given key because of the risk of a repeat. + nonce := make([]byte, 12) + if _, err := io.ReadFull(rand.Reader, nonce); err != nil { + panic(err.Error()) + } + + aesgcm, err := cipher.NewGCM(block) + if err != nil { + panic(err.Error()) + } + + ciphertext := aesgcm.Seal(nil, nonce, plaintext, nil) + fmt.Printf("%x\n", ciphertext) +} + +func ExampleNewGCM_decrypt() { + // Load your secret key from a safe place and reuse it across multiple + // Seal/Open calls. (Obviously don't use this example key for anything + // real.) If you want to convert a passphrase to a key, use a suitable + // package like bcrypt or scrypt. + // When decoded the key should be 16 bytes (AES-128) or 32 (AES-256). + key, _ := hex.DecodeString("6368616e676520746869732070617373776f726420746f206120736563726574") + ciphertext, _ := hex.DecodeString("c3aaa29f002ca75870806e44086700f62ce4d43e902b3888e23ceff797a7a471") + nonce, _ := hex.DecodeString("64a9433eae7ccceee2fc0eda") + + block, err := aes.NewCipher(key) + if err != nil { + panic(err.Error()) + } + + aesgcm, err := cipher.NewGCM(block) + if err != nil { + panic(err.Error()) + } + + plaintext, err := aesgcm.Open(nil, nonce, ciphertext, nil) + if err != nil { + panic(err.Error()) + } + + fmt.Printf("%s\n", plaintext) + // Output: exampleplaintext +} + +func ExampleNewCBCDecrypter() { + // Load your secret key from a safe place and reuse it across multiple + // NewCipher calls. (Obviously don't use this example key for anything + // real.) If you want to convert a passphrase to a key, use a suitable + // package like bcrypt or scrypt. + key, _ := hex.DecodeString("6368616e676520746869732070617373") + ciphertext, _ := hex.DecodeString("73c86d43a9d700a253a96c85b0f6b03ac9792e0e757f869cca306bd3cba1c62b") + + block, err := aes.NewCipher(key) + if err != nil { + panic(err) + } + + // The IV needs to be unique, but not secure. Therefore it's common to + // include it at the beginning of the ciphertext. + if len(ciphertext) < aes.BlockSize { + panic("ciphertext too short") + } + iv := ciphertext[:aes.BlockSize] + ciphertext = ciphertext[aes.BlockSize:] + + // CBC mode always works in whole blocks. + if len(ciphertext)%aes.BlockSize != 0 { + panic("ciphertext is not a multiple of the block size") + } + + mode := cipher.NewCBCDecrypter(block, iv) + + // CryptBlocks can work in-place if the two arguments are the same. + mode.CryptBlocks(ciphertext, ciphertext) + + // If the original plaintext lengths are not a multiple of the block + // size, padding would have to be added when encrypting, which would be + // removed at this point. For an example, see + // https://tools.ietf.org/html/rfc5246#section-6.2.3.2. However, it's + // critical to note that ciphertexts must be authenticated (i.e. by + // using crypto/hmac) before being decrypted in order to avoid creating + // a padding oracle. + + fmt.Printf("%s\n", ciphertext) + // Output: exampleplaintext +} + +func ExampleNewCBCEncrypter() { + // Load your secret key from a safe place and reuse it across multiple + // NewCipher calls. (Obviously don't use this example key for anything + // real.) If you want to convert a passphrase to a key, use a suitable + // package like bcrypt or scrypt. + key, _ := hex.DecodeString("6368616e676520746869732070617373") + plaintext := []byte("exampleplaintext") + + // CBC mode works on blocks so plaintexts may need to be padded to the + // next whole block. For an example of such padding, see + // https://tools.ietf.org/html/rfc5246#section-6.2.3.2. Here we'll + // assume that the plaintext is already of the correct length. + if len(plaintext)%aes.BlockSize != 0 { + panic("plaintext is not a multiple of the block size") + } + + block, err := aes.NewCipher(key) + if err != nil { + panic(err) + } + + // The IV needs to be unique, but not secure. Therefore it's common to + // include it at the beginning of the ciphertext. + ciphertext := make([]byte, aes.BlockSize+len(plaintext)) + iv := ciphertext[:aes.BlockSize] + if _, err := io.ReadFull(rand.Reader, iv); err != nil { + panic(err) + } + + mode := cipher.NewCBCEncrypter(block, iv) + mode.CryptBlocks(ciphertext[aes.BlockSize:], plaintext) + + // It's important to remember that ciphertexts must be authenticated + // (i.e. by using crypto/hmac) as well as being encrypted in order to + // be secure. + + fmt.Printf("%x\n", ciphertext) +} + +func ExampleNewCFBDecrypter() { + // Load your secret key from a safe place and reuse it across multiple + // NewCipher calls. (Obviously don't use this example key for anything + // real.) If you want to convert a passphrase to a key, use a suitable + // package like bcrypt or scrypt. + key, _ := hex.DecodeString("6368616e676520746869732070617373") + ciphertext, _ := hex.DecodeString("7dd015f06bec7f1b8f6559dad89f4131da62261786845100056b353194ad") + + block, err := aes.NewCipher(key) + if err != nil { + panic(err) + } + + // The IV needs to be unique, but not secure. Therefore it's common to + // include it at the beginning of the ciphertext. + if len(ciphertext) < aes.BlockSize { + panic("ciphertext too short") + } + iv := ciphertext[:aes.BlockSize] + ciphertext = ciphertext[aes.BlockSize:] + + stream := cipher.NewCFBDecrypter(block, iv) + + // XORKeyStream can work in-place if the two arguments are the same. + stream.XORKeyStream(ciphertext, ciphertext) + fmt.Printf("%s", ciphertext) + // Output: some plaintext +} + +func ExampleNewCFBEncrypter() { + // Load your secret key from a safe place and reuse it across multiple + // NewCipher calls. (Obviously don't use this example key for anything + // real.) If you want to convert a passphrase to a key, use a suitable + // package like bcrypt or scrypt. + key, _ := hex.DecodeString("6368616e676520746869732070617373") + plaintext := []byte("some plaintext") + + block, err := aes.NewCipher(key) + if err != nil { + panic(err) + } + + // The IV needs to be unique, but not secure. Therefore it's common to + // include it at the beginning of the ciphertext. + ciphertext := make([]byte, aes.BlockSize+len(plaintext)) + iv := ciphertext[:aes.BlockSize] + if _, err := io.ReadFull(rand.Reader, iv); err != nil { + panic(err) + } + + stream := cipher.NewCFBEncrypter(block, iv) + stream.XORKeyStream(ciphertext[aes.BlockSize:], plaintext) + + // It's important to remember that ciphertexts must be authenticated + // (i.e. by using crypto/hmac) as well as being encrypted in order to + // be secure. + fmt.Printf("%x\n", ciphertext) +} + +func ExampleNewCTR() { + // Load your secret key from a safe place and reuse it across multiple + // NewCipher calls. (Obviously don't use this example key for anything + // real.) If you want to convert a passphrase to a key, use a suitable + // package like bcrypt or scrypt. + key, _ := hex.DecodeString("6368616e676520746869732070617373") + plaintext := []byte("some plaintext") + + block, err := aes.NewCipher(key) + if err != nil { + panic(err) + } + + // The IV needs to be unique, but not secure. Therefore it's common to + // include it at the beginning of the ciphertext. + ciphertext := make([]byte, aes.BlockSize+len(plaintext)) + iv := ciphertext[:aes.BlockSize] + if _, err := io.ReadFull(rand.Reader, iv); err != nil { + panic(err) + } + + stream := cipher.NewCTR(block, iv) + stream.XORKeyStream(ciphertext[aes.BlockSize:], plaintext) + + // It's important to remember that ciphertexts must be authenticated + // (i.e. by using crypto/hmac) as well as being encrypted in order to + // be secure. + + // CTR mode is the same for both encryption and decryption, so we can + // also decrypt that ciphertext with NewCTR. + + plaintext2 := make([]byte, len(plaintext)) + stream = cipher.NewCTR(block, iv) + stream.XORKeyStream(plaintext2, ciphertext[aes.BlockSize:]) + + fmt.Printf("%s\n", plaintext2) + // Output: some plaintext +} + +func ExampleNewOFB() { + // Load your secret key from a safe place and reuse it across multiple + // NewCipher calls. (Obviously don't use this example key for anything + // real.) If you want to convert a passphrase to a key, use a suitable + // package like bcrypt or scrypt. + key, _ := hex.DecodeString("6368616e676520746869732070617373") + plaintext := []byte("some plaintext") + + block, err := aes.NewCipher(key) + if err != nil { + panic(err) + } + + // The IV needs to be unique, but not secure. Therefore it's common to + // include it at the beginning of the ciphertext. + ciphertext := make([]byte, aes.BlockSize+len(plaintext)) + iv := ciphertext[:aes.BlockSize] + if _, err := io.ReadFull(rand.Reader, iv); err != nil { + panic(err) + } + + stream := cipher.NewOFB(block, iv) + stream.XORKeyStream(ciphertext[aes.BlockSize:], plaintext) + + // It's important to remember that ciphertexts must be authenticated + // (i.e. by using crypto/hmac) as well as being encrypted in order to + // be secure. + + // OFB mode is the same for both encryption and decryption, so we can + // also decrypt that ciphertext with NewOFB. + + plaintext2 := make([]byte, len(plaintext)) + stream = cipher.NewOFB(block, iv) + stream.XORKeyStream(plaintext2, ciphertext[aes.BlockSize:]) + + fmt.Printf("%s\n", plaintext2) + // Output: some plaintext +} + +func ExampleStreamReader() { + // Load your secret key from a safe place and reuse it across multiple + // NewCipher calls. (Obviously don't use this example key for anything + // real.) If you want to convert a passphrase to a key, use a suitable + // package like bcrypt or scrypt. + key, _ := hex.DecodeString("6368616e676520746869732070617373") + + encrypted, _ := hex.DecodeString("cf0495cc6f75dafc23948538e79904a9") + bReader := bytes.NewReader(encrypted) + + block, err := aes.NewCipher(key) + if err != nil { + panic(err) + } + + // If the key is unique for each ciphertext, then it's ok to use a zero + // IV. + var iv [aes.BlockSize]byte + stream := cipher.NewOFB(block, iv[:]) + + reader := &cipher.StreamReader{S: stream, R: bReader} + // Copy the input to the output stream, decrypting as we go. + if _, err := io.Copy(os.Stdout, reader); err != nil { + panic(err) + } + + // Note that this example is simplistic in that it omits any + // authentication of the encrypted data. If you were actually to use + // StreamReader in this manner, an attacker could flip arbitrary bits in + // the output. + + // Output: some secret text +} + +func ExampleStreamWriter() { + // Load your secret key from a safe place and reuse it across multiple + // NewCipher calls. (Obviously don't use this example key for anything + // real.) If you want to convert a passphrase to a key, use a suitable + // package like bcrypt or scrypt. + key, _ := hex.DecodeString("6368616e676520746869732070617373") + + bReader := bytes.NewReader([]byte("some secret text")) + + block, err := aes.NewCipher(key) + if err != nil { + panic(err) + } + + // If the key is unique for each ciphertext, then it's ok to use a zero + // IV. + var iv [aes.BlockSize]byte + stream := cipher.NewOFB(block, iv[:]) + + var out bytes.Buffer + + writer := &cipher.StreamWriter{S: stream, W: &out} + // Copy the input to the output buffer, encrypting as we go. + if _, err := io.Copy(writer, bReader); err != nil { + panic(err) + } + + // Note that this example is simplistic in that it omits any + // authentication of the encrypted data. If you were actually to use + // StreamReader in this manner, an attacker could flip arbitrary bits in + // the decrypted result. + + fmt.Printf("%x\n", out.Bytes()) + // Output: cf0495cc6f75dafc23948538e79904a9 +} |