code.gitea.io/gitea@v1.22.3/modules/secret/secret.go (about)

     1  // Copyright 2019 The Gitea Authors. All rights reserved.
     2  // SPDX-License-Identifier: MIT
     3  
     4  package secret
     5  
     6  import (
     7  	"crypto/aes"
     8  	"crypto/cipher"
     9  	"crypto/rand"
    10  	"crypto/sha256"
    11  	"encoding/base64"
    12  	"encoding/hex"
    13  	"errors"
    14  	"fmt"
    15  	"io"
    16  )
    17  
    18  // AesEncrypt encrypts text and given key with AES.
    19  func AesEncrypt(key, text []byte) ([]byte, error) {
    20  	block, err := aes.NewCipher(key)
    21  	if err != nil {
    22  		return nil, fmt.Errorf("AesEncrypt invalid key: %v", err)
    23  	}
    24  	b := base64.StdEncoding.EncodeToString(text)
    25  	ciphertext := make([]byte, aes.BlockSize+len(b))
    26  	iv := ciphertext[:aes.BlockSize]
    27  	if _, err = io.ReadFull(rand.Reader, iv); err != nil {
    28  		return nil, fmt.Errorf("AesEncrypt unable to read IV: %w", err)
    29  	}
    30  	cfb := cipher.NewCFBEncrypter(block, iv)
    31  	cfb.XORKeyStream(ciphertext[aes.BlockSize:], []byte(b))
    32  	return ciphertext, nil
    33  }
    34  
    35  // AesDecrypt decrypts text and given key with AES.
    36  func AesDecrypt(key, text []byte) ([]byte, error) {
    37  	block, err := aes.NewCipher(key)
    38  	if err != nil {
    39  		return nil, err
    40  	}
    41  	if len(text) < aes.BlockSize {
    42  		return nil, errors.New("AesDecrypt ciphertext too short")
    43  	}
    44  	iv := text[:aes.BlockSize]
    45  	text = text[aes.BlockSize:]
    46  	cfb := cipher.NewCFBDecrypter(block, iv)
    47  	cfb.XORKeyStream(text, text)
    48  	data, err := base64.StdEncoding.DecodeString(string(text))
    49  	if err != nil {
    50  		return nil, fmt.Errorf("AesDecrypt invalid decrypted base64 string: %w", err)
    51  	}
    52  	return data, nil
    53  }
    54  
    55  // EncryptSecret encrypts a string with given key into a hex string
    56  func EncryptSecret(key, str string) (string, error) {
    57  	keyHash := sha256.Sum256([]byte(key))
    58  	plaintext := []byte(str)
    59  	ciphertext, err := AesEncrypt(keyHash[:], plaintext)
    60  	if err != nil {
    61  		return "", fmt.Errorf("failed to encrypt by secret: %w", err)
    62  	}
    63  	return hex.EncodeToString(ciphertext), nil
    64  }
    65  
    66  // DecryptSecret decrypts a previously encrypted hex string
    67  func DecryptSecret(key, cipherHex string) (string, error) {
    68  	keyHash := sha256.Sum256([]byte(key))
    69  	ciphertext, err := hex.DecodeString(cipherHex)
    70  	if err != nil {
    71  		return "", fmt.Errorf("failed to decrypt by secret, invalid hex string: %w", err)
    72  	}
    73  	plaintext, err := AesDecrypt(keyHash[:], ciphertext)
    74  	if err != nil {
    75  		return "", fmt.Errorf("failed to decrypt by secret, the key (maybe SECRET_KEY?) might be incorrect: %w", err)
    76  	}
    77  	return string(plaintext), nil
    78  }