summaryrefslogtreecommitdiff
path: root/src/solvers
diff options
context:
space:
mode:
Diffstat (limited to 'src/solvers')
-rw-r--r--src/solvers/Challenge4.scala29
-rw-r--r--src/solvers/XorDecrypt.scala12
2 files changed, 38 insertions, 3 deletions
diff --git a/src/solvers/Challenge4.scala b/src/solvers/Challenge4.scala
new file mode 100644
index 0000000..f71f6c0
--- /dev/null
+++ b/src/solvers/Challenge4.scala
@@ -0,0 +1,29 @@
+package ixee.cryptopals.solvers
+
+import scala.io.Source
+import ixee.cryptopals.utils.ByteUtils._
+import ixee.cryptopals.utils.ConversionUtils._
+import ixee.cryptopals.utils.FunctionUtils._
+import ixee.cryptopals.utils._
+
+object Challenge4 {
+ def findSingleCharacterXor(strings: Seq[Seq[Byte]]): (String, Int) = {
+ strings
+ .map(XorDecrypt.findBestSingleByteKey)
+ .zip(strings)
+ .zipWithIndex
+ .map { pair => (pair._1._1, pair._1._2, pair._2) }
+ .filter(_._1 != 0)
+ .map { triplet => (XorDecrypt.decryptToAscii(triplet._2)(triplet._1), triplet._3) }
+ .map { pair => (pair._1, TextScorer.score(pair._1.asBytes), pair._2) }
+ .sortBy(_._2)
+ .map { triplet => (triplet._1, triplet._3) }
+ .head
+ }
+
+ def run(inputFile: String) = {
+ findSingleCharacterXor(
+ Source.fromFile(inputFile).getLines().toSeq.map(hexStr2Bytes(_))
+ )
+ }
+}
diff --git a/src/solvers/XorDecrypt.scala b/src/solvers/XorDecrypt.scala
index b7f7c43..6b82c34 100644
--- a/src/solvers/XorDecrypt.scala
+++ b/src/solvers/XorDecrypt.scala
@@ -2,18 +2,24 @@ package ixee.cryptopals.solvers
import ixee.cryptopals.utils._
import ixee.cryptopals.utils.ByteUtils._
+import ixee.cryptopals.utils.FunctionUtils._
object XorDecrypt {
implicit val freq = Frequencies.cornell40kSample
- def tryBestDecrypt(ciphertext: Seq[Byte]) = {
- val key = findBestSingleByteKey(ciphertext)
+ def decryptToAscii(ciphertext: Seq[Byte])(key: Byte): String = {
new String((ciphertext xor Stream.continually(key)).toArray)
}
+ def tryBestDecrypt(ciphertext: Seq[Byte]): String = {
+ (findBestSingleByteKey _ :| decryptToAscii(ciphertext) _)(ciphertext)
+ }
+
def findBestSingleByteKey(ciphertext: Seq[Byte]): Byte =
candidates(ciphertext)
- .minBy(_._1)._2.toByte
+ .reduceOption( (a: (Double, Int), b: (Double, Int)) =>
+ if (a._1 < b._1) a else b
+ ).map(_._2.toByte).getOrElse(0.toByte)
def candidates(ciphertext: Seq[Byte]) =
(0 until 256)