github.com/goravel/framework@v1.13.9/crypt/aes.go (about)

     1  package crypt
     2  
     3  import (
     4  	"crypto/aes"
     5  	"crypto/cipher"
     6  	"crypto/rand"
     7  	"encoding/base64"
     8  	"errors"
     9  	"io"
    10  
    11  	"github.com/gookit/color"
    12  
    13  	"github.com/goravel/framework/contracts/config"
    14  	"github.com/goravel/framework/support"
    15  	"github.com/goravel/framework/support/json"
    16  )
    17  
    18  type AES struct {
    19  	key []byte
    20  }
    21  
    22  // NewAES returns a new AES hasher.
    23  func NewAES(config config.Config) *AES {
    24  	key := config.GetString("app.key")
    25  
    26  	// Don't use AES in artisan when the key is empty.
    27  	if support.Env == support.EnvArtisan && len(key) == 0 {
    28  		return nil
    29  	}
    30  
    31  	// check key length before using it
    32  	if len(key) != 16 && len(key) != 24 && len(key) != 32 {
    33  		color.Redln("[Crypt] Empty or invalid APP_KEY, please reset it.\nExample command:\ngo run . artisan key:generate")
    34  		return nil
    35  	}
    36  	keyBytes := []byte(key)
    37  	return &AES{
    38  		key: keyBytes,
    39  	}
    40  }
    41  
    42  // EncryptString encrypts the given string, and returns the iv and ciphertext as base64 encoded strings.
    43  func (b *AES) EncryptString(value string) (string, error) {
    44  	block, err := aes.NewCipher(b.key)
    45  	if err != nil {
    46  		return "", err
    47  	}
    48  
    49  	plaintext := []byte(value)
    50  
    51  	iv := make([]byte, 12)
    52  	if _, err = io.ReadFull(rand.Reader, iv); err != nil {
    53  		return "", err
    54  	}
    55  
    56  	aesgcm, err := cipher.NewGCM(block)
    57  	if err != nil {
    58  		return "", err
    59  	}
    60  
    61  	ciphertext := aesgcm.Seal(nil, iv, plaintext, nil)
    62  
    63  	var jsonEncoded []byte
    64  	jsonEncoded, err = json.Marshal(map[string][]byte{
    65  		"iv":    iv,
    66  		"value": ciphertext,
    67  	})
    68  
    69  	if err != nil {
    70  		return "", err
    71  	}
    72  
    73  	return base64.StdEncoding.EncodeToString(jsonEncoded), nil
    74  }
    75  
    76  // DecryptString decrypts the given iv and ciphertext, and returns the plaintext.
    77  func (b *AES) DecryptString(payload string) (string, error) {
    78  	decodePayload, err := base64.StdEncoding.DecodeString(payload)
    79  	if err != nil {
    80  		return "", err
    81  	}
    82  
    83  	decodeJson := make(map[string][]byte)
    84  	err = json.Unmarshal(decodePayload, &decodeJson)
    85  	if err != nil {
    86  		return "", err
    87  	}
    88  
    89  	// check if the json payload has the correct keys
    90  	if _, ok := decodeJson["iv"]; !ok {
    91  		return "", errors.New("decrypt payload error: missing iv key")
    92  	}
    93  	if _, ok := decodeJson["value"]; !ok {
    94  		return "", errors.New("decrypt payload error: missing value key")
    95  	}
    96  
    97  	decodeIv := decodeJson["iv"]
    98  	decodeCiphertext := decodeJson["value"]
    99  
   100  	block, err := aes.NewCipher(b.key)
   101  	if err != nil {
   102  		return "", err
   103  	}
   104  
   105  	aesgcm, err := cipher.NewGCM(block)
   106  	if err != nil {
   107  		return "", err
   108  	}
   109  
   110  	plaintext, err := aesgcm.Open(nil, decodeIv, decodeCiphertext, nil)
   111  	if err != nil {
   112  		return "", err
   113  	}
   114  
   115  	return string(plaintext), nil
   116  }