Merge branch 'dev' into 'main'
continuous-integration/drone/push Build is passing Details

Add a simple experimental analyzer for Simple substitution ciphers

See merge request KKlochko/cipher-analytical-machine!3
main
KKlochko 2 years ago
commit 3232eeaa4f

@ -7,7 +7,27 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased]
## [0.9.15] - 2023-11-26
### Changed
- Update the CHANGELOG.
- Update the version.
- Update the README.
## [0.9.14] - 2023-11-26
### Added
- Add analyzer for the simple substitution cipher.
- Add the analyzer options and their actions for the simple substiotution.
## [0.9.13] - 2023-11-26
### Fixed
- Fix the test name.
## [0.9.12] - 2023-11-20
### Changed
- Update the CHANGELOG.
- Update the version.
- Update the README.
@ -291,7 +311,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Added
- Project initialization.
[Unreleased]: https://gitlab.com/KKlochko/cipher-analytical-machine/-/compare/0.9.12...main?from_project_id=50218541&straight=false
[Unreleased]: https://gitlab.com/KKlochko/cipher-analytical-machine/-/compare/0.9.15...main?from_project_id=50218541&straight=false
[0.9.15]: https://gitlab.com/KKlochko/cipher-analytical-machine/-/compare/0.9.14...0.0.9.15?from_project_id=50218541&straight=false
[0.9.14]: https://gitlab.com/KKlochko/cipher-analytical-machine/-/compare/0.9.13...0.0.9.14?from_project_id=50218541&straight=false
[0.9.13]: https://gitlab.com/KKlochko/cipher-analytical-machine/-/compare/0.9.12...0.0.9.13?from_project_id=50218541&straight=false
[0.9.12]: https://gitlab.com/KKlochko/cipher-analytical-machine/-/compare/0.9.11...0.0.9.12?from_project_id=50218541&straight=false
[0.9.11]: https://gitlab.com/KKlochko/cipher-analytical-machine/-/compare/0.9.10...0.0.9.11?from_project_id=50218541&straight=false
[0.9.10]: https://gitlab.com/KKlochko/cipher-analytical-machine/-/compare/0.9.9...0.9.10?from_project_id=50218541&straight=false

@ -12,7 +12,7 @@ You need install java, before run the application.
Run the application with a command:
$ java -jar cipher-analytical-machine-VERSION-standalone.jar [args]
$ java -jar cipher-analytical-machine-0.9.12-standalone.jar [args]
$ java -jar cipher-analytical-machine-0.9.15-standalone.jar [args]
## License

@ -1,4 +1,4 @@
(defproject cipher-analytical-machine "0.9.12"
(defproject cipher-analytical-machine "0.9.15"
:description "A program helps to learn how ciphers works."
:url "https://gitlab.com/KKlochko/cipher-analytical-machine"
:license {:name "LGPL"

@ -1,8 +1,10 @@
(ns cipher-analytical-machine.analyzers.simple-substitution
(:require [clojure.string :as cs]
[clojure.math.combinatorics :as comb]
[cipher-analytical-machine.symbols.frequencies :as frequencies]
[cipher-analytical-machine.ciphers.simple-substitution :as ss]
[cipher-analytical-machine.analyzers.analyzers :as analyzers]
[cipher-analytical-machine.analyzers.analyzers :as ca]
[cipher-analytical-machine.analyzers.caesar :as caesar])
(:gen-class))
@ -42,3 +44,35 @@
(->> (map get-all-permutation-for-block possible-key-vector)
(get-all-combinations-for-blocks)))
(defn get-possible-keys
"Return keys for a cipher text. A key is a map {\\a \\e, ...} to decrypt a text."
[cipher-text frequency-table]
(let [freq-symbol-str (frequencies/map-to-string frequency-table) ; "etaoinsrhldcumfpgwybvkxjqz"
char-map (-> (analyzers/count-characters cipher-text)
(analyzers/reverse-count-characters))]
(map (fn [comb] (zipmap comb freq-symbol-str))
(-> (get-possible-key-vector-from-reversed-count-map char-map)
(get-possible-key-combinations)))))
(defn get-plain-data
"Return the plain data (score, text, key) from a ciphertext (a string of character). The function is case-insensitive."
[cipher-text letter-frequencies]
(let [cipher-text (cs/lower-case cipher-text)
keys (get-possible-keys cipher-text letter-frequencies)]
(->> (map (fn [key] [(ss/decrypt-message-by-symbol-table key cipher-text) key]) keys)
(map (fn [[text key]] [(ca/chi-squared-statistic text letter-frequencies) text key]))
)))
(defn get-plaintext-and-key
"Return the possible plaintext from a ciphertext that encoded with numbers. The function is case-insensitive."
[cipher-text letter-frequencies]
(let [maybe-key (->> (frequencies/map-to-string letter-frequencies)
(ss/generate-sorted-substitution-table))
cipher-text (->> (cs/split cipher-text #",")
(map #(Integer/parseInt %))
(ss/decrypt-message-by-symbol-table maybe-key))]
(->> (get-plain-data cipher-text letter-frequencies)
(map (fn [el] (drop 1 el)) ))))

@ -1,6 +1,7 @@
(ns cipher-analytical-machine.cli.actions.cracking
(:require
[cipher-analytical-machine.analyzers.caesar :as caesar-analyzers]
[cipher-analytical-machine.analyzers.simple-substitution :as ss-analyzers]
[cipher-analytical-machine.symbols.frequencies :as symbol-frequencies])
(:gen-class))
@ -18,10 +19,27 @@
:else
(caesar-analyzers/get-plaintext message symbols frequencies))))
(defn cracking-simple-substitution-with-caesar
[options arguments]
(let [analyzer (:analyzer options)
message (:message options)
symbols (:symbols options)
frequencies (-> (get options :language "en")
(symbol-frequencies/default-frequency-factory))]
(cond
(= analyzer "Chi^2")
(ss-analyzers/get-plaintext-and-key message frequencies)
:else
(ss-analyzers/get-plaintext-and-key message frequencies))))
(defn cracking-actions
[options arguments action-type]
(let [cipher (:cipher options)]
(cond
(= cipher "Caesar")
(cracking-caesar options arguments))))
(cracking-caesar options arguments)
(= cipher "Simple substitution and Caesar")
(cracking-simple-substitution-with-caesar options arguments))))

@ -32,7 +32,8 @@
(option-values-as-row "Ciphers" cipher-options))
(def analyzers-options
{"Caesar" #{"Chi^2"}})
{"Caesar" #{"Chi^2" "Frequency"}
"Simple substitution and Caesar" #{"Chi^2" "Frequency"}})
(defn get-available-analyzers-options-as-string
"Return the formatted string of analyzers options."

@ -3,7 +3,7 @@
[clojure.test :refer :all]
[cipher-analytical-machine.symbols.frequencies :refer :all]))
(deftest calculate-char-index-test
(deftest map-to-string-test
(let [symbol-map english-letter-frequencies]
(testing "The map must be converted to 'etaoinsrhldcumfpgwybvkxjqz'"
(is (= "etaoinsrhldcumfpgwybvkxjqz"

Loading…
Cancel
Save