├── .github ├── FUNDING.yml ├── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md └── workflows │ └── clojure.yml ├── .gitignore ├── CHANGELOG.md ├── LICENSE ├── README.md ├── project.clj ├── src └── clojure_aes │ ├── add_round_key.clj │ ├── constants.clj │ ├── core.clj │ ├── decrypt │ ├── inverse_cipher_core.clj │ ├── inverse_mix_columns.clj │ ├── inverse_shift_rows.clj │ └── inverse_sub_bytes.clj │ ├── encrypt │ ├── cipher_core.clj │ ├── mix_columns.clj │ ├── shift_row.clj │ └── sub_bytes.clj │ ├── main.clj │ ├── shared.clj │ └── utils.clj ├── target └── uberjar │ ├── clojure-aes-0.1.4-standalone.jar │ ├── clojure-aes-0.1.4.jar │ ├── clojure-aes-0.1.5-standalone.jar │ └── clojure-aes-0.1.5.jar └── test └── clojure_aes └── core_test.clj /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: griffinscribe-llc 4 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. Scroll down to '....' 18 | 4. See error 19 | 20 | **Expected behavior** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Screenshots** 24 | If applicable, add screenshots to help explain your problem. 25 | 26 | **Desktop (please complete the following information):** 27 | - OS: [e.g. iOS] 28 | - Browser [e.g. chrome, safari] 29 | - Version [e.g. 22] 30 | 31 | **Smartphone (please complete the following information):** 32 | - Device: [e.g. iPhone6] 33 | - OS: [e.g. iOS8.1] 34 | - Browser [e.g. stock browser, safari] 35 | - Version [e.g. 22] 36 | 37 | **Additional context** 38 | Add any other context about the problem here. 39 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /.github/workflows/clojure.yml: -------------------------------------------------------------------------------- 1 | name: Clojure CI 2 | 3 | on: 4 | push: 5 | branches: [ "main" ] 6 | pull_request: 7 | branches: [ "main" ] 8 | 9 | jobs: 10 | build: 11 | 12 | runs-on: ubuntu-latest 13 | 14 | steps: 15 | - uses: actions/checkout@v3 16 | - name: Install dependencies 17 | run: lein deps 18 | - name: Run tests 19 | run: lein test 20 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | pom.xml 2 | pom.xml.asc 3 | *.jar 4 | *.class 5 | /lib/ 6 | /classes/ 7 | /target/ 8 | /checkouts/ 9 | .lein-deps-sum 10 | .lein-repl-history 11 | .lein-plugins/ 12 | .lein-failures 13 | .nrepl-port 14 | .cpcache/ 15 | .clj-kondo/ 16 | .lsp/ 17 | .calva/ 18 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | All notable changes to this project will be documented in this file. This change log follows the conventions of [keepachangelog.com](http://keepachangelog.com/). 3 | 4 | ## 0.1.5 - 2023-02-07 5 | ### Unreleased 6 | - Bump Clojure version to 1.11.1 7 | - Place debug statements behind optional verbose flag. (Progress towards https://github.com/GriffinScribe-LLC/clojure-aes/issues/2 @yogthos) 8 | 9 | ## 0.1.4 - 2021-01-25 10 | ### Added 11 | - Initial Release 12 | 13 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Eclipse Public License - v 2.0 2 | 3 | THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE 4 | PUBLIC LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION 5 | OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT. 6 | 7 | 1. DEFINITIONS 8 | 9 | "Contribution" means: 10 | 11 | a) in the case of the initial Contributor, the initial content 12 | Distributed under this Agreement, and 13 | 14 | b) in the case of each subsequent Contributor: 15 | i) changes to the Program, and 16 | ii) additions to the Program; 17 | where such changes and/or additions to the Program originate from 18 | and are Distributed by that particular Contributor. A Contribution 19 | "originates" from a Contributor if it was added to the Program by 20 | such Contributor itself or anyone acting on such Contributor's behalf. 21 | Contributions do not include changes or additions to the Program that 22 | are not Modified Works. 23 | 24 | "Contributor" means any person or entity that Distributes the Program. 25 | 26 | "Licensed Patents" mean patent claims licensable by a Contributor which 27 | are necessarily infringed by the use or sale of its Contribution alone 28 | or when combined with the Program. 29 | 30 | "Program" means the Contributions Distributed in accordance with this 31 | Agreement. 32 | 33 | "Recipient" means anyone who receives the Program under this Agreement 34 | or any Secondary License (as applicable), including Contributors. 35 | 36 | "Derivative Works" shall mean any work, whether in Source Code or other 37 | form, that is based on (or derived from) the Program and for which the 38 | editorial revisions, annotations, elaborations, or other modifications 39 | represent, as a whole, an original work of authorship. 40 | 41 | "Modified Works" shall mean any work in Source Code or other form that 42 | results from an addition to, deletion from, or modification of the 43 | contents of the Program, including, for purposes of clarity any new file 44 | in Source Code form that contains any contents of the Program. Modified 45 | Works shall not include works that contain only declarations, 46 | interfaces, types, classes, structures, or files of the Program solely 47 | in each case in order to link to, bind by name, or subclass the Program 48 | or Modified Works thereof. 49 | 50 | "Distribute" means the acts of a) distributing or b) making available 51 | in any manner that enables the transfer of a copy. 52 | 53 | "Source Code" means the form of a Program preferred for making 54 | modifications, including but not limited to software source code, 55 | documentation source, and configuration files. 56 | 57 | "Secondary License" means either the GNU General Public License, 58 | Version 2.0, or any later versions of that license, including any 59 | exceptions or additional permissions as identified by the initial 60 | Contributor. 61 | 62 | 2. GRANT OF RIGHTS 63 | 64 | a) Subject to the terms of this Agreement, each Contributor hereby 65 | grants Recipient a non-exclusive, worldwide, royalty-free copyright 66 | license to reproduce, prepare Derivative Works of, publicly display, 67 | publicly perform, Distribute and sublicense the Contribution of such 68 | Contributor, if any, and such Derivative Works. 69 | 70 | b) Subject to the terms of this Agreement, each Contributor hereby 71 | grants Recipient a non-exclusive, worldwide, royalty-free patent 72 | license under Licensed Patents to make, use, sell, offer to sell, 73 | import and otherwise transfer the Contribution of such Contributor, 74 | if any, in Source Code or other form. This patent license shall 75 | apply to the combination of the Contribution and the Program if, at 76 | the time the Contribution is added by the Contributor, such addition 77 | of the Contribution causes such combination to be covered by the 78 | Licensed Patents. The patent license shall not apply to any other 79 | combinations which include the Contribution. No hardware per se is 80 | licensed hereunder. 81 | 82 | c) Recipient understands that although each Contributor grants the 83 | licenses to its Contributions set forth herein, no assurances are 84 | provided by any Contributor that the Program does not infringe the 85 | patent or other intellectual property rights of any other entity. 86 | Each Contributor disclaims any liability to Recipient for claims 87 | brought by any other entity based on infringement of intellectual 88 | property rights or otherwise. As a condition to exercising the 89 | rights and licenses granted hereunder, each Recipient hereby 90 | assumes sole responsibility to secure any other intellectual 91 | property rights needed, if any. For example, if a third party 92 | patent license is required to allow Recipient to Distribute the 93 | Program, it is Recipient's responsibility to acquire that license 94 | before distributing the Program. 95 | 96 | d) Each Contributor represents that to its knowledge it has 97 | sufficient copyright rights in its Contribution, if any, to grant 98 | the copyright license set forth in this Agreement. 99 | 100 | e) Notwithstanding the terms of any Secondary License, no 101 | Contributor makes additional grants to any Recipient (other than 102 | those set forth in this Agreement) as a result of such Recipient's 103 | receipt of the Program under the terms of a Secondary License 104 | (if permitted under the terms of Section 3). 105 | 106 | 3. REQUIREMENTS 107 | 108 | 3.1 If a Contributor Distributes the Program in any form, then: 109 | 110 | a) the Program must also be made available as Source Code, in 111 | accordance with section 3.2, and the Contributor must accompany 112 | the Program with a statement that the Source Code for the Program 113 | is available under this Agreement, and informs Recipients how to 114 | obtain it in a reasonable manner on or through a medium customarily 115 | used for software exchange; and 116 | 117 | b) the Contributor may Distribute the Program under a license 118 | different than this Agreement, provided that such license: 119 | i) effectively disclaims on behalf of all other Contributors all 120 | warranties and conditions, express and implied, including 121 | warranties or conditions of title and non-infringement, and 122 | implied warranties or conditions of merchantability and fitness 123 | for a particular purpose; 124 | 125 | ii) effectively excludes on behalf of all other Contributors all 126 | liability for damages, including direct, indirect, special, 127 | incidental and consequential damages, such as lost profits; 128 | 129 | iii) does not attempt to limit or alter the recipients' rights 130 | in the Source Code under section 3.2; and 131 | 132 | iv) requires any subsequent distribution of the Program by any 133 | party to be under a license that satisfies the requirements 134 | of this section 3. 135 | 136 | 3.2 When the Program is Distributed as Source Code: 137 | 138 | a) it must be made available under this Agreement, or if the 139 | Program (i) is combined with other material in a separate file or 140 | files made available under a Secondary License, and (ii) the initial 141 | Contributor attached to the Source Code the notice described in 142 | Exhibit A of this Agreement, then the Program may be made available 143 | under the terms of such Secondary Licenses, and 144 | 145 | b) a copy of this Agreement must be included with each copy of 146 | the Program. 147 | 148 | 3.3 Contributors may not remove or alter any copyright, patent, 149 | trademark, attribution notices, disclaimers of warranty, or limitations 150 | of liability ("notices") contained within the Program from any copy of 151 | the Program which they Distribute, provided that Contributors may add 152 | their own appropriate notices. 153 | 154 | 4. COMMERCIAL DISTRIBUTION 155 | 156 | Commercial distributors of software may accept certain responsibilities 157 | with respect to end users, business partners and the like. While this 158 | license is intended to facilitate the commercial use of the Program, 159 | the Contributor who includes the Program in a commercial product 160 | offering should do so in a manner which does not create potential 161 | liability for other Contributors. Therefore, if a Contributor includes 162 | the Program in a commercial product offering, such Contributor 163 | ("Commercial Contributor") hereby agrees to defend and indemnify every 164 | other Contributor ("Indemnified Contributor") against any losses, 165 | damages and costs (collectively "Losses") arising from claims, lawsuits 166 | and other legal actions brought by a third party against the Indemnified 167 | Contributor to the extent caused by the acts or omissions of such 168 | Commercial Contributor in connection with its distribution of the Program 169 | in a commercial product offering. The obligations in this section do not 170 | apply to any claims or Losses relating to any actual or alleged 171 | intellectual property infringement. In order to qualify, an Indemnified 172 | Contributor must: a) promptly notify the Commercial Contributor in 173 | writing of such claim, and b) allow the Commercial Contributor to control, 174 | and cooperate with the Commercial Contributor in, the defense and any 175 | related settlement negotiations. The Indemnified Contributor may 176 | participate in any such claim at its own expense. 177 | 178 | For example, a Contributor might include the Program in a commercial 179 | product offering, Product X. That Contributor is then a Commercial 180 | Contributor. If that Commercial Contributor then makes performance 181 | claims, or offers warranties related to Product X, those performance 182 | claims and warranties are such Commercial Contributor's responsibility 183 | alone. Under this section, the Commercial Contributor would have to 184 | defend claims against the other Contributors related to those performance 185 | claims and warranties, and if a court requires any other Contributor to 186 | pay any damages as a result, the Commercial Contributor must pay 187 | those damages. 188 | 189 | 5. NO WARRANTY 190 | 191 | EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT 192 | PERMITTED BY APPLICABLE LAW, THE PROGRAM IS PROVIDED ON AN "AS IS" 193 | BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR 194 | IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF 195 | TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR 196 | PURPOSE. Each Recipient is solely responsible for determining the 197 | appropriateness of using and distributing the Program and assumes all 198 | risks associated with its exercise of rights under this Agreement, 199 | including but not limited to the risks and costs of program errors, 200 | compliance with applicable laws, damage to or loss of data, programs 201 | or equipment, and unavailability or interruption of operations. 202 | 203 | 6. DISCLAIMER OF LIABILITY 204 | 205 | EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT 206 | PERMITTED BY APPLICABLE LAW, NEITHER RECIPIENT NOR ANY CONTRIBUTORS 207 | SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 208 | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST 209 | PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 210 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 211 | ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE 212 | EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE 213 | POSSIBILITY OF SUCH DAMAGES. 214 | 215 | 7. GENERAL 216 | 217 | If any provision of this Agreement is invalid or unenforceable under 218 | applicable law, it shall not affect the validity or enforceability of 219 | the remainder of the terms of this Agreement, and without further 220 | action by the parties hereto, such provision shall be reformed to the 221 | minimum extent necessary to make such provision valid and enforceable. 222 | 223 | If Recipient institutes patent litigation against any entity 224 | (including a cross-claim or counterclaim in a lawsuit) alleging that the 225 | Program itself (excluding combinations of the Program with other software 226 | or hardware) infringes such Recipient's patent(s), then such Recipient's 227 | rights granted under Section 2(b) shall terminate as of the date such 228 | litigation is filed. 229 | 230 | All Recipient's rights under this Agreement shall terminate if it 231 | fails to comply with any of the material terms or conditions of this 232 | Agreement and does not cure such failure in a reasonable period of 233 | time after becoming aware of such noncompliance. If all Recipient's 234 | rights under this Agreement terminate, Recipient agrees to cease use 235 | and distribution of the Program as soon as reasonably practicable. 236 | However, Recipient's obligations under this Agreement and any licenses 237 | granted by Recipient relating to the Program shall continue and survive. 238 | 239 | Everyone is permitted to copy and distribute copies of this Agreement, 240 | but in order to avoid inconsistency the Agreement is copyrighted and 241 | may only be modified in the following manner. The Agreement Steward 242 | reserves the right to publish new versions (including revisions) of 243 | this Agreement from time to time. No one other than the Agreement 244 | Steward has the right to modify this Agreement. The Eclipse Foundation 245 | is the initial Agreement Steward. The Eclipse Foundation may assign the 246 | responsibility to serve as the Agreement Steward to a suitable separate 247 | entity. Each new version of the Agreement will be given a distinguishing 248 | version number. The Program (including Contributions) may always be 249 | Distributed subject to the version of the Agreement under which it was 250 | received. In addition, after a new version of the Agreement is published, 251 | Contributor may elect to Distribute the Program (including its 252 | Contributions) under the new version. 253 | 254 | Except as expressly stated in Sections 2(a) and 2(b) above, Recipient 255 | receives no rights or licenses to the intellectual property of any 256 | Contributor under this Agreement, whether expressly, by implication, 257 | estoppel or otherwise. All rights in the Program not expressly granted 258 | under this Agreement are reserved. Nothing in this Agreement is intended 259 | to be enforceable by any entity that is not a Contributor or Recipient. 260 | No third-party beneficiary rights are created under this Agreement. 261 | 262 | Exhibit A - Form of Secondary Licenses Notice 263 | 264 | "This Source Code may also be made available under the following 265 | Secondary Licenses when the conditions for such availability set forth 266 | in the Eclipse Public License, v. 2.0 are satisfied: GNU General Public 267 | License as published by the Free Software Foundation, either version 2 268 | of the License, or (at your option) any later version, with the GNU 269 | Classpath Exception which is available at 270 | https://www.gnu.org/software/classpath/license.html." 271 | 272 | Simply including a copy of this Agreement, including this Exhibit A 273 | is not sufficient to license the Source Code under Secondary Licenses. 274 | 275 | If it is not possible or desirable to put the notice in a particular 276 | file, then You may include the notice in a location (such as a LICENSE 277 | file in a relevant directory) where a recipient would be likely to 278 | look for such a notice. 279 | 280 | You may add additional accurate notices of copyright ownership. 281 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Clojure-aes 2 | [![Clojars Project](https://img.shields.io/clojars/v/com.griffinscribe/clojure-aes.svg)](https://clojars.org/com.griffinscribe/clojure-aes) 3 | 4 | Pure Clojure implementation of the Advanced Encryption Standard (AES) for encryption and decryption using 128, 192, and 256 bit keys based on the [NIST specification](https://csrc.nist.gov/csrc/media/publications/fips/197/final/documents/fips-197.pdf). 5 | 6 | ## Installation 7 | 8 | Leiningen/Boot 9 | 10 | Add the following into `:dependencies` in your project.clj file: 11 | 12 | ```clojure 13 | [com.griffinscribe/clojure-aes "0.1.4"] 14 | ``` 15 | 16 | 17 | Clojure CLI/deps.edn 18 | 19 | ```clojure 20 | com.griffinscribe/clojure-aes {:mvn/version "0.1.4"} 21 | ``` 22 | 23 | Gradle 24 | 25 | ```clojure 26 | compile 'com.griffinscribe:clojure-aes:0.1.4' 27 | ``` 28 | 29 | Maven 30 | 31 | ```java 32 | 33 | com.griffinscribe 34 | clojure-aes 35 | 0.1.4 36 | 37 | ``` 38 | 39 | (Version "0.1.5" only available via compilation from source via `lein uberjar`) 40 | 41 | Command-line access: 42 | 43 | Clone the repo, and `cd` into the root directory of the project 44 | 45 | If there is no jar file located at `./target/uberjar/clojure-aes-0.1.4-standalone.jar`, 46 | dowload leiningen (https://github.com/technomancy/leiningen), run `lein uberjar` in the root directory of the project (same directory that the `project.clj` file is located in) to create a jar file. Then proceed with the below-mentioned `java` command 47 | 48 | ## Usage 49 | 50 | ```clojure 51 | (:require [clojure-aes.core :as aes]) 52 | ``` 53 | 54 | Encryption: 55 | 56 | ```clojure 57 | (let [message "1a57bbfeeefc417d203494788f3ba2c8" 58 | secret-key "629cdd27509b3d2fe2adb7ec7ff0e6cf4a6c24f4c5ebbf80c38d25f8fc54c649" 59 | key-length 256 60 | cipher-text (aes/encrypt secret-key message key-length)] 61 | cipher-text) 62 | ``` 63 | 64 | 65 | Decryption: 66 | 67 | ```clojure 68 | (let [cipher-text "2ace987331c0d3e57479dd7037103028" 69 | secret-key "629cdd27509b3d2fe2adb7ec7ff0e6cf4a6c24f4c5ebbf80c38d25f8fc54c649" 70 | key-length 256 71 | message (aes/decrypt secret-key cipher-text key-length)] 72 | message) 73 | ``` 74 | 75 | 76 | Version 0.1.4 currently supports an input message of 16 bytes (hex-formatted) at a time. 77 | Version 0.1.5 is unreleased to Clojars, but can be compiled from source, or downloaded as an uberjar from the target directory. 78 | 79 | Command line usage: 80 | `cd` into project root, and run the following. 81 | 82 | $ java -jar clojure-aes-0.1.4-standalone.jar [args] 83 | where the args passed in are the secret-key, the message, the key-length and a flag for encryption or decryption. 84 | 85 | Example encryption: 86 | 87 | ```bash 88 | $ java -jar target/uberjar/clojure-aes-0.1.4-standalone.jar 629cdd27509b3d2fe2adb7ec7ff0e6cf4a6c24f4c5ebbf80 526b00c38662e0c58a49ce6ccc83fe9a 192 -e 89 | ``` 90 | => a953e8cf02e51d6f42e30be9910c9cde 91 | 92 | The first arg is the secret key. The second arg is the message to be encrypted or decrypted. Third arg is the key-length, the third arg indicates whether encryption or decryption will be used. 93 | `-e` indicates that encryption will be used. Use `-d` for decryption. 94 | 95 | A 4th arg may optionally be passed as "-v" to indicate if verbose logging should be enabled to display the internal representation of the message in its various transformations through the encryption and decryption functions. Output follows format described in fips-197.pdf. 96 | 97 | Example decryption: 98 | 99 | ```bash 100 | $ java -jar target/uberjar/clojure-aes-0.1.4-standalone.jar 629cdd27509b3d2fe2adb7ec7ff0e6cf4a6c24f4c5ebbf80 a953e8cf02e51d6f42e30be9910c9cde 192 -d 101 | ``` 102 | => 526b00c38662e0c58a49ce6ccc83fe9a 103 | 104 | 105 | ## TESTS 106 | This library passes all test cases in Appendix C of https://csrc.nist.gov/csrc/media/publications/fips/197/final/documents/fips-197.pdf, 107 | including encryption for 128, 192, and 256 bits, as well as decryption for keys of 128, 192 and 256 bits. 108 | 109 | Additional tests are accessible in https://github.com/GriffinScribe-LLC/clojure-aes/blob/main/test/clojure_aes/core_test.clj 110 | All major functions/units are individually tested, and integration test exists at the end of that file. 111 | 112 | To run the unit tests from the command-line, install leiningen (See installation section of readme). Then go to the root directory of the project, and run `lein test`. 113 | 114 | To run the tests in the REPL, start up a Clojure REPL in Emacs, navigate to the test file, load it via `ctrl-c ctrl-k` and use the Emacs cider test functionality to run the tests. Use the keystrokes `ctrl-c ctrl-t n` for all tests in the namespace; `ctrl-c ctrl-t t` to run a specific test. Documentation for cider is found at https://docs.cider.mx/cider/testing/running_tests.html 115 | 116 | ## API Documentation 117 | https://cljdoc.org/d/com.griffinscribe/clojure-aes/0.1.4/api/clojure-aes 118 | 119 | ## Resources used 120 | https://csrc.nist.gov/csrc/media/publications/fips/197/final/documents/fips-197.pdf 121 | 122 | Consulted `Introduction to Cryptography with Coding Theory` 2E, 123 | pages 151-161 by Wade Trappe and Lawrence C. Washington. 124 | 125 | 126 | ## License 127 | 128 | Copyright © 2021-2023 GriffinScribe, LLC. All Rights Reserved. 129 | 130 | Distributed under the Eclipse Public License, the same as Clojure. 131 | 132 | 133 | -------------------------------------------------------------------------------- /project.clj: -------------------------------------------------------------------------------- 1 | (defproject com.griffinscribe/clojure-aes "0.1.5" 2 | :description "Pure Clojure implementation of the Advanced Encryption Standard (AES). Supports encryption and decryption for 128, 192, and 256 bit keys." 3 | :url "https://github.com/griffinscribe-llc/clojure-aes" 4 | :license {:name "EPL-2.0 OR GPL-2.0-or-later WITH Classpath-exception-2.0" 5 | :url "https://www.eclipse.org/legal/epl-2.0/"} 6 | :dependencies [[org.clojure/clojure "1.11.1"]] 7 | :min-lein-version "2.0.0" 8 | :main clojure-aes.main 9 | :target-path "target/%s" 10 | :source-paths ["src/"] 11 | :resource-paths ["resources" "target/cljsbuild"] 12 | :repositories [["releases" {:url "https://repo.clojars.org" 13 | :creds :gpg}]] 14 | :deploy-repositories {"releases" {:url "https://repo.clojars.org" :creds :gpg}} 15 | :deploy-branches ["main"] 16 | :scm {:name "git" 17 | :url "https://github.com/griffinscribe-llc/clojure-aes"} 18 | :profiles {:uberjar {:aot :all 19 | :jvm-opts ["-Dclojure.compiler.direct-linking=true"]}}) 20 | -------------------------------------------------------------------------------- /src/clojure_aes/add_round_key.clj: -------------------------------------------------------------------------------- 1 | (ns clojure-aes.add-round-key 2 | (:require [clojure-aes.utils :as utils] 3 | [clojure-aes.shared :as shared])) 4 | 5 | (defn addRoundKey 6 | "The round key is XORed with the result of the above layer 7 | `State` is a 4 x nb (nb usually = 4) matrix, `expanded-key` is a 4 x nk matrix, where nk = number of 32 bit in key, for 128 bits this is 4. 192 bits nk = 6, 256 bits nk = 8" 8 | [state expanded-key round-num] 9 | (let [round-key (utils/matrix-transposition 10 | (vec 11 | (for [x (range (* 4 round-num) 12 | (+ (* round-num 4) 4))] 13 | (shared/separate-four-bytes 14 | (nth expanded-key x))))) 15 | xor-cols (fn [state-col round-key-col] 16 | (vec (for [z (range 0 4)] 17 | (bit-xor (nth state-col z) 18 | (nth round-key-col z))))) 19 | new-state (vec 20 | (for [y (range 0 4)] 21 | (let [state-col (nth state y) 22 | round-key-col (nth round-key y)] 23 | (xor-cols state-col round-key-col))))] 24 | (utils/debug-aes round-num "k_sch " 25 | (utils/matrix-transposition round-key)) 26 | (utils/print-array round-key "round key value" round-num) 27 | (utils/print-array new-state "state after addRoundKey:" round-num) 28 | new-state)) 29 | -------------------------------------------------------------------------------- /src/clojure_aes/constants.clj: -------------------------------------------------------------------------------- 1 | (ns clojure-aes.constants) 2 | 3 | (def initial-key-128 4 | [0x2b 0x7e 0x15 0x16 5 | 0x28 0xae 0xd2 0xa6 6 | 0xab 0xf7 0x15 0x88 7 | 0x09 0xcf 0x4f 0x3c]) 8 | 9 | (def initial-key-expanded-128 10 | [0x2b7e1516, 0x28aed2a6, 0xabf71588, 0x09cf4f3c, 11 | 0xa0fafe17, 0x88542cb1, 0x23a33939, 0x2a6c7605, 12 | 0xf2c295f2, 0x7a96b943, 0x5935807a, 0x7359f67f, 13 | 0x3d80477d, 0x4716fe3e, 0x1e237e44, 0x6d7a883b, 14 | 0xef44a541, 0xa8525b7f, 0xb671253b, 0xdb0bad00, 15 | 0xd4d1c6f8, 0x7c839d87, 0xcaf2b8bc, 0x11f915bc, 16 | 0x6d88a37a, 0x110b3efd, 0xdbf98641, 0xca0093fd, 17 | 0x4e54f70e, 0x5f5fc9f3, 0x84a64fb2, 0x4ea6dc4f, 18 | 0xead27321, 0xb58dbad2, 0x312bf560, 0x7f8d292f, 19 | 0xac7766f3, 0x19fadc21, 0x28d12941, 0x575c006e, 20 | 0xd014f9a8, 0xc9ee2589, 0xe13f0cc8, 0xb6630ca6]) 21 | 22 | (def initial-key-192 23 | [0x8e 0x73 0xb0 0xf7 24 | 0xda 0x0e 0x64 0x52 25 | 0xc8 0x10 0xf3 0x2b 26 | 0x80 0x90 0x79 0xe5 27 | 0x62 0xf8 0xea 0xd2 28 | 0x52 0x2c 0x6b 0x7b]) 29 | 30 | (def initial-key-expanded-192 31 | [ 0x8e73b0f7 0xda0e6452 0xc810f32b 0x809079e5 32 | 0x62f8ead2 0x522c6b7b 0xfe0c91f7 0x2402f5a5 33 | 0xec12068e 0x6c827f6b 0x0e7a95b9 0x5c56fec2 34 | 0x4db7b4bd 0x69b54118 0x85a74796 0xe92538fd 35 | 0xe75fad44 0xbb095386 0x485af057 0x21efb14f 36 | 0xa448f6d9 0x4d6dce24 0xaa326360 0x113b30e6 37 | 0xa25e7ed5 0x83b1cf9a 0x27f93943 0x6a94f767 38 | 0xc0a69407 0xd19da4e1 0xec1786eb 0x6fa64971 39 | 0x485f7032 0x22cb8755 0xe26d1352 0x33f0b7b3 40 | 0x40beeb28 0x2f18a259 0x6747d26b 0x458c553e 41 | 0xa7e1466c 0x9411f1df 0x821f750a 0xad07d753 42 | 0xca400538 0x8fcc5006 0x282d166a 0xbc3ce7b5 43 | 0xe98ba06f 0x448c773c 0x8ecc7204 0x01002202]) 44 | 45 | (def initial-key-256 46 | [ 0x60 0x3d 0xeb 0x10 47 | 0x15 0xca 0x71 0xbe 48 | 0x2b 0x73 0xae 0xf0 49 | 0x85 0x7d 0x77 0x81 50 | 0x1f 0x35 0x2c 0x07 51 | 0x3b 0x61 0x08 0xd7 52 | 0x2d 0x98 0x10 0xa3 53 | 0x09 0x14 0xdf 0xf4]) 54 | 55 | 56 | (def initial-key-expanded-256 57 | [ 0x603deb10 0x15ca71be 0x2b73aef0 0x857d7781 58 | 0x1f352c07 0x3b6108d7 0x2d9810a3 0x0914dff4 59 | 0x9ba35411 0x8e6925af 0xa51a8b5f 0x2067fcde 60 | 0xa8b09c1a 0x93d194cd 0xbe49846e 0xb75d5b9a 61 | 0xd59aecb8 0x5bf3c917 0xfee94248 0xde8ebe96 62 | 0xb5a9328a 0x2678a647 0x98312229 0x2f6c79b3 63 | 0x812c81ad 0xdadf48ba 0x24360af2 0xfab8b464 64 | 0x98c5bfc9 0xbebd198e 0x268c3ba7 0x09e04214 65 | 0x68007bac 0xb2df3316 0x96e939e4 0x6c518d80 66 | 0xc814e204 0x76a9fb8a 0x5025c02d 0x59c58239 67 | 0xde136967 0x6ccc5a71 0xfa256395 0x9674ee15 68 | 0x5886ca5d 0x2e2f31d7 0x7e0af1fa 0x27cf73c3 69 | 0x749c47ab 0x18501dda 0xe2757e4f 0x7401905a 70 | 0xcafaaae3 0xe4d59b34 0x9adf6ace 0xbd10190d 71 | 0xfe4890d1 0xe6188d0b 0x046df344 0x706c631e]) 72 | 73 | (def roundConstant 74 | [0x00000000, 75 | 0x01000000, 0x02000000, 0x04000000, 0x08000000, 76 | 0x10000000, 0x20000000, 0x40000000, 0x80000000, 77 | 0x1B000000, 0x36000000, 0x6C000000, 0xD8000000, 78 | 0xAB000000, 0x4D000000, 0x9A000000, 0x2F000000, 79 | 0x5E000000, 0xBC000000, 0x63000000, 0xC6000000, 80 | 0x97000000, 0x35000000, 0x6A000000, 0xD4000000, 81 | 0xB3000000, 0x7D000000, 0xFA000000, 0xEF000000, 82 | 0xC5000000, 0x91000000, 0x39000000, 0x72000000, 83 | 0xE4000000, 0xD3000000, 0xBD000000, 0x61000000, 84 | 0xC2000000, 0x9F000000, 0x25000000, 0x4A000000, 85 | 0x94000000, 0x33000000, 0x66000000, 0xCC000000, 86 | 0x83000000, 0x1D000000, 0x3A000000, 0x74000000, 87 | 0xE8000000, 0xCB000000, 0x8D000000]) 88 | 89 | (def state [[0x19,0xa0,0x9a,0xe9], 90 | [0x3d,0xf4,0xc6,0xf8], 91 | [0xe3,0xe2,0x8d,0x48], 92 | [0xbe,0x2b,0x2a,0x08]]) 93 | 94 | (def sub-state [[0xd4,0xe0,0xb8,0x1e], 95 | [0x27,0xbf,0xb4,0x41], 96 | [0x11,0x98,0x5d,0x52], 97 | [0xae,0xf1,0xe5,0x30]]) 98 | 99 | (def shift-state [[0xd4, 0xe0, 0xb8, 0x1e], 100 | [0xbf, 0xb4, 0x41, 0x27], 101 | [0x5d, 0x52, 0x11, 0x98], 102 | [0x30, 0xae, 0xf1, 0xe5]]) 103 | 104 | (def mix-state [[0x04, 0xe0, 0x48, 0x28], 105 | [0x66, 0xcb, 0xf8, 0x06], 106 | [0x81, 0x19, 0xd3, 0x26], 107 | [0xe5, 0x9a, 0x7a, 0x4c]]) 108 | 109 | (def round-state [ [0xa4, 0x68, 0x6b, 0x02], 110 | [0x9c, 0x9f, 0x5b, 0x6a], 111 | [0x7f, 0x35, 0xea, 0x50], 112 | [0xf2, 0x2b, 0x43, 0x49]]) 113 | 114 | (def mix-column-matrix 115 | {:column-order {:col1 [2 1 1 3] 116 | :col2 [3 2 1 1] 117 | :col3 [1 3 2 1] 118 | :col4 [1 1 3 2]} 119 | :row-order {:row1 [2 3 1 1] 120 | :row2 [1 2 3 1] 121 | :row3 [1 1 2 3] 122 | :row4 [3 1 1 2]}}) 123 | 124 | (def inv-mix-column-matrix 125 | {:column-order {:col1 [ 0x0E 0x09 0x0D 0x0B ] 126 | :col2 [ 0x0B 0x0E 0x09 0x0D ] 127 | :col3 [ 0x0D 0x0B 0x0E 0x09 ] 128 | :col4 [ 0x09 0x0D 0x0B 0x0E ]} 129 | :row-order {:row1 [ 0x0E 0x0B 0x0D 0x09 ] 130 | :row2 [ 0x09 0x0E 0x0B 0x0D ] 131 | :row3 [ 0x0D 0x09 0x0E 0x0B ] 132 | :row4 [ 0x0B 0x0D 0x09 0x0E ]}}) 133 | 134 | (def sbox [ 135 | [ 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76 ] , 136 | [ 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0 ] , 137 | [ 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15 ] , 138 | [ 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75 ] , 139 | [ 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84 ] , 140 | [ 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf ] , 141 | [ 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8 ] , 142 | [ 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2 ] , 143 | [ 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73 ] , 144 | [ 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb ] , 145 | [ 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79 ] , 146 | [ 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08 ] , 147 | [ 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a ] , 148 | [ 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e ] , 149 | [ 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf ] , 150 | [ 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16 ]]) 151 | 152 | (def sbox-affine-matrix 153 | [[1 0 0 0 1 1 1 1] 154 | [1 1 0 0 0 1 1 1] 155 | [1 1 1 0 0 0 1 1] 156 | [1 1 1 1 0 0 0 1] 157 | [1 1 1 1 1 0 0 0] 158 | [0 1 1 1 1 1 0 0] 159 | [0 0 1 1 1 1 1 0] 160 | [0 0 0 1 1 1 1 1]]) 161 | 162 | (def inv-sbox [ 163 | [ 0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb ] , 164 | [ 0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb ] , 165 | [ 0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e ] , 166 | [ 0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25 ] , 167 | [ 0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92 ] , 168 | [ 0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84 ] , 169 | [ 0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06 ] , 170 | [ 0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b ] , 171 | [ 0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73 ] , 172 | [ 0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e ] , 173 | [ 0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b ] , 174 | [ 0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4 ] , 175 | [ 0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f ] , 176 | [ 0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef ] , 177 | [ 0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61 ] , 178 | [ 0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d ]]) 179 | 180 | 181 | 182 | -------------------------------------------------------------------------------- /src/clojure_aes/core.clj: -------------------------------------------------------------------------------- 1 | (ns clojure-aes.core 2 | (:require [clojure-aes.constants :as c] 3 | [clojure-aes.encrypt.shift-row :as sr] 4 | [clojure-aes.utils :as utils] 5 | [clojure-aes.shared :as shared] 6 | [clojure-aes.encrypt.sub-bytes :as sb] 7 | [clojure-aes.encrypt.cipher-core :as cc] 8 | [clojure-aes.decrypt.inverse-cipher-core :as icc])) 9 | 10 | (defn key-expansion 11 | "Takes an initial 4x4 byte-array `cipher-key` and expands it to have 44, 52, or 60 columns, based on the `num-bits` passed in. Allowed values for `num-bits` is 128, 192, or 256." 12 | [cipher-key num-bits] 13 | (let [expanded-key (atom []) 14 | Nb 4 15 | nk (shared/number-of-32bit-words-in-key num-bits) 16 | num-rounds (shared/number-of-rounds num-bits) 17 | counter (atom nk) 18 | temp (atom []) 19 | add-at-index (fn [index val-vec] 20 | (reset! expanded-key 21 | (assoc @expanded-key index val-vec))) 22 | sub-vec (fn [offset] 23 | (vec (take 4 (drop offset cipher-key)))) 24 | initialize-expanded (fn [] 25 | (vec 26 | (for [x (range nk)] 27 | (shared/combine-four-bytes 28 | (sub-vec (* x 4))))))] 29 | (reset! expanded-key (initialize-expanded)) 30 | (while (< @counter (* Nb (inc num-rounds))) 31 | (reset! temp (nth @expanded-key (dec @counter))) 32 | (if (= 0 (mod @counter nk)) 33 | (reset! temp (bit-xor 34 | (sb/subWord 35 | (sr/rotWord @temp 1)) 36 | (nth c/roundConstant (/ @counter nk)))) 37 | (when (and (> nk 6) 38 | (= 4 (mod @counter nk))) 39 | (reset! temp (sb/subWord @temp)))) 40 | 41 | (add-at-index @counter 42 | (bit-xor 43 | (nth @expanded-key (- @counter nk)) 44 | @temp)) 45 | (swap! counter inc)) 46 | @expanded-key)) 47 | 48 | (defn encrypt 49 | "Separates the incoming `bit-key` and `message` into byte arrays, and encrypts the `message` using the `bit-key`." 50 | [bit-key message bits & [verbose?]] 51 | (let [secret-key (utils/break-message-to-bytes bit-key) 52 | plain-text (utils/break-message-to-bytes message) 53 | split-plain-text [(vec (take 4 plain-text)) 54 | (vec (take 4 (drop 4 plain-text))) 55 | (vec (take 4 (drop 8 plain-text))) 56 | (vec (take 4 (drop 12 plain-text)))] 57 | expanded-key (key-expansion secret-key bits)] 58 | (apply str (utils/byte-to-hex-string 59 | (flatten 60 | (cc/cipher 61 | split-plain-text 62 | expanded-key 63 | bits 64 | secret-key 65 | verbose?)))))) 66 | 67 | (defn decrypt 68 | "Separates the incoming `bit-key` and `message` into byte arrays, and decrypts the `message` using the `bit-key`." 69 | [bit-key message bits & [verbose?]] 70 | (let [secret-key (utils/break-message-to-bytes bit-key) 71 | cipher-text (utils/break-message-to-bytes message) 72 | split-cipher-text [(vec (take 4 cipher-text)) 73 | (vec (take 4 (drop 4 cipher-text))) 74 | (vec (take 4 (drop 8 cipher-text))) 75 | (vec (take 4 (drop 12 cipher-text)))] 76 | expanded-key (key-expansion secret-key bits)] 77 | (apply str (utils/byte-to-hex-string 78 | (flatten 79 | (icc/inv-cipher split-cipher-text 80 | expanded-key 81 | bits 82 | secret-key 83 | verbose?)))))) 84 | 85 | -------------------------------------------------------------------------------- /src/clojure_aes/decrypt/inverse_cipher_core.clj: -------------------------------------------------------------------------------- 1 | (ns clojure-aes.decrypt.inverse-cipher-core 2 | (:require [clojure-aes.shared :as shared] 3 | [clojure-aes.decrypt.inverse-shift-rows :as isr] 4 | [clojure-aes.utils :as utils] 5 | [clojure-aes.decrypt.inverse-sub-bytes :as isb] 6 | [clojure-aes.decrypt.inverse-mix-columns :as imc] 7 | [clojure-aes.add-round-key :as ark])) 8 | 9 | (defn inv-cipher 10 | "Decrypts the passed in `cipher-text` a 4x4 byte array, using the designated secret-key, a byte array." 11 | [cipher-text expanded-key num-bits secret-key & [debug-print]] 12 | (let [merged-cipher-text (apply str 13 | (flatten (utils/byte2-to-hex-string 14 | cipher-text))) 15 | merged-secret-key (apply str (flatten 16 | (utils/byte-to-hex-string secret-key))) 17 | state (atom cipher-text) 18 | num-rounds (shared/number-of-rounds num-bits) 19 | loop-transform #(doseq [n (reverse (range 1 num-rounds))] 20 | (utils/print-array @state "round start" n) 21 | (reset! state 22 | (-> @state 23 | (isr/inv-shift-rows n) 24 | (isb/inv-sub-bytes n) 25 | (ark/addRoundKey expanded-key n) 26 | (imc/inv-mixColumns n)))) 27 | final-transformation #(-> @state 28 | (isr/inv-shift-rows 0) 29 | (isb/inv-sub-bytes 0) 30 | (ark/addRoundKey expanded-key 0))] 31 | 32 | (when debug-print 33 | (println "\nStarting decryption") 34 | (println (str "Cipher TEXT: " merged-cipher-text)) 35 | (println (str "KEY: " merged-secret-key))) 36 | (utils/print-array @state "round start" 0) 37 | (reset! state (ark/addRoundKey 38 | (utils/matrix-transposition @state) 39 | expanded-key num-rounds)) 40 | (loop-transform) 41 | (reset! state (final-transformation)) 42 | (utils/print-array @state "decryption finished" num-rounds) 43 | (utils/debug-aes num-rounds "output" (utils/matrix-transposition @state)) 44 | (when debug-print 45 | (println "Cipher text " merged-cipher-text " successfully decrypted as" 46 | (apply str (flatten 47 | (utils/byte2-to-hex-string 48 | (utils/matrix-transposition @state))))) 49 | (println "Decryption finished.")) 50 | (utils/matrix-transposition @state))) 51 | -------------------------------------------------------------------------------- /src/clojure_aes/decrypt/inverse_mix_columns.clj: -------------------------------------------------------------------------------- 1 | (ns clojure-aes.decrypt.inverse-mix-columns 2 | (:require [clojure-aes.constants :as c] 3 | [clojure-aes.shared :as shared] 4 | [clojure-aes.utils :as utils])) 5 | 6 | (defn inv-mixColumns 7 | "This transformation is the inverse of mixColumns. (see Section 5.3.3) of FIPS 197" 8 | [state round-num] 9 | (let [state-transposed (utils/matrix-transposition state) 10 | matrix-rows (vals (-> c/inv-mix-column-matrix :row-order)) 11 | multiply-column-fn (fn [index matrix-index] 12 | (let [matrix-row (nth matrix-rows matrix-index) 13 | col (nth state-transposed index) 14 | [m0 m1 m2 m3 ] matrix-row 15 | [c0 c1 c2 c3] col 16 | new-byte (bit-xor 17 | (shared/ffmultiply c0 m0) 18 | (shared/ffmultiply c1 m1) 19 | (shared/ffmultiply c2 m2) 20 | (shared/ffmultiply c3 m3))] 21 | new-byte)) 22 | generate-column (fn [col-num] 23 | [(multiply-column-fn col-num 0) 24 | (multiply-column-fn col-num 1) 25 | (multiply-column-fn col-num 2) 26 | (multiply-column-fn col-num 3)]) 27 | result [(generate-column 0) 28 | (generate-column 1) 29 | (generate-column 2) 30 | (generate-column 3)]] 31 | (utils/debug-aes round-num "after inv-mixColumns: " result ) 32 | (utils/matrix-transposition result))) 33 | -------------------------------------------------------------------------------- /src/clojure_aes/decrypt/inverse_shift_rows.clj: -------------------------------------------------------------------------------- 1 | (ns clojure-aes.decrypt.inverse-shift-rows 2 | (:require [clojure-aes.utils :as utils])) 3 | 4 | (defn inv-shift-rows 5 | "Cyclically shifting the last three rows of the 4x4 state by different offsets to the right." 6 | [[row1 row2 row3 row4] round-num] 7 | (let [[row2-a row2-b row2-c row2-d] row2 8 | [row3-a row3-b row3-c row3-d] row3 9 | [row4-a row4-b row4-c row4-d] row4 10 | transformed [row1 11 | [row2-d row2-a row2-b row2-c] 12 | [row3-c row3-d row3-a row3-b] 13 | [row4-b row4-c row4-d row4-a]]] 14 | (utils/print-array transformed "after inv-shift-rows" round-num) 15 | transformed)) 16 | -------------------------------------------------------------------------------- /src/clojure_aes/decrypt/inverse_sub_bytes.clj: -------------------------------------------------------------------------------- 1 | (ns clojure-aes.decrypt.inverse-sub-bytes 2 | (:require [clojure-aes.constants :as c] 3 | [clojure-aes.utils :as utils])) 4 | 5 | (defn inv-subWord 6 | "Takes a four-byte input word and substitutes each byte in that word with its appropriate value from the inverse S-Box." 7 | [word] 8 | (let [extract-bytes (fn [word mask shift] 9 | (bit-shift-right 10 | (bit-and mask word) shift)) 11 | byte1 (extract-bytes word 0xff000000 24) 12 | byte2 (extract-bytes word 0x00ff0000 16) 13 | byte3 (extract-bytes word 0x0000ff00 8) 14 | byte4 (extract-bytes word 0x000000ff 0) 15 | top-bits (fn [byte] 16 | (bit-shift-right byte 4)) 17 | bottom-bits (fn [byte] 18 | (bit-and byte 0xf)) 19 | s-byte (fn [row col] 20 | (-> c/inv-sbox 21 | (nth row) 22 | (nth col))) 23 | transform-byte (fn [byte word-loc] 24 | (-> (s-byte (top-bits byte) 25 | (bottom-bits byte)) 26 | (bit-shift-left (* 4 word-loc)))) 27 | new-word (+ (transform-byte byte1 6) 28 | (transform-byte byte2 4) 29 | (transform-byte byte3 2) 30 | (transform-byte byte4 0))] 31 | new-word)) 32 | 33 | (defn inv-sub-bytes 34 | "This transformation extracts each word from the State, and calculates the lookup for each byte within each word from inv-sbox" 35 | [[row1 row2 row3 row4] round-num] 36 | (let [calculate-row (fn -row-calcuate [row] 37 | (into [] 38 | (for [word row] 39 | (bit-and 0xff 40 | (inv-subWord word))))) 41 | 42 | new-row1 (calculate-row row1) 43 | new-row2 (calculate-row row2) 44 | new-row3 (calculate-row row3) 45 | new-row4 (calculate-row row4) 46 | new-state [new-row1 new-row2 new-row3 new-row4]] 47 | (utils/print-array new-state "after subBytes" round-num) 48 | (utils/debug-aes round-num "s_box after subBytes: " new-state) 49 | new-state)) 50 | -------------------------------------------------------------------------------- /src/clojure_aes/encrypt/cipher_core.clj: -------------------------------------------------------------------------------- 1 | (ns clojure-aes.encrypt.cipher-core 2 | (:require [clojure-aes.shared :as shared] 3 | [clojure-aes.encrypt.sub-bytes :as sb] 4 | [clojure-aes.encrypt.mix-columns :as mc] 5 | [clojure-aes.encrypt.shift-row :as sr] 6 | [clojure-aes.add-round-key :as ark] 7 | [clojure-aes.utils :as utils])) 8 | 9 | (defn cipher 10 | "Encrypts the passed-in `plain-text`, a 4x4 byte array, using the designated `secret-key` (a byte arrray), the `expanded-key` (another byte array) and the number of bits in the secret-key." 11 | [plain-text expanded-key num-bits secret-key & [debug-print]] 12 | (let [merged-plaintext (apply str (flatten 13 | (utils/byte2-to-hex-string plain-text))) 14 | merged-secret-key (apply str (flatten 15 | (utils/byte-to-hex-string secret-key))) 16 | state (atom plain-text) 17 | num-rounds (shared/number-of-rounds num-bits) 18 | loop-transform #(doseq [n (range 1 num-rounds)] 19 | (utils/debug-aes n "start " (utils/matrix-transposition @state)) 20 | (when debug-print 21 | (utils/print-array @state "round start" n)) 22 | (reset! state 23 | (-> @state 24 | (sb/subBytes n) 25 | (sr/shift-rows n) 26 | (mc/mixColumns n) 27 | (ark/addRoundKey expanded-key n)))) 28 | final-transformation #(-> @state 29 | (sb/subBytes num-rounds) 30 | (sr/shift-rows num-rounds) 31 | (ark/addRoundKey expanded-key 32 | num-rounds))] 33 | (when debug-print 34 | (println "\nStarting encryption") 35 | (println (str "PLAINTEXT: " merged-plaintext)) 36 | (println (str "KEY: " merged-secret-key)) 37 | (println "\nCIPHER (ENCRYPT):") 38 | (utils/debug-aes 0 "input " plain-text) 39 | (utils/print-array @state "round start" 0)) 40 | 41 | (reset! state (ark/addRoundKey (utils/matrix-transposition @state) expanded-key 0)) 42 | (loop-transform) 43 | (reset! state (final-transformation)) 44 | 45 | (when debug-print 46 | (utils/print-array @state "encryption finished" num-rounds) 47 | (utils/debug-aes num-rounds "output" (utils/matrix-transposition @state)) 48 | (println "Plaintext " merged-plaintext 49 | " successfully encrypted to" 50 | (apply str (flatten 51 | (utils/byte2-to-hex-string 52 | (utils/matrix-transposition @state))))) 53 | (println "Encryption finished.")) 54 | 55 | (utils/matrix-transposition @state))) 56 | -------------------------------------------------------------------------------- /src/clojure_aes/encrypt/mix_columns.clj: -------------------------------------------------------------------------------- 1 | (ns clojure-aes.encrypt.mix-columns 2 | (:require [clojure-aes.shared :as shared] 3 | [clojure-aes.utils :as utils] 4 | [clojure-aes.constants :as c])) 5 | 6 | (defn mixColumns 7 | "This transformation treats each column in state as a four-term polynomial. This polynomial is multiplied (modulo another polynomial) by a fixed polynomial with coefficients (see Sections 4.3 and 5.1.3) of FIPS 197." 8 | [state round-num] 9 | (let [transposed (utils/matrix-transposition state) 10 | matrix-rows (vals (-> c/mix-column-matrix :row-order)) 11 | multiply-column-fn (fn [index matrix-index] 12 | (let [matrix-row (nth matrix-rows matrix-index) 13 | col (nth transposed index) 14 | [m0 m1 m2 m3 ] matrix-row 15 | [c0 c1 c2 c3] col 16 | new-byte (bit-xor 17 | (shared/ffmultiply c0 m0) 18 | (shared/ffmultiply c1 m1) 19 | (shared/ffmultiply c2 m2) 20 | (shared/ffmultiply c3 m3))] 21 | new-byte)) 22 | generate-column (fn [col-num] 23 | [(multiply-column-fn col-num 0) 24 | (multiply-column-fn col-num 1) 25 | (multiply-column-fn col-num 2) 26 | (multiply-column-fn col-num 3)]) 27 | result [(generate-column 0) 28 | (generate-column 1) 29 | (generate-column 2) 30 | (generate-column 3)] 31 | transposed-state (utils/matrix-transposition result)] 32 | (utils/print-array transposed-state "after mixColumns:" round-num) 33 | (utils/debug-aes round-num "m_col " (utils/matrix-transposition transposed-state)) 34 | transposed-state)) 35 | -------------------------------------------------------------------------------- /src/clojure_aes/encrypt/shift_row.clj: -------------------------------------------------------------------------------- 1 | (ns clojure-aes.encrypt.shift-row 2 | (:require [clojure-aes.utils :as utils])) 3 | 4 | (defn rotWord 5 | "Transforms a word (4 bytes) by rotating/wrapping each byte cyclically to the left based on the number of rotations." 6 | [word amount] 7 | (let [extract-bytes (fn [word mask shift] 8 | (bit-shift-right 9 | (bit-and mask word) shift)) 10 | byte1 (extract-bytes word 0xff000000 24) 11 | byte2 (extract-bytes word 0x00ff0000 16) 12 | byte3 (extract-bytes word 0x0000ff00 8) 13 | byte4 (extract-bytes word 0x000000ff 0) 14 | new-byte-val (fn [byte offset] 15 | (bit-shift-left byte offset)) 16 | new-word-val (fn [a b c d] 17 | (+ (new-byte-val a 24) 18 | (new-byte-val b 16) 19 | (new-byte-val c 8) 20 | (new-byte-val d 0))) 21 | 22 | rotations (mod amount 4)] 23 | (cond 24 | (= 0 rotations) word 25 | (= 1 rotations) (new-word-val byte2 byte3 byte4 byte1) 26 | (= 2 rotations) (new-word-val byte3 byte4 byte1 byte2) 27 | (= 3 rotations) (new-word-val byte4 byte1 byte2 byte3)))) 28 | 29 | (defn shift-rows 30 | "Cyclically shifts the last three rows of the 4x4 state matrix by different offsets to the left." 31 | [[row1 row2 row3 row4] round-num] 32 | (let [[row2-a row2-b row2-c row2-d] row2 33 | [row3-a row3-b row3-c row3-d] row3 34 | [row4-a row4-b row4-c row4-d] row4 35 | transformed [row1 36 | [row2-b row2-c row2-d row2-a] 37 | [row3-c row3-d row3-a row3-b] 38 | [row4-d row4-a row4-b row4-c]]] 39 | (utils/print-array transformed "after shift-rows" round-num) 40 | (utils/debug-aes round-num "s_row " (utils/matrix-transposition transformed)) 41 | transformed)) 42 | 43 | 44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /src/clojure_aes/encrypt/sub_bytes.clj: -------------------------------------------------------------------------------- 1 | (ns clojure-aes.encrypt.sub-bytes 2 | (:require [clojure-aes.constants :as c] 3 | [clojure-aes.utils :as utils])) 4 | 5 | (defn subWord 6 | "Takes a four-byte input word and substitutes each byte in that word with its appropriate value from the S-Box." 7 | [word] 8 | (let [extract-bytes (fn [word mask shift] 9 | (bit-shift-right 10 | (bit-and mask word) shift)) 11 | byte1 (extract-bytes word 0xff000000 24) 12 | byte2 (extract-bytes word 0x00ff0000 16) 13 | byte3 (extract-bytes word 0x0000ff00 8) 14 | byte4 (extract-bytes word 0x000000ff 0) 15 | top-bits (fn [byte] 16 | (bit-shift-right byte 4)) 17 | bottom-bits (fn [byte] 18 | (bit-and byte 0xf)) 19 | s-byte (fn [row col] 20 | (-> c/sbox 21 | (nth row) 22 | (nth col))) 23 | transform-byte (fn [byte word-loc] 24 | (-> (s-byte (top-bits byte) 25 | (bottom-bits byte)) 26 | (bit-shift-left (* 4 word-loc)))) 27 | new-word (+ (transform-byte byte1 6) 28 | (transform-byte byte2 4) 29 | (transform-byte byte3 2) 30 | (transform-byte byte4 0))] 31 | new-word)) 32 | 33 | (defn subBytes 34 | "Substitutes each byte in the 4x4 state array with its corresponding value from the S-Box." 35 | [[row1 row2 row3 row4] round-num] 36 | (let [calculate-row (fn [row] 37 | (into [] 38 | (for [word row] 39 | (bit-and 0xff 40 | (subWord word))))) 41 | new-row1 (calculate-row row1) 42 | new-row2 (calculate-row row2) 43 | new-row3 (calculate-row row3) 44 | new-row4 (calculate-row row4) 45 | new-state [new-row1 new-row2 new-row3 new-row4]] 46 | (utils/print-array new-state "after subBytes" round-num) 47 | (utils/debug-aes round-num "s_box " (utils/matrix-transposition new-state)) 48 | new-state)) 49 | -------------------------------------------------------------------------------- /src/clojure_aes/main.clj: -------------------------------------------------------------------------------- 1 | (ns clojure-aes.main 2 | (:gen-class) 3 | (:require [clojure-aes.core :as core] 4 | [clojure-aes.utils :as u])) 5 | 6 | (defn -main 7 | "Initial entry point for command line usage" 8 | [& [secret-key message key-length scheme debug-print]] 9 | 10 | (when (= "-v" debug-print) 11 | (println "\nActual Input:") 12 | (println "message: " message ) 13 | (println "key-length:" key-length) 14 | (println "scheme:" scheme)) 15 | 16 | (if-not (and secret-key message key-length scheme) 17 | 18 | (do 19 | (println "\nRequired input: secret-key, message, key-length (in bits), scheme ") 20 | (println "Secret-key (hex-formatted). Example: 526b00c38662e0c58a49ce6ccc83fe9a") 21 | (println "Message (hex-formatted, 16-bytes). Example: 629cdd27509b3d2fe2adb7ec7ff0e6cf4a6c24f4c5ebbf80 ") 22 | (println "Key-length: 192") 23 | (println "Scheme: pass the `-d` flag for decryption; `-e` for encryption") 24 | (println "verbose: pass the `-v` flag for verbose logging of internal state representation throughout encryption and decryption.") 25 | (println "\n Example usage: java -jar target/uberjar/clojure-aes-0.1.0-SNAPSHOT-standalone.jar 629cdd27509b3d2fe2adb7ec7ff0e6cf4a6c24f4c5ebbf80 526b00c38662e0c58a49ce6ccc83fe9a 192 -e ")) 26 | 27 | (let [length (Integer/valueOf key-length) 28 | verbose? (= "-v" debug-print)] 29 | (when verbose? 30 | (reset! u/debug-print true )) 31 | (when (= scheme "-d") 32 | (let [decrypted-result (core/decrypt 33 | secret-key message length verbose?)] 34 | (println decrypted-result) 35 | decrypted-result)) 36 | (when (= scheme "-e") 37 | (let [encrypted-result (core/encrypt 38 | secret-key message length verbose?)] 39 | (println encrypted-result) 40 | encrypted-result))))) 41 | -------------------------------------------------------------------------------- /src/clojure_aes/shared.clj: -------------------------------------------------------------------------------- 1 | (ns clojure-aes.shared) 2 | 3 | (defn msb-1? 4 | "Determines if the most significant bit in the byte is 1." 5 | [byte] 6 | (= 1 (bit-shift-right byte 7))) 7 | 8 | (defn number-of-rounds 9 | "Computes the number of rounds based on the number of bits passed in." 10 | [num-bits] 11 | (cond (= num-bits (or 128 "128")) 10 12 | (= num-bits (or 192 "192")) 12 13 | (= num-bits (or 256 "256")) 14 14 | :else nil)) 15 | 16 | (defn number-of-32bit-words-in-key 17 | "Computes the number of 32-bit words in the key." 18 | [num-bits] 19 | (cond (= num-bits (or 128 "128")) 4 20 | (= num-bits (or 192 "192")) 6 21 | (= num-bits (or 256 "256")) 8 22 | :else nil)) 23 | 24 | (defn combine-four-bytes 25 | "Takes an array of four bytes, and combines them into a single word." 26 | [byte-array] 27 | (let [[byte1 byte2 byte3 byte4] byte-array 28 | word (+ byte4 29 | (bit-shift-left byte3 8) 30 | (bit-shift-left byte2 16) 31 | (bit-shift-left byte1 24))] 32 | word)) 33 | 34 | (defn separate-four-bytes 35 | "Takes a word (4 bytes) and returns a vector with each individual byte of the word." 36 | [word] 37 | (let [extract-fn (fn [offset mask] 38 | (bit-shift-right 39 | (bit-and word mask) 40 | offset)) 41 | byte-1 (extract-fn 24 0xff000000) 42 | byte-2 (extract-fn 16 0xff0000) 43 | byte-3 (extract-fn 8 0xff00) 44 | byte-4 (extract-fn 0 0xff) 45 | separated [byte-1 byte-2 byte-3 byte-4]] 46 | separated)) 47 | 48 | (defn ffAdd 49 | "Adds two bytes in a finite field via xor operation." 50 | [byte1 byte2] 51 | (bit-xor byte1 byte2)) 52 | 53 | (defn xtime 54 | "Multiplies a byte by two in a finite field, bit-xoring if the high bit is set." 55 | [byte-in] 56 | (let [irred-poly 0x1b 57 | shift-left (fn [byte] 58 | (bit-shift-left byte 1)) 59 | full-mask 0xff 60 | should-xor? (fn [byte] 61 | (if (msb-1? byte) 62 | (bit-and full-mask 63 | (bit-xor irred-poly 64 | (shift-left byte))) 65 | (bit-and full-mask 66 | (shift-left byte))))] 67 | (should-xor? byte-in))) 68 | 69 | (defn ffmultiply 70 | "Multiplies two bytes (8 bits apiece) together in a finite field." 71 | [byte-a byte-b] 72 | (let [a (max byte-a byte-b) 73 | b (min byte-a byte-b) 74 | one a 75 | two (xtime one) 76 | three (xtime two) 77 | four (xtime three) 78 | five (xtime four) 79 | six (xtime five) 80 | seven (xtime six) 81 | eight (xtime seven) 82 | bit-and-equal? (fn [mask] 83 | (= mask (bit-and mask b)))] 84 | (cond-> 0x0 85 | (bit-and-equal? 128) (bit-xor eight) 86 | (bit-and-equal? 64) (bit-xor seven) 87 | (bit-and-equal? 32) (bit-xor six) 88 | (bit-and-equal? 16) (bit-xor five) 89 | (bit-and-equal? 8) (bit-xor four) 90 | (bit-and-equal? 4) (bit-xor three) 91 | (bit-and-equal? 2) (bit-xor two) 92 | (bit-and-equal? 1) (bit-xor one)))) 93 | -------------------------------------------------------------------------------- /src/clojure_aes/utils.clj: -------------------------------------------------------------------------------- 1 | (ns clojure-aes.utils) 2 | 3 | (def debug-print (atom false)) 4 | 5 | (defn hexify 6 | "Convert byte sequence to hex string." 7 | [coll] 8 | (let [hex [\0 \1 \2 \3 \4 \5 \6 \7 \8 \9 \a \b \c \d \e \f]] 9 | (letfn [(hexify-byte [b] 10 | (let [v (bit-and b 0xFF)] 11 | [(hex (bit-shift-right v 4)) 12 | (hex (bit-and v 0x0F))]))] 13 | (apply str (mapcat hexify-byte coll))))) 14 | 15 | (defn hexify-str 16 | "Extracts bytes, converts to hex, and outputs a joined version." 17 | [s] 18 | (hexify (.getBytes s))) 19 | 20 | (defn unhexify "Convert hex string to byte sequence." 21 | [s] 22 | (letfn [(unhexify-2 [c1 c2] 23 | (unchecked-byte 24 | (+ (bit-shift-left (Character/digit c1 16) 4) 25 | (Character/digit c2 16))))] 26 | (map #(apply unhexify-2 %) (partition 2 s)))) 27 | 28 | (defn unhexify-str 29 | "Concatenate the unhexified characters." 30 | [s] 31 | (apply str (map char (unhexify s)))) 32 | 33 | (defn break-message-to-bytes 34 | "Takes a string of 16 concatenated hex vals and extracts the values." 35 | [message] 36 | (let [bytes (re-seq #".{1,2}" message) ] 37 | (vec 38 | (for [byte bytes ] 39 | (.intValue (BigInteger. byte 16)))))) 40 | 41 | 42 | (defn matrix-transposition 43 | "Tranposes the matrix `m`" 44 | [m] 45 | (apply mapv vector m)) 46 | 47 | (defn byte-to-hex-string 48 | "Converts a one-dimension array into hex formatted string." 49 | [byte-array] 50 | (map #(format "%02x" %) byte-array)) 51 | 52 | (defn byte2-to-hex-string 53 | "Converts a two-dimension array into hex formatted string." 54 | [state] 55 | (map #(map (fn [e] (format "%02x" e)) 56 | %) 57 | state)) 58 | 59 | (defn print-array 60 | "Print debug info for each round: hex array format" 61 | [state round-type round-num] 62 | (when @debug-print 63 | (println "round: " round-num "stage: " round-type )) 64 | (doseq [row state] 65 | (when @debug-print 66 | (prn (byte-to-hex-string row))))) 67 | 68 | (defn debug-aes 69 | "Print debug info for each round: single string hex-format." 70 | [round-num round-type state] 71 | (let [byte-string (byte2-to-hex-string state)] 72 | (when @debug-print 73 | (prn (str "round[" round-num "]." 74 | round-type " " 75 | (apply str (flatten byte-string))))))) 76 | -------------------------------------------------------------------------------- /target/uberjar/clojure-aes-0.1.4-standalone.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GriffinScribe-LLC/clojure-aes/1924d1e6ca8c42e74040fc69f5eb208d71ed831a/target/uberjar/clojure-aes-0.1.4-standalone.jar -------------------------------------------------------------------------------- /target/uberjar/clojure-aes-0.1.4.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GriffinScribe-LLC/clojure-aes/1924d1e6ca8c42e74040fc69f5eb208d71ed831a/target/uberjar/clojure-aes-0.1.4.jar -------------------------------------------------------------------------------- /target/uberjar/clojure-aes-0.1.5-standalone.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GriffinScribe-LLC/clojure-aes/1924d1e6ca8c42e74040fc69f5eb208d71ed831a/target/uberjar/clojure-aes-0.1.5-standalone.jar -------------------------------------------------------------------------------- /target/uberjar/clojure-aes-0.1.5.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GriffinScribe-LLC/clojure-aes/1924d1e6ca8c42e74040fc69f5eb208d71ed831a/target/uberjar/clojure-aes-0.1.5.jar -------------------------------------------------------------------------------- /test/clojure_aes/core_test.clj: -------------------------------------------------------------------------------- 1 | (ns clojure-aes.core-test 2 | (:require [clojure.test :refer [deftest is testing]] 3 | [clojure-aes.core :as core] 4 | [clojure-aes.constants :as c] 5 | [clojure-aes.encrypt.shift-row :as sr] 6 | [clojure-aes.add-round-key :as ark] 7 | [clojure-aes.shared :as shared] 8 | [clojure-aes.encrypt.mix-columns :as mc] 9 | [clojure-aes.encrypt.sub-bytes :as sb] 10 | [clojure-aes.encrypt.cipher-core :as cipher-core] 11 | [clojure-aes.utils :as utils] 12 | [clojure-aes.decrypt.inverse-shift-rows :as isr] 13 | [clojure-aes.decrypt.inverse-mix-columns :as imc] 14 | [clojure-aes.decrypt.inverse-sub-bytes :as isb])) 15 | 16 | (deftest combine-four-bytes 17 | (testing "Test that a vector of four bytes is transformed correctly into a word" 18 | (let [vec-to-combine [ 0x28 0xae 0xd2 0xa6] 19 | desired 0x28aed2a6] 20 | (is (= desired (shared/combine-four-bytes vec-to-combine) ) 21 | "Failed to combine the bytes accurately")))) 22 | 23 | (deftest separate-four-bytes 24 | (testing "Test that a word is transformed correctly to a vector of four bytes" 25 | (let [word-to-separate 0x28aed2a6 26 | desired [ 0x28 0xae 0xd2 0xa6]] 27 | (is (= desired (shared/separate-four-bytes word-to-separate)) 28 | "Failed to separate the bytes accurately")))) 29 | 30 | (deftest matrix-transposition-test 31 | (testing "Matrix transposition works" 32 | (let [state c/shift-state 33 | expected-state 34 | [[212 191 93 48] 35 | [224 180 82 174] 36 | [184 65 17 241] 37 | [30 39 152 229]]] 38 | (is (= expected-state (utils/matrix-transposition state) ) 39 | "Matrix failed to transpose correctly")))) 40 | 41 | (deftest ffadd-test 42 | (testing "finite field addition" 43 | (let [byte1 0x57 44 | byte2 0x83 45 | expected 0xd4] 46 | (is (= expected (shared/ffAdd byte1 byte2)) 47 | "Finite field addition failed to xor correctly")))) 48 | 49 | (deftest xtime-test 50 | (testing "Computes the doubling of a byte value mod an irreducible polynomial" 51 | (let [initial-byte 0x57 52 | second-byte 0xae 53 | third-byte 0x47 54 | fourth-byte 0x8e 55 | fifth-byte 0x07] 56 | (is (= second-byte (shared/xtime initial-byte)) 57 | "Xtime failed for first byte, with msb not set") 58 | (is (= third-byte (shared/xtime second-byte)) 59 | "Xtime failed for second byte, with msb set") 60 | (is (= fourth-byte (shared/xtime third-byte)) 61 | "Xtime failed for third byte, with msb not set") 62 | (is (= fifth-byte (shared/xtime fourth-byte)) 63 | "Xtime failed for fourth byte, with msb set")))) 64 | 65 | (deftest ffmultiply-test 66 | (testing "finite field multiplication" 67 | (let [byte1 0x57 68 | byte2 0x13 69 | expected 0xfe] 70 | (is (= expected (shared/ffmultiply byte1 byte2)) 71 | "Finite field multiplication failed to xor correctly")))) 72 | 73 | (deftest rotword-test 74 | (testing "Tests that the output word is formed correctly by rotating bytes in the input word " 75 | (let [initial-word1 0x09cf4f3c 76 | initial-word2 0x2a6c7605 77 | expected-rotated-1-word1 0xcf4f3c09 78 | expected-rotated-1-word2 0x6c76052a 79 | expected-rotated-2-word1 0x4f3c09cf 80 | expected-rotated-2-word2 0x76052a6c 81 | expected-rotated-3-word1 0x3c09cf4f 82 | expected-rotated-3-word2 0x052a6c76] 83 | (is (= initial-word1 (sr/rotWord initial-word1 0)) 84 | "Expected word1 shouldn't have any rotations") 85 | (is (= initial-word2 (sr/rotWord initial-word2 0)) 86 | "Expected word2 shouldn't have any rotations") 87 | (is (= initial-word1 (sr/rotWord initial-word1 -4)) 88 | "Expected word1 shouldn't have any rotations") 89 | (is (= initial-word2 (sr/rotWord initial-word2 -4)) 90 | "Expected word2 shouldn't have any rotations") 91 | (is (= expected-rotated-1-word1 (sr/rotWord initial-word1 1)) 92 | "Expected word1 is not rotated correctly with 1 rotation") 93 | (is (= expected-rotated-1-word2 (sr/rotWord initial-word2 1)) 94 | "Expected word2 is not rotated correctly with 1 rotation") 95 | (is (= expected-rotated-2-word1 (sr/rotWord initial-word1 2)) 96 | "Expected word2 is not rotated correctly with 2 rotations") 97 | (is (= expected-rotated-2-word2 (sr/rotWord initial-word2 2)) 98 | "Expected word2 is not rotated correctly with 2 rotations") 99 | (is (= expected-rotated-3-word1 (sr/rotWord initial-word1 3)) 100 | "Expected word2 is not rotated correctly with 3 rotations") 101 | (is (= expected-rotated-3-word2 (sr/rotWord initial-word2 3)) 102 | "Expected word2 is not rotated correctly with 3 rotations")))) 103 | 104 | (deftest shift-row-test 105 | (testing "verifies that the shift-row function works as specified in the specs of FIBS 197" 106 | (let [initial-state [[1 2 3 4] 107 | [5 6 7 8] 108 | [9 10 11 12] 109 | [13 14 15 16]] 110 | expected-vector [[1 2 3 4] 111 | [6 7 8 5] 112 | [11 12 9 10] 113 | [16 13 14 15]] 114 | result-state (sr/shift-rows initial-state 0)] 115 | (is (= expected-vector result-state ) 116 | "Failed: bytes were not shifted accurately")))) 117 | 118 | (deftest subWord-test 119 | (testing "Takes a four-byte input word and substitutes each byte in that word with its appropriate value from the S-Box." 120 | (let [word1 0x00102030 121 | expected-word1 0x63cab704 122 | word2 0x40506070 123 | expected-word2 0x0953d051 124 | word3 0x8090a0b0 125 | expected-word3 0xcd60e0e7 126 | word4 0xc0d0e0f0 127 | expected-word4 0xba70e18c] 128 | (is (= expected-word1 (sb/subWord word1)) 129 | "Word1 was not transformed correctly by the sbox transformation.") 130 | (is (= expected-word2 (sb/subWord word2)) 131 | "Word2 was not transformed correctly by the sbox transformation.") 132 | (is (= expected-word3 (sb/subWord word3)) 133 | "Word3 was not transformed correctly by the sbox transformation.") 134 | (is (= expected-word4 (sb/subWord word4)) 135 | "Word4 was not transformed correctly by the sbox transformation.")))) 136 | 137 | (deftest subBytes-test 138 | (testing "Test that the subBytes transformation accurately transforms the state" 139 | (is (= c/sub-state (sb/subBytes c/state 0)) 140 | "SubBytes function failed to transform the state accurately."))) 141 | 142 | (deftest mixColumns-test 143 | (testing "Test that the mixColumns transformation accurately transforms the state (shift-state)" 144 | (is (= c/mix-state (mc/mixColumns c/shift-state 0)) 145 | "mixColumns function failed to transform the state accurately."))) 146 | 147 | (deftest keyExpansion-test 148 | (testing "Ensures that the key expands correctly" 149 | (let [expected-key-128 c/initial-key-expanded-128 150 | num-bits-128 128 151 | expected-key-192 c/initial-key-expanded-192 152 | num-bits-192 192 153 | expected-key-256 c/initial-key-expanded-256 154 | num-bits-256 256] 155 | (is (= expected-key-128 (core/key-expansion c/initial-key-128 num-bits-128)) 156 | "Expanded key with 128 bits is not accurate") 157 | (is (= expected-key-192 (core/key-expansion c/initial-key-192 num-bits-192)) 158 | "Expanded key with 192 bits is not accurate") 159 | (is (= expected-key-256 (core/key-expansion c/initial-key-256 num-bits-256)) 160 | "Expanded key with 256 bits is not accurate")))) 161 | 162 | (deftest addRoundKey-round0-test 163 | (testing "Test that the addRoundKey transformation accurately transforms the state on start 0" 164 | (let [secret-key [0x2b 0x7e 0x15 0x16 165 | 0x28 0xae 0xd2 0xa6 166 | 0xab 0xf7 0x15 0x88 167 | 0x09 0xcf 0x4f 0x3c] 168 | num-bits 128 169 | key-expanded (core/key-expansion secret-key num-bits) 170 | plain-text [[0x32, 0x43, 0xf6, 0xa8] 171 | [0x88, 0x5a, 0x30, 0x8d] 172 | [0x31, 0x31, 0x98, 0xa2] 173 | [0xe0, 0x37, 0x07, 0x34] ] 174 | expected [[0x19 0xa0 0x9a 0xe9] 175 | [0x3d 0xf4 0xc6 0xf8] 176 | [0xe3 0xe2 0x8d 0x48] 177 | [0xbe 0x2b 0x2a 0x8]] ] 178 | (is (= expected 179 | (ark/addRoundKey 180 | (utils/matrix-transposition plain-text) 181 | key-expanded 182 | 0)) 183 | "AddRoundKey function for 128 bits failed to transform the state accurately on the zeroeth round.")))) 184 | 185 | (deftest cipher-test 186 | (testing "Integration test of cipher function, which encrypts the input by various calls to subBytes, shiftRows, mixColumns, and addRoundKey" 187 | (let [ num-bits-128 128 188 | input-128-2 [[0x32, 0x43, 0xf6, 0xa8] 189 | [0x88, 0x5a, 0x30, 0x8d] 190 | [0x31, 0x31, 0x98, 0xa2] 191 | [0xe0, 0x37, 0x07, 0x34] ] 192 | expected-128-2 [[0x39, 0x25, 0x84, 0x1d] 193 | [0x02, 0xdc, 0x09, 0xfb] 194 | [0xdc, 0x11, 0x85, 0x97] 195 | [0x19, 0x6a, 0x0b, 0x32]] 196 | key-2 [0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, 197 | 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c] 198 | expanded-key-2 (core/key-expansion key-2 num-bits-128) 199 | 200 | plain-text [[0x00 0x11 0x22 0x33] 201 | [0x44 0x55 0x66 0x77] 202 | [0x88 0x99 0xaa 0xbb] 203 | [0xcc 0xdd 0xee 0xff]] 204 | 205 | key [0x00 0x01 0x02 0x03 206 | 0x04 0x05 0x06 0x07 207 | 0x08 0x09 0x0a 0x0b 208 | 0x0c 0x0d 0x0e 0x0f] 209 | expanded-key (core/key-expansion key num-bits-128) 210 | expected [[0x69 0xc4 0xe0 0xd8] 211 | [0x6a 0x7b 0x04 0x30] 212 | [0xd8 0xcd 0xb7 0x80] 213 | [0x70 0xb4 0xc5 0x5a]]] 214 | (is (= expected 215 | (cipher-core/cipher plain-text 216 | expanded-key 217 | num-bits-128 218 | key)) 219 | "Input text was not encrypted per AES standard for 128 bits.") 220 | (is (= expected-128-2 221 | (cipher-core/cipher input-128-2 222 | expanded-key-2 223 | num-bits-128 224 | key-2)) 225 | "Input text was not encrypted per AES standard for 128 bits.")))) 226 | 227 | (deftest cipher-128-test 228 | (testing "Test that aes algorithm encrypts message with 128-bit key correctly" 229 | (let [message "2d2eac399c50fab7b0c86e4b94b61fac" 230 | key-128 "629cdd27509b3d2fe2adb7ec7ff0e6cf" 231 | expected "d8d1888cfced26f85ea422d4fd56e0ef"] 232 | (is (= expected (core/encrypt key-128 message 128)) 233 | "Message with 128-bit key failed to encrypt correctly")))) 234 | 235 | (deftest cipher-192-test 236 | (testing "Test that aes algorithm encrypts message with 192-bit key correctly" 237 | (let [message "526b00c38662e0c58a49ce6ccc83fe9a" 238 | key-192 "629cdd27509b3d2fe2adb7ec7ff0e6cf4a6c24f4c5ebbf80" 239 | expected "a953e8cf02e51d6f42e30be9910c9cde"] 240 | (is (= expected (core/encrypt key-192 message 192)) 241 | "Message with 192-bit key failed to encrypt correctly")))) 242 | 243 | (deftest cipher-256-test 244 | (testing "Test that aes algorithm encrypts message with 256-bit key correctly" 245 | (let [message "1a57bbfeeefc417d203494788f3ba2c8" 246 | key-256 "629cdd27509b3d2fe2adb7ec7ff0e6cf4a6c24f4c5ebbf80c38d25f8fc54c649" 247 | expected "2ace987331c0d3e57479dd7037103028"] 248 | (is (= expected (core/encrypt key-256 message 256)) 249 | "Message with 256-bit key failed to encrypt correctly")))) 250 | 251 | (deftest inv-shiftRows-test 252 | (testing "Test that the inv-shiftRows transformation accurately transforms the state (sub-state)" 253 | (let [initial-state [[212 224 184 30] 254 | [39 191 180 65] 255 | [17 152 93 82] 256 | [174 241 229 48]] 257 | expected-state [[212 224 184 30] 258 | [65 39 191 180] 259 | [93 82 17 152] 260 | [241 229 48 174]]] 261 | (is (= expected-state (isr/inv-shift-rows initial-state 0)) 262 | "inv-shiftRows function failed to transform the state accurately.")))) 263 | 264 | (deftest inv-sub-word-test 265 | (testing "Takes a four-byte input word and substitutes each byte in that word with its appropriate value from the inv S-Box." 266 | (let [word1 0x63cab704 267 | expected-word1 0x00102030 268 | word2 0x0953d051 269 | expected-word2 0x40506070 270 | word3 0xcd60e0e7 271 | expected-word3 0x8090a0b0 272 | word4 0xba70e18c 273 | expected-word4 0xc0d0e0f0 ] 274 | (is (= expected-word1 (isb/inv-subWord word1)) 275 | "Word1 was not transformed correctly by the inv-sbox transformation.") 276 | (is (= expected-word2 (isb/inv-subWord word2)) 277 | "Word2 was not transformed correctly by the inv-sbox transformation.") 278 | (is (= expected-word3 (isb/inv-subWord word3)) 279 | "Word3 was not transformed correctly by the inv-sbox transformation.") 280 | (is (= expected-word4 (isb/inv-subWord word4)) 281 | "Word4 was not transformed correctly by the inv-sbox transformation.")))) 282 | 283 | (deftest inv-sub-bytes-test 284 | (testing "Test that the inv-sub-bytes transformation accurately transforms the state" 285 | (is (= c/sub-state (sb/subBytes c/state 0)) 286 | "inv-sub-bytes function failed to transform the state accurately."))) 287 | 288 | (deftest inv-mixColumns-test 289 | (testing "Test that the inv-mixColumns transformation accurately transforms the state" 290 | (is (= c/shift-state (imc/inv-mixColumns c/mix-state 0)) 291 | "inv-mixColumns function failed to transform the state accurately."))) 292 | 293 | (deftest inv-cipher-128-test 294 | (testing "Test that aes algorithm decrypts message with 128-bit key correctly" 295 | (let [message "0f2d64db78cdaec2a710554fb436df40" 296 | key-128 "629cdd27509b3d2fe2adb7ec7ff0e6cf" 297 | expected "ce711b1dd332f008cea7445507ab0738"] 298 | (is (= expected (core/decrypt key-128 message 128)) 299 | "Message with 128-bit key failed to decrypt correctly")))) 300 | 301 | (deftest inv-cipher-192-test 302 | (testing "Test that aes algorithm encrypts message with 192-bit key correctly" 303 | (let [message "4b75c65e5e26f261afb18955c8cce7bf" 304 | key-192 "629cdd27509b3d2fe2adb7ec7ff0e6cf4a6c24f4c5ebbf80" 305 | expected "c8a08456e9211688ea1a8d0cfb0656bb"] 306 | (is (= expected (core/decrypt key-192 message 192)) 307 | "Message with 192-bit key failed to decrypt correctly")))) 308 | 309 | (deftest inv-cipher-256-test 310 | (testing "Test that aes algorithm encrypts message with 256-bit key correctly" 311 | (let [message "2db70585ca50215c2a449261542462dd" 312 | key-256 "629cdd27509b3d2fe2adb7ec7ff0e6cf4a6c24f4c5ebbf80c38d25f8fc54c649" 313 | expected "fce6c0a79b4787d0c10f7254fa55b045"] 314 | (is (= expected (core/decrypt key-256 message 256)) 315 | "Message with 256-bit key failed to decrypt correctly")))) 316 | 317 | ;;; appendix c tests taken from https://csrc.nist.gov/csrc/media/publications/fips/197/final/documents/fips-197.pdf 318 | (deftest cipher-128-test-appendix-c 319 | (testing "Test that aes algorithm encrypts message with 128-bit key correctly from appendix c" 320 | (let [message "00112233445566778899aabbccddeeff" 321 | key-128 "000102030405060708090a0b0c0d0e0f" 322 | expected "69c4e0d86a7b0430d8cdb78070b4c55a"] 323 | (is (= expected (core/encrypt key-128 message 128)) 324 | "Message with 128-bit key failed to encrypt correctly from appendix c")))) 325 | 326 | (deftest inv-cipher-128-test-appendix-c 327 | (testing "Test that aes algorithm decrypts message with 128-bit key correctly from appendix c" 328 | (let [message "69c4e0d86a7b0430d8cdb78070b4c55a" 329 | key-128 "000102030405060708090a0b0c0d0e0f" 330 | expected "00112233445566778899aabbccddeeff"] 331 | (is (= expected (core/decrypt key-128 message 128)) 332 | "Message with 128-bit key failed to decrypt correctly from appendix c")))) 333 | 334 | (deftest cipher-192-test-appendix-c 335 | (testing "Test that aes algorithm encrypts message with 192-bit key correctly from appendix c" 336 | (let [message "526b00c38662e0c58a49ce6ccc83fe9a" 337 | key-192 "629cdd27509b3d2fe2adb7ec7ff0e6cf4a6c24f4c5ebbf80" 338 | expected "a953e8cf02e51d6f42e30be9910c9cde"] 339 | (is (= expected (core/encrypt key-192 message 192)) 340 | "Message with 192-bit key failed to encrypt correctly from appendix c")))) 341 | 342 | (deftest inv-cipher-192-test-appendix-c 343 | (testing "Test that aes algorithm encrypts message with 192-bit key correctly from appendix c" 344 | (let [message "a953e8cf02e51d6f42e30be9910c9cde" 345 | key-192 "629cdd27509b3d2fe2adb7ec7ff0e6cf4a6c24f4c5ebbf80" 346 | expected "526b00c38662e0c58a49ce6ccc83fe9a"] 347 | (is (= expected (core/decrypt key-192 message 192)) 348 | "Message with 192-bit key failed to decrypt correctly from appendix c")))) 349 | 350 | (deftest cipher-256-test-appendix-c 351 | (testing "Test that aes algorithm encrypts message with 256-bit key correctly from appendix c" 352 | (let [message "1a57bbfeeefc417d203494788f3ba2c8" 353 | key-256 "629cdd27509b3d2fe2adb7ec7ff0e6cf4a6c24f4c5ebbf80c38d25f8fc54c649" 354 | expected "2ace987331c0d3e57479dd7037103028"] 355 | (is (= expected (core/encrypt key-256 message 256)) 356 | "Message with 256-bit key failed to encrypt correctly from appendix c")))) 357 | 358 | (deftest inv-cipher-256-test-appendix-c 359 | (testing "Test that aes algorithm encrypts message with 256-bit key correctly from appendix c" 360 | (let [message "2ace987331c0d3e57479dd7037103028" 361 | key-256 "629cdd27509b3d2fe2adb7ec7ff0e6cf4a6c24f4c5ebbf80c38d25f8fc54c649" 362 | expected "1a57bbfeeefc417d203494788f3ba2c8"] 363 | (is (= expected (core/decrypt key-256 message 256)) 364 | "Message with 256-bit key failed to decrypt correctly from appendix c")))) 365 | 366 | 367 | --------------------------------------------------------------------------------