# Symmetric Ciphers

## Introduction

For symmetric ciphers, we provide a low level as well as a high-level api construction.

Symmetric ciphers, as an introduction, have the following basic properties, for all non-empty m (as, if a message is empty, you’re not encrypting anything and c = m):

`````` E(K, m) = c
D(K, c) = m
D(K, E(K, m)) = m

Where:
E: Encryption function
D: Decryption function
K: Some symmetric key
m: Some message, or plainText
c: Some ciphertext
``````

However, in practice, block ciphers (and most secure stream ciphers like Salsa20) require a nonce as well (called an initialization vector for block ciphers). As such, we need to either provide it explicitly, or implicitly in our cipher construction. TSec provides such an implicit construction using `IvStrategy`.

## Usage

These are the imports you will need for basic usage:

``````  import tsec.common._
import tsec.cipher.symmetric._
import tsec.cipher.symmetric.jca._
import cats.effect.IO
``````

In tsec, we provide a few default constructions for simple AES encryption: `AES/CTR` and `AES/CBC`. For Authenticated encryption, we provide an `AES/GCM` construction.

To be able to generate initialization vectors for a particular cipher, you must either have an implicit `IvStrategy[A]`(where A is the algorithm type, i.e `AES128GCM`) in scope, or pass it explicitly, or use it to generate a nonce of the right size:

``````scala>   val toEncrypt = "hi hello welcome to tsec".utf8Bytes
toEncrypt: Array[Byte] = Array(104, 105, 32, 104, 101, 108, 108, 111, 32, 119, 101, 108, 99, 111, 109, 101, 32, 116, 111, 32, 116, 115, 101, 99)

scala>   implicit val ctrStrategy: IvGen[IO, AES128CTR] = AES128CTR.defaultIvStrategy[IO]
ctrStrategy: tsec.cipher.symmetric.IvGen[cats.effect.IO,tsec.cipher.symmetric.jca.AES128CTR] = tsec.cipher.symmetric.jca.JCAIvGen\$\$anon\$1@79273a4f

scala>   implicit val cachedInstance                    = AES128CTR.genEncryptor[IO] //Cache the implicit

scala>   val onlyEncrypt: IO[String] =
|     for {
|       key       <- AES128CTR.generateKey[IO] //Generate our key
|       encrypted <- AES128CTR.encrypt[IO](PlainText(toEncrypt), key) //Encrypt our message
|       decrypted <- AES128CTR.decrypt[IO](encrypted, key)
|     } yield decrypted.toUtf8String // "hi hello welcome to tsec!"
onlyEncrypt: cats.effect.IO[String] = IO\$2035788375

scala>   /** You can also turn it into a singular array with the IV concatenated at the end */
|   val onlyEncrypt2: IO[String] =
|     for {
|       key       <- AES128CTR.generateKey[IO]                        //Generate our key
|       encrypted <- AES128CTR.encrypt[IO](PlainText(toEncrypt), key) //Encrypt our message
|       array = encrypted.toConcatenated
|       from      <- IO.fromEither(AES128CTR.ciphertextFromConcat(array))
|       decrypted <- AES128CTR.decrypt[IO](from, key)
|     } yield decrypted.toUtf8String // "hi hello welcome to tsec!"
onlyEncrypt2: cats.effect.IO[String] = IO\$1076642142
``````

For authenticated encryption and decryption

``````scala>   implicit val gcmstrategy        = AES128GCM.defaultIvStrategy[IO]
gcmstrategy: tsec.cipher.symmetric.IvGen[cats.effect.IO,tsec.cipher.symmetric.jca.AES128GCM] = tsec.cipher.symmetric.jca.package\$GCM\$\$anon\$4@2db82155

scala>   implicit val cachedAADEncryptor = AES128GCM.genEncryptor[IO]

aad: tsec.cipher.symmetric.AAD.Type = Array(109, 121, 65, 100, 100, 105, 116, 105, 111, 110, 97, 108, 65, 117, 116, 104, 101, 110, 116, 105, 99, 97, 116, 105, 111, 110, 68, 97, 116, 97)

|     for {
|       key       <- AES128GCM.generateKey[IO]                                    //Generate our key
|     } yield decrypted.toUtf8String // "hi hello welcome to tsec!"
``````

Finally, For more advanced usage, i.e you know which cipher you want specifically, you must import both padding as well as the primitive package.

Note: This is not recommended. Use at your own risk.

``````scala>   /** For more advanced usage, i.e you know which cipher you want specifically, you must import padding
|     * as well as the low level package
|     *
|     * this is not recommended, but useful for.. science!
|     *
|     */

scala>   import tsec.cipher.symmetric.jca.primitive._
import tsec.cipher.symmetric.jca.primitive._

scala>   val desStrategy = JCAIvGen.random[IO, DES]
desStrategy: tsec.cipher.symmetric.IvGen[cats.effect.IO,tsec.cipher.symmetric.jca.DES] = tsec.cipher.symmetric.jca.JCAIvGen\$\$anon\$1@707b0b9b

scala>   implicit val instance = JCAPrimitiveCipher.sync[IO, DES, CBC, PKCS7Padding]