github.com/tickoalcantara12/micro/v3@v3.0.0-20221007104245-9d75b9bcbab9/service/network/tunnel/mucp/crypto.go (about)

     1  // Licensed under the Apache License, Version 2.0 (the "License");
     2  // you may not use this file except in compliance with the License.
     3  // You may obtain a copy of the License at
     4  //
     5  //     https://www.apache.org/licenses/LICENSE-2.0
     6  //
     7  // Unless required by applicable law or agreed to in writing, software
     8  // distributed under the License is distributed on an "AS IS" BASIS,
     9  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    10  // See the License for the specific language governing permissions and
    11  // limitations under the License.
    12  //
    13  // Original source: github.com/micro/go-micro/v3/network/tunnel/mucp/crypto.go
    14  
    15  package mucp
    16  
    17  import (
    18  	"crypto/aes"
    19  	"crypto/cipher"
    20  	"crypto/rand"
    21  	"crypto/sha256"
    22  
    23  	"github.com/tickoalcantara12/micro/v3/service/network/tunnel"
    24  	"github.com/oxtoacart/bpool"
    25  )
    26  
    27  var (
    28  	// the local buffer pool
    29  	// gcmStandardNonceSize from crypto/cipher/gcm.go is 12 bytes
    30  	// 100 - is max size of pool
    31  	noncePool = bpool.NewBytePool(100, 12)
    32  )
    33  
    34  // hash hahes the data into 32 bytes key and returns it
    35  // hash uses sha256 underneath to hash the supplied key
    36  func hash(key []byte) []byte {
    37  	sum := sha256.Sum256(key)
    38  	return sum[:]
    39  }
    40  
    41  // Encrypt encrypts data and returns the encrypted data
    42  func Encrypt(gcm cipher.AEAD, data []byte) ([]byte, error) {
    43  	var err error
    44  
    45  	// get new byte array the size of the nonce from pool
    46  	// NOTE: we might use smaller nonce size in the future
    47  	nonce := noncePool.Get()
    48  	if _, err = rand.Read(nonce); err != nil {
    49  		return nil, err
    50  	}
    51  	defer noncePool.Put(nonce)
    52  
    53  	// NOTE: we prepend the nonce to the payload
    54  	// we need to do this as we need the same nonce
    55  	// to decrypt the payload when receiving it
    56  	return gcm.Seal(nonce, nonce, data, nil), nil
    57  }
    58  
    59  // Decrypt decrypts the payload and returns the decrypted data
    60  func newCipher(key []byte) (cipher.AEAD, error) {
    61  	var err error
    62  
    63  	// generate a new AES cipher using our 32 byte key for decrypting the message
    64  	c, err := aes.NewCipher(hash(key))
    65  	if err != nil {
    66  		return nil, err
    67  	}
    68  
    69  	// gcm or Galois/Counter Mode, is a mode of operation
    70  	// for symmetric key cryptographic block ciphers
    71  	// - https://en.wikipedia.org/wiki/Galois/Counter_Mode
    72  	gcm, err := cipher.NewGCM(c)
    73  	if err != nil {
    74  		return nil, err
    75  	}
    76  
    77  	return gcm, nil
    78  }
    79  
    80  func Decrypt(gcm cipher.AEAD, data []byte) ([]byte, error) {
    81  	var err error
    82  
    83  	nonceSize := gcm.NonceSize()
    84  
    85  	if len(data) < nonceSize {
    86  		return nil, tunnel.ErrDecryptingData
    87  	}
    88  
    89  	// NOTE: we need to parse out nonce from the payload
    90  	// we prepend the nonce to every encrypted payload
    91  	nonce, ciphertext := data[:nonceSize], data[nonceSize:]
    92  	ciphertext, err = gcm.Open(ciphertext[:0], nonce, ciphertext, nil)
    93  	if err != nil {
    94  		return nil, err
    95  	}
    96  
    97  	return ciphertext, nil
    98  }