Use sensible way of encrypting and decrypting data
This ensures the ciphertext also is authenticated.
This commit is contained in:
92
en/09.6.md
92
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
|
||||
|
||||
Reference in New Issue
Block a user