package test

import (
	"bytes"
	"crypto/aes"
	"crypto/cipher"
	"crypto/sha256"
	b64 "encoding/base64"
	"fmt"
	"log"
	"strings"
	"testing"
)

func NewSHA256(data []byte) []byte {
	hash := sha256.Sum256(data)
	//log.Println(string(hash[:]))
	return hash[:]
}
func TestAESDecryptCBC(t *testing.T) {
	aes_key := fmt.Sprint("CRDRIAF", strings.Repeat("\000", 9))
	iv := "lksdasfsaskllopl"
	//encyptedBase64Str := "bGtzZGFzZnNhc2tsbG9wbBpU1Y0wlp3dYU9muV5XTQCwg+vYcdM/fZkFM3mhAUVqlDM/5ulZnt/aqsfGRgQKrA=="
	encyptedBase64Str := "bGtzZGFzZnNhc2tsbG9wbPgjjiyZf45DW58MW+L/dQCDWftYOKP66r4Q1Y77tREvOwXAZCtkaQfahCHQnPnAkg==\n"
	encyptedBytes, err := b64.StdEncoding.DecodeString(encyptedBase64Str)
	if err != nil {
		log.Println(err)
	}
	encyptedStr := string(encyptedBytes)
	log.Print(len(encyptedStr))
	actualEncyptedStr := encyptedStr[48:len(encyptedStr)]
	decryptedString := DecryptCBC(actualEncyptedStr, aes_key, iv)
	log.Print(strings.TrimSpace(decryptedString))
}
func TestAESEncryptCBC(t *testing.T) {
	aes_key := fmt.Sprint("CRDRIAF", strings.Repeat("\000", 9))
	iv := "lksdasfsaskllopl"
	plainText := "Hello World"
	encryptedString := EncryptCBC(plainText, aes_key, iv)
	log.Print("encryptedString")
	log.Print(encryptedString)
	log.Print(len(encryptedString))
	//just checking if decrypting well
	decryptedString := DecryptCBC(encryptedString, aes_key, iv)
	log.Print(decryptedString)
	plainTextBytes, err := b64.StdEncoding.DecodeString(decryptedString)
	if err != nil {
		log.Println(err)
	}
	log.Print(string(plainTextBytes))
	//
	hash_map := string(NewSHA256([]byte(fmt.Sprint(encryptedString, aes_key))))
	log.Print("hash_map")
	log.Print(hash_map)
	log.Print(len(hash_map))
	encodedFinalValue := b64.StdEncoding.EncodeToString([]byte(fmt.Sprint(iv, hash_map, encryptedString)))
	log.Print(encodedFinalValue)
	//checking with actual decryption process
	encyptedBytes, err := b64.StdEncoding.DecodeString(encodedFinalValue)
	if err != nil {
		log.Println(err)
	}
	encyptedStr := string(encyptedBytes)
	log.Print(len(encyptedStr))
	log.Print(encyptedStr)
	actualEncyptedStr := encyptedStr[48:len(encyptedStr)]
	log.Print(actualEncyptedStr)
	decryptedFinalString := DecryptCBC(actualEncyptedStr, aes_key, iv)
	log.Print("decryptedFinalString")
	log.Print(decryptedFinalString)
}

func EncryptCBC(plainText string, encKey string, iv string) (encryptedString string) {
	bKey := []byte(encKey)
	bIV := []byte(iv)
	//cipherTextDecoded, err := hex.DecodeString(cipherText)
	//if err != nil {
	//	panic(err)
	//}
	block, err := aes.NewCipher(bKey)
	if err != nil {
		panic(err)
	}
	//paddding with spaces
	if block.BlockSize() < 1 || block.BlockSize() > 255 {
		panic(fmt.Sprintf("inappropriate block size %d", block.BlockSize()))
	}
	plainBuf := []byte(plainText)
	i := block.BlockSize() - (len(plainBuf) % block.BlockSize())
	spaceByte := []byte(" ")
	finalPlainBytes := append(plainBuf, bytes.Repeat(spaceByte, i)...)
	finalPlainText := string(finalPlainBytes)
	//paddding with spaces ended
	bCipherText := make([]byte, len(finalPlainText))
	mode := cipher.NewCBCEncrypter(block, bIV)
	mode.CryptBlocks([]byte(bCipherText), []byte(finalPlainText))
	return strings.Trim(string(bCipherText), " ")
}
func DecryptCBC(cipherText string, encKey string, iv string) (decryptedString string) {
	bKey := []byte(encKey)
	bIV := []byte(iv)
	//cipherTextDecoded, err := hex.DecodeString(cipherText)
	//if err != nil {
	//	panic(err)
	//}
	block, err := aes.NewCipher(bKey)
	if err != nil {
		panic(err)
	}
	bPlaintext := make([]byte, len(cipherText))
	mode := cipher.NewCBCDecrypter(block, bIV)
	mode.CryptBlocks([]byte(bPlaintext), []byte(cipherText))
	return strings.Trim(string(bPlaintext), " ")
}
