From 9657ebbe0e6150e42218ad9c00524832ef364aba Mon Sep 17 00:00:00 2001 From: Leon Klingele Date: Tue, 11 Apr 2017 13:07:26 +0200 Subject: [PATCH] Use sensible way of encrypting and decrypting data This ensures the ciphertext also is authenticated. --- en/09.6.md | 92 +++++++++++++++++++++++++++++++++--------------------- 1 file changed, 57 insertions(+), 35 deletions(-) diff --git a/en/09.6.md b/en/09.6.md index de0af06b..840621a7 100644 --- a/en/09.6.md +++ b/en/09.6.md @@ -4,58 +4,80 @@ The previous section describes how to securely store passwords, but sometimes it ## Advanced encryption and decryption -The Go language supports symmetric encryption algorithms in its `crypto` package. Two advanced encryption modules are: +The Go language supports symmetric encryption algorithms in its `crypto` package. Do not use anything except AES in [GCM mode](https://en.wikipedia.org/wiki/Galois/Counter_Mode) if you don't know what you're doing! - `crypto/aes` package: AES (Advanced Encryption Standard), also known as Rijndael encryption method, is used by the U.S. federal government as a block encryption standard. -- `crypto/des` package: DES (Data Encryption Standard), is a symmetric encryption standard . It's currently the most widely used key system, especially in protecting the security of financial data. It used to be the United States federal government's encryption standard, but has now been replaced by AES. -Because using these two encryption algorithms is quite similar, we'll just use the `aes` package in the following example to demonstrate how you'd typically use these packages: +In the following example we demonstrate how to encrypt data using AES in GCM mode: package main import ( "crypto/aes" "crypto/cipher" + "crypto/rand" + "errors" "fmt" - "os" + "io" + "log" ) - var commonIV = []byte{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f} - func main() { - // Need to encrypt a string - plaintext := []byte("My name is Astaxie") - // If there is an incoming string of words to be encrypted, set plaintext to that incoming string - if len(os.Args) > 1 { - plaintext = []byte(os.Args[1]) - } + text := []byte("My name is Astaxie") + key := []byte("the-key-has-to-be-32-bytes-long!") - // aes encryption string - key_text := "astaxie12798akljzmknm.ahkjkljl;k" - if len(os.Args) > 2 { - key_text = os.Args[2] - } - - fmt.Println(len(key_text)) - - // Create the aes encryption algorithm - c, err := aes.NewCipher([]byte(key_text)) + ciphertext, err := encrypt(text, key) if err != nil { - fmt.Printf("Error: NewCipher(%d bytes) = %s", len(key_text), err) - os.Exit(-1) + // TODO: Properly handle error + log.Fatal(err) + } + fmt.Printf("%s => %x\n", text, ciphertext) + + plaintext, err := decrypt(ciphertext, key) + if err != nil { + // TODO: Properly handle error + log.Fatal(err) + } + fmt.Printf("%x => %s\n", ciphertext, plaintext) + } + + func encrypt(plaintext []byte, key []byte) ([]byte, error) { + c, err := aes.NewCipher(key) + if err != nil { + return nil, err } - // Encrypted string - cfb := cipher.NewCFBEncrypter(c, commonIV) - ciphertext := make([]byte, len(plaintext)) - cfb.XORKeyStream(ciphertext, plaintext) - fmt.Printf("%s=>%x\n", plaintext, ciphertext) + gcm, err := cipher.NewGCM(c) + if err != nil { + return nil, err + } - // Decrypt strings - cfbdec := cipher.NewCFBDecrypter(c, commonIV) - plaintextCopy := make([]byte, len(plaintext)) - cfbdec.XORKeyStream(plaintextCopy, ciphertext) - fmt.Printf("%x=>%s\n", ciphertext, plaintextCopy) + nonce := make([]byte, gcm.NonceSize()) + if _, err = io.ReadFull(rand.Reader, nonce); err != nil { + return nil, err + } + + return gcm.Seal(nonce, nonce, plaintext, nil), nil + } + + func decrypt(ciphertext []byte, key []byte) ([]byte, error) { + c, err := aes.NewCipher(key) + if err != nil { + return nil, err + } + + gcm, err := cipher.NewGCM(c) + if err != nil { + return nil, err + } + + nonceSize := gcm.NonceSize() + if len(ciphertext) < nonceSize { + return nil, errors.New("ciphertext too short") + } + + nonce, ciphertext := ciphertext[:nonceSize], ciphertext[nonceSize:] + return gcm.Open(nil, nonce, ciphertext, nil) } Calling the above function `aes.NewCipher` (whose []byte key parameter must be 16, 24 or 32, corresponding to the AES-128, AES-192 or AES-256 algorithms, respectively), returns a `cipher.Block` Interface that implements three functions: @@ -77,7 +99,7 @@ These three functions implement encryption and decryption operations; see the Go ## Summary -This section describes encryption algorithms which can be used in different ways according to your web application's encryption and decryption needs. For applications with even basic security requirements it is recommended to use AES. +This section describes encryption algorithms which can be used in different ways according to your web application's encryption and decryption needs. For applications with even basic security requirements it is recommended to use AES in GCM mode. ## Links