package ixee.cryptopals.utils.crypto import javax.crypto.Cipher import ixee.cryptopals.utils.ConversionUtils._ import ixee.cryptopals.utils.FunctionUtils._ import ixee.cryptopals.utils.CryptoUtils._ import ixee.cryptopals.utils.TupleUtils._ import ixee.cryptopals.utils.ByteUtils._ class CBCDecrypter(cipher: Cipher, init: Seq[Byte]) { val blockSize = 16 var state: Seq[Byte] = init var leftover: Seq[Byte] = Seq() def dec(data: Seq[Byte]): Seq[Byte] = { val (blocks, newLeftover) = blockized(leftover ++ data)(blockSize) leftover = newLeftover blocks.map(decBlock _).foldLeft(Seq[Byte]())(_ ++ _) } def decBlock(data: Seq[Byte]): Seq[Byte] = { val ret = cipher.update(data.toArray).toSeq xor state state = data ret } def end(): Seq[Byte] = cipher.doFinal((pkcs7pad(leftover, blockSize) xor state).toArray) def blockized(data: Seq[Byte])(size: Int): (Seq[Seq[Byte]], Seq[Byte]) = groupBlocks <-: data.splitAt(data.length - (data.length % size)) def groupBlocks: Seq[Byte] => Seq[Seq[Byte]] = _.grouped(blockSize).toSeq }