-
Notifications
You must be signed in to change notification settings - Fork 2.6k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
#1828: Support encrypted DNS txt records
Signed-off-by: Viacheslav Sychov <[email protected]>
- Loading branch information
Showing
11 changed files
with
423 additions
and
52 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,134 @@ | ||
/* | ||
Copyright 2017 The Kubernetes Authors. | ||
Licensed under the Apache License, Version 2.0 (the "License"); | ||
you may not use this file except in compliance with the License. | ||
You may obtain a copy of the License at | ||
http://www.apache.org/licenses/LICENSE-2.0 | ||
Unless required by applicable law or agreed to in writing, software | ||
distributed under the License is distributed on an "AS IS" BASIS, | ||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
See the License for the specific language governing permissions and | ||
limitations under the License. | ||
*/ | ||
|
||
package endpoint | ||
|
||
import ( | ||
"bytes" | ||
"compress/gzip" | ||
"crypto/aes" | ||
"crypto/cipher" | ||
"crypto/rand" | ||
"encoding/base64" | ||
"fmt" | ||
"io" | ||
|
||
log "github.com/sirupsen/logrus" | ||
) | ||
|
||
// EncryptText gzip input data and encrypts it using the supplied AES key | ||
func EncryptText(text string, aesKey []byte, nonceEncoded []byte) (string, error) { | ||
block, err := aes.NewCipher(aesKey) | ||
if err != nil { | ||
return "", err | ||
} | ||
|
||
gcm, err := cipher.NewGCM(block) | ||
if err != nil { | ||
return "", err | ||
} | ||
|
||
nonce := make([]byte, gcm.NonceSize()) | ||
if nonceEncoded == nil { | ||
if _, err = io.ReadFull(rand.Reader, nonce); err != nil { | ||
return "", err | ||
} | ||
} else { | ||
if _, err = base64.StdEncoding.Decode(nonce, nonceEncoded); err != nil { | ||
return "", err | ||
} | ||
} | ||
|
||
data, err := compressData([]byte(text)) | ||
if err != nil { | ||
return "", err | ||
} | ||
|
||
cipherData := gcm.Seal(nonce, nonce, data, nil) | ||
return base64.StdEncoding.EncodeToString(cipherData), nil | ||
} | ||
|
||
// DecryptText decrypt gziped data using a supplied AES encryption key ang ungzip it | ||
// in case of decryption failed, will return original input and decryption error | ||
func DecryptText(text string, aesKey []byte) (decryptResult string, encryptNonce string, err error) { | ||
block, err := aes.NewCipher(aesKey) | ||
if err != nil { | ||
return "", "", err | ||
} | ||
gcm, err := cipher.NewGCM(block) | ||
if err != nil { | ||
return "", "", err | ||
} | ||
nonceSize := gcm.NonceSize() | ||
data, err := base64.StdEncoding.DecodeString(text) | ||
if err != nil { | ||
return "", "", err | ||
} | ||
if len(data) <= nonceSize { | ||
return "", "", fmt.Errorf("the encoded data from text %#v is shorter than %#v bytes and can't be decoded", text, nonceSize) | ||
} | ||
nonce, ciphertext := data[:nonceSize], data[nonceSize:] | ||
plaindata, err := gcm.Open(nil, nonce, ciphertext, nil) | ||
if err != nil { | ||
return "", "", err | ||
} | ||
plaindata, err = decompressData(plaindata) | ||
if err != nil { | ||
log.Debugf("Failed to decompress data based on the base64 encoded text %#v. Got error %#v.", text, err) | ||
return "", "", err | ||
} | ||
|
||
return string(plaindata), base64.StdEncoding.EncodeToString(nonce), nil | ||
} | ||
|
||
// decompressData gzip compressed data | ||
func decompressData(data []byte) (resData []byte, err error) { | ||
gz, err := gzip.NewReader(bytes.NewBuffer(data)) | ||
if err != nil { | ||
return nil, err | ||
} | ||
defer gz.Close() | ||
var b bytes.Buffer | ||
if _, err = b.ReadFrom(gz); err != nil { | ||
return nil, err | ||
} | ||
|
||
return b.Bytes(), nil | ||
} | ||
|
||
// compressData by gzip, for minify data stored in registry | ||
func compressData(data []byte) (compressedData []byte, err error) { | ||
var b bytes.Buffer | ||
gz, err := gzip.NewWriterLevel(&b, gzip.BestCompression) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
defer gz.Close() | ||
if _, err = gz.Write(data); err != nil { | ||
return nil, err | ||
} | ||
|
||
if err = gz.Flush(); err != nil { | ||
return nil, err | ||
} | ||
|
||
if err = gz.Close(); err != nil { | ||
return nil, err | ||
} | ||
|
||
return b.Bytes(), nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
/* | ||
Copyright 2017 The Kubernetes Authors. | ||
Licensed under the Apache License, Version 2.0 (the "License"); | ||
you may not use this file except in compliance with the License. | ||
You may obtain a copy of the License at | ||
http://www.apache.org/licenses/LICENSE-2.0 | ||
Unless required by applicable law or agreed to in writing, software | ||
distributed under the License is distributed on an "AS IS" BASIS, | ||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
See the License for the specific language governing permissions and | ||
limitations under the License. | ||
*/ | ||
|
||
package endpoint | ||
|
||
import ( | ||
"testing" | ||
|
||
"github.com/stretchr/testify/require" | ||
) | ||
|
||
func TestEncrypt(t *testing.T) { | ||
// Verify that text encryption and decryption works | ||
aesKey := []byte("s%zF`.*'5`9.AhI2!B,.~hmbs^.*TL?;") | ||
plaintext := "Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum." | ||
encryptedtext, err := EncryptText(plaintext, aesKey, nil) | ||
require.NoError(t, err) | ||
decryptedtext, _, err := DecryptText(encryptedtext, aesKey) | ||
require.NoError(t, err) | ||
if plaintext != decryptedtext { | ||
t.Errorf("Original plain text %#v differs from the resulting decrypted text %#v", plaintext, decryptedtext) | ||
} | ||
|
||
// Verify that decrypt returns an error and empty data if wrong AES encryption key is used | ||
decryptedtext, _, err = DecryptText(encryptedtext, []byte("s'J!jD`].LC?g&Oa11AgTub,j48ts/96")) | ||
require.Error(t, err) | ||
if decryptedtext != "" { | ||
t.Error("Data decryption failed, empty string should be as result") | ||
} | ||
|
||
// Verify that decrypt returns an error and empty data if unencrypted input is is supplied | ||
decryptedtext, _, err = DecryptText(plaintext, aesKey) | ||
require.Error(t, err) | ||
if decryptedtext != "" { | ||
t.Errorf("Data decryption failed, empty string should be as result") | ||
} | ||
|
||
// Verify that a known encrypted text is decrypted to what is expected | ||
encryptedtext = "0Mfzf6wsN8llrfX0ucDZ6nlc2+QiQfKKedjPPLu5atb2I35L9nUZeJcCnuLVW7CVW3K0h94vSuBLdXnMrj8Vcm0M09shxaoF48IcCpD03XtQbKXqk2hPbsW6+JybvplHIQGr16/PcjUSObGmR9yjf38+qEltApkKvrPjsyw43BX4eE10rL0Bln33UJD7/w+zazRDPFlAcbGtkt0ETKHnvyB3/aCddLipvrhjCXj2ZY/ktRF6h716kJRgXU10dCIQHFYU45MIdxI+k10HK3yZqhI2V0Gp2xjrFV/LRQ7/OS9SFee4asPWUYxbCEsnOzp8qc0dCPFSo1dtADzWnUZnsAcbnjtudT4milfLJc5CxDk1v3ykqQ/ajejwHjWQ7b8U6AsTErbezfdcqrb5IzkLgHb5TosnfrdDmNc9GcKfpsrCHbVY8KgNwMVdtwavLv7d9WM6sooUlZ3t0sABGkzagXQmPRvwLnkSOlie5XrnzWo8/8/4UByLga29CaXO" | ||
decryptedtext, _, err = DecryptText(encryptedtext, aesKey) | ||
require.NoError(t, err) | ||
if decryptedtext != plaintext { | ||
t.Error("Decryption of text didn't result in expected plaintext result.") | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.