Compare commits

..
80 Commits
Author SHA1 Message Date
KKlochko f9ddae3998 Update the README.
continuous-integration/drone/push Build is passing
continuous-integration/drone/tag Build is passing
2023-11-20 21:28:29 +02:00
KKlochko 31d2e8f753 Update the version. 2023-11-20 21:28:07 +02:00
KKlochko 60907c9a3b Update the CHANGELOG. 2023-11-20 21:27:38 +02:00
KKlochko 481735d9df Add the function that return all key combinations for a possible key vector.
continuous-integration/drone/push Build is passing
2023-11-14 21:55:29 +02:00
KKlochko d6ba958b5b Rename the function from get-possible-keys to get-all-combinations-for-blocks. 2023-11-14 21:54:38 +02:00
KKlochko d1b2ddc351 Add a function to get all permutations for a block.
continuous-integration/drone/push Build is passing
2023-11-13 20:53:07 +02:00
KKlochko 6a1ecf93db Add a function to get the ordered sequence that can form a key.
continuous-integration/drone/push Build is passing
2023-11-12 21:51:42 +02:00
KKlochko c03dc68458 Add a function to convert a count map to a reversed map. 2023-11-12 21:50:02 +02:00
KKlochko 2cc5be57c8 Add functions to get possible keys.
continuous-integration/drone/push Build is passing
2023-11-11 15:21:16 +02:00
KKlochko ddfd5c473d Add the default frequency factory.
continuous-integration/drone/push Build is passing
2023-11-03 20:33:23 +02:00
KKlochko fcae272944 Add key validation for Caesar and Gamma ciphers.
continuous-integration/drone/push Build is passing
2023-11-01 15:07:13 +02:00
KKlochko 1e45771b3e Add key? to check if a string is a gamma key. 2023-11-01 15:05:08 +02:00
KKlochko e145382570 Add int-string? to check if a string is a number.
continuous-integration/drone/push Build is passing
2023-11-01 15:02:44 +02:00
KKlochko 91dc00ea0d Rename unsigned-int? to unsigned-int-string? 2023-11-01 15:01:22 +02:00
KKlochko 0261c97d76 Add the option for the gamma cipher.
continuous-integration/drone/push Build is passing
2023-10-31 16:50:25 +02:00
KKlochko 79b72fccca Fix the key parsing in the gamma actions. 2023-10-31 16:49:30 +02:00
KKlochko 5843695a40 Add the action of decryption for the gamma cipher. 2023-10-31 16:48:40 +02:00
KKlochko 4f89fede56 Add the action of encryption for the gamma cipher.
continuous-integration/drone/push Build is passing
2023-10-30 20:15:40 +02:00
KKlochko 53f89d4b4f Add a function to decrypt a message with the gamma cipher.
continuous-integration/drone/push Build is passing
2023-10-29 19:05:12 +02:00
KKlochko bcb347a8d9 Add a function to encrypt a message with the gamma cipher.
continuous-integration/drone/push Build is passing
2023-10-28 17:16:04 +03:00
KKlochko 124133a407 Refactor the simple substitute to use the decrypt-by-table function. 2023-10-28 17:14:55 +03:00
KKlochko e80e3a6cf0 Add the functions to encrypt and decrypt with the gamma cipher.
continuous-integration/drone/push Build is passing
2023-10-27 21:40:47 +03:00
KKlochko e2e49ec392 Add the gamma generator.
continuous-integration/drone/push Build is passing
2023-10-26 21:33:29 +03:00
KKlochko 3a3682f2c4 Add the main for the cli module.
continuous-integration/drone/push Build is passing
2023-10-25 22:03:02 +03:00
KKlochko e70b72f0ec Update the simple substitution cipher to split the decrypt-message.
continuous-integration/drone/push Build is passing
2023-10-24 21:39:51 +03:00
KKlochko 172f85ea6f Add functions to make a frequency map.
continuous-integration/drone/push Build is passing
2023-10-24 21:24:03 +03:00
KKlochko 6f70417b78 Add the simple substitution cipher.
continuous-integration/drone/push Build is passing
2023-10-23 15:55:14 +03:00
KKlochko d357e82b54 Add the parser to parse the string as an integer if it's needed. 2023-10-23 15:51:30 +03:00
KKlochko 553f4788e4 Add a function to invert the table in a decoded json. 2023-10-23 15:50:05 +03:00
KKlochko 5a4b88bd08 Add the parsers to parse keys.
continuous-integration/drone/push Build is passing
2023-10-22 17:54:16 +03:00
KKlochko 79ae13aa5a Add a generator for the sorted substitution table.
continuous-integration/drone/push Build is passing
2023-10-22 17:26:54 +03:00
KKlochko 126a706292 Update the simple substitution cipher to split the functions. 2023-10-22 17:26:04 +03:00
KKlochko 178c85b0cb Add the simple substitution cipher.
continuous-integration/drone/push Build is passing
2023-10-21 21:45:43 +03:00
KKlochko 2db631d8da Update the diffs in the CHANGELOG.
continuous-integration/drone/push Build is passing
continuous-integration/drone/tag Build is passing
2023-10-21 16:56:32 +03:00
KKlochko 05009f1a96 Update the CI/CD configuration to publish the artifacts to the release.
continuous-integration/drone/push Build is passing
2023-10-21 16:47:22 +03:00
KKlochko 7c19e48828 Update the README. 2023-10-21 16:46:57 +03:00
KKlochko 40725f55a1 Update the version. 2023-10-21 16:46:32 +03:00
KKlochko 633cdc471f Update the CHANGELOG. 2023-10-21 16:46:15 +03:00
KKlochko dab131a32e Remove the option for FrequencyAnalyzer.
continuous-integration/drone/push Build is passing
2023-10-20 22:04:05 +03:00
KKlochko f465d1112e Remove the test for FrequencyAnalyzer. 2023-10-20 22:03:10 +03:00
KKlochko 5919ba8864 Refactor to move actions to separated files. 2023-10-20 22:01:20 +03:00
KKlochko a56704226b Add the IsNonsense interface for FrequencyAnalyzer.
continuous-integration/drone/push Build is failing
2023-10-14 21:32:56 +03:00
Kryls1fer b53559030f Update the frequency analyzer. 2023-10-14 21:18:50 +03:00
KKlochko ef87a719a3 Add validations to check if a cipher or an analyzer is available.
continuous-integration/drone/push Build is passing
2023-10-14 17:28:21 +03:00
KKlochko 2f0254f677 Add the available ciphers and analyzer for the help. 2023-10-14 17:26:20 +03:00
KKlochko 6339774bd1 Add the analyzer options and their actions. 2023-10-14 17:22:03 +03:00
KKlochko a44fc24bee Refactor to move options to a separated file. 2023-10-14 17:11:36 +03:00
KKlochko ac2cf2ac58 Fix the bug that the default language symbols override the symbols.
continuous-integration/drone/push Build is passing
2023-10-13 21:46:48 +03:00
KKlochko 043257bb64 Update the FrequencyAnalyzer to use the frequency string instead.
continuous-integration/drone/push Build is passing
2023-10-12 22:10:41 +03:00
KKlochko de35d4e2d3 Add the function to make a frequency string from a map. 2023-10-12 22:04:39 +03:00
KKlochko 476a24c900 Fix the typo "frequences" to frequencies. 2023-10-12 22:00:01 +03:00
KKlochko 4d7e9da1d1 Refactor the project structure.
continuous-integration/drone/push Build is passing
2023-10-11 21:12:10 +03:00
KKlochko 77efa81c54 Add the Gitlab CI/CD configuration.
continuous-integration/drone/push Build is passing
2023-10-09 20:00:50 +03:00
KKlochko 51609b1d27 Add the clojure wrapper for the frequency analizer and its test.
continuous-integration/drone/push Build is passing
2023-10-05 20:10:05 +03:00
KKlochko 40af8401b2 Add a frequency analyzer as a stub. 2023-10-05 20:08:41 +03:00
KKlochko 0a87ab9e91 Add the Caesar decrypted interface for Java. 2023-10-05 20:07:43 +03:00
KKlochko 9c1a8b1bae Add the java source path. 2023-10-05 20:07:11 +03:00
KKlochko c3ea58f867 Add the CHANGELOG.
continuous-integration/drone/push Build is passing
2023-10-05 17:50:22 +03:00
KKlochko df8f580f93 Fix writing to a file only when the option is set.
continuous-integration/drone/push Build is passing
2023-10-02 22:29:22 +03:00
KKlochko 871fc3ed55 Fix checking for file existence only when the options are set. 2023-10-02 22:26:32 +03:00
KKlochko 79a498022e Add the file errors to prevent using an invalid file path.
continuous-integration/drone/push Build is passing
2023-09-28 21:00:17 +03:00
KKlochko 5d56abbee9 Add the output option to save into a file. 2023-09-28 20:59:58 +03:00
KKlochko 4607f7f013 Update Caesar Analyzers to be case-insensitive and testable.
continuous-integration/drone/push Build is passing
2023-09-22 21:04:11 +03:00
KKlochko 79e316c51b Update the Caesar to be case-insensitive and skip unknown symbols.
continuous-integration/drone/push Build is passing
2023-09-21 21:05:22 +03:00
KKlochko 20c1d1ef1b Update symbol defaults, factories to have only lower alphabets.
continuous-integration/drone/push Build is passing
2023-09-21 21:01:52 +03:00
KKlochko 6833ade696 Add the language option for symbols. 2023-09-21 20:57:25 +03:00
KKlochko 9e4c46814c Update the CLI to have separated actions and an option initializer. 2023-09-21 20:55:43 +03:00
KKlochko 6f15eedacd Add tests for the cipher-analyzers module.
continuous-integration/drone/push Build is passing
2023-09-18 22:01:02 +03:00
KKlochko 182d9894f7 Rename the cipher_analyzer module to cipher-analyzer. 2023-09-18 21:57:32 +03:00
KKlochko e3954804c8 Add the cracking option.
continuous-integration/drone/push Build is passing
2023-09-17 21:45:09 +03:00
KKlochko b1f3bb8585 Rename the symbol_frequences module to symbol-frequences. 2023-09-17 21:43:09 +03:00
KKlochko a6f3ca160f Update the nonsense for the is-nonsense? test.
continuous-integration/drone/push Build is passing
2023-09-16 22:16:46 +03:00
KKlochko 001b2a8b65 Rename the language_analyzer module to language-analyzer. 2023-09-16 22:16:08 +03:00
KKlochko e8a023fe61 Add the symbol option and its default. 2023-09-16 22:08:12 +03:00
KKlochko 6d282e5ad4 Add the action-type to distinguish the actions. 2023-09-16 22:05:53 +03:00
KKlochko 5ca5765e01 Add symbol factories for punctuation, space, defaults symbols. 2023-09-16 22:02:18 +03:00
KKlochko a7ccad8e1e Add the caesar-analyzers to get the plaintext from a ciphertext.
continuous-integration/drone/push Build is failing
2023-09-15 21:30:37 +03:00
KKlochko 79e2957402 Add Chi-squared Statistic function to analyze texts.
continuous-integration/drone/push Build is failing
2023-09-14 21:09:28 +03:00
KKlochko 4750242a1d Add the frequences of symbols as defaults. 2023-09-14 20:50:28 +03:00
KKlochko 174abd8072 Add a simple language analyzers.
continuous-integration/drone/push Build is failing
2023-09-13 21:37:53 +03:00
41 changed files with 1965 additions and 200 deletions
+36
View File
@@ -5,6 +5,42 @@ name: default
steps:
- name: test
image: clojure:temurin-11-lein-2.10.0-alpine
volumes:
- name: package_cache
path: /root/.m2/
commands:
- lein test
- name: build
image: clojure:temurin-11-lein-2.10.0-alpine
volumes:
- name: package_cache
path: /root/.m2/
commands:
- lein uberjar
when:
event: tag
- name: gitea_release
image: plugins/gitea-release
settings:
api_key:
from_secret: API_KEY
base_url:
from_secret: BASE_URL
files:
- target/uberjar/*.jar
checksum:
- md5
- sha1
- sha256
- sha512
- adler32
- crc32
when:
event: tag
volumes:
- name: package_cache
temp: {}
+10
View File
@@ -0,0 +1,10 @@
image: clojure:temurin-11-lein-2.10.0-alpine
stages:
- test
unit tests:
stage: test
script:
- lein test
+339
View File
@@ -0,0 +1,339 @@
# Change Log
All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [Unreleased]
## [0.9.12] - 2023-11-20
- Update the CHANGELOG.
- Update the version.
- Update the README.
## [0.9.11] - 2023-11-14
### Added
- Add the function that return all key combinations for a possible key vector.
### Changed
- Rename the function from get-possible-keys to get-all-combinations-for-blocks.
## [0.9.10] - 2023-11-13
### Added
- Add a function to get all permutations for a block.
## [0.9.9] - 2023-11-12
### Added
- Add a function to convert a count map to a reversed map.
- Add a function to get the ordered sequence that can form a key.
## [0.9.8] - 2023-11-11
### Added
- Add functions to get possible keys.
## [0.9.7] - 2023-11-03
### Added
- Add the default frequency factory.
## [0.9.6] - 2023-11-01
### Added
- Add int-string? to check if a string is a number.
- Add key? to check if a string is a gamma key.
- Add key validation for Caesar and Gamma ciphers.
### Changed
- Rename unsigned-int? to unsigned-int-string?
## [0.9.5] - 2023-10-31
## [0.9.5] - 2023-10-31
### Added
- Add the option for the gamma cipher.
## [0.9.4] - 2023-10-31
### Fixed
- Fix the key parsing in the gamma actions.
## [0.9.3] - 2023-10-31
### Added
- Add the action of encryption for the gamma cipher.
- Add the action of decryption for the gamma cipher.
## [0.9.2] - 2023-10-29
### Added
- Add a function to encrypt a message with the gamma cipher.
- Add a function to decrypt a message with the gamma cipher.
## [0.9.1] - 2023-10-28
### Changed
- Refactor the simple substitute to use the decrypt-by-table function.
## [0.9.0] - 2023-10-27
### Added
- Add the gamma generator.
- Add the functions to encrypt and decrypt with the gamma cipher.
## [0.8.5] - 2023-10-25
### Added
- Add the main for the cli module.
## [0.8.4] - 2023-10-24
### Changed
- Update the simple substitution cipher to split the decrypt-message.
## [0.8.3] - 2023-10-24
### Added
- Add functions to make a frequency map.
## [0.8.2] - 2023-10-23
### Added
- Add a function to invert the table in a decoded json.
- Add the parser to parse the string as an integer if it's needed.
- Add the simple substitution cipher.
## [0.8.1] - 2023-10-22
### Added
- Add a generator for the sorted substitution table.
- Add the parsers to parse keys.
### Changed
- Update the simple substitution cipher to split the functions.
## [0.8.0] - 2023-10-21
### Added
- Add the simple substitution cipher.
## [0.7.2] - 2023-10-21
### Changed
- Update the CHANGELOG.
- Update the version.
- Update the README.
- Update the CI/CD configuration to publish the artifacts to the release.
- Update the diffs in the CHANGELOG.
## [0.7.1] - 2023-10-20
### Removed
- Remove the test for FrequencyAnalyzer.
- Remove the option for FrequencyAnalyzer.
## [0.7.0] - 2023-10-20
### Changed
- Refactor to move actions to separated files.
## [0.6.3] - 2023-10-14
### Added
- Add the IsNonsense interface for FrequencyAnalyzer.
### Changed
- Update the frequency analyzer.
## [0.6.2] - 2023-10-14
### Added
- Add the analyzer options and their actions.
- Add the available ciphers and analyzer for the help.
- Add validations to check if a cipher or an analyzer is available.
### Changed
- Refactor to move options to a separated file.
## [0.6.1] - 2023-10-13
### Added
- Add the function to make a frequency string from a map.
### Fixed
- Fix the bug that the default language symbols override the symbols.
### Changed
- Update the FrequencyAnalyzer to use the frequency string instead.
## [0.6.0] - 2023-10-12
### Fixed
- Fix the typo "frequences" to frequencies.
### Changed
- Refactor the project structure.
## [0.5.5] - 2023-10-09
### Added
- Add the Gitlab CI/CD configuration.
## [0.5.4] - 2023-10-05
### Added
- Add the java source path.
- Add the Caesar decrypted interface for Java.
- Add a frequency analyzer as a stub.
- Add the clojure wrapper for the frequency analizer and its test.
## [0.5.3] - 2023-10-05
### Added
- Add the CHANGELOG.
## [0.5.2] - 2023-10-02
### Fixed
- Fix checking for file existence only when the options are set.
- Fix writing to a file only when the option is set.
## [0.5.1] - 2023-09-28
### Added
- Add the output option to save into a file.
- Add the file errors to prevent using an invalid file path.
## [0.5.0] - 2023-09-22
### Changed
- Update symbol defaults, factories to have only lower alphabets.
- Update the Caesar to be case-insensitive and skip unknown symbols.
- Update Caesar Analyzers to be case-insensitive and testable.
## [0.4.3] - 2023-09-21
### Added
- Add the language option for symbols.
### Changed
- Update the CLI to have separated actions and an option initializer.
## [0.4.2] - 2023-09-18
### Added
- Add tests for the cipher-analyzers module.
### Changed
- Rename the cipher_analyzer module to cipher-analyzers.
## [0.4.1] - 2023-09-17
### Added
- Add symbol factories for punctuation, space, defaults symbols.
- Add the action-type to distinguish the actions.
- Add the symbol option and its default.
- Add the cracking option.
### Changed
- Rename the language_analyzer module to language-analyzer.
- Update the nonsense for the is-nonsense? test.
- Rename the symbol_frequences module to symbol-frequences.
## [0.4.0] - 2023-09-15
### Added
- Add Chi-squared Statistic function to analyze texts.
- Add the caesar-analyzers to get the plaintext from a ciphertext.
## [0.3.5] - 2023-09-14
### Added
- Add the frequences of symbols as defaults.
## [0.3.4] - 2023-09-13
### Added
- Add a simple language analyzers.
## [0.3.3] - 2023-09-12
### Added
- Add an option to read a message from a file.
## [0.3.2] - 2023-09-11
### Added
- Add the CI/CD configuration.
## [0.3.1] - 2023-09-11
### Added
- Add factories for symbols.
- Add tests for factories.
## [0.3.0] - 2023-09-10
### Added
- Add a simple cli interface.
## [0.2.0] - 2023-09-09
### Added
- Add a implementation of Caesar cipher.
## [0.1.0] - 2023-09-09
### Added
- Project initialization.
[Unreleased]: https://gitlab.com/KKlochko/cipher-analytical-machine/-/compare/0.9.12...main?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
[0.9.9]: https://gitlab.com/KKlochko/cipher-analytical-machine/-/compare/0.9.8...0.9.9?from_project_id=50218541&straight=false
[0.9.8]: https://gitlab.com/KKlochko/cipher-analytical-machine/-/compare/0.9.7...0.9.8?from_project_id=50218541&straight=false
[0.9.7]: https://gitlab.com/KKlochko/cipher-analytical-machine/-/compare/0.9.6...0.9.7?from_project_id=50218541&straight=false
[0.9.6]: https://gitlab.com/KKlochko/cipher-analytical-machine/-/compare/0.9.5...0.9.6?from_project_id=50218541&straight=false
[0.9.5]: https://gitlab.com/KKlochko/cipher-analytical-machine/-/compare/0.9.4...0.9.5?from_project_id=50218541&straight=false
[0.9.4]: https://gitlab.com/KKlochko/cipher-analytical-machine/-/compare/0.9.3...0.9.4?from_project_id=50218541&straight=false
[0.9.3]: https://gitlab.com/KKlochko/cipher-analytical-machine/-/compare/0.9.2...0.9.3?from_project_id=50218541&straight=false
[0.9.2]: https://gitlab.com/KKlochko/cipher-analytical-machine/-/compare/0.9.1...0.9.2?from_project_id=50218541&straight=false
[0.9.1]: https://gitlab.com/KKlochko/cipher-analytical-machine/-/compare/0.9.0...0.9.1?from_project_id=50218541&straight=false
[0.9.0]: https://gitlab.com/KKlochko/cipher-analytical-machine/-/compare/0.8.5...0.9.0?from_project_id=50218541&straight=false
[0.8.5]: https://gitlab.com/KKlochko/cipher-analytical-machine/-/compare/0.8.4...0.8.5?from_project_id=50218541&straight=false
[0.8.4]: https://gitlab.com/KKlochko/cipher-analytical-machine/-/compare/0.8.3...0.8.4?from_project_id=50218541&straight=false
[0.8.3]: https://gitlab.com/KKlochko/cipher-analytical-machine/-/compare/0.8.2...0.8.3?from_project_id=50218541&straight=false
[0.8.2]: https://gitlab.com/KKlochko/cipher-analytical-machine/-/compare/0.8.1...0.8.2?from_project_id=50218541&straight=false
[0.8.1]: https://gitlab.com/KKlochko/cipher-analytical-machine/-/compare/0.8.0...0.8.1?from_project_id=50218541&straight=false
[0.8.0]: https://gitlab.com/KKlochko/cipher-analytical-machine/-/compare/0.7.2...0.8.0?from_project_id=50218541&straight=false
[0.7.2]: https://gitlab.com/KKlochko/cipher-analytical-machine/-/compare/0.7.1...0.7.2?from_project_id=50218541&straight=false
[0.7.1]: https://gitlab.com/KKlochko/cipher-analytical-machine/-/compare/0.7.0...0.7.1?from_project_id=50218541&straight=false
[0.7.0]: https://gitlab.com/KKlochko/cipher-analytical-machine/-/compare/0.6.3...0.7.0?from_project_id=50218541&straight=false
[0.6.3]: https://gitlab.com/KKlochko/cipher-analytical-machine/-/compare/0.6.2...0.6.3?from_project_id=50218541&straight=false
[0.6.2]: https://gitlab.com/KKlochko/cipher-analytical-machine/-/compare/0.6.1...0.6.2?from_project_id=50218541&straight=false
[0.6.1]: https://gitlab.com/KKlochko/cipher-analytical-machine/-/compare/0.6.0...0.6.1?from_project_id=50218541&straight=false
[0.6.0]: https://gitlab.com/KKlochko/cipher-analytical-machine/-/compare/0.5.5...0.6.0?from_project_id=50218541&straight=false
[0.5.5]: https://gitlab.com/KKlochko/cipher-analytical-machine/-/compare/0.5.4...0.5.5?from_project_id=50218541&straight=false
[0.5.4]: https://gitlab.com/KKlochko/cipher-analytical-machine/-/compare/0.5.3...0.5.4?from_project_id=50218541&straight=false
[0.5.3]: https://gitlab.com/KKlochko/cipher-analytical-machine/-/compare/0.5.2...0.5.3?from_project_id=50218541&straight=false
[0.5.2]: https://gitlab.com/KKlochko/cipher-analytical-machine/-/compare/0.5.1...0.5.2?from_project_id=50218541&straight=false
[0.5.1]: https://gitlab.com/KKlochko/cipher-analytical-machine/-/compare/0.5.0...0.5.1?from_project_id=50218541&straight=false
[0.5.0]: https://gitlab.com/KKlochko/cipher-analytical-machine/-/compare/0.4.3...0.5.0?from_project_id=50218541&straight=false
[0.4.3]: https://gitlab.com/KKlochko/cipher-analytical-machine/-/compare/0.4.2...0.4.3?from_project_id=50218541&straight=false
[0.4.2]: https://gitlab.com/KKlochko/cipher-analytical-machine/-/compare/0.4.1...0.4.2?from_project_id=50218541&straight=false
[0.4.1]: https://gitlab.com/KKlochko/cipher-analytical-machine/-/compare/0.4.0...0.4.1?from_project_id=50218541&straight=false
[0.4.0]: https://gitlab.com/KKlochko/cipher-analytical-machine/-/compare/0.3.5...0.4.0?from_project_id=50218541&straight=false
[0.3.5]: https://gitlab.com/KKlochko/cipher-analytical-machine/-/compare/0.3.4...0.3.5?from_project_id=50218541&straight=false
[0.3.4]: https://gitlab.com/KKlochko/cipher-analytical-machine/-/compare/0.3.3...0.3.4?from_project_id=50218541&straight=false
[0.3.3]: https://gitlab.com/KKlochko/cipher-analytical-machine/-/compare/0.3.2...0.3.3?from_project_id=50218541&straight=false
[0.3.2]: https://gitlab.com/KKlochko/cipher-analytical-machine/-/compare/0.3.1...0.3.2?from_project_id=50218541&straight=false
[0.3.1]: https://gitlab.com/KKlochko/cipher-analytical-machine/-/compare/0.3.0...0.3.1?from_project_id=50218541&straight=false
[0.3.0]: https://gitlab.com/KKlochko/cipher-analytical-machine/-/compare/0.2.0...0.3.0?from_project_id=50218541&straight=false
[0.2.0]: https://gitlab.com/KKlochko/cipher-analytical-machine/-/compare/0.1.0...0.2.0?from_project_id=50218541&straight=false
[0.1.0]: https://gitlab.com/KKlochko/cipher-analytical-machine/-/commit/a7a715b94276fc8f46fb6a44139636d27b551599
+3 -1
View File
@@ -11,10 +11,12 @@ Download from https://gitlab.com/KKlochko/cipher-analytical-machine.
You need install java, before run the application.
Run the application with a command:
$ java -jar cipher-analytical-machine-0.1.0-standalone.jar [args]
$ java -jar cipher-analytical-machine-VERSION-standalone.jar [args]
$ java -jar cipher-analytical-machine-0.9.12-standalone.jar [args]
## License
Copyright © 2023 Kostiantyn Klochko
Under the GNU Lesser General Public License v3.0 or later.
+7 -2
View File
@@ -1,11 +1,16 @@
(defproject cipher-analytical-machine "0.1.0-SNAPSHOT"
(defproject cipher-analytical-machine "0.9.12"
:description "A program helps to learn how ciphers works."
:url "https://gitlab.com/KKlochko/cipher-analytical-machine"
:license {:name "LGPL"
:url "http://www.gnu.org/licenses/lgpl-3.0.txt"}
:dependencies [[org.clojure/clojure "1.11.1"]
[org.clojure/tools.cli "1.0.219"]]
[org.clojure/tools.cli "1.0.219"]
[org.apache.tika/tika-core "1.28.5"]
[org.apache.tika/tika-langdetect "1.28.5"]
[cheshire "5.12.0"]
[org.clojure/math.combinatorics "0.2.0"]]
:main ^:skip-aot cipher-analytical-machine.core
:java-source-paths ["src/main/java"]
:target-path "target/%s"
:profiles {:uberjar {:aot :all
:jvm-opts ["-Dclojure.compiler.direct-linking=true"]}})
@@ -0,0 +1,67 @@
(ns cipher-analytical-machine.analyzers.analyzers
(:require [clojure.string :as cs])
(:gen-class))
(defn count-characters
"Count the letters and return map."
[text]
(reduce
(fn [acc val]
(assoc acc val
(inc (get acc val 0))))
{} text))
(defn reverse-count-characters
"Convert a map of pairs to a map where the characters grouped by the count and a count is the key."
[count-map]
(reduce
(fn [acc [symbol count]]
(->> (conj (get acc count []) symbol)
(into [])
(assoc acc count)))
{} count-map))
(defn chi-squared-letter-statistic
"To calculate the frequency distribution of a letter."
[letter-count letter-frequence length-text]
(let [letter-frequence (* length-text letter-frequence)]
(/ (Math/pow
(- letter-count letter-frequence) 2)
letter-frequence)))
(defn chi-squared-statistic
"To calculate the frequency distribution of a language. More detail about the algorithm here: http://practicalcryptography.com/cryptanalysis/text-characterisation/chi-squared-statistic/"
[text letter-frequencies]
(let [length-text (count text)
letter-counts (count-characters (cs/lower-case text))]
;letter-counts
(reduce
(fn [acc [char count]]
(+ acc
(if (contains? letter-frequencies char)
(chi-squared-letter-statistic count
(get letter-frequencies char)
length-text)
0)))
0
letter-counts)))
(defn sort-map-by-count
"Return a list of pairs from a map of pairs where a pair is a character and its count. The order is descending."
[count-map]
(->> count-map
(reduce (fn [acc [char count]] (conj acc [char count])) [])
(sort-by #(- (second %)))))
(defn table-to-string
"Return the string from a frequency table."
[table]
(->> (map first table)
(apply str)))
(defn symbol-frequency-table
"Return a table where pairs is a symbol from a cipher text and its value which is a symbol from frequency table."
[cipher-table frequency-table]
(zipmap (table-to-string (sort-map-by-count cipher-table))
(table-to-string (sort-map-by-count frequency-table))))
@@ -0,0 +1,64 @@
(ns cipher-analytical-machine.analyzers.caesar
(:require [cipher-analytical-machine.ciphers.caesar :as caesar]
[clojure.string :as cs]
[cipher-analytical-machine.analyzers.language :as language]
[cipher-analytical-machine.analyzers.analyzers :as ca])
(:import [cipher_analytical_machine.ciphers.caesar Decrypted]
[cipher_analytical_machine.analyzers.caesar IsNonsense]
[cipher_analytical_machine.analyzers.caesar FrequencyAnalyzer])
(:gen-class))
(defn get-all-texts
"Return a list of pairs which have a key and a second posible plaintext."
[ciphertext symbols]
(let [keys (range (count symbols))]
(reduce
(fn [acc key]
(conj acc [key (caesar/decrypt-message ciphertext key symbols)]))
'() keys)))
(defn get-all-scores
"For pairs (key, plaintext) finds scores and return list of pairs [key, score]."
[letter-frequencies pairs]
(map (fn [[key text]]
[key (ca/chi-squared-statistic text letter-frequencies)])
pairs))
(defn get-min-score-pair
"For pairs (key, plaintext) finds scores and return list of pairs [key, score]."
[pairs]
(reduce
(fn [[key value] [new-key new-value]]
(if (> value new-value) [new-key new-value]
[key value]))
[0 Double/MAX_VALUE]
pairs))
(defn get-key
"To find the key with frequencies of letters."
[ciphertext symbols letter-frequencies]
(->> (get-all-texts ciphertext symbols)
(get-all-scores letter-frequencies)
(get-min-score-pair)
(first)))
(defn get-plaintext
"Return the plaintext from a ciphertext. The function is case-insensitive."
[ciphertext symbols letter-frequencies]
(let [ciphertext (cs/lower-case ciphertext)]
(caesar/decrypt-message ciphertext
(get-key ciphertext symbols letter-frequencies)
symbols)))
(defn frequency-analizer-get-plaintext
"Return the plaintext from a ciphertext using simple analizer. The function is case-insensitive."
[ciphertext symbols letter-frequencies-string language-code]
(let [decrypt (reify Decrypted
(decrypt [this message key symbols]
(caesar/decrypt-message message key symbols)))
is-nonsense (reify IsNonsense
(isNonsense [this message]
(language/is-nonsense? message language-code)))]
(-> (new FrequencyAnalyzer ciphertext symbols letter-frequencies-string decrypt is-nonsense)
.crack)))
@@ -0,0 +1,21 @@
(ns cipher-analytical-machine.analyzers.language
(:import [org.apache.tika.language LanguageIdentifier])
(:gen-class))
(defn detect-language
"Return a identified language."
[text]
(-> (new LanguageIdentifier text)
.getLanguage))
(defn is-language?
"Check if the text written a language."
[text language-id]
(= (detect-language text)
language-id))
(defn is-nonsense?
"Check if the text written a language is not a language."
[text language-id]
(not (is-language? text language-id)))
@@ -0,0 +1,44 @@
(ns cipher-analytical-machine.analyzers.simple-substitution
(:require [clojure.string :as cs]
[clojure.math.combinatorics :as comb]
[cipher-analytical-machine.ciphers.simple-substitution :as ss]
[cipher-analytical-machine.analyzers.analyzers :as analyzers]
[cipher-analytical-machine.analyzers.caesar :as caesar])
(:gen-class))
(defn get-possible-key-vector
"Convert a possible key map to a vector of possible keys. For example, if you have a map: {\\a [\\a \\b \\c] \\b [\\b \\c] \\c [\\a \\c]}, then the vector is [[\\a \\b \\c] [\\b \\c] [\\a \\c]]."
[possible-key-map symbols]
(reduce
(fn [acc el]
(conj acc (get possible-key-map el)))
[] symbols))
(defn get-possible-key-vector-from-reversed-count-map
"Convert a reversed count map to a vector. Example, from {2 [\\a \\b] 1 [\\d] 3 [\\e]} to [[\\e] [\\a \\b] [\\d]])."
[reversed-count-map]
(->> reversed-count-map
(into [])
(sort-by #(- (first %)))
(map second)
(into [])))
(defn get-all-permutation-for-block
"Return a vector for all possible blocks that can be made from a vector of symbols."
[symbols]
(->> (comb/permutations symbols)
(map cs/join)
(into [])))
(defn get-all-combinations-for-blocks
"Return the all combination of blocks in a possible key vector. For example, if you have a map: {\\a [\\a \"bf\" \\c] \\b [\"bf\" \\c] \\c [\\a \\c]}, then the vector is [[\\a \"bf\" \\c] [\"bf\" \\c] [\\a \\c]] and keys (\"abfa\" \"abfc\" ...)."
[possible-key-vector]
(->> (apply comb/cartesian-product possible-key-vector)
(map cs/join)))
(defn get-possible-key-combinations
"Return possible keys for a possible key vector. For example, if you have a map: {\\a [\\a \\b \\c] \\e [\\f \\g] \\c [\\a \\c]}, then the keys are (\"abcefg\" \"abcegf\" ...)."
[possible-key-vector]
(->> (map get-all-permutation-for-block possible-key-vector)
(get-all-combinations-for-blocks)))
@@ -1,4 +1,4 @@
(ns cipher-analytical-machine.caesar
(ns cipher-analytical-machine.ciphers.caesar
(:require [clojure.string :as cs])
(:gen-class))
@@ -14,21 +14,28 @@
(+ key)
(mod max-index)))
(defn encrypt-or-skip
"If symbols do not have a character, then it will be skipped."
[index character key symbols max-index]
(if (nil? index) character
(get symbols
(encrypt-index index key max-index))))
(defn encrypt-char
"Calculates new index of a character. Uses a char from symbols, the key and max-index (exclusive)."
[char key symbols max-index]
(get symbols
(-> char
(calculate-char-index symbols)
(encrypt-index key max-index))))
(encrypt-or-skip char key symbols max-index)))
(defn encrypt-message
"Encrypt a message using the Caesar cipher."
"Encrypt a message using the Caesar cipher. The function is case-insensitive."
[message key symbols]
(let [max-index (count symbols)]
(cs/join
(map (fn [char] (encrypt-char char key symbols max-index))
message))))
(->> message
(cs/lower-case)
(map (fn [char] (encrypt-char char key symbols max-index)))
(cs/join))))
(defn decrypt-message
"Decrypt the ciphtext using the Caesar cipher."
@@ -0,0 +1,78 @@
(ns cipher-analytical-machine.ciphers.gamma
(:require
[clojure.set :as set]
[clojure.string :as cs]
[cipher-analytical-machine.ciphers.simple-substitution :as ss])
(:gen-class))
(defn add-mod
[f s module]
(-> (+ f s)
(mod module)))
(defn generate-seq
"Generate a lazy sequence for a key (a b c)."
[a b c module]
((fn build-seq [a b c]
(lazy-seq (cons a (build-seq b c (add-mod a c module))))) a b c))
(defn generate-gamma-seq
"Generate the gamma seq from a sequence."
[acc seq module]
(if (= (second seq) nil) acc
(generate-gamma-seq
(conj acc (add-mod (first seq) (second seq) module))
(rest seq)
module)))
(defn generate-gamma
"Generate the gamma from a key (a b c)."
[a b c module size]
(generate-gamma-seq []
(->> (generate-seq a b c module)
(take (inc size)))
module))
(defn encrypt-array
"Encrypt an array using the gamma cipher. The function is case-insensitive. The key is an array of three elements [a b c]. The array contains integer in range [0, module)."
[key module array]
(let [size (count array)
gamma (->> (apply conj [key module size])
(apply generate-gamma))]
(->> gamma
(map vector array)
(map (fn [[a g]] (add-mod a g module))))))
(defn encrypt-message
"Encrypt a message using the gamma cipher. The function is case-insensitive. The key is an array of three elements [a b c]. The array contains integer in range [0, module)."
[key symbols message]
(let [module (count symbols)
table (ss/generate-sorted-substitution-table symbols)]
(->> message
(ss/decrypt-by-table (set/map-invert table))
(encrypt-array key module)
(ss/decrypt-by-table table)
(cs/join))))
(defn decrypt-array
"Decrypt an array using the gamma cipher. The function is case-insensitive. The key is an array of three elements [a b c]. The array contains integer in range [0, module)."
[key module array]
(let [size (count array)
gamma (->> (apply conj [key module size])
(apply generate-gamma))]
(->> gamma
(map -)
(map vector array)
(map (fn [[a g]] (add-mod a g module))))))
(defn decrypt-message
"Decrypt a message using the gamma cipher. The function is case-insensitive. The key is an array of three elements [a b c]. The array contains integer in range [0, module)."
[key symbols message]
(let [module (count symbols)
table (ss/generate-sorted-substitution-table symbols)]
(->> message
(ss/decrypt-by-table (set/map-invert table))
(decrypt-array key module)
(ss/decrypt-by-table table)
(cs/join))))
@@ -0,0 +1,74 @@
(ns cipher-analytical-machine.ciphers.simple-substitution
(:require [clojure.string :as cs]
[cipher-analytical-machine.ciphers.caesar :as caesar])
(:gen-class))
(defn shuffled-numbers
"Generate the shuffled order for integer list."
[size]
(-> size
(take (range))
(shuffle)))
(defn generate-substitution-table
"Generate the map (char, int) for the substittion."
[symbols]
(->> (count symbols)
(shuffled-numbers)
(zipmap symbols)))
(defn generate-sorted-substitution-table
"Generate the map (char, int) for the substittion. BUT a value is the index of a symbol (from 0)."
[symbols]
(-> (count symbols)
(take (range))
(zipmap symbols)))
(defn find-value-in-table
"It uses the substitution table to find the value of a char or a number."
[char substitution-table]
(get substitution-table char))
(defn decrypt-by-table
"Decrypt a message by the substitution-table"
[substitution-table message]
(map (fn [char] (find-value-in-table char substitution-table)) message))
(defn encrypt-message
"Encrypt a message using the simple substitution cipher. The function is case-insensitive. If a symbol isn't in the symbols list, then it will be removed."
[message substitution-table]
(->> message
(decrypt-by-table substitution-table)
(remove nil?)
(cs/join \,)))
(defn encrypt-message-with-caesar
"Encrypt a message using the simple substitution cipher and the Caesar cipher. The function is case-insensitive. If a symbol isn't in the symbols list, then it will be removed."
[message key substitution-table symbols]
(-> message
(caesar/encrypt-message key symbols)
(encrypt-message substitution-table)))
(defn decrypt-message-by-symbol-table
"Decrypt a message using the simple substitution cipher. The function is case-insensitive. The substitution-table must be (symbols, symbols)."
[substitution-table message]
(->> message
(decrypt-by-table substitution-table)
(remove nil?)
(cs/join)))
(defn decrypt-message
"Decrypt a message using the simple substitution cipher. The function is case-insensitive. The substitution-table must be (int, symbols)."
[message substitution-table]
(let [message (cs/split message #",")]
(->> message
(map #(Integer/parseInt %))
(decrypt-message-by-symbol-table substitution-table))))
(defn decrypt-message-with-caesar
"Decrypt a message using the simple substitution cipher and the Caesar cipher. The function is case-insensitive."
[message key substitution-table symbols]
(-> message
(decrypt-message substitution-table)
(caesar/decrypt-message key symbols)))
-98
View File
@@ -1,98 +0,0 @@
(ns cipher-analytical-machine.cli
(:require
[cipher-analytical-machine.file :as file]
[cipher-analytical-machine.caesar :as caesar]
[clojure.string :as cs]
[clojure.tools.cli :refer [parse-opts]])
(:gen-class))
(def cipher-options
#{"Caesar"})
(def cli-options
[["-m" "--message MESSAGE" "The message will be encrypted or decrypted."]
["-M" "--message-file MESSAGE-FILE" "The file contains the message that will be encrypted or decrypted."]
["-k" "--key KEY" "The key will be used to encrypt or decrypt."]
["-c" "--cipher CIPHER" "The cipher will be used to encrypt or decrypt a message."
:default "Caesar"]
["-e" "--encrypt" "Encrypt the message."]
["-d" "--decrypt" "Decrypt the message."]
["-h" "--help"]])
(defn usage [options-summary]
(->> ["This is cipher-analytical-machine. It can help you to learn how ciphers works."
""
"Usage: cipher-analytical-machine [options]"
""
"Options:"
options-summary
""]
(cs/join \newline)))
(defn error-msg [errors]
(str "The following errors occurred while parsing your command:\n\n"
(cs/join \newline errors)))
(defn map-has-keys?
"Return true if all keys in the map."
[map keys]
(every? #(contains? map %) keys))
(defn validate-args
"Validate command line arguments. Either return a map indicating the program
should exit (with an error message, and optional ok status), or a map
indicating the action the program should take and the options provided."
[args]
(let [{:keys [options arguments errors summary]} (parse-opts args cli-options)]
(cond
(:help options)
{:exit-message (usage summary) :ok? true}
errors
{:exit-message (error-msg errors)}
(map-has-keys? options [:encrypt, :decrypt])
{:exit-message (error-msg ["You can't use enctypt and decrypt mode at the same time!!!"])}
(map-has-keys? options [:message, :message-file])
{:exit-message (error-msg ["You can't use message and message-file options at the same time!!!"])}
(and (map-has-keys? options [:cipher, :key])
(or (contains? options :message)
(contains? options :message-file))
(or (contains? options :encrypt)
(contains? options :decrypt)))
{:options options :arguments arguments}
:else
{:exit-message (usage summary)})))
(defn exit
[exit-message status]
(println exit-message)
(System/exit (if status 0 1)))
(defn get-message
"Return the message"
[options arguments]
(cond
(contains? options :message)
(:message options)
(contains? options :message-file)
(file/read-file (:message-file options))))
(defn actions
[options arguments]
(println (str options arguments))
(let [message (get-message options arguments)
key (Integer/parseInt (:key options))
symbols "abc"]
(println
(cond
(contains? options :encrypt)
(caesar/encrypt-message message key symbols)
(contains? options :decrypt)
(caesar/decrypt-message message key symbols)))))
@@ -0,0 +1,27 @@
(ns cipher-analytical-machine.cli.actions.cracking
(:require
[cipher-analytical-machine.analyzers.caesar :as caesar-analyzers]
[cipher-analytical-machine.symbols.frequencies :as symbol-frequencies])
(:gen-class))
(defn cracking-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")
(caesar-analyzers/get-plaintext message symbols frequencies)
:else
(caesar-analyzers/get-plaintext message symbols frequencies))))
(defn cracking-actions
[options arguments action-type]
(let [cipher (:cipher options)]
(cond
(= cipher "Caesar")
(cracking-caesar options arguments))))
@@ -0,0 +1,69 @@
(ns cipher-analytical-machine.cli.actions.cryptography
(:require
[clojure.string :as cs]
[cipher-analytical-machine.ciphers.caesar :as caesar]
[cipher-analytical-machine.ciphers.simple-substitution :as ss]
[cipher-analytical-machine.ciphers.gamma :as gamma]
[cipher-analytical-machine.parsers.parsers :as ps]
[cipher-analytical-machine.parsers.simple-substitution :as pss])
(:gen-class))
(defn caesar-actions
[options arguments action-type]
(let [message (:message options)
key (Integer/parseInt (:key options))
symbols (:symbols options)]
(cond
(= action-type :encrypt)
(caesar/encrypt-message message key symbols)
(= action-type :decrypt)
(caesar/decrypt-message message key symbols))))
(defn simple-substitution-with-caesar-actions
[options arguments action-type]
(let [message (:message options)
key (:key options)
symbols (:symbols options)]
(cond
(= action-type :encrypt)
(let [data (pss/generate-table-or-decode-json key symbols)
key (ps/parse-unsigned-int (get data "key"))
substitution-table (get data "table")]
(println (pss/encode-key-and-substitution-table-to-json key substitution-table))
(ss/encrypt-message-with-caesar message key substitution-table symbols))
(= action-type :decrypt)
(let [data (-> (pss/decode-key-and-substitution-table-from-json key)
(pss/invert-table-in-map))
key (get data "key")
substitution-table (get data "table")]
(ss/decrypt-message-with-caesar message key substitution-table symbols)))))
(defn gamma-actions
[options arguments action-type]
(let [message (:message options)
key (->> (cs/split (:key options) #",")
(map #(Integer/parseInt %))
(into []))
symbols (:symbols options)]
(cond
(= action-type :encrypt)
(gamma/encrypt-message key symbols message)
(= action-type :decrypt)
(gamma/decrypt-message key symbols message))))
(defn cryptography-actions
[options arguments action-type]
(let [cipher (:cipher options)]
(cond
(= cipher "Caesar")
(caesar-actions options arguments action-type)
(= cipher "Simple substitution and Caesar")
(simple-substitution-with-caesar-actions options arguments action-type)
(= cipher "Gamma")
(gamma-actions options arguments action-type))))
+180
View File
@@ -0,0 +1,180 @@
(ns cipher-analytical-machine.cli.cli
(:require
[cipher-analytical-machine.parsers.parsers :as ps]
[cipher-analytical-machine.parsers.gamma :as gamma-ps]
[cipher-analytical-machine.cli.file :as file]
[cipher-analytical-machine.symbols.factories :as sf]
[cipher-analytical-machine.cli.options :as options]
[clojure.string :as cs]
[cipher-analytical-machine.cli.actions.cryptography :as cryptography]
[cipher-analytical-machine.cli.actions.cracking :as cracking]
[clojure.tools.cli :refer [parse-opts]])
(:gen-class))
(defn usage [options-summary]
(->> ["This is cipher-analytical-machine. It can help you to learn how ciphers works."
""
"Usage: cipher-analytical-machine [options]"
""
"Options:"
options-summary
""
"Available values"
""
(options/get-available-cipher-options-as-string)
""
(options/get-available-analyzers-options-as-string)
""]
(cs/join \newline)))
(defn error-msg [errors]
(str "The following errors occurred while parsing your command:\n\n"
(cs/join \newline errors)))
(defn map-has-keys?
"Return true if all keys in the map."
[map keys]
(every? #(contains? map %) keys))
(defn validate-args
"Validate command line arguments. Either return a map indicating the program
should exit (with an error message, and optional ok status), or a map
indicating the action the program should take and the options provided."
[args]
(let [{:keys [options arguments errors summary]} (parse-opts args options/cli-options)]
(cond
(:help options)
{:exit-message (usage summary) :ok? true}
errors
{:exit-message (error-msg errors)}
(map-has-keys? options [:encrypt, :decrypt])
{:exit-message (error-msg ["You can't use enctypt and decrypt mode at the same time!!!"])}
(map-has-keys? options [:message, :message-file])
{:exit-message (error-msg ["You can't use message and message-file options at the same time!!!"])}
(and (contains? options :message-file)
(file/is-file-not-exists? (:message-file options)))
{:exit-message (error-msg ["Please, check the path to the message file!!!"])}
(and (contains? options :output-file)
(file/is-file-exists? (:output-file options)))
{:exit-message (error-msg ["Please, choose another file!!! Overwriting was prevented!!!"])}
(false? (contains? options/cipher-options (:cipher options)))
{:exit-message (error-msg ["Please, choose an available cipher!!!\n"
(options/get-available-cipher-options-as-string)])}
(and (map-has-keys? options [:cipher, :cracking, :analyzer])
(false? (contains?
(get options/analyzers-options (:cipher options)) (:analyzer options))))
{:exit-message (error-msg ["Please, choose an available analyzer!!!\n"
(options/get-available-analyzers-options-as-string)])}
(and (map-has-keys? options [:cipher, :key])
(or (contains? options :message)
(contains? options :message-file))
(or (contains? options :encrypt)
(contains? options :decrypt)))
(cond
(and (= (:cipher options) "Caesar")
(false? (ps/int-string? (:key options))))
{:exit-message (error-msg ["Please, use the key format: [+-](integer)!!! Example: 10, +9, -7."])}
(and (= (:cipher options) "Gamma")
(false? (gamma-ps/key? (:key options))))
{:exit-message (error-msg ["Please, use the key format: [+-](integer),[+-](integer),[+-](integer) !!! Example: 10,+9,-7."])}
(contains? options :encrypt)
{:options options :arguments arguments :action-type :encrypt}
(contains? options :decrypt)
{:options options :arguments arguments :action-type :decrypt})
(and (map-has-keys? options [:cipher, :cracking])
(or (contains? options :message)
(contains? options :message-file)))
{:options options :arguments arguments :action-type :cracking}
:else
{:exit-message (usage summary)})))
(defn exit
[exit-message status]
(println exit-message)
(System/exit (if status 0 1)))
(defn get-or-load-option
"Return the option value or load the value from a file."
[options arguments option]
(let [file-option (keyword (str (name option) "-file"))]
(cond
(contains? options option)
(option options)
(contains? options file-option)
(file/read-file (file-option options)))))
(defn set-option
"Set a option in the option map."
[options option value]
(-> options
(assoc option value)))
(defn set-symbols
"Set defaults symbols for a language."
[options]
(if (contains? options :language)
(set-option options :symbols
(sf/default-symbol-factory (:language options)))
options))
(defn load-and-set-option
"Load the option and set it."
[options option]
(->> (get-or-load-option options nil option)
(set-option options option)))
(defn load-all-options
"Load all options."
[options]
(-> options
(set-symbols)
(load-and-set-option :message)))
(defn save-output
"Save the output to a file"
[output options]
(let [file-path (:output-file options)]
(file/write-file file-path output)))
(defn show-and-save-output
"Print and save the output to a file if needed"
[output options]
(when (contains? options :output-file)
(save-output output options))
(println output))
(defn actions
[options arguments action-type]
(let [options (load-all-options options)]
(->
(cond
(contains? #{:encrypt :decrypt} action-type)
(cryptography/cryptography-actions options arguments action-type)
(= action-type :cracking)
(cracking/cracking-actions options arguments action-type))
(show-and-save-output options))))
(defn cli-main
[args]
(let [{:keys [options arguments action-type exit-message ok?]} (validate-args args)]
(if exit-message
(exit exit-message ok?)
(actions options arguments action-type))))
@@ -1,4 +1,4 @@
(ns cipher-analytical-machine.file
(ns cipher-analytical-machine.cli.file
(:require [clojure.java.io :as io])
(:gen-class))
@@ -16,3 +16,6 @@
(defn read-file [file-path]
(slurp file-path))
(defn write-file [file-path content]
(spit file-path content))
@@ -0,0 +1,64 @@
(ns cipher-analytical-machine.cli.options
(:require
[cipher-analytical-machine.symbols.factories :as sf]
[clojure.string :as cs])
(:gen-class))
(defn option-values-as-row
"Return the formatted string of values for an option."
[option values]
(str option ": " (cs/join ", " values)))
(defn option-values-as-list
"Return the formatted string of values for an option as a multiline list."
[option values]
(str option ": \n - " (cs/join "\n - " values)))
(defn map-of-option-value-as-list
"Return the formatted string of values for an option as a multiline list.
The values are a map of pairs (suboption and its options)."
[option values]
(let [values (map #(apply option-values-as-row %) values)]
(option-values-as-list option values)))
(def cipher-options
#{"Caesar" "Simple substitution and Caesar" "Gamma"})
(def default-cipher "Caesar")
(defn get-available-cipher-options-as-string
"Return the formatted string of analyzers options."
[]
(option-values-as-row "Ciphers" cipher-options))
(def analyzers-options
{"Caesar" #{"Chi^2"}})
(defn get-available-analyzers-options-as-string
"Return the formatted string of analyzers options."
[]
(map-of-option-value-as-list "Analyzers" analyzers-options))
(def language-options
#{"en", "uk"})
(def default-symbols
(sf/default-symbol-factory "en"))
(def cli-options
[["-m" "--message MESSAGE" "The message will be encrypted or decrypted."]
["-M" "--message-file MESSAGE-FILE" "The file contains the message that will be encrypted or decrypted."]
["-k" "--key KEY" "The key will be used to encrypt or decrypt."]
["-c" "--cipher CIPHER" "The cipher will be used to encrypt or decrypt a message."
:default default-cipher]
["-e" "--encrypt" "Encrypt the message."]
["-d" "--decrypt" "Decrypt the message."]
["-s" "--symbols SYMBOLS" "The string will be used as a set of symbols for a cipher."
:default default-symbols]
["-l" "--language CODE" "The string will be used to set a default symbols for a cipher."
:validate [#(contains? language-options %) "Must be a code from the list: en, uk!!!"]]
["-C" "--cracking" "Cracking the encrypted message."]
["-a" "--analyzer ANALYZER" "The way of cracking."]
["-O" "--output-file OUTPUT-FILE" "Save the program output to a file."]
["-h" "--help"]])
+2 -5
View File
@@ -1,12 +1,9 @@
(ns cipher-analytical-machine.core
(:require
[cipher-analytical-machine.cli :as cli])
[cipher-analytical-machine.cli.cli :as cli])
(:gen-class))
(defn -main
[& args]
(let [{:keys [options arguments exit-message ok?]} (cli/validate-args args)]
(if exit-message
(cli/exit exit-message ok?)
(cli/actions options arguments))))
(cli/cli-main args))
@@ -0,0 +1,9 @@
(ns cipher-analytical-machine.parsers.gamma
(:gen-class))
(defn key?
"Return true if the string is an key of three integers."
[str]
(if (re-matches #"[+-]?\b\d+\b,[+-]?\b\d+\b,[+-]?\b\d+\b" str)
true false))
@@ -0,0 +1,29 @@
(ns cipher-analytical-machine.parsers.parsers
(:require [cheshire.core :as cc])
(:gen-class))
(defn unsigned-int-string?
"Return true if the string is an unsigned integer."
[str]
(if (re-matches #"\d+" str)
true false))
(defn int-string?
"Return true if the string is an signed integer."
[str]
(if (re-matches #"[+-]?\b\d+\b" str)
true false))
(defn parse-unsigned-int
"Return an integer if the argument is an integer."
[str-or-int]
(cond
(int? str-or-int)
str-or-int
(unsigned-int-string? str-or-int)
(Integer/parseInt str-or-int)
:else
nil))
@@ -0,0 +1,54 @@
(ns cipher-analytical-machine.parsers.simple-substitution
(:require
[cipher-analytical-machine.ciphers.simple-substitution :as ss]
[cipher-analytical-machine.parsers.parsers :as ps]
[clojure.set :as set]
[cheshire.core :as cc])
(:gen-class))
(defn encode-key-and-substitution-table-to-json
[key substitution-table]
(-> {"key" key}
(assoc "table" substitution-table)
(cc/generate-string)))
(defn decode-key
"Returns the first character if the string is a char. Return the number if the string is a number."
[str]
(if (ps/unsigned-int-string? str)
(Integer/parseInt str)
(first str)))
(defn decode-pair
"Decode a numbers as a string and a char as a string"
[acc [key value]]
(if (ps/unsigned-int-string? key)
(assoc acc (decode-key key) (decode-key value))
(assoc acc (decode-key key) value)))
(defn decode-substitution-table
[substitution-table-map-from-json]
(reduce decode-pair {} substitution-table-map-from-json))
(defn decode-key-and-substitution-table-from-json
[json]
(let [data (cc/parse-string json)]
(assoc data "table" (decode-substitution-table (get data "table")))))
(defn generate-table-or-decode-json
"It generate the table and return map with the key and the table if the argument is a key. Else it decode the json."
[key-or-json symbols]
(if (ps/unsigned-int-string? key-or-json)
(-> {"key" key-or-json}
(assoc "table" (ss/generate-substitution-table symbols)))
(decode-key-and-substitution-table-from-json key-or-json)))
(defn invert-table-in-map
"Invert the table in a decoded json (key, table)"
[decoded-json]
(->>
(-> decoded-json
(get "table")
(set/map-invert))
(assoc decoded-json "table")))
@@ -1,34 +0,0 @@
(ns cipher-analytical-machine.symbol_factories
(:require [clojure.string :as cs])
(:gen-class))
(defn lower-english-alphabet-factory
"Return the English alphabet with only lowercase letters"
[]
(reduce
(fn [acc val] (str acc (char val)))
""
(range (int \a) (inc (int \z)))))
(defn english-alphabet-factory
"Return the English alphabet with lower and upper case letters"
[]
(let [letters (lower-english-alphabet-factory)]
(str letters (cs/upper-case letters))))
(defn lower-ukrainian-alphabet-factory
"Return the Ukrainian alphabet with only lowercase letters"
[]
"абвгґдеєжзиіїйклмнопрстуфхцчшщьюя")
(defn ukrainian-alphabet-factory
"Return the Ukrainian alphabet with lower and upper case letters"
[]
(let [letters (lower-ukrainian-alphabet-factory)]
(str letters (cs/upper-case letters))))
(defn digit-set-factory
"Return digits"
[]
"0123456789")
@@ -0,0 +1,47 @@
(ns cipher-analytical-machine.symbols.factories
(:require [clojure.string :as cs])
(:gen-class))
(defn english-alphabet-factory
"Return the English alphabet with only lowercase letters"
[]
(reduce
(fn [acc val] (str acc (char val)))
""
(range (int \a) (inc (int \z)))))
(defn ukrainian-alphabet-factory
"Return the Ukrainian alphabet with only lowercase letters"
[]
"абвгґдеєжзиіїйклмнопрстуфхцчшщьюя")
(defn digit-set-factory
"Return digits"
[]
"0123456789")
(defn punctuation-symbol-factory
"Return punctuation symbols"
[]
".,:;-!?")
(defn space-symbol-factory
"Return punctuation symbols"
[]
" \t\n")
(defn default-symbol-factory
"Return a default string of symbols for a language"
[language-code]
(cond
(= language-code "en")
(str (english-alphabet-factory)
\ )
(= language-code "uk")
(str (ukrainian-alphabet-factory)
\ )
:else
(default-symbol-factory "en")))
@@ -0,0 +1,92 @@
(ns cipher-analytical-machine.symbols.frequencies
(:gen-class))
(defn map-to-string
"Convert the map of frequencies to the frequency string. Letters are sorted by frequency in descending order."
[frequency-map]
(->> frequency-map
(reduce (fn [acc el] (conj acc el)) [])
(sort-by last)
(map first)
(reverse)
(apply str)))
(def english-letter-frequencies {
\a 0.0804
\b 0.0154
\c 0.0306
\d 0.0399
\e 0.1251
\f 0.0230
\g 0.0196
\h 0.0549
\i 0.0726
\j 0.0016
\k 0.0067
\l 0.0414
\m 0.0253
\n 0.0709
\o 0.0760
\p 0.0200
\q 0.0011
\r 0.0612
\s 0.0654
\t 0.0925
\u 0.0271
\v 0.0099
\w 0.0192
\x 0.0019
\y 0.0173
\z 0.0009
})
(def ukrainian-letter-frequencies {
\а 0.064
\б 0.013
0.046
\г 0.013
0.0001
0.027
\е 0.042
0.005
0.007
0.020
0.055
\і 0.044
0.010
0.009
0.033
0.027
0.029
0.068
\о 0.086
\п 0.025
\р 0.043
\с 0.037
0.045
\у 0.027
0.003
\х 0.011
0.010
0.011
0.005
0.004
0.016
0.008
0.019
\ 0.138
})
(defn default-frequency-factory
"Returns a default map of letter frequencies for a language"
[language-code]
(cond
(= language-code "en")
english-letter-frequencies
(= language-code "uk")
ukrainian-letter-frequencies
:else
english-letter-frequencies))
@@ -0,0 +1,53 @@
package cipher_analytical_machine.analyzers.caesar;
import cipher_analytical_machine.analyzers.caesar.IsNonsense;
import cipher_analytical_machine.ciphers.caesar.Decrypted;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
public class FrequencyAnalyzer {
private String ciphertext;
private String symbols;
private String symbol_frequences;
private Decrypted decryptor;
private IsNonsense isNonsense;
public FrequencyAnalyzer(String ciphertext, String symbols, String symbol_frequences, Decrypted decryptor, IsNonsense isNonsense) {
this.ciphertext = ciphertext;
this.symbol_frequences = symbol_frequences;
this.symbols = symbols;
this.decryptor = decryptor;
this.isNonsense = isNonsense;
}
public String crack() {
// Знаходимо кількість літер
Map<Character, Integer> encryptedLetterCounts = new HashMap<>();
for (char c : ciphertext.toLowerCase().toCharArray()) {
encryptedLetterCounts.put(c, encryptedLetterCounts.getOrDefault(c, 0) + 1);
}
// Знаходимо букву, яка зустрічається найчастіше
char mostFrequentEncryptedLetter = ' ';
int mostFrequentEncryptedLetterCount = 0;
for (Entry<Character, Integer> entry : encryptedLetterCounts.entrySet()) {
if (entry.getValue() > mostFrequentEncryptedLetterCount) {
mostFrequentEncryptedLetter = entry.getKey();
mostFrequentEncryptedLetterCount = entry.getValue();
}
}
// Обчислимо зміщення
int size = symbols.length();
int indexOfMostFrequentEncryptedLetter = symbols.indexOf(mostFrequentEncryptedLetter);
int indexOfMostFrequentLetter = symbols.indexOf(symbol_frequences.charAt(0));
int shift = (indexOfMostFrequentEncryptedLetter - indexOfMostFrequentLetter) % size;
return decryptor.decrypt(ciphertext, shift, symbols);
}
}
@@ -0,0 +1,6 @@
package cipher_analytical_machine.analyzers.caesar;
public interface IsNonsense {
boolean isNonsense(String message);
}
@@ -0,0 +1,6 @@
package cipher_analytical_machine.ciphers.caesar;
public interface Decrypted {
String decrypt(String message, int key, String symbols);
}
@@ -0,0 +1,47 @@
(ns cipher-analytical-machine.analyzers.analyzers-test
(:require
[clojure.test :refer :all]
[cipher-analytical-machine.analyzers.analyzers :refer :all]))
(deftest count-characters-test
(testing "Count two dublicates and one uniq character from a string."
(is (= {\a 2 \b 1}
(count-characters "aba")))))
(deftest reverse-count-characters-test
(testing "The symbols must be grouped as a vector and the count must be a key."
(are [count-map expected-map]
(= expected-map (reverse-count-characters count-map))
{\a 1 \b 2 \c 1} {1 [\a \c] 2 [\b]}
{\a 1 \b 2 \c 3} {1 [\a] 2 [\b] 3 [\c]})))
(deftest chi-squared-letter-statistic-test
(testing "If the frequence of A is 0.1, the text length is 100 and contains 20 times, then the chi-squared is 10."
(is (= 10.0
(chi-squared-letter-statistic 20 0.1 100))))
(testing "If the frequence of A is 0.1, the text length is 10 and contains 5 times, then the chi-squared is 16.0."
(is (= 16.0
(chi-squared-letter-statistic 5 0.1 10)))))
(deftest chi-squared-statistic-test
(let [text "aaaaabbbbb"]
(testing "If the frequencies of a and b is 0.1, the text length is 10 and contains them 5 times, then score is 32."
(is (= 32.0
(chi-squared-statistic text {\a 0.1 \b 0.1}))))))
(deftest sort-map-by-count-test
(testing "Test the sort in descending order."
(is (= [[\b 3] [\a 2] [\c 1]]
(sort-map-by-count {\a 2 \b 3 \c 1} )))))
(deftest table-to-string-test
(testing "Test the sort in descending order."
(is (= "bac"
(table-to-string [[\b 3] [\a 2] [\c 1]])))))
(deftest symbol-frequency-table-test
(testing "Test the sort in descending order."
(is (= {\d \b, \e \a, \f \c}
(symbol-frequency-table {\d 3 \e 2 \f 1} {\b 3 \a 2 \c 1})))))
@@ -0,0 +1,76 @@
(ns cipher-analytical-machine.analyzers.caesar-test
(:require
[clojure.test :refer :all]
[cipher-analytical-machine.analyzers.caesar :refer :all]
[cipher-analytical-machine.symbols.frequencies :as sf]
[cipher-analytical-machine.analyzers.analyzers :as ca]
[clojure.string :as cs]))
(deftest get-all-texts-test
(testing "There're three text when the text is 'abc' and the set of symbol is 'abc'."
(is (= 3 (count (get-all-texts "abc" "abc")))))
(testing "A pair must have an integer and a string."
(let [pairs (get-all-texts "abc" "abc")
pair (first pairs)]
(is (and (int? (first pair))
(string? (last pair))))))
(testing "There're 27 combinations for a 'Hello World'."
(let [ciphertext "khoorczruog"
symbols "abcdefghijklmnopqrstuvwxyz "]
(is (= 27 (count (get-all-texts ciphertext symbols)))))))
(deftest get-all-scores-test
(testing "There're 27 combinations for a 'Hello World'."
(let [ciphertext "khoorczruog"
symbols "abcdefghijklmnopqrstuvwxyz "
frequencies sf/english-letter-frequencies
text-pairs (get-all-texts ciphertext symbols)]
(is (= 27 (count (get-all-scores frequencies text-pairs)))))))
(deftest get-min-score-pair-test
(testing "If a key is one, then the min score pair is 15."
(let [scores (list [0 20.0] [1 15.0] [2 30.0])
min-score-pair (get-min-score-pair scores)]
(is (= [1 15.0] min-score-pair)))))
(deftest get-key-test
(let [plaintext "hello world"
ciphertext "khoorczruog"
key 3
symbols "abcdefghijklmnopqrstuvwxyz "
frequencies sf/english-letter-frequencies]
(testing "The plaintext is encrypted with 3 as the key."
(is (= key (get-key ciphertext symbols frequencies)))))
(let [; З поеми "Кавказ" Тараса Григоровича Шевченка:
plaintext "Борітеся – поборете, Вам Бог помагає! За вас правда, за вас слава. І воля святая!"
ciphertext "жхчощйшде–ецхжхчйщй,езєуежхиецхуєиєк!емєезєшецчєзїє,емєезєшештєзє.еоезхтдешздщєд!"
key 7
symbols "абвгґдеєжзиіїйклмнопрстуфхцчшщьюя "
frequencies sf/ukrainian-letter-frequencies]
(testing "The plaintext is encrypted with 3 as the key."
(is (= key (get-key ciphertext symbols frequencies))))))
(deftest get-plaintext-test
(let [plaintext "hello world"
ciphertext "khoorczruog"
symbols "abcdefghijklmnopqrstuvwxyz "
frequencies sf/english-letter-frequencies]
(testing "The plaintext is encrypted with 3 as the key."
(is (= plaintext (get-plaintext ciphertext symbols frequencies))))
(testing "The ciphertext is case-insensitive."
(is (= plaintext (get-plaintext "KhoorcZruog" symbols frequencies)))))
(let [; З поеми "Кавказ" Тараса Григоровича Шевченка:
plaintext "Борітеся – поборете, Вам Бог помагає! За вас правда, за вас слава. І воля святая!"
ciphertext "жхчощйшде–ецхжхчйщй,езєуежхиецхуєиєк!емєезєшецчєзїє,емєезєшештєзє.еоезхтдешздщєд!"
key 7
symbols "абвгґдеєжзиіїйклмнопрстуфхцчшщьюя "
frequencies sf/ukrainian-letter-frequencies]
(testing "The ciphertext is case-insensitive."
(is (= (cs/lower-case plaintext)
(get-plaintext ciphertext symbols frequencies))))))
@@ -0,0 +1,45 @@
(ns cipher-analytical-machine.analyzers.language-test
(:require
[clojure.test :refer :all]
[cipher-analytical-machine.analyzers.language :refer :all]
))
(deftest detect-language-test
(testing "Checking the English text"
(is (= "en" (detect-language "This is a sentence that uses English."))))
(testing "Checking the Ukrainian text"
(is (= "uk" (detect-language "Текст, що написаний українською."))))
(testing "Checking a gibberish that uses English letters"
(is (= "lt" (detect-language "dfgjldfjgdfl gjdfg idfjig hdgesr khs e."))))
(testing "Checking a gibberish that uses Ukrainian letters"
(is (= "uk" (detect-language "іаврпшшцді врадів аргів аріл варї йцґ.")))))
(deftest is-language?-test
(testing "Checking the English text"
(is (is-language? "This is a sentence that uses English." "en")))
(testing "Checking the Ukrainian text"
(is (is-language? "Текст, що написаний українською." "uk")))
(testing "Checking a gibberish that uses English letters"
(is (is-language? "dfgjldfjgdfl gjdfg idfjig hdgesr khs e." "lt")))
(testing "Checking a gibberish that uses Ukrainian letters"
(is (is-language? "іаврпшшцді врадів аргів аріл варї йцґ." "uk"))))
(deftest is-nonsense?-test
(testing "Checking the English text"
(is (not (is-nonsense? "This is a sentence that uses English." "en"))))
(testing "Checking the Ukrainian text"
(is (not (is-nonsense? "Текст, що написаний українською." "uk"))))
(testing "Checking a gibberish that uses English letters"
(is (is-nonsense? "dfgjldfjgdfl gjdfg idfjig hdgesr khs e." "en")))
(testing "Checking a gibberish that uses Ukrainian letters"
(is (is-nonsense? "іаврпшшцді івафі лоінїмч йцувіа івапґ." "uk"))))
@@ -0,0 +1,50 @@
(ns cipher-analytical-machine.analyzers.simple-substitution-test
(:require
[clojure.test :refer :all]
[cipher-analytical-machine.symbols.frequencies :as sf]
[cipher-analytical-machine.ciphers.simple-substitution :as ss]
[cipher-analytical-machine.analyzers.simple-substitution :refer :all])
(:gen-class))
(deftest get-possible-keys-vector-test
(testing "The vector must be ordered by symbols"
(are [possible-keys-map symbols expected-key-vector]
(= expected-key-vector (get-possible-key-vector possible-keys-map symbols))
{\a [\a \b] \b [\b \a] \c [\a \c]} "abc" [[\a \b] [\b \a] [\a \c]]
{\a [\a \b] \c [\b \a] \b [\a \c]} "abc" [[\a \b] [\a \c] [\b \a]])))
(deftest get-possible-key-vector-from-reversed-count-map-test
(testing "The block order must be in descending order"
(are [reversed-count-map expected-key-vector]
(= expected-key-vector (get-possible-key-vector-from-reversed-count-map reversed-count-map))
{1 [\a \c] 2 [\b]} [[\b] [\a \c]]
{2 [\a] 1 [\b] 3 [\c]} [[\c] [\a] [\b]])))
(deftest get-all-permutation-for-block-test
(testing "It must return all permutations"
(are [symbols expected-permutations]
(= expected-permutations (get-all-permutation-for-block symbols))
[\a \b] ["ab" "ba"]
[\a \b \c] ["abc" "acb" "bac" "bca" "cab" "cba"])))
(deftest get-all-combinations-for-blocks-test
(testing "The keys must be the all combinations of blocks"
(are [possible-keys-vector expected-keys]
(= expected-keys (get-all-combinations-for-blocks possible-keys-vector))
[[\a \b] [\f] [\a \c] [\g]] '("afag" "afcg" "bfag" "bfcg")
[[\a \b] [\a \c]] '("aa" "ac" "ba" "bc")
[[\a \b \c] [\a \c] [\b \c]] '("aab" "aac" "acb" "acc" "bab" "bac" "bcb" "bcc" "cab" "cac" "ccb" "ccc"))))
(deftest get-possible-key-combinations-test
(testing "The keys must be the all combinations, but the blocks must create a permutations which will be joined as a combination"
(are [possible-keys-vector expected-keys]
(= expected-keys (get-possible-key-combinations possible-keys-vector))
[[\a \b] [\f] [\e \c] [\g]] '("abfecg" "abfceg" "bafecg" "bafceg")
[[\a \b] [\a \c]] '("abac" "abca" "baac" "baca")
[[\a \b \c] [\a \c] [\b \c]] '("abcacbc" "abcaccb" "abccabc" "abccacb"
"acbacbc" "acbaccb" "acbcabc" "acbcacb"
"bacacbc" "bacaccb" "baccabc" "baccacb"
"bcaacbc" "bcaaccb" "bcacabc" "bcacacb"
"cabacbc" "cabaccb" "cabcabc" "cabcacb"
"cbaacbc" "cbaaccb" "cbacabc" "cbacacb"))))
@@ -1,7 +1,7 @@
(ns cipher-analytical-machine.caesar-test
(ns cipher-analytical-machine.ciphers.caesar-test
(:require
[clojure.test :refer :all]
[cipher-analytical-machine.caesar :refer :all]
[cipher-analytical-machine.ciphers.caesar :refer :all]
))
(deftest calculate-char-index-test
@@ -51,14 +51,20 @@
(testing "The message 'abc' is encrypted to 'bca'"
(is (= "bca" (encrypt-message "abc" 1 symbols))))
(testing "The message 'ABC' is encrypted to 'bca', because of case-insensitive."
(is (= "bca" (encrypt-message "ABC" 1 symbols))))
(testing "The message 'bca' is decrypted to 'abc'"
(is (= "abc" (encrypt-message "bca" -1 symbols))))))
(deftest decrypt-message-text
(let [symbols "abc"]
(testing "The message 'bca' is decrypted to 'abc'"
(is (= "abc" (decrypt-message "bca" 1 symbols)))
(is (= "abc" (decrypt-message "bca" 1 symbols))))
(testing "The message 'BCA' is decrypted to 'abc', because of case-insensitive."
(is (= "abc" (decrypt-message "BCA" 1 symbols))))
(testing "The message 'abc' is encrypted to 'bca'"
(is (= "bca" (decrypt-message "abc" -1 symbols)))))))
(is (= "bca" (decrypt-message "abc" -1 symbols))))))
@@ -0,0 +1,62 @@
(ns cipher-analytical-machine.ciphers.gamma-test
(:require
[clojure.test :refer :all]
[cipher-analytical-machine.ciphers.gamma :refer :all]))
(deftest add-mod-test
(testing "The remainder must be as expected."
(are [a b module expected]
(= expected (add-mod a b module))
5 2 4 3
1 2 3 0
2 2 3 1)))
(deftest generate-seq-test
(testing "Checking that the next element of a sequence is calculated by (e[i-1] + e[i-3] % mod)."
(are [a b c module size expected]
(= expected (take size (generate-seq a b c module)))
4 32 15 33 10 [4 32 15 19 18 0 19 4 4 23]
1 2 3 3 9 [1 2 3 1 0 0 1 1 1])))
(deftest generate-gamma-seq-test
(testing "Checking that the next element of a sequence is calculated by (s[i] + s[i+1] % mod)."
(are [acc seq module expected]
(= expected (generate-gamma-seq acc seq module))
[] [4 32 15 19 18 0 19 4 4 23] 33 [3 14 1 4 18 19 23 8 27]
[] [1 2 3 1 0 0 1 1 1] 3 [0 2 1 1 0 1 2 2])))
(deftest generate-gamma-test
(testing "Checking that the gamma is generated as expected."
(are [a b c module size expected]
(= expected (generate-gamma a b c module size))
4 32 15 33 10 [3 14 1 4 18 19 23 8 27 17]
1 2 3 3 9 [0 2 1 1 0 1 2 2 0])))
(deftest encrypt-array-test
(testing "Checking that the message is encrypted as expected: (msg+gamma)%module."
(are [key module array expected]
(= expected (encrypt-array key module array))
[4 32 15] 33 [3 14 1 4 18 19 23 8 27 17] [6 28 2 8 3 5 13 16 21 1]
[1 2 3 ] 3 [0 2 1 1 0 1 2 2 0] [0 1 2 2 0 2 1 1 0])))
(deftest encrypt-message-test
(testing "Checking that the message is encrypted as expected"
(are [key symbols message expected]
(= expected (encrypt-message key symbols message))
[4 32 15] "абвгґдеєжзиіїйклмнопрстуфхцчшщьюя" "гкбґопужчн" "ешвжгдймсб"
[1 2 3 ] "абв" "авббабвва" "абввавбба")))
(deftest decrypt-array-test
(testing "Checking that the message is decrypted as expected."
(are [key module array expected]
(= expected (decrypt-array key module array))
[4 32 15] 33 [6 28 2 8 3 5 13 16 21 1] [3 14 1 4 18 19 23 8 27 17]
[1 2 3 ] 3 [0 1 2 2 0 2 1 1 0] [0 2 1 1 0 1 2 2 0])))
(deftest decrypt-message-test
(testing "Checking that the message is decrypted as expected"
(are [key symbols message expected]
(= expected (decrypt-message key symbols message))
[4 32 15] "абвгґдеєжзиіїйклмнопрстуфхцчшщьюя" "ешвжгдймсб" "гкбґопужчн"
[1 2 3 ] "абв" "абввавбба" "авббабвва")))
@@ -0,0 +1,85 @@
(ns cipher-analytical-machine.ciphers.simple-substitution-test
(:require
[clojure.test :refer :all]
[cipher-analytical-machine.ciphers.simple-substitution :refer :all]))
(deftest find-value-in-table-test
(let [table {\a 1 \b 2 \c 3}
rtable {1 \a 2 \b 3 \c}]
(testing "If the symbol is in the table as a key, then the result won't nil."
(are [key expected]
(= expected (find-value-in-table key table))
\a 1
\d nil
1 nil
5 nil))
(testing "If the digit is in the reversed table as a key, then the result won't nil."
(are [key expected]
(= expected (find-value-in-table key rtable))
\a nil
\d nil
1 \a
5 nil))))
(deftest generate-sorted-substitution-table-test
(testing "If the symbol is in the table as a key, then the result won't nil."
(are [symbols expected-table]
(= expected-table (generate-sorted-substitution-table symbols))
"abc" {0 \a 1 \b 2 \c}
"a" {0 \a})))
(deftest encrypt-message-test
(let [symbols "abc"
table {\a 1 \b 2 \c 3}]
(testing "The function must encrypt the message and remove unknown symbols."
(are [message expected]
(= expected (encrypt-message message table))
"abc" "1,2,3"
"aDbdc" "1,2,3"))))
(deftest encrypt-message-with-caesar-test
(let [symbols "abc"
table {\a 1 \b 2 \c 3}]
(testing "The function must encrypt the message and remove unknown symbols."
(are [message key expected]
(= expected (encrypt-message-with-caesar message key table symbols))
"abc" 0 "1,2,3"
"abc" 1 "2,3,1"
"aDbdc" 0 "1,2,3"))))
(deftest decrypt-by-table-test
(let [table {\d \a \e \b \f \c}]
(testing "The function must decrypt the message by the table."
(are [message expected]
(= expected (decrypt-by-table table message))
"def" '(\a \b \c)
"abf" '(nil nil \c)
"fed" '(\c \b \a)))))
(deftest decrypt-message-by-symbol-table-test
(let [table {\d \a \e \b \f \c}]
(testing "The function must decrypt the message and remove unknown numbers."
(are [message expected]
(= expected (decrypt-message-by-symbol-table table message))
"def" "abc"
"daef" "abc"))))
(deftest decrypt-message-test
(let [table {1 \a 2 \b 3 \c}]
(testing "The function must decrypt the message and remove unknown numbers."
(are [message expected]
(= expected (decrypt-message message table))
"1,2,3" "abc"
"1,12,2,3" "abc"))))
(deftest decrypt-message-with-caesar-test
(let [symbols "abc"
table {1 \a 2 \b 3 \c}]
(testing "The function must decrypt the message and remove unknown numbers."
(are [message key expected]
(= expected (decrypt-message-with-caesar message key table symbols))
"1,2,3" 0 "abc"
"2,3,1" 1 "abc"
"1,12,2,3" 0 "abc"))))
@@ -0,0 +1,20 @@
(ns cipher-analytical-machine.parsers.gamma-test
(:require
[clojure.test :refer :all]
[cipher-analytical-machine.parsers.gamma :refer :all]))
(deftest key?-test
(testing "The function return true only if the key in the format '%d,%d,%d'."
(are [str expected]
(= expected
(key? str))
"9" false
"9,10" false
"10,9,8" true
"-10,9,-8" true
"-10,-9,-8" true
"asd 10 " false
" 10 " false
"-10" false
"abc" false)))
@@ -0,0 +1,40 @@
(ns cipher-analytical-machine.parsers.parsers-test
(:require
[clojure.test :refer :all]
[cipher-analytical-machine.parsers.parsers :refer :all]))
(deftest unsigned-int-string?-test
(testing "The function return true only for an unsingned integer as a string."
(are [str expected]
(= expected
(unsigned-int-string? str))
"9" true
"9" true
"10" true
"asd 10 " false
" 10 " false
"-10" false
"abc" false)))
(deftest int-string?-test
(testing "The function return true only for an singned integer as a string."
(are [str expected]
(= expected
(int-string? str))
"9" true
"10" true
"-10" true
"asd -10 " false
" -10 " false
"abc" false)))
(deftest parse-unsigned-int-test
(testing "The function parse the integer if the string is an integer."
(are [str-or-int expected]
(= expected
(parse-unsigned-int str-or-int))
"9" 9
9 9
"10" 10
"-10" nil
"abc" nil)))
@@ -0,0 +1,49 @@
(ns cipher-analytical-machine.parsers.simple-substitution-test
(:require
[clojure.test :refer :all]
[cipher-analytical-machine.parsers.simple-substitution :refer :all]))
(deftest encode-key-and-substitution-table-to-json-test
(testing "The encoder must parse the map and create a json."
(are [key table expected-json]
(= expected-json
(encode-key-and-substitution-table-to-json key table))
1 {0 \a 1 \b 2 \c} "{\"key\":1,\"table\":{\"0\":\"a\",\"1\":\"b\",\"2\":\"c\"}}"
2 {\a 0 \b 1 \c 2} "{\"key\":2,\"table\":{\"a\":0,\"b\":1,\"c\":2}}")))
(deftest decode-key-and-substitution-table-from-json-test
(testing "The decoder must parse the json and create a map."
(are [json expected-data]
(= expected-data
(decode-key-and-substitution-table-from-json json))
"{\"key\":1, \"table\":{\"0\":\"a\",\"1\":\"b\",\"2\":\"c\"}}" {"key" 1 "table" {0 \a 1 \b 2 \c}}
"{\"key\":2, \"table\":{\"a\":0,\"b\":1,\"c\":2}}" {"key" 2 "table" {\a 0 \b 1 \c 2}})))
(deftest generate-table-or-decode-json-test
(let [symbols "abc"]
(testing "The function decodes the json."
(are [json expected-data]
(= expected-data
(generate-table-or-decode-json json symbols))
"{\"key\":1, \"table\":{\"0\":\"a\",\"1\":\"b\",\"2\":\"c\"}}" {"key" 1 "table" {0 \a 1 \b 2 \c}}
"{\"key\":2, \"table\":{\"a\":0,\"b\":1,\"c\":2}}" {"key" 2 "table" {\a 0 \b 1 \c 2}}))
(testing "The function generates the table, because the argument is a key."
(are [json expected-data]
(let [data (generate-table-or-decode-json json symbols)]
(and (= (get expected-data "key")
(get data "key"))
(= (keys (get expected-data "table"))
(keys (get data "table"))))
(generate-table-or-decode-json json symbols))
"1" {"key" 1 "table" {0 \a 1 \b 2 \c}}
"2" {"key" 2 "table" {\a 0 \b 1 \c 2}}))))
(deftest invert-table-in-map-test
(testing "The function invert the table in a decoded json."
(are [decoded-json expected-data]
(= expected-data
(invert-table-in-map decoded-json))
{"key" 1 "table" {0 \a 1 \b 2 \c}} {"key" 1 "table" {\a 0 \b 1 \c 2}}
{"key" 2 "table" {\a 0 \b 1 \c 2}} {"key" 2 "table" {0 \a 1 \b 2 \c}})))
@@ -1,46 +0,0 @@
(ns cipher-analytical-machine.symbol-factories-test
(:require
[clojure.test :refer :all]
[cipher-analytical-machine.symbol_factories :refer :all]
))
(deftest lower-english-alphabet-factory-test
(let [symbols (lower-english-alphabet-factory)]
(testing "It must have same order"
(is (= "abcdefghijklmnopqrstuvwxyz" symbols)))
(testing "It must have 26 letters"
(is (= 26 (count symbols))))))
(deftest english-alphabet-factory-test
(let [symbols (english-alphabet-factory)]
(testing "It must have same order"
(is (= "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" symbols)))
(testing "It must have 2*26 letters"
(is (= (* 2 26) (count symbols))))))
(deftest lower-ukrainian-alphabet-factory-test
(let [symbols (lower-ukrainian-alphabet-factory)]
(testing "It must have same order"
(is (= "абвгґдеєжзиіїйклмнопрстуфхцчшщьюя" symbols)))
(testing "It must have 33 letters"
(is (= 33 (count symbols))))))
(deftest ukrainian-alphabet-factory-test
(let [symbols (ukrainian-alphabet-factory)]
(testing "It must have same order"
(is (= "абвгґдеєжзиіїйклмнопрстуфхцчшщьюяАБВГҐДЕЄЖЗИІЇЙКЛМНОПРСТУФХЦЧШЩЬЮЯ" symbols)))
(testing "It must have 2*33 letters"
(is (= (* 2 33) (count symbols))))))
(deftest digit-set-factory-test
(let [symbols (digit-set-factory)]
(testing "It must have same order"
(is (= "0123456789" symbols)))
(testing "It must have 10 digits"
(is (= 10 (count symbols))))))
@@ -0,0 +1,59 @@
(ns cipher-analytical-machine.symbols.factories-test
(:require
[clojure.test :refer :all]
[cipher-analytical-machine.symbols.factories :refer :all]
))
(deftest english-alphabet-factory-test
(let [symbols (english-alphabet-factory)]
(testing "It must have the same order."
(is (= "abcdefghijklmnopqrstuvwxyz" symbols)))
(testing "It must have 26 letters."
(is (= 26 (count symbols))))))
(deftest ukrainian-alphabet-factory-test
(let [symbols (ukrainian-alphabet-factory)]
(testing "It must have the same order."
(is (= "абвгґдеєжзиіїйклмнопрстуфхцчшщьюя" symbols)))
(testing "It must have 33 letters."
(is (= 33 (count symbols))))))
(deftest digit-set-factory-test
(let [symbols (digit-set-factory)]
(testing "It must have the same order."
(is (= "0123456789" symbols)))
(testing "It must have 10 digits."
(is (= 10 (count symbols))))))
(deftest punctuation-symbol-factory-test
(let [symbols (punctuation-symbol-factory)]
(testing "It must have the same order."
(is (= ".,:;-!?" symbols)))
(testing "It must have 7 symbols."
(is (= 7 (count symbols))))))
(deftest space-symbol-factory-test
(let [symbols (space-symbol-factory)]
(testing "It must have the same order."
(is (= " \t\n" symbols)))
(testing "It must have 3 symbols."
(is (= 3 (count symbols))))))
(deftest default-symbol-factory-test
(testing "If language code is 'en', then it must have 27 symbols."
(let [symbols (default-symbol-factory "en")]
(is (= 27 (count symbols)))))
(testing "If language code is 'uk', then it must have 34 symbols."
(let [symbols (default-symbol-factory "uk")]
(is (= 34 (count symbols)))))
(testing "If language code is unidentified, then it must have the 'en'."
(let [symbols (default-symbol-factory "Maybe a code")]
(is (= 27 (count symbols))))))
@@ -0,0 +1,21 @@
(ns cipher-analytical-machine.symbols.frequencies-test
(:require
[clojure.test :refer :all]
[cipher-analytical-machine.symbols.frequencies :refer :all]))
(deftest calculate-char-index-test
(let [symbol-map english-letter-frequencies]
(testing "The map must be converted to 'etaoinsrhldcumfpgwybvkxjqz'"
(is (= "etaoinsrhldcumfpgwybvkxjqz"
(map-to-string symbol-map))))))
(deftest default-frequency-factory-test
(testing "Factory supports languages: English (en), Ukrainian (uk). If language code is unidentified, then it must have the 'en'."
(are [language-code expected-map-size]
(->> (default-frequency-factory language-code)
count
(= expected-map-size))
"en" 26
"uk" 34
"Maybe a code" 26)))