git.iko.soy/typeable/oauth2-proxy
on master help sign in
Ensure Cipher.Decrypt doesn't mangle input ciphertext []byte
commit7bb5fc0a810165225a8a56791bcb081febae642b authorNick Meves <nick.meves@greenhouse.io> dateMon 11 May 2020, 12:27 (6 years ago) parente823d87
2 files changed+16−6
pkg/encryption/cipher.go+8−6 pkg/encryption/cipher_test.go+8
pkg/encryption/cipher.go+8−6
@@ -50,7 +50,7 @@ func NewBase64Cipher(initCipher func([]byte) (Cipher, error), secret []byte) (Ci
5050 return &Base64Cipher{Cipher: c}, nil
5151}
5252
53−// Encrypt encrypts a value with AES CFB & Base64 encodes it
53+// Encrypt encrypts a value with the embedded Cipher & Base64 encodes it
5454func (c *Base64Cipher) Encrypt(value []byte) ([]byte, error) {
5555 encrypted, err := c.Cipher.Encrypt([]byte(value))
5656 if err != nil {
@@ -60,7 +60,7 @@ func (c *Base64Cipher) Encrypt(value []byte) ([]byte, error) {
6060 return []byte(base64.StdEncoding.EncodeToString(encrypted)), nil
6161}
6262
63−// Decrypt Base64 decodes a value & decrypts it with AES CFB
63+// Decrypt Base64 decodes a value & decrypts it with the embedded Cipher
6464func (c *Base64Cipher) Decrypt(ciphertext []byte) ([]byte, error) {
6565 encrypted, err := base64.StdEncoding.DecodeString(string(ciphertext))
6666 if err != nil {
@@ -103,12 +103,12 @@ func (c *CFBCipher) Decrypt(ciphertext []byte) ([]byte, error) {
103103 return nil, fmt.Errorf("encrypted value should be at least %d bytes, but is only %d bytes", aes.BlockSize, len(ciphertext))
104104 }
105105
106− iv := ciphertext[:aes.BlockSize]
107− ciphertext = ciphertext[aes.BlockSize:]
106+ iv, ciphertext := ciphertext[:aes.BlockSize], ciphertext[aes.BlockSize:]
107+ plaintext := make([]byte, len(ciphertext))
108108 stream := cipher.NewCFBDecrypter(c.Block, iv)
109− stream.XORKeyStream(ciphertext, ciphertext)
109+ stream.XORKeyStream(plaintext, ciphertext)
110110
111− return ciphertext, nil
111+ return plaintext, nil
112112}
113113
114114type GCMCipher struct {
@@ -135,6 +135,8 @@ func (c *GCMCipher) Encrypt(value []byte) ([]byte, error) {
135135 if _, err = io.ReadFull(rand.Reader, nonce); err != nil {
136136 return nil, err
137137 }
138+ // Using nonce as Seal's dst argument results in it being the first
139+ // chunk of bytes in the ciphertext. Decrypt retrieves the nonce/IV from this.
138140 ciphertext := gcm.Seal(nonce, nonce, value, nil)
139141 return ciphertext, nil
140142}
pkg/encryption/cipher_test.go+8
@@ -84,9 +84,17 @@ func TestEncryptAndDecrypt(t *testing.T) {
8484 assert.Equal(t, nil, err)
8585 assert.NotEqual(t, encrypted, data)
8686
87+ // Ensure our Decrypt function doesn't decrypt in place
88+ immutable := make([]byte, len(encrypted))
89+ copy(immutable, encrypted)
90+
8791 decrypted, err := c.Decrypt(encrypted)
8892 assert.Equal(t, nil, err)
93+ // Original data back
8994 assert.Equal(t, data, decrypted)
95+ // Decrypt didn't operate in-place on []byte
96+ assert.Equal(t, encrypted, immutable)
97+ // Encrypt/Decrypt actually did something
9098 assert.NotEqual(t, encrypted, decrypted)
9199 })
92100 }