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  }