/*
Copyright (c) Edgeless Systems GmbH

SPDX-License-Identifier: AGPL-3.0-only
*/

/*
Package crypto provides encryption and decryption functions for the s3proxy.
It uses AES-256-GCM to encrypt and decrypt data.
*/
package crypto

import (
	"fmt"

	aeadsubtle "github.com/tink-crypto/tink-go/v2/aead/subtle"
	kwpsubtle "github.com/tink-crypto/tink-go/v2/kwp/subtle"
	"github.com/tink-crypto/tink-go/v2/subtle/random"
)

// Encrypt generates a random key to encrypt a plaintext using AES-256-GCM.
// The generated key is encrypted using the supplied key encryption key (KEK).
// The ciphertext and encrypted data encryption key (DEK) are returned.
func Encrypt(plaintext []byte, kek [32]byte) (ciphertext []byte, encryptedDEK []byte, err error) {
	dek := random.GetRandomBytes(32)
	aesgcm, err := aeadsubtle.NewAESGCMSIV(dek)
	if err != nil {
		return nil, nil, fmt.Errorf("getting aesgcm: %w", err)
	}

	ciphertext, err = aesgcm.Encrypt(plaintext, []byte(""))
	if err != nil {
		return nil, nil, fmt.Errorf("encrypting plaintext: %w", err)
	}

	keywrapper, err := kwpsubtle.NewKWP(kek[:])
	if err != nil {
		return nil, nil, fmt.Errorf("getting kwp: %w", err)
	}

	encryptedDEK, err = keywrapper.Wrap(dek)
	if err != nil {
		return nil, nil, fmt.Errorf("wrapping dek: %w", err)
	}

	return ciphertext, encryptedDEK, nil
}

// Decrypt decrypts a ciphertext using AES-256-GCM.
// The encrypted DEK is decrypted using the supplied KEK.
func Decrypt(ciphertext, encryptedDEK []byte, kek [32]byte) ([]byte, error) {
	keywrapper, err := kwpsubtle.NewKWP(kek[:])
	if err != nil {
		return nil, fmt.Errorf("getting kwp: %w", err)
	}

	dek, err := keywrapper.Unwrap(encryptedDEK)
	if err != nil {
		return nil, fmt.Errorf("unwrapping dek: %w", err)
	}

	aesgcm, err := aeadsubtle.NewAESGCMSIV(dek)
	if err != nil {
		return nil, fmt.Errorf("getting aesgcm: %w", err)
	}

	plaintext, err := aesgcm.Decrypt(ciphertext, []byte(""))
	if err != nil {
		return nil, fmt.Errorf("decrypting ciphertext: %w", err)
	}

	return plaintext, nil
}