From 0af5a2e4ade0b032e1ec6d25c51de2ff95dd2799 Mon Sep 17 00:00:00 2001 From: iximeow Date: Thu, 27 Nov 2014 02:06:03 -0800 Subject: Rough cut of challenge 10 --- src/utils/CryptoUtils.scala | 21 +++++++++++++++------ src/utils/FunctionUtils.scala | 2 +- src/utils/TupleUtils.scala | 5 ++++- src/utils/crypto/CBCCipher.scala | 23 ++++++++++++++++++----- src/utils/crypto/CBCDecrypter.scala | 36 ++++++++++++++++++++++++++++++++++++ 5 files changed, 74 insertions(+), 13 deletions(-) create mode 100644 src/utils/crypto/CBCDecrypter.scala (limited to 'src/utils') diff --git a/src/utils/CryptoUtils.scala b/src/utils/CryptoUtils.scala index 2b4d38e..430934b 100644 --- a/src/utils/CryptoUtils.scala +++ b/src/utils/CryptoUtils.scala @@ -1,18 +1,27 @@ package ixee.cryptopals.utils -import ixee.cryptopals.utils.crypto.CBCCipher +import ixee.cryptopals.utils.crypto._ import javax.crypto.Cipher import javax.crypto.spec.SecretKeySpec object CryptoUtils { - def pkcs7pad(s: String, blockSize: Int) = { + def pkcs7pad(s: Seq[Byte], blockSize: Int): Seq[Byte] = { val padLength = blockSize - (s.length % blockSize) - s + s"${padLength.toChar}" * padLength + s ++ Stream.continually(padLength.toByte).take(padLength) } - def cbcDecryptInstance(ecbCipher: Cipher, key: SecretKeySpec): CBCCipher = { - ecbCipher.init(Cipher.DECRYPT_MODE, key) - new CBCCipher(ecbCipher) + def cbcDecryptInstance(cipherPrim: String, key: Seq[Byte], iv: Seq[Byte]): CBCDecrypter = { + val keySpec = new SecretKeySpec(key.toArray, cipherPrim) + val cipher = Cipher.getInstance(s"$cipherPrim/ECB/NoPadding") + cipher.init(Cipher.DECRYPT_MODE, keySpec) + new CBCDecrypter(cipher, iv) + } + + def cbcEncryptInstance(cipherPrim: String, key: Seq[Byte], iv: Seq[Byte]): CBCEncrypter = { + val keySpec = new SecretKeySpec(key.toArray, cipherPrim) + val cipher = Cipher.getInstance(s"$cipherPrim/ECB/NoPadding") + cipher.init(Cipher.ENCRYPT_MODE, keySpec) + new CBCEncrypter(cipher, iv) } } diff --git a/src/utils/FunctionUtils.scala b/src/utils/FunctionUtils.scala index 7456898..21ad8d0 100644 --- a/src/utils/FunctionUtils.scala +++ b/src/utils/FunctionUtils.scala @@ -4,7 +4,7 @@ object FunctionUtils { // Because doing (_ f _).tupled confuses the inferencer... def tup[A, B, C](f: (A, B) => C): ((A, B)) => C = f.tupled - def iden[A](x: A) = x + def ident[A]: A => A = { x => x } implicit class Compositor[A, B](f: A => B) { def :|[C](g: B => C): A => C = f.andThen(g) diff --git a/src/utils/TupleUtils.scala b/src/utils/TupleUtils.scala index 2a6dd6c..2318c11 100644 --- a/src/utils/TupleUtils.scala +++ b/src/utils/TupleUtils.scala @@ -1,10 +1,13 @@ package ixee.cryptopals.utils +import ixee.cryptopals.utils.FunctionUtils._ + object TupleUtils { implicit class Tuple2[A, B](t: (A, B)) { def mapAll[C, D](_1: A => C = ident, _2: B => D = ident): (C, D) = (_1(t._1), _2(t._2)) - def <-:(f: A => C + def <-:[C](f: A => C): (C, B) = (f(t._1), t._2) + def :->[D](f: B => D): (A, D) = (t._1, f(t._2)) } } diff --git a/src/utils/crypto/CBCCipher.scala b/src/utils/crypto/CBCCipher.scala index e1ece8a..d6d99ff 100644 --- a/src/utils/crypto/CBCCipher.scala +++ b/src/utils/crypto/CBCCipher.scala @@ -1,21 +1,34 @@ 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 CBCEncrypter(cipher: Cipher, init: Seq[Byte]) { + val blockSize = 16 -class CBCCipher(cipher: Cipher, init: Seq[Byte]) { var state: Seq[Byte] = init var leftover: Seq[Byte] = Seq() def enc(data: Seq[Byte]): Seq[Byte] = { - (blocks, leftover) = blockized(leftover append data) - blocks.map(encBlock).reduce(_ append _) + val (blocks, newLeftover) = blockized(leftover ++ data)(blockSize) + leftover = newLeftover + blocks.map(encBlock _).foldLeft(Seq[Byte]())(_ ++ _) } def encBlock(data: Seq[Byte]): Seq[Byte] = { - state = cipher.doFinal((data xor state).toArray) + state = cipher.update((data xor state).toArray) state } + def end(): Seq[Byte] = + cipher.doFinal((pkcs7pad(leftover, blockSize) xor state).toArray) + def blockized(data: Seq[Byte])(size: Int): (Seq[Seq[Byte]], Seq[Byte]) = - data.splitAt(data.length - (data.length % size)) + groupBlocks <-: data.splitAt(data.length - (data.length % size)) + + def groupBlocks: Seq[Byte] => Seq[Seq[Byte]] = _.grouped(blockSize).toSeq } diff --git a/src/utils/crypto/CBCDecrypter.scala b/src/utils/crypto/CBCDecrypter.scala new file mode 100644 index 0000000..a6cf855 --- /dev/null +++ b/src/utils/crypto/CBCDecrypter.scala @@ -0,0 +1,36 @@ + +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 +} -- cgit v1.1