github.com/gitbundle/modules@v0.0.0-20231025071548-85b91c5c3b01/encrypt/aesgcm.go (about)

     1  // Copyright 2023 The GitBundle Inc. All rights reserved.
     2  // Copyright 2017 The Gitea Authors. All rights reserved.
     3  // Use of this source code is governed by a MIT-style
     4  // license that can be found in the LICENSE file.
     5  
     6  // Copyright 2019 Drone IO, Inc.
     7  //
     8  // Licensed under the Apache License, Version 2.0 (the "License");
     9  // you may not use this file except in compliance with the License.
    10  // You may obtain a copy of the License at
    11  //
    12  //      http://www.apache.org/licenses/LICENSE-2.0
    13  //
    14  // Unless required by applicable law or agreed to in writing, software
    15  // distributed under the License is distributed on an "AS IS" BASIS,
    16  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    17  // See the License for the specific language governing permissions and
    18  // limitations under the License.
    19  
    20  package encrypt
    21  
    22  import (
    23  	"crypto/aes"
    24  	"crypto/cipher"
    25  	"crypto/rand"
    26  	"errors"
    27  	"io"
    28  )
    29  
    30  // Aesgcm provides an encrypter that uses the aesgcm encryption
    31  // algorithm.
    32  type Aesgcm struct {
    33  	block  cipher.Block
    34  	Compat bool
    35  }
    36  
    37  // Encrypt encrypts the plaintext using aesgcm.
    38  func (e *Aesgcm) Encrypt(plaintext string) ([]byte, error) {
    39  	gcm, err := cipher.NewGCM(e.block)
    40  	if err != nil {
    41  		return nil, err
    42  	}
    43  
    44  	nonce := make([]byte, gcm.NonceSize())
    45  	_, err = io.ReadFull(rand.Reader, nonce)
    46  	if err != nil {
    47  		return nil, err
    48  	}
    49  
    50  	return gcm.Seal(nonce, nonce, []byte(plaintext), nil), nil
    51  }
    52  
    53  // Decrypt decrypts the ciphertext using aesgcm.
    54  func (e *Aesgcm) Decrypt(ciphertext []byte) (string, error) {
    55  	gcm, err := cipher.NewGCM(e.block)
    56  	if err != nil {
    57  		return "", err
    58  	}
    59  
    60  	if len(ciphertext) < gcm.NonceSize() {
    61  		// if the decryption utility is running in compatibility
    62  		// mode, it will return the ciphertext as plain text if
    63  		// decryption fails. This should be used when running the
    64  		// database in mixed-mode, where there is a mix of encrypted
    65  		// and unencrypted content.
    66  		if e.Compat {
    67  			return string(ciphertext), nil
    68  		}
    69  		return "", errors.New("malformed ciphertext")
    70  	}
    71  
    72  	plaintext, err := gcm.Open(nil,
    73  		ciphertext[:gcm.NonceSize()],
    74  		ciphertext[gcm.NonceSize():],
    75  		nil,
    76  	)
    77  	// if the decryption utility is running in compatibility
    78  	// mode, it will return the ciphertext as plain text if
    79  	// decryption fails. This should be used when running the
    80  	// database in mixed-mode, where there is a mix of encrypted
    81  	// and unencrypted content.
    82  	if err != nil && e.Compat {
    83  		return string(ciphertext), nil
    84  	}
    85  	return string(plaintext), err
    86  }
    87  
    88  func AesGcmKey32Encrypt(key, plaintext []byte) ([]byte, error) {
    89  	if len(key) != 32 {
    90  		return nil, errKeySize
    91  	}
    92  	return AesGcmEncrypt(key, plaintext)
    93  }
    94  
    95  func AesGcmKey32Decrypt(key, ciphertext []byte) ([]byte, error) {
    96  	if len(key) != 32 {
    97  		return nil, errKeySize
    98  	}
    99  	return AesGcmDecrypt(key, ciphertext)
   100  }
   101  
   102  // AesGcmEncrypt (from legacy package): encrypts plaintext with the given key using AES in GCM mode. should be replaced.
   103  func AesGcmEncrypt(key, plaintext []byte) ([]byte, error) {
   104  	block, err := aes.NewCipher(key)
   105  	if err != nil {
   106  		return nil, err
   107  	}
   108  
   109  	gcm, err := cipher.NewGCM(block)
   110  	if err != nil {
   111  		return nil, err
   112  	}
   113  
   114  	nonce := make([]byte, gcm.NonceSize())
   115  	_, err = io.ReadFull(rand.Reader, nonce)
   116  	if err != nil {
   117  		return nil, err
   118  	}
   119  
   120  	return gcm.Seal(nonce, nonce, []byte(plaintext), nil), nil
   121  }
   122  
   123  // AesGcmDecrypt (from legacy package): decrypts ciphertext with the given key using AES in GCM mode. should be replaced.
   124  func AesGcmDecrypt(key, ciphertext []byte) ([]byte, error) {
   125  	block, err := aes.NewCipher(key)
   126  	if err != nil {
   127  		return nil, err
   128  	}
   129  
   130  	gcm, err := cipher.NewGCM(block)
   131  	if err != nil {
   132  		return nil, err
   133  	}
   134  
   135  	if len(ciphertext) < gcm.NonceSize() {
   136  		return nil, errors.New("malformed ciphertext")
   137  	}
   138  
   139  	plainText, err := gcm.Open(nil,
   140  		ciphertext[:gcm.NonceSize()],
   141  		ciphertext[gcm.NonceSize():],
   142  		nil,
   143  	)
   144  	if err != nil {
   145  		return nil, err
   146  	}
   147  
   148  	return plainText, nil
   149  }