// Package aescts provides AES CBC CipherText Stealing encryption and decryption methods
package aescts

import (
	"crypto/aes"
	"crypto/cipher"
	"errors"
	"fmt"
)

// Encrypt the message with the key and the initial vector.
// Returns: next iv, ciphertext bytes, error
func Encrypt(key, iv, plaintext []byte) ([]byte, []byte, error) {
	l := len(plaintext)

	block, err := aes.NewCipher(key)
	if err != nil {
		return []byte{}, []byte{}, fmt.Errorf("Error creating cipher: %v", err)
	}
	mode := cipher.NewCBCEncrypter(block, iv)

	m := make([]byte, len(plaintext))
	copy(m, plaintext)

	/*For consistency, ciphertext stealing is always used for the last two
	blocks of the data to be encrypted, as in [RC5].  If the data length
	is a multiple of the block size, this is equivalent to plain CBC mode
	with the last two ciphertext blocks swapped.*/
	/*The initial vector carried out from one encryption for use in a
	subsequent encryption is the next-to-last block of the encryption
	output; this is the encrypted form of the last plaintext block.*/
	if l <= aes.BlockSize {
		m, _ = zeroPad(m, aes.BlockSize)
		mode.CryptBlocks(m, m)
		return m, m, nil
	}
	if l%aes.BlockSize == 0 {
		mode.CryptBlocks(m, m)
		iv = m[len(m)-aes.BlockSize:]
		rb, _ := swapLastTwoBlocks(m, aes.BlockSize)
		return iv, rb, nil
	}
	m, _ = zeroPad(m, aes.BlockSize)
	rb, pb, lb, err := tailBlocks(m, aes.BlockSize)
	if err != nil {
		return []byte{}, []byte{}, fmt.Errorf("Error tailing blocks: %v", err)
	}
	var ct []byte
	if rb != nil {
		// Encrpt all but the lats 2 blocks and update the rolling iv
		mode.CryptBlocks(rb, rb)
		iv = rb[len(rb)-aes.BlockSize:]
		mode = cipher.NewCBCEncrypter(block, iv)
		ct = append(ct, rb...)
	}
	mode.CryptBlocks(pb, pb)
	mode = cipher.NewCBCEncrypter(block, pb)
	mode.CryptBlocks(lb, lb)
	// Cipher Text Stealing (CTS) - Ref: https://en.wikipedia.org/wiki/Ciphertext_stealing#CBC_ciphertext_stealing
	// Swap the last two cipher blocks
	// Truncate the ciphertext to the length of the original plaintext
	ct = append(ct, lb...)
	ct = append(ct, pb...)
	return lb, ct[:l], nil
}

// Decrypt the ciphertext with the key and the initial vector.
func Decrypt(key, iv, ciphertext []byte) ([]byte, error) {
	// Copy the cipher text as golang slices even when passed by value to this method can result in the backing arrays of the calling code value being updated.
	ct := make([]byte, len(ciphertext))
	copy(ct, ciphertext)
	if len(ct) < aes.BlockSize {
		return []byte{}, fmt.Errorf("Ciphertext is not large enough. It is less that one block size. Blocksize:%v; Ciphertext:%v", aes.BlockSize, len(ct))
	}
	// Configure the CBC
	block, err := aes.NewCipher(key)
	if err != nil {
		return nil, fmt.Errorf("Error creating cipher: %v", err)
	}
	var mode cipher.BlockMode

	//If ciphertext is multiple of blocksize we just need to swap back the last two blocks and then do CBC
	//If the ciphertext is just one block we can't swap so we just decrypt
	if len(ct)%aes.BlockSize == 0 {
		if len(ct) > aes.BlockSize {
			ct, _ = swapLastTwoBlocks(ct, aes.BlockSize)
		}
		mode = cipher.NewCBCDecrypter(block, iv)
		message := make([]byte, len(ct))
		mode.CryptBlocks(message, ct)
		return message[:len(ct)], nil
	}

	// Cipher Text Stealing (CTS) using CBC interface. Ref: https://en.wikipedia.org/wiki/Ciphertext_stealing#CBC_ciphertext_stealing
	// Get ciphertext of the 2nd to last (penultimate) block (cpb), the last block (clb) and the rest (crb)
	crb, cpb, clb, _ := tailBlocks(ct, aes.BlockSize)
	v := make([]byte, len(iv), len(iv))
	copy(v, iv)
	var message []byte
	if crb != nil {
		//If there is more than just the last and the penultimate block we decrypt it and the last bloc of this becomes the iv for later
		rb := make([]byte, len(crb))
		mode = cipher.NewCBCDecrypter(block, v)
		v = crb[len(crb)-aes.BlockSize:]
		mode.CryptBlocks(rb, crb)
		message = append(message, rb...)
	}

	// We need to modify the cipher text
	// Decryt the 2nd to last (penultimate) block with a the original iv
	pb := make([]byte, aes.BlockSize)
	mode = cipher.NewCBCDecrypter(block, iv)
	mode.CryptBlocks(pb, cpb)
	// number of byte needed to pad
	npb := aes.BlockSize - len(ct)%aes.BlockSize
	//pad last block using the number of bytes needed from the tail of the plaintext 2nd to last (penultimate) block
	clb = append(clb, pb[len(pb)-npb:]...)

	// Now decrypt the last block in the penultimate position (iv will be from the crb, if the is no crb it's zeros)
	// iv for the penultimate block decrypted in the last position becomes the modified last block
	lb := make([]byte, aes.BlockSize)
	mode = cipher.NewCBCDecrypter(block, v)
	v = clb
	mode.CryptBlocks(lb, clb)
	message = append(message, lb...)

	// Now decrypt the penultimate block in the last position (iv will be from the modified last block)
	mode = cipher.NewCBCDecrypter(block, v)
	mode.CryptBlocks(cpb, cpb)
	message = append(message, cpb...)

	// Truncate to the size of the original cipher text
	return message[:len(ct)], nil
}

func tailBlocks(b []byte, c int) ([]byte, []byte, []byte, error) {
	if len(b) <= c {
		return []byte{}, []byte{}, []byte{}, errors.New("bytes slice is not larger than one block so cannot tail")
	}
	// Get size of last block
	var lbs int
	if l := len(b) % aes.BlockSize; l == 0 {
		lbs = aes.BlockSize
	} else {
		lbs = l
	}
	// Get last block
	lb := b[len(b)-lbs:]
	// Get 2nd to last (penultimate) block
	pb := b[len(b)-lbs-c : len(b)-lbs]
	if len(b) > 2*c {
		rb := b[:len(b)-lbs-c]
		return rb, pb, lb, nil
	}
	return nil, pb, lb, nil
}

func swapLastTwoBlocks(b []byte, c int) ([]byte, error) {
	rb, pb, lb, err := tailBlocks(b, c)
	if err != nil {
		return nil, err
	}
	var out []byte
	if rb != nil {
		out = append(out, rb...)
	}
	out = append(out, lb...)
	out = append(out, pb...)
	return out, nil
}

// zeroPad pads bytes with zeros to nearest multiple of message size m.
func zeroPad(b []byte, m int) ([]byte, error) {
	if m <= 0 {
		return nil, errors.New("Invalid message block size when padding")
	}
	if b == nil || len(b) == 0 {
		return nil, errors.New("Data not valid to pad: Zero size")
	}
	if l := len(b) % m; l != 0 {
		n := m - l
		z := make([]byte, n)
		b = append(b, z...)
	}
	return b, nil
}
