summaryrefslogtreecommitdiff
path: root/src/utils
diff options
context:
space:
mode:
Diffstat (limited to 'src/utils')
-rw-r--r--src/utils/CryptoUtils.scala21
-rw-r--r--src/utils/FunctionUtils.scala2
-rw-r--r--src/utils/TupleUtils.scala5
-rw-r--r--src/utils/crypto/CBCCipher.scala23
-rw-r--r--src/utils/crypto/CBCDecrypter.scala36
5 files changed, 74 insertions, 13 deletions
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
+}