sigs.k8s.io/external-dns@v0.14.1/endpoint/crypto.go (about) 1 /* 2 Copyright 2017 The Kubernetes Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package endpoint 18 19 import ( 20 "bytes" 21 "compress/gzip" 22 "crypto/aes" 23 "crypto/cipher" 24 "crypto/rand" 25 "encoding/base64" 26 "fmt" 27 "io" 28 29 log "github.com/sirupsen/logrus" 30 ) 31 32 const standardGcmNonceSize = 12 33 34 // GenerateNonce creates a random nonce of a fixed size 35 func GenerateNonce() ([]byte, error) { 36 nonce := make([]byte, standardGcmNonceSize) 37 if _, err := io.ReadFull(rand.Reader, nonce); err != nil { 38 return nil, err 39 } 40 return []byte(base64.StdEncoding.EncodeToString(nonce)), nil 41 } 42 43 // EncryptText gzip input data and encrypts it using the supplied AES key 44 func EncryptText(text string, aesKey []byte, nonceEncoded []byte) (string, error) { 45 block, err := aes.NewCipher(aesKey) 46 if err != nil { 47 return "", err 48 } 49 50 gcm, err := cipher.NewGCMWithNonceSize(block, standardGcmNonceSize) 51 if err != nil { 52 return "", err 53 } 54 55 nonce := make([]byte, standardGcmNonceSize) 56 if _, err = base64.StdEncoding.Decode(nonce, nonceEncoded); err != nil { 57 return "", err 58 } 59 60 data, err := compressData([]byte(text)) 61 if err != nil { 62 return "", err 63 } 64 65 cipherData := gcm.Seal(nonce, nonce, data, nil) 66 return base64.StdEncoding.EncodeToString(cipherData), nil 67 } 68 69 // DecryptText decrypt gziped data using a supplied AES encryption key ang ungzip it 70 // in case of decryption failed, will return original input and decryption error 71 func DecryptText(text string, aesKey []byte) (decryptResult string, encryptNonce string, err error) { 72 block, err := aes.NewCipher(aesKey) 73 if err != nil { 74 return "", "", err 75 } 76 gcm, err := cipher.NewGCM(block) 77 if err != nil { 78 return "", "", err 79 } 80 nonceSize := gcm.NonceSize() 81 data, err := base64.StdEncoding.DecodeString(text) 82 if err != nil { 83 return "", "", err 84 } 85 if len(data) <= nonceSize { 86 return "", "", fmt.Errorf("the encoded data from text %#v is shorter than %#v bytes and can't be decoded", text, nonceSize) 87 } 88 nonce, ciphertext := data[:nonceSize], data[nonceSize:] 89 plaindata, err := gcm.Open(nil, nonce, ciphertext, nil) 90 if err != nil { 91 return "", "", err 92 } 93 plaindata, err = decompressData(plaindata) 94 if err != nil { 95 log.Debugf("Failed to decompress data based on the base64 encoded text %#v. Got error %#v.", text, err) 96 return "", "", err 97 } 98 99 return string(plaindata), base64.StdEncoding.EncodeToString(nonce), nil 100 } 101 102 // decompressData gzip compressed data 103 func decompressData(data []byte) (resData []byte, err error) { 104 gz, err := gzip.NewReader(bytes.NewBuffer(data)) 105 if err != nil { 106 return nil, err 107 } 108 defer gz.Close() 109 var b bytes.Buffer 110 if _, err = b.ReadFrom(gz); err != nil { 111 return nil, err 112 } 113 114 return b.Bytes(), nil 115 } 116 117 // compressData by gzip, for minify data stored in registry 118 func compressData(data []byte) (compressedData []byte, err error) { 119 var b bytes.Buffer 120 gz, err := gzip.NewWriterLevel(&b, gzip.BestCompression) 121 if err != nil { 122 return nil, err 123 } 124 125 defer gz.Close() 126 if _, err = gz.Write(data); err != nil { 127 return nil, err 128 } 129 130 if err = gz.Flush(); err != nil { 131 return nil, err 132 } 133 134 if err = gz.Close(); err != nil { 135 return nil, err 136 } 137 138 return b.Bytes(), nil 139 }