├── .editorconfig ├── .github ├── CODEOWNERS └── workflows │ ├── archive.yml │ ├── ghpages.yml │ ├── publish.yml │ └── update.yml ├── .gitignore ├── .note.xml ├── CONTRIBUTING.md ├── LICENSE.md ├── Makefile ├── README.md ├── draft-irtf-cfrg-aegis-aead.md ├── reference-implementations ├── aegis128l.zig ├── aegis128x.zig ├── aegis256.zig ├── aegis256x.zig ├── build.zig └── tests.zig └── test-vectors ├── aegis-128l-test-vectors.json ├── aegis-128x2-test-vectors.json ├── aegis-128x4-test-vectors.json ├── aegis-256-test-vectors.json ├── aegis-256x2-test-vectors.json ├── aegis-256x4-test-vectors.json ├── aegismac-test-vectors.json ├── aesround-test-vector.json └── gen.py /.editorconfig: -------------------------------------------------------------------------------- 1 | # See http://editorconfig.org 2 | 3 | root = true 4 | 5 | [*.{md,xml,org}] 6 | charset = utf-8 7 | insert_final_newline = true 8 | trim_trailing_whitespace = true 9 | -------------------------------------------------------------------------------- /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | draft-irtf-cfrg-aegis-aead.md fde@00f.net fabio@esse.ch @samuel-lucas6 2 | /reference-implementations/ @jedisct1 3 | -------------------------------------------------------------------------------- /.github/workflows/archive.yml: -------------------------------------------------------------------------------- 1 | name: "Archive Issues and Pull Requests" 2 | 3 | on: 4 | schedule: 5 | - cron: '0 0 * * 0,2,4' 6 | repository_dispatch: 7 | types: [archive] 8 | workflow_dispatch: 9 | inputs: 10 | archive_full: 11 | description: 'Recreate the archive from scratch' 12 | default: false 13 | type: boolean 14 | 15 | jobs: 16 | build: 17 | name: "Archive Issues and Pull Requests" 18 | runs-on: ubuntu-latest 19 | permissions: 20 | contents: write 21 | steps: 22 | - name: "Checkout" 23 | uses: actions/checkout@v4 24 | 25 | # Note: No caching for this build! 26 | 27 | - name: "Update Archive" 28 | uses: martinthomson/i-d-template@v1 29 | env: 30 | ARCHIVE_FULL: ${{ inputs.archive_full }} 31 | with: 32 | make: archive 33 | token: ${{ github.token }} 34 | 35 | - name: "Update GitHub Pages" 36 | uses: martinthomson/i-d-template@v1 37 | with: 38 | make: gh-archive 39 | token: ${{ github.token }} 40 | 41 | - name: "Save Archive" 42 | uses: actions/upload-artifact@v4 43 | with: 44 | path: archive.json 45 | -------------------------------------------------------------------------------- /.github/workflows/ghpages.yml: -------------------------------------------------------------------------------- 1 | name: "Update Editor's Copy" 2 | 3 | on: 4 | push: 5 | paths-ignore: 6 | - README.md 7 | - CONTRIBUTING.md 8 | - LICENSE.md 9 | - .gitignore 10 | pull_request: 11 | paths-ignore: 12 | - README.md 13 | - CONTRIBUTING.md 14 | - LICENSE.md 15 | - .gitignore 16 | 17 | jobs: 18 | build: 19 | name: "Update Editor's Copy" 20 | runs-on: ubuntu-latest 21 | permissions: 22 | contents: write 23 | steps: 24 | - name: "Checkout" 25 | uses: actions/checkout@v4 26 | 27 | - name: "Setup" 28 | id: setup 29 | run: date -u "+date=%FT%T" >>"$GITHUB_OUTPUT" 30 | 31 | - name: "Caching" 32 | uses: actions/cache@v4 33 | with: 34 | path: | 35 | .refcache 36 | .venv 37 | .gems 38 | node_modules 39 | .targets.mk 40 | key: i-d-${{ steps.setup.outputs.date }} 41 | restore-keys: i-d- 42 | 43 | - name: "Build Drafts" 44 | uses: martinthomson/i-d-template@v1 45 | with: 46 | token: ${{ github.token }} 47 | 48 | - name: "Update GitHub Pages" 49 | uses: martinthomson/i-d-template@v1 50 | if: ${{ github.event_name == 'push' }} 51 | with: 52 | make: gh-pages 53 | token: ${{ github.token }} 54 | 55 | - name: "Archive Built Drafts" 56 | uses: actions/upload-artifact@v4 57 | with: 58 | path: | 59 | draft-*.html 60 | draft-*.txt 61 | -------------------------------------------------------------------------------- /.github/workflows/publish.yml: -------------------------------------------------------------------------------- 1 | name: "Publish New Draft Version" 2 | 3 | on: 4 | push: 5 | tags: 6 | - "draft-*" 7 | workflow_dispatch: 8 | inputs: 9 | email: 10 | description: "Submitter email" 11 | default: "" 12 | type: string 13 | 14 | jobs: 15 | build: 16 | name: "Publish New Draft Version" 17 | runs-on: ubuntu-latest 18 | steps: 19 | - name: "Checkout" 20 | uses: actions/checkout@v4 21 | 22 | # See https://github.com/actions/checkout/issues/290 23 | - name: "Get Tag Annotations" 24 | run: git fetch -f origin ${{ github.ref }}:${{ github.ref }} 25 | 26 | - name: "Setup" 27 | id: setup 28 | run: date -u "+date=%FT%T" >>"$GITHUB_OUTPUT" 29 | 30 | - name: "Caching" 31 | uses: actions/cache@v4 32 | with: 33 | path: | 34 | .refcache 35 | .venv 36 | .gems 37 | node_modules 38 | .targets.mk 39 | key: i-d-${{ steps.setup.outputs.date }} 40 | restore-keys: i-d- 41 | 42 | - name: "Build Drafts" 43 | uses: martinthomson/i-d-template@v1 44 | with: 45 | token: ${{ github.token }} 46 | 47 | - name: "Upload to Datatracker" 48 | uses: martinthomson/i-d-template@v1 49 | with: 50 | make: upload 51 | env: 52 | UPLOAD_EMAIL: ${{ inputs.email }} 53 | 54 | - name: "Archive Submitted Drafts" 55 | uses: actions/upload-artifact@v4 56 | with: 57 | path: "versioned/draft-*-[0-9][0-9].*" 58 | -------------------------------------------------------------------------------- /.github/workflows/update.yml: -------------------------------------------------------------------------------- 1 | name: "Update Generated Files" 2 | # This rule is not run automatically. 3 | # It can be run manually to update all of the files that are part 4 | # of the template, specifically: 5 | # - README.md 6 | # - CONTRIBUTING.md 7 | # - .note.xml 8 | # - .github/CODEOWNERS 9 | # - Makefile 10 | # 11 | # 12 | # This might be useful if you have: 13 | # - added, removed, or renamed drafts (including after adoption) 14 | # - added, removed, or changed draft editors 15 | # - changed the title of drafts 16 | # 17 | # Note that this removes any customizations you have made to 18 | # the affected files. 19 | on: workflow_dispatch 20 | 21 | jobs: 22 | build: 23 | name: "Update Files" 24 | runs-on: ubuntu-latest 25 | steps: 26 | - name: "Checkout" 27 | uses: actions/checkout@v4 28 | 29 | - name: "Update Generated Files" 30 | uses: martinthomson/i-d-template@v1 31 | with: 32 | make: update-files 33 | token: ${{ github.token }} 34 | 35 | - name: "Push Update" 36 | run: git push 37 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.html 2 | *.pdf 3 | *.redxml 4 | *.swp 5 | *.txt 6 | *.upload 7 | *~ 8 | .refcache 9 | .tags 10 | .targets.mk 11 | /*-[0-9][0-9].xml 12 | archive.json 13 | draft-irtf-cfrg-aegis-aead.xml 14 | lib 15 | report.xml 16 | venv/ 17 | reference-implementations/.zig-cache 18 | versioned/ 19 | -------------------------------------------------------------------------------- /.note.xml: -------------------------------------------------------------------------------- 1 | 2 | Source for this draft and an issue tracker can be found at 3 | . 4 | 5 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | This repository relates to activities in the Internet Engineering Task Force 4 | ([IETF](https://www.ietf.org/)). All material in this repository is considered 5 | Contributions to the IETF Standards Process, as defined in the intellectual 6 | property policies of IETF currently designated as 7 | [BCP 78](https://www.rfc-editor.org/info/bcp78), 8 | [BCP 79](https://www.rfc-editor.org/info/bcp79) and the 9 | [IETF Trust Legal Provisions (TLP) Relating to IETF Documents](http://trustee.ietf.org/trust-legal-provisions.html). 10 | 11 | Any edit, commit, pull request, issue, comment or other change made to this 12 | repository constitutes Contributions to the IETF Standards Process 13 | (https://www.ietf.org/). 14 | 15 | You agree to comply with all applicable IETF policies and procedures, including, 16 | BCP 78, 79, the TLP, and the TLP rules regarding code components (e.g. being 17 | subject to a Simplified BSD License) in Contributions. 18 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | # License 2 | 3 | See the 4 | [guidelines for contributions](https://github.com/cfrg/draft-irtf-cfrg-aegis-aead/blob/main/CONTRIBUTING.md). 5 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | LIBDIR := lib 2 | include $(LIBDIR)/main.mk 3 | 4 | $(LIBDIR)/main.mk: 5 | ifneq (,$(shell grep "path *= *$(LIBDIR)" .gitmodules 2>/dev/null)) 6 | git submodule sync 7 | git submodule update $(CLONE_ARGS) --init 8 | else 9 | git clone \ 10 | -b main https://github.com/martinthomson/i-d-template $(LIBDIR) 11 | endif 12 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # The AEGIS Family Of Authenticated Encryption Algorithms 2 | 3 | This is the working area for the individual Internet-Draft, "The AEGIS family of authenticated encryption algorithms". 4 | 5 | * [Editor's Copy](https://cfrg.github.io/draft-irtf-cfrg-aegis-aead/#go.draft-irtf-cfrg-aegis-aead.html) 6 | * [Datatracker Page](https://datatracker.ietf.org/doc/draft-irtf-cfrg-aegis-aead) 7 | * [Individual Draft](https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-aegis-aead) 8 | * [Compare Editor's Copy to Individual Draft](https://cfrg.github.io/draft-irtf-cfrg-aegis-aead/#go.draft-irtf-cfrg-aegis-aead.diff) 9 | 10 | ## Known Implementations 11 | 12 | | Name | Language | 13 | | ----------------------------------------------------------------------------------------------------------------------------------- | ----------------- | 14 | | [This document's reference implementations](https://github.com/cfrg/draft-irtf-cfrg-aegis-aead/tree/main/reference-implementations) | Zig | 15 | | [CAESAR reference AEGIS-128L implementations](https://github.com/jedisct1/supercop/tree/master/crypto_aead/aegis128l) | C | 16 | | [CAESAR reference AEGIS-256 implementations](https://github.com/jedisct1/supercop/tree/master/crypto_aead/aegis256) | C | 17 | | [Linux kernel](https://cregit.linuxsources.org/code/5.0/arch/x86/crypto/aegis128l-aesni-glue.c.html) | C | 18 | | [libsodium](https://libsodium.org) | C | 19 | | [angt/aegis256](https://github.com/angt/aegis256) | C | 20 | | [TwoEightNine/aegis](https://github.com/TwoEightNine/aegis) | C | 21 | | [libaegis](https://github.com/aegis-aead/libaegis) | C | 22 | | [aegis-bitsliced](https://github.com/aegis-aead/aegis-bitsliced) | C | 23 | | [google/aegis-cipher](https://github.com/google/aegis_cipher) | C++ | 24 | | [aegis](https://crates.io/crates/aegis) | Rust | 25 | | [raycrypt](https://github.com/somehybrid/raycrypt/tree/main/src/aeads/aegis256) | Rust | 26 | | [crypto-rust](https://github.com/sayantn/crypto-rust/tree/master/src/) | Rust | 27 | | [aegis-cl](https://github.com/conradludgate/aegis-cl) | Rust | 28 | | [Zig standard library](https://github.com/ziglang/zig/blob/master/lib/std/crypto/aegis.zig) | Zig | 29 | | [x13a/py-aegis](https://github.com/x13a/py-aegis) | Python | 30 | | [ericlagergren/aegis](https://github.com/ericlagergren/aegis) | Go | 31 | | [samuel-lucas6/AEGIS.NET](https://github.com/samuel-lucas6/AEGIS.NET) | C# | 32 | | [arc.crypto](https://github.com/archi-Doc/Arc.Crypto/tree/main/Arc.Crypto/Encryption/Aegis) | C# | 33 | | [aegis-128L](https://github.com/Sayem98/aegis-128L) | JavaScript | 34 | | [aegis-js](https://github.com/psve/aegis-js) | JavaScript | 35 | | [aegis-kotlin](https://github.com/psve/aegis-kotlin) | Kotlin | 36 | | [aegis-jasmin](https://github.com/aegis-aead/aegis-jasmin) | Assembly (Jasmin) | 37 | | [aegis-java](https://github.com/aegis-aead/aegis-java) | Java | 38 | | [moonbit-aegis](https://github.com/jedisct1/moonbit-aegis) | Moonbit | 39 | | [sodium-compat](https://github.com/paragonie/sodium_compat/tree/master/src/Core/AEGIS) | PHP | 40 | | [aegis-ts](https://github.com/stknob/aegis-ts) | TypeScript | 41 | | [yawning/odin](https://github.com/Yawning/Odin/commit/00e013bd1e62e237c37b3b848eb4163e9c183ca0) | Odin | 42 | 43 | ### Hardware implementations 44 | 45 | | Name | Language | 46 | | ------------------------------------------------------------------------------------ | ------------- | 47 | | [Athena/AEGIS](https://cryptography.gmu.edu/athena/index.php?id=CAESAR_source_codes) | RTL VHDL | 48 | | [AEGIS256 UVM Verification](https://github.com/aymanaadel/AEGIS256_UVM_Verification) | SystemVerilog | 49 | 50 | ## AEGIS support in TLS stacks 51 | 52 | - [Experimental support for BoringSSL](https://github.com/aegis-aead/boringssl/tree/aegis) 53 | - [Experimental support for OpenSSL](https://github.com/aegis-aead/openssl/tree/aegis) 54 | - [Facebook's Fizz](https://github.com/facebookincubator/fizz) 55 | - [PicoTLS](https://github.com/h2o/picotls) 56 | - [Zig TLS client](https://ziglang.org/documentation/master/std/#A;std:crypto.tls.CipherSuite) 57 | 58 | ## Test vectors 59 | 60 | For convenience, test vectors can be downloaded in JSON format from the [`test-vectors` directory](https://github.com/cfrg/draft-irtf-cfrg-aegis-aead/tree/main/test-vectors). 61 | 62 | Project Wycheproof includes additional test vectors: 63 | 64 | * [for AEGIS-128L](https://github.com/C2SP/wycheproof/blob/master/testvectors/aegis128L_test.json) 65 | * [for AEGIS-256](https://github.com/C2SP/wycheproof/blob/master/testvectors/aegis256_test.json) 66 | 67 | Project Rooterberg also includes an extensive set of [test vectors for AEGIS variants](https://github.com/bleichenbacher-daniel/Rooterberg/tree/main/test_vectors/aead). 68 | 69 | ## Contributing 70 | 71 | See the 72 | [guidelines for contributions](https://github.com/cfrg/draft-irtf-cfrg-aegis-aead/blob/main/CONTRIBUTING.md). 73 | 74 | Contributions can be made by creating pull requests. 75 | The GitHub interface supports creating pull requests using the Edit (✏) button. 76 | 77 | ## Command Line Usage 78 | 79 | Formatted text and HTML versions of the draft can be built using `make`. 80 | 81 | ```sh 82 | $ make 83 | ``` 84 | 85 | Command line usage requires that you have the necessary software installed. See 86 | [the instructions](https://github.com/martinthomson/i-d-template/blob/main/doc/SETUP.md). 87 | -------------------------------------------------------------------------------- /draft-irtf-cfrg-aegis-aead.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "The AEGIS Family of Authenticated Encryption Algorithms" 3 | docname: draft-irtf-cfrg-aegis-aead-latest 4 | category: info 5 | 6 | ipr: trust200902 7 | keyword: Internet-Draft 8 | workgroup: Crypto Forum 9 | submissionType: IRTF 10 | 11 | stand_alone: yes 12 | smart_quotes: yes 13 | pi: [toc, sortrefs, symrefs] 14 | 15 | author: 16 | - 17 | name: Frank Denis 18 | organization: Fastly Inc. 19 | email: fde@00f.net 20 | - 21 | name: Samuel Lucas 22 | organization: Individual Contributor 23 | email: samuel-lucas6@pm.me 24 | 25 | informative: 26 | 27 | AEGIS: 28 | title: "AEGIS: A Fast Authenticated Encryption Algorithm (v1.1)" 29 | venue: CAESAR Competition 30 | target: https://competitions.cr.yp.to/round3/aegisv11.pdf 31 | author: 32 | - 33 | ins: H. Wu 34 | name: Hongjun Wu 35 | org: Nanyang Technological University 36 | - 37 | ins: B. Preneel 38 | name: Bart Preneel 39 | org: KU Leuven 40 | date: 2016 41 | 42 | AIKRS24: 43 | title: "Differential fault attack on AES-based encryption schemes: application to B5G/6G ciphers—Rocca, Rocca-S and AEGIS" 44 | rc: "Journal of Cryptographic Engineering, 2024" 45 | seriesinfo: 46 | DOI: 10.1007/s13389-024-00360-6 47 | author: 48 | - 49 | ins: R. Anand 50 | name: Ravi Anand 51 | org: Indraprastha Institute of Information Technology Delhi; University of Hyogo 52 | - 53 | ins: T. Isobe 54 | name: Takanori Isobe 55 | org: University of Hyogo 56 | - 57 | ins: A. K. Kundu 58 | name: Anup Kumar Kundu 59 | org: Indian Statistical Institute Kolkata 60 | - 61 | ins: M. Rahman 62 | name: Mostafizar Rahman 63 | org: University of Hyogo 64 | - 65 | ins: S. Suryawanshi 66 | name: Sahiba Suryawanshi 67 | org: University of Hyogo; Indian Institute of Technology Bhilai 68 | date: 2024 69 | 70 | BS23: 71 | title: "Single-query Quantum Hidden Shift Attacks" 72 | rc: "Cryptology ePrint Archive, Paper 2023/1306" 73 | target: https://eprint.iacr.org/2023/1306 74 | author: 75 | - 76 | ins: X. Bonnetain 77 | name: Xavier Bonnetain 78 | org: Université de Lorraine, CNRS, Inria, LORIA 79 | - 80 | ins: A. Schrottenloher 81 | name: André Schrottenloher 82 | org: Université de Rennes, CNRS, Inria, IRISA 83 | date: 2023 84 | 85 | D23: 86 | title: "Adding more parallelism to the AEGIS authenticated encryption algorithms" 87 | rc: "Cryptology ePrint Archive, Paper 2023/523" 88 | target: https://eprint.iacr.org/2023/523 89 | author: 90 | - 91 | ins: F. Denis 92 | name: Frank Denis 93 | org: Fastly Inc. 94 | date: 2023 95 | 96 | ENP20: 97 | title: "Analyzing the Linear Keystream Biases in AEGIS" 98 | rc: "IACR Transactions on Symmetric Cryptology, 2019(4), pp. 348–368" 99 | seriesinfo: 100 | DOI: 10.13154/tosc.v2019.i4.348-368 101 | author: 102 | - 103 | ins: M. Eichlseder 104 | name: Maria Eichlseder 105 | org: Graz University of Technology 106 | - 107 | ins: M. Nageler 108 | name: Marcel Nageler 109 | org: Graz University of Technology 110 | - 111 | ins: R. Primas 112 | name: Robert Primas 113 | org: Graz University of Technology 114 | date: 2020 115 | 116 | FLLW17: 117 | title: "Reforgeability of Authenticated Encryption Schemes" 118 | rc: "Cryptology ePrint Archive, Paper 2017/332" 119 | target: https://eprint.iacr.org/2017/332 120 | author: 121 | - 122 | ins: C. Forler 123 | name: Christian Forler 124 | org: Beuth Hochschule für Technik Berlin 125 | - 126 | ins: E. List 127 | name: Eik List 128 | org: Bauhaus-Universität Weimar 129 | - 130 | ins: S. Lucks 131 | name: Stefan Lucks 132 | org: Bauhaus-Universität Weimar 133 | - 134 | ins: J. Wenzel 135 | name: Jakob Wenzel 136 | org: Bauhaus-Universität Weimar 137 | date: 2017 138 | 139 | IR23: 140 | title: "Key Committing Security Analysis of AEGIS" 141 | rc: "Cryptology ePrint Archive, Paper 2023/1495" 142 | target: https://eprint.iacr.org/2023/1495 143 | author: 144 | - 145 | ins: T. Isobe 146 | name: Takanori Isobe 147 | org: University of Hyogo 148 | - 149 | ins: M. Rahman 150 | name: Mostafizar Rahman 151 | org: University of Hyogo 152 | date: 2023 153 | 154 | JLD22: 155 | title: "Guess-and-Determine Attacks on AEGIS" 156 | rc: "The Computer Journal, vol 65, 2022(8), pp. 2221–2230" 157 | seriesinfo: 158 | DOI: 10.1093/comjnl/bxab059 159 | author: 160 | - 161 | ins: L. Jiao 162 | name: Lin Jiao 163 | org: State Key Laboratory of Cryptology 164 | - 165 | ins: Y. Li 166 | name: Yongqiang Li 167 | org: State Key Laboratory of Information Security, Institute of Information Engineering, Chinese Academy of Sciences; School of Cyber Security, University of Chinese Academy of Sciences 168 | - 169 | ins: S. Du 170 | name: Shaoyu Du 171 | org: State Key Laboratory of Cryptology 172 | date: 2022 173 | 174 | LGR21: 175 | title: "Partitioning Oracle Attacks" 176 | rc: "30th USENIX Security Symposium (USENIX Security 21), pp. 195–212" 177 | target: https://www.usenix.org/conference/usenixsecurity21/presentation/len 178 | author: 179 | - 180 | ins: J. Len 181 | name: Julia Len 182 | org: Cornell Tech 183 | - 184 | ins: P. Grubbs 185 | name: Paul Grubbs 186 | org: Cornell Tech 187 | - 188 | ins: T. Ristenpart 189 | name: Thomas Ristenpart 190 | org: Cornell Tech 191 | date: 2021 192 | 193 | LIMS21: 194 | title: "Weak Keys in Reduced AEGIS and Tiaoxin" 195 | rc: "IACR Transactions on Symmetric Cryptology, 2021(2), pp. 104–139" 196 | seriesinfo: 197 | DOI: 10.46586/tosc.v2021.i2.104-139 198 | author: 199 | - 200 | ins: F. Liu 201 | name: Fukang Liu 202 | org: East China Normal University; University of Hyogo 203 | - 204 | ins: T. Isobe 205 | name: Takanori Isobe 206 | org: University of Hyogo; National Institute of Information and Communications Technology; PRESTO, Japan Science and Technology Agency 207 | - 208 | ins: W. Meier 209 | name: Willi Meier 210 | org: University of Applied Sciences and Arts Northwestern Switzerland 211 | - 212 | ins: K. Sakamoto 213 | name: Kosei Sakamoto 214 | org: University of Hyogo 215 | date: 2021 216 | 217 | M14: 218 | title: "Linear Biases in AEGIS Keystream" 219 | rc: "Selected Areas in Cryptography. SAC 2014. Lecture Notes in Computer Science, vol 8781, pp. 290–305" 220 | seriesinfo: 221 | DOI: 10.1007/978-3-319-13051-4_18 222 | author: 223 | - 224 | ins: B. Minaud 225 | name: Brice Minaud 226 | org: ANSSI 227 | date: 2014 228 | 229 | SSI24: 230 | title: "Bit-Wise Analysis for Forgery Attacks on AES-Based AEAD Schemes" 231 | rc: "Advances in Information and Computer Security. IWSEC 2024. Lecture Notes in Computer Science, vol 14977" 232 | seriesinfo: 233 | DOI: 10.1007/978-981-97-7737-2_1 234 | author: 235 | - 236 | ins: T. Shiraya 237 | name: Takuro Shiraya 238 | org: University of Hyogo 239 | - 240 | ins: K. Sakamoto 241 | name: Kosei Sakamoto 242 | org: Mitsubishi Electric Corporation 243 | - 244 | ins: T. Isobe 245 | name: Takanori Isobe 246 | org: University of Hyogo 247 | date: 2024 248 | 249 | STSI23: 250 | title: "MILP-based security evaluation for AEGIS/Tiaoxin-346/Rocca" 251 | rc: "IET Information Security, vol 17, 2023(3), pp. 458-467" 252 | seriesinfo: 253 | DOI: 10.1049/ise2.12109 254 | author: 255 | - 256 | ins: T. Shiraya 257 | name: Takuro Shiraya 258 | org: University of Hyogo 259 | - 260 | ins: N. Takeuchi 261 | name: Nobuyuki Takeuchi 262 | org: University of Hyogo 263 | - 264 | ins: K. Sakamoto 265 | name: Kosei Sakamoto 266 | org: University of Hyogo 267 | - 268 | ins: T. Isobe 269 | name: Takanori Isobe 270 | org: University of Hyogo; National Institute of Information and Communications Technology 271 | date: 2023 272 | 273 | TEST-VECTORS: 274 | title: "AEGIS Test Vectors" 275 | refcontent: commit 8e289c40 276 | target: https://github.com/cfrg/draft-irtf-cfrg-aegis-aead/tree/8e289c40/test-vectors 277 | date: 2025 278 | 279 | VV18: 280 | title: "Can Caesar Beat Galois?" 281 | rc: "Applied Cryptography and Network Security. ACNS 2018. Lecture Notes in Computer Science, vol 10892, pp. 476–494" 282 | seriesinfo: 283 | DOI: 10.1007/978-3-319-93387-0_25 284 | author: 285 | - 286 | ins: S. Vaudenay 287 | name: Serge Vaudenay 288 | org: EPFL 289 | - 290 | ins: D. Vizár 291 | name: Damian Vizár 292 | org: EPFL 293 | date: 2018 294 | 295 | --- abstract 296 | 297 | This document describes the AEGIS-128L, AEGIS-256, AEGIS-128X, and AEGIS-256X AES-based authenticated encryption algorithms designed for high-performance applications. 298 | 299 | The document is a product of the Crypto Forum Research Group (CFRG). It is not an IETF product and is not a standard. 300 | 301 | 302 | --- middle 303 | 304 | # Introduction 305 | 306 | This document describes the AEGIS family of Authenticated Encryption with Associated Data (AEAD) algorithms {{AEGIS}}, which were chosen for high-performance applications in the CAESAR (Competition for Authenticated Encryption: Security, Applicability, and Robustness) competition. 307 | 308 | Among the finalists, AEGIS-128 was chosen as the winner for this category. However, AEGIS-128L, another finalist, offers enhanced performance and a stronger security margin {{ENP20}} {{JLD22}} {{LIMS21}} {{STSI23}}. 309 | Additionally, AEGIS-256, which also reached the final round, provides 256-bit security and supports higher usage limits. 310 | 311 | Therefore, this document specifies the following variants: 312 | 313 | - AEGIS-128L, which has a 128-bit key, a 128-bit nonce, a 1024-bit state, a 128- or 256-bit authentication tag, and processes 256-bit input blocks. 314 | - AEGIS-256, which has a 256-bit key, a 256-bit nonce, a 768-bit state, a 128- or 256-bit authentication tag, and processes 128-bit input blocks. 315 | - AEGIS-128X, which is a mode based on AEGIS-128L, specialized for CPUs with large vector registers and vector AES instructions. 316 | - AEGIS-256X, which is a mode based on AEGIS-256, specialized for CPUs with large vector registers and vector AES instructions. 317 | 318 | All variants are inverse-free and constructed from the AES encryption round function {{!FIPS-AES=FIPS.197.2001}}. 319 | 320 | The AEGIS cipher family offers performance that significantly exceeds AES-GCM on CPUs with AES instructions. Similarly, software implementations not using AES instructions can also be faster, although to a lesser extent. 321 | 322 | Unlike with AES-GCM, nonces can be safely chosen at random with no practical limit when using AEGIS-256 and AEGIS-256X. AEGIS-128L and AEGIS-128X also allow for more messages to be safely encrypted when using random nonces. 323 | 324 | With some existing AEAD schemes, such as AES-GCM, an attacker can generate a ciphertext that successfully decrypts under multiple different keys (a partitioning oracle attack) {{LGR21}}. This ability to craft a (ciphertext, authentication tag) pair that verifies under multiple keys significantly reduces the number of required interactions with the oracle to perform an exhaustive search, making it practical if the key space is small. For example, with password-based encryption, an attacker can guess a large number of passwords at a time by recursively submitting such a ciphertext to an oracle, which speeds up a password search by reducing it to a binary search. 325 | 326 | With AEGIS, finding distinct (key, nonce) pairs that successfully decrypt a given (associated data, ciphertext, authentication tag) tuple is believed to have a complexity that depends on the tag size. A 128-bit tag provides 64-bit committing security, which is generally acceptable for interactive protocols. With a 256-bit tag, finding a collision becomes impractical. 327 | 328 | Unlike most other AES-based AEAD constructions, leaking a state does not leak the key or previous states. 329 | 330 | Finally, an AEGIS key is not required after the initialization function, and there is no key schedule. Thus, ephemeral keys can be erased from memory before any data has been encrypted or decrypted, mitigating cold boot attacks. 331 | 332 | Note that an earlier version of Hongjun Wu and Bart Preneel's paper introducing AEGIS specified AEGIS-128L and AEGIS-256 with a different `Finalize` function. We follow the specification of {{AEGIS}}, which can be found in the References section of this document. 333 | 334 | # Conventions and Definitions 335 | 336 | {::boilerplate bcp14-tagged} 337 | 338 | Throughout this document, "byte" is used interchangeably with "octet" and refers to an 8-bit sequence. 339 | 340 | Primitives: 341 | 342 | - `{}`: an empty bit array. 343 | - `|x|`: the length of `x` in bits. 344 | - `a ^ b`: the bitwise exclusive OR operation between `a` and `b`. 345 | - `a & b`: the bitwise AND operation between `a` and `b`. 346 | - `a || b`: the concatenation of `a` and `b`. 347 | - `a mod b`: the remainder of the Euclidean division between `a` as the dividend and `b` as the divisor. 348 | - `LE64(x)`: returns the little-endian encoding of unsigned 64-bit integer `x`. 349 | - `ZeroPad(x, n)`: returns `x` after appending zeros until its length is a multiple of `n` bits. No padding is added if the length of `x` is already a multiple of `n`, including when `x` is empty. 350 | - `Truncate(x, n)`: returns the first `n` bits of `x`. 351 | - `Split(x, n)`: returns `x` split into `n`-bit blocks, ignoring partial blocks. 352 | - `Tail(x, n)`: returns the last `n` bits of `x`. 353 | - `AESRound(in, rk)`: a single round of the AES encryption round function, which is the composition of the `SubBytes`, `ShiftRows`, `MixColums`, and `AddRoundKey` transformations, as defined in Section 5 of {{FIPS-AES}}. Here, `in` is the 128-bit AES input state, and `rk` is the 128-bit round key. 354 | - `Repeat(n, F)`: `n` sequential evaluations of the function `F`. 355 | - `CtEq(a, b)`: compares `a` and `b` in constant-time, returning `True` for an exact match and `False` otherwise. 356 | 357 | AEGIS internal functions: 358 | 359 | - `Update(M0, M1)` or `Update(M)`: the state update function. 360 | - `Init(key, nonce)`: the initialization function. 361 | - `Absorb(ai)`: the input block absorption function. 362 | - `Enc(xi)`: the input block encryption function. 363 | - `Dec(ci)`: the input block decryption function. 364 | - `DecPartial(cn)`: the input block decryption function for the last ciphertext bits when they do not fill an entire block. 365 | - `Finalize(ad_len_bits, msg_len_bits)`: the authentication tag generation function. 366 | 367 | Input blocks are 256 bits for AEGIS-128L and 128 bits for AEGIS-256. 368 | 369 | AES blocks: 370 | 371 | - `Si`: the `i`-th AES block of the current state. 372 | - `S'i`: the `i`-th AES block of the next state. 373 | - `{Si, ...Sj}`: the vector of the `i`-th AES block of the current state to the `j`-th block of the current state. 374 | - `C0`: an AES block built from the following bytes in hexadecimal format: `{ 0x00, 0x01, 0x01, 0x02, 0x03, 0x05, 0x08, 0x0d, 0x15, 0x22, 0x37, 0x59, 0x90, 0xe9, 0x79, 0x62 }`. 375 | - `C1`: an AES block built from the following bytes in hexadecimal format: `{ 0xdb, 0x3d, 0x18, 0x55, 0x6d, 0xc2, 0x2f, 0xf1, 0x20, 0x11, 0x31, 0x42, 0x73, 0xb5, 0x28, 0xdd }`. 376 | 377 | AES blocks are always 128 bits in length. 378 | 379 | Input and output values: 380 | 381 | - `key`: the encryption key (128 bits for AEGIS-128L, 256 bits for AEGIS-256). 382 | - `nonce`: the public nonce (128 bits for AEGIS-128L, 256 bits for AEGIS-256). 383 | - `ad`: the associated data. 384 | - `msg`: the plaintext. 385 | - `ct`: the ciphertext. 386 | - `tag`: the authentication tag (128 or 256 bits). 387 | 388 | # The AEGIS-128L Algorithm 389 | 390 | AEGIS-128L has a 1024-bit state, made of eight 128-bit blocks `{S0, ...S7}`. 391 | 392 | The parameters for this algorithm, whose meaning is defined in {{!RFC5116, Section 4}}, are: 393 | 394 | - `K_LEN` (key length) is 16 bytes (128 bits). 395 | - `P_MAX` (maximum length of the plaintext) is 261 - 1 bytes (264 - 8 bits). 396 | - `A_MAX` (maximum length of the associated data) is 261 - 1 bytes (264 - 8 bits). 397 | - `N_MIN` (minimum nonce length) = `N_MAX` (maximum nonce length) = 16 bytes (128 bits). 398 | - `C_MAX` (maximum ciphertext length) = `P_MAX` + tag length = (261 - 1) + 16 or 32 bytes (in bits: (264 - 8) + 128 or 256 bits). 399 | 400 | Distinct associated data inputs, as described in {{!RFC5116, Section 3}}, MUST be unambiguously encoded as a single input. 401 | It is up to the application to create a structure in the associated data input if needed. 402 | 403 | ## Authenticated Encryption 404 | 405 | ~~~ 406 | Encrypt(msg, ad, key, nonce) 407 | ~~~ 408 | 409 | The `Encrypt` function encrypts a message and returns the ciphertext along with an authentication tag that verifies the authenticity of the message and associated data, if provided. 410 | 411 | Security: 412 | 413 | - For a given key, the nonce MUST NOT be reused under any circumstances; doing so allows an attacker to recover the internal state. 414 | - The key MUST be randomly chosen from a uniform distribution. 415 | 416 | Inputs: 417 | 418 | - `msg`: the message to be encrypted (length MUST be less than or equal to `P_MAX`). 419 | - `ad`: the associated data to authenticate (length MUST be less than or equal to `A_MAX`). 420 | - `key`: the encryption key. 421 | - `nonce`: the public nonce. 422 | 423 | Outputs: 424 | 425 | - `ct`: the ciphertext. 426 | - `tag`: the authentication tag. 427 | 428 | Steps: 429 | 430 | ~~~ 431 | Init(key, nonce) 432 | 433 | ct = {} 434 | 435 | ad_blocks = Split(ZeroPad(ad, 256), 256) 436 | for ai in ad_blocks: 437 | Absorb(ai) 438 | 439 | msg_blocks = Split(ZeroPad(msg, 256), 256) 440 | for xi in msg_blocks: 441 | ct = ct || Enc(xi) 442 | 443 | tag = Finalize(|ad|, |msg|) 444 | ct = Truncate(ct, |msg|) 445 | 446 | return ct and tag 447 | ~~~ 448 | 449 | ## Authenticated Decryption 450 | 451 | ~~~ 452 | Decrypt(ct, tag, ad, key, nonce) 453 | ~~~ 454 | 455 | The `Decrypt` function decrypts a ciphertext, verifies that the authentication tag is correct, and returns the message on success or an error if tag verification failed. 456 | 457 | Security: 458 | 459 | - If tag verification fails, the decrypted message and wrong authentication tag MUST NOT be given as output. The decrypted message MUST be overwritten with zeros before the function returns. 460 | - The comparison of the input `tag` with the `expected_tag` MUST be done in constant time. 461 | 462 | Inputs: 463 | 464 | - `ct`: the ciphertext to decrypt (length MUST be less than or equal to `C_MAX`). 465 | - `tag`: the authentication tag. 466 | - `ad`: the associated data to authenticate (length MUST be less than or equal to `A_MAX`). 467 | - `key`: the encryption key. 468 | - `nonce`: the public nonce. 469 | 470 | Outputs: 471 | 472 | - Either the decrypted message `msg` or an error indicating that the authentication tag is invalid for the given inputs. 473 | 474 | Steps: 475 | 476 | ~~~ 477 | Init(key, nonce) 478 | 479 | msg = {} 480 | 481 | ad_blocks = Split(ZeroPad(ad, 256), 256) 482 | for ai in ad_blocks: 483 | Absorb(ai) 484 | 485 | ct_blocks = Split(ct, 256) 486 | cn = Tail(ct, |ct| mod 256) 487 | 488 | for ci in ct_blocks: 489 | msg = msg || Dec(ci) 490 | 491 | if cn is not empty: 492 | msg = msg || DecPartial(cn) 493 | 494 | expected_tag = Finalize(|ad|, |msg|) 495 | 496 | if CtEq(tag, expected_tag) is False: 497 | erase msg 498 | erase expected_tag 499 | return "verification failed" error 500 | else: 501 | return msg 502 | ~~~ 503 | 504 | ## The Update Function 505 | 506 | ~~~ 507 | Update(M0, M1) 508 | ~~~ 509 | 510 | The `Update` function is the core of the AEGIS-128L algorithm. 511 | It updates the state `{S0, ...S7}` using two 128-bit values. 512 | 513 | Inputs: 514 | 515 | - `M0`: the first 128-bit block to be absorbed. 516 | - `M1`: the second 128-bit block to be absorbed. 517 | 518 | Modifies: 519 | 520 | - `{S0, ...S7}`: the state. 521 | 522 | Steps: 523 | 524 | ~~~ 525 | S'0 = AESRound(S7, S0 ^ M0) 526 | S'1 = AESRound(S0, S1) 527 | S'2 = AESRound(S1, S2) 528 | S'3 = AESRound(S2, S3) 529 | S'4 = AESRound(S3, S4 ^ M1) 530 | S'5 = AESRound(S4, S5) 531 | S'6 = AESRound(S5, S6) 532 | S'7 = AESRound(S6, S7) 533 | 534 | S0 = S'0 535 | S1 = S'1 536 | S2 = S'2 537 | S3 = S'3 538 | S4 = S'4 539 | S5 = S'5 540 | S6 = S'6 541 | S7 = S'7 542 | ~~~ 543 | 544 | ## The Init Function 545 | 546 | ~~~ 547 | Init(key, nonce) 548 | ~~~ 549 | 550 | The `Init` function constructs the initial state `{S0, ...S7}` using the given `key` and `nonce`. 551 | 552 | Inputs: 553 | 554 | - `key`: the encryption key. 555 | - `nonce`: the public nonce. 556 | 557 | Defines: 558 | 559 | - `{S0, ...S7}`: the initial state. 560 | 561 | Steps: 562 | 563 | ~~~ 564 | S0 = key ^ nonce 565 | S1 = C1 566 | S2 = C0 567 | S3 = C1 568 | S4 = key ^ nonce 569 | S5 = key ^ C0 570 | S6 = key ^ C1 571 | S7 = key ^ C0 572 | 573 | Repeat(10, Update(nonce, key)) 574 | ~~~ 575 | 576 | ## The Absorb Function 577 | 578 | ~~~ 579 | Absorb(ai) 580 | ~~~ 581 | 582 | The `Absorb` function absorbs a 256-bit input block `ai` into the state `{S0, ...S7}`. 583 | 584 | Inputs: 585 | 586 | - `ai`: the 256-bit input block. 587 | 588 | Steps: 589 | 590 | ~~~ 591 | t0, t1 = Split(ai, 128) 592 | Update(t0, t1) 593 | ~~~ 594 | 595 | ## The Enc Function 596 | 597 | ~~~ 598 | Enc(xi) 599 | ~~~ 600 | 601 | The `Enc` function encrypts a 256-bit input block `xi` using the state `{S0, ...S7}`. 602 | 603 | Inputs: 604 | 605 | - `xi`: the 256-bit input block. 606 | 607 | Outputs: 608 | 609 | - `ci`: the 256-bit encrypted block. 610 | 611 | Steps: 612 | 613 | ~~~ 614 | z0 = S1 ^ S6 ^ (S2 & S3) 615 | z1 = S2 ^ S5 ^ (S6 & S7) 616 | 617 | t0, t1 = Split(xi, 128) 618 | out0 = t0 ^ z0 619 | out1 = t1 ^ z1 620 | 621 | Update(t0, t1) 622 | ci = out0 || out1 623 | 624 | return ci 625 | ~~~ 626 | 627 | ## The Dec Function 628 | 629 | ~~~ 630 | Dec(ci) 631 | ~~~ 632 | 633 | The `Dec` function decrypts a 256-bit input block `ci` using the state `{S0, ...S7}`. 634 | 635 | Inputs: 636 | 637 | - `ci`: the 256-bit encrypted block. 638 | 639 | Outputs: 640 | 641 | - `xi`: the 256-bit decrypted block. 642 | 643 | Steps: 644 | 645 | ~~~ 646 | z0 = S1 ^ S6 ^ (S2 & S3) 647 | z1 = S2 ^ S5 ^ (S6 & S7) 648 | 649 | t0, t1 = Split(ci, 128) 650 | out0 = t0 ^ z0 651 | out1 = t1 ^ z1 652 | 653 | Update(out0, out1) 654 | xi = out0 || out1 655 | 656 | return xi 657 | ~~~ 658 | 659 | ## The DecPartial Function 660 | 661 | ~~~ 662 | DecPartial(cn) 663 | ~~~ 664 | 665 | The `DecPartial` function decrypts the last ciphertext bits `cn` using the state `{S0, ...S7}` when they do not fill an entire block. 666 | 667 | Inputs: 668 | 669 | - `cn`: the encrypted input. 670 | 671 | Outputs: 672 | 673 | - `xn`: the decryption of `cn`. 674 | 675 | Steps: 676 | 677 | ~~~ 678 | z0 = S1 ^ S6 ^ (S2 & S3) 679 | z1 = S2 ^ S5 ^ (S6 & S7) 680 | 681 | t0, t1 = Split(ZeroPad(cn, 256), 128) 682 | out0 = t0 ^ z0 683 | out1 = t1 ^ z1 684 | 685 | xn = Truncate(out0 || out1, |cn|) 686 | 687 | v0, v1 = Split(ZeroPad(xn, 256), 128) 688 | Update(v0, v1) 689 | 690 | return xn 691 | ~~~ 692 | 693 | ## The Finalize Function 694 | 695 | ~~~ 696 | Finalize(ad_len_bits, msg_len_bits) 697 | ~~~ 698 | 699 | The `Finalize` function computes a 128- or 256-bit tag that authenticates the message and associated data. 700 | 701 | Inputs: 702 | 703 | - `ad_len_bits`: the length of the associated data in bits. 704 | - `msg_len_bits`: the length of the message in bits. 705 | 706 | Outputs: 707 | 708 | - `tag`: the authentication tag. 709 | 710 | Steps: 711 | 712 | ~~~ 713 | t = S2 ^ (LE64(ad_len_bits) || LE64(msg_len_bits)) 714 | 715 | Repeat(7, Update(t, t)) 716 | 717 | if tag_len_bits == 128: 718 | tag = S0 ^ S1 ^ S2 ^ S3 ^ S4 ^ S5 ^ S6 719 | else: # 256 bits 720 | tag = (S0 ^ S1 ^ S2 ^ S3) || (S4 ^ S5 ^ S6 ^ S7) 721 | 722 | return tag 723 | ~~~ 724 | 725 | # The AEGIS-256 Algorithm 726 | 727 | AEGIS-256 has a 768-bit state, made of six 128-bit blocks `{S0, ...S5}`. 728 | 729 | The parameters for this algorithm, whose meaning is defined in {{!RFC5116, Section 4}}, are: 730 | 731 | - `K_LEN` (key length) is 32 bytes (256 bits). 732 | - `P_MAX` (maximum length of the plaintext) is 261 - 1 bytes (264 - 8 bits). 733 | - `A_MAX` (maximum length of the associated data) is 261 - 1 bytes (264 - 8 bits). 734 | - `N_MIN` (minimum nonce length) = `N_MAX` (maximum nonce length) = 32 bytes (256 bits). 735 | - `C_MAX` (maximum ciphertext length) = `P_MAX` + tag length = (261 - 1) + 16 or 32 bytes (in bits: (264 - 8) + 128 or 256 bits). 736 | 737 | Distinct associated data inputs, as described in {{!RFC5116, Section 3}}, MUST be unambiguously encoded as a single input. 738 | It is up to the application to create a structure in the associated data input if needed. 739 | 740 | ## Authenticated Encryption 741 | 742 | ~~~ 743 | Encrypt(msg, ad, key, nonce) 744 | ~~~ 745 | 746 | The `Encrypt` function encrypts a message and returns the ciphertext along with an authentication tag that verifies the authenticity of the message and associated data, if provided. 747 | 748 | Security: 749 | 750 | - For a given key, the nonce MUST NOT be reused under any circumstances; doing so allows an attacker to recover the internal state. 751 | - The key MUST be randomly chosen from a uniform distribution. 752 | 753 | Inputs: 754 | 755 | - `msg`: the message to be encrypted (length MUST be less than or equal to `P_MAX`). 756 | - `ad`: the associated data to authenticate (length MUST be less than or equal to `A_MAX`). 757 | - `key`: the encryption key. 758 | - `nonce`: the public nonce. 759 | 760 | Outputs: 761 | 762 | - `ct`: the ciphertext. 763 | - `tag`: the authentication tag. 764 | 765 | Steps: 766 | 767 | ~~~ 768 | Init(key, nonce) 769 | 770 | ct = {} 771 | 772 | ad_blocks = Split(ZeroPad(ad, 128), 128) 773 | for ai in ad_blocks: 774 | Absorb(ai) 775 | 776 | msg_blocks = Split(ZeroPad(msg, 128), 128) 777 | for xi in msg_blocks: 778 | ct = ct || Enc(xi) 779 | 780 | tag = Finalize(|ad|, |msg|) 781 | ct = Truncate(ct, |msg|) 782 | 783 | return ct and tag 784 | ~~~ 785 | 786 | ## Authenticated Decryption 787 | 788 | ~~~ 789 | Decrypt(ct, tag, ad, key, nonce) 790 | ~~~ 791 | 792 | The `Decrypt` function decrypts a ciphertext, verifies that the authentication tag is correct, and returns the message on success or an error if tag verification failed. 793 | 794 | Security: 795 | 796 | - If tag verification fails, the decrypted message and wrong authentication tag MUST NOT be given as output. The decrypted message MUST be overwritten with zeros before the function returns. 797 | - The comparison of the input `tag` with the `expected_tag` MUST be done in constant time. 798 | 799 | Inputs: 800 | 801 | - `ct`: the ciphertext to decrypt (length MUST be less than or equal to `C_MAX`). 802 | - `tag`: the authentication tag. 803 | - `ad`: the associated data to authenticate (length MUST be less than or equal to `A_MAX`). 804 | - `key`: the encryption key. 805 | - `nonce`: the public nonce. 806 | 807 | Outputs: 808 | 809 | - Either the decrypted message `msg` or an error indicating that the authentication tag is invalid for the given inputs. 810 | 811 | Steps: 812 | 813 | ~~~ 814 | Init(key, nonce) 815 | 816 | msg = {} 817 | 818 | ad_blocks = Split(ZeroPad(ad, 128), 128) 819 | for ai in ad_blocks: 820 | Absorb(ai) 821 | 822 | ct_blocks = Split(ZeroPad(ct, 128), 128) 823 | cn = Tail(ct, |ct| mod 128) 824 | 825 | for ci in ct_blocks: 826 | msg = msg || Dec(ci) 827 | 828 | if cn is not empty: 829 | msg = msg || DecPartial(cn) 830 | 831 | expected_tag = Finalize(|ad|, |msg|) 832 | 833 | if CtEq(tag, expected_tag) is False: 834 | erase msg 835 | erase expected_tag 836 | return "verification failed" error 837 | else: 838 | return msg 839 | ~~~ 840 | 841 | ## The Update Function 842 | 843 | ~~~ 844 | Update(M) 845 | ~~~ 846 | 847 | The `Update` function is the core of the AEGIS-256 algorithm. 848 | It updates the state `{S0, ...S5}` using a 128-bit value. 849 | 850 | Inputs: 851 | 852 | - `msg`: the 128-bit block to be absorbed. 853 | 854 | Modifies: 855 | 856 | - `{S0, ...S5}`: the state. 857 | 858 | Steps: 859 | 860 | ~~~ 861 | S'0 = AESRound(S5, S0 ^ M) 862 | S'1 = AESRound(S0, S1) 863 | S'2 = AESRound(S1, S2) 864 | S'3 = AESRound(S2, S3) 865 | S'4 = AESRound(S3, S4) 866 | S'5 = AESRound(S4, S5) 867 | 868 | S0 = S'0 869 | S1 = S'1 870 | S2 = S'2 871 | S3 = S'3 872 | S4 = S'4 873 | S5 = S'5 874 | ~~~ 875 | 876 | ## The Init Function 877 | 878 | ~~~ 879 | Init(key, nonce) 880 | ~~~ 881 | 882 | The `Init` function constructs the initial state `{S0, ...S5}` using the given `key` and `nonce`. 883 | 884 | Inputs: 885 | 886 | - `key`: the encryption key. 887 | - `nonce`: the public nonce. 888 | 889 | Defines: 890 | 891 | - `{S0, ...S5}`: the initial state. 892 | 893 | Steps: 894 | 895 | ~~~ 896 | k0, k1 = Split(key, 128) 897 | n0, n1 = Split(nonce, 128) 898 | 899 | S0 = k0 ^ n0 900 | S1 = k1 ^ n1 901 | S2 = C1 902 | S3 = C0 903 | S4 = k0 ^ C0 904 | S5 = k1 ^ C1 905 | 906 | Repeat(4, 907 | Update(k0) 908 | Update(k1) 909 | Update(k0 ^ n0) 910 | Update(k1 ^ n1) 911 | ) 912 | ~~~ 913 | 914 | ## The Absorb Function 915 | 916 | ~~~ 917 | Absorb(ai) 918 | ~~~ 919 | 920 | The `Absorb` function absorbs a 128-bit input block `ai` into the state `{S0, ...S5}`. 921 | 922 | Inputs: 923 | 924 | - `ai`: the 128-bit input block. 925 | 926 | Steps: 927 | 928 | ~~~ 929 | Update(ai) 930 | ~~~ 931 | 932 | ## The Enc Function 933 | 934 | ~~~ 935 | Enc(xi) 936 | ~~~ 937 | 938 | The `Enc` function encrypts a 128-bit input block `xi` using the state `{S0, ...S5}`. 939 | 940 | Inputs: 941 | 942 | - `xi`: the 128-bit input block. 943 | 944 | Outputs: 945 | 946 | - `ci`: the 128-bit encrypted block. 947 | 948 | Steps: 949 | 950 | ~~~ 951 | z = S1 ^ S4 ^ S5 ^ (S2 & S3) 952 | 953 | Update(xi) 954 | 955 | ci = xi ^ z 956 | 957 | return ci 958 | ~~~ 959 | 960 | ## The Dec Function 961 | 962 | ~~~ 963 | Dec(ci) 964 | ~~~ 965 | 966 | The `Dec` function decrypts a 128-bit input block `ci` using the state `{S0, ...S5}`. 967 | 968 | Inputs: 969 | 970 | - `ci`: the 128-bit encrypted block. 971 | 972 | Outputs: 973 | 974 | - `xi`: the 128-bit decrypted block. 975 | 976 | Steps: 977 | 978 | ~~~ 979 | z = S1 ^ S4 ^ S5 ^ (S2 & S3) 980 | 981 | xi = ci ^ z 982 | 983 | Update(xi) 984 | 985 | return xi 986 | ~~~ 987 | 988 | ## The DecPartial Function 989 | 990 | ~~~ 991 | DecPartial(cn) 992 | ~~~ 993 | 994 | The `DecPartial` function decrypts the last ciphertext bits `cn` using the state `{S0, ...S5}` when they do not fill an entire block. 995 | 996 | Inputs: 997 | 998 | - `cn`: the encrypted input. 999 | 1000 | Outputs: 1001 | 1002 | - `xn`: the decryption of `cn`. 1003 | 1004 | Steps: 1005 | 1006 | ~~~ 1007 | z = S1 ^ S4 ^ S5 ^ (S2 & S3) 1008 | 1009 | t = ZeroPad(cn, 128) 1010 | out = t ^ z 1011 | 1012 | xn = Truncate(out, |cn|) 1013 | 1014 | v = ZeroPad(xn, 128) 1015 | Update(v) 1016 | 1017 | return xn 1018 | ~~~ 1019 | 1020 | ## The Finalize Function 1021 | 1022 | ~~~ 1023 | Finalize(ad_len_bits, msg_len_bits) 1024 | ~~~ 1025 | 1026 | The `Finalize` function computes a 128- or 256-bit tag that authenticates the message and associated data. 1027 | 1028 | Inputs: 1029 | 1030 | - `ad_len_bits`: the length of the associated data in bits. 1031 | - `msg_len_bits`: the length of the message in bits. 1032 | 1033 | Outputs: 1034 | 1035 | - `tag`: the authentication tag. 1036 | 1037 | Steps: 1038 | 1039 | ~~~ 1040 | t = S3 ^ (LE64(ad_len_bits) || LE64(msg_len_bits)) 1041 | 1042 | Repeat(7, Update(t)) 1043 | 1044 | if tag_len_bits == 128: 1045 | tag = S0 ^ S1 ^ S2 ^ S3 ^ S4 ^ S5 1046 | else: # 256 bits 1047 | tag = (S0 ^ S1 ^ S2) || (S3 ^ S4 ^ S5) 1048 | 1049 | return tag 1050 | ~~~ 1051 | 1052 | # Parallel Modes 1053 | 1054 | Some CPUs, such as Intel and Intel-compatible CPUs with the VAES extensions, include instructions to efficiently apply the AES round function to a vector of AES blocks. 1055 | 1056 | AEGIS-128X and AEGIS-256X are optional, specialized modes designed to take advantage of these instructions. They share the same properties as the ciphers they are based on but can be significantly faster on these platforms, even for short messages. 1057 | 1058 | AEGIS-128X and AEGIS-256X are parallel evaluations of multiple AEGIS-128L and AEGIS-256 instances, respectively, with distinct initial states. On CPUs with wide vector registers, different states can be stored in different 128-bit lanes of the same vector register, allowing parallel updates using vector instructions. 1059 | 1060 | The modes are parameterized by the parallelism degree. With 256-bit registers, 2 parallel operations can be applied to 128-bit AES blocks. With 512-bit registers, the number of instances can be raised to 4. 1061 | 1062 | The state of a parallel mode is represented as a vector of AEGIS-128L or AEGIS-256 states. 1063 | 1064 | ## Additional Conventions and Definitions 1065 | 1066 | - `D`: the degree of parallelism. 1067 | - `R`: the absorption and output rate of the mode. With AEGIS-128X, the rate is `256 * D` bits. With AEGIS-256X, the rate is `128 * D` bits. 1068 | - `V[j,i]`: the `j`-th AES block of the `i`-th state. `i` is in the `[0..D)` range. For AEGIS-128X, `j` is in the `[0..8)` range, while for AEGIS-256X, `j` is in the `[0..6)` range. 1069 | - `V'[j,i]`: the `j`-th AES block of the next `i`-th state. 1070 | - `ctx[i]`: the `i`-th context separator. This is a 128-bit mask made of a byte representing the state index, followed by a byte representing the highest index and 112 all-zero bits. 1071 | - `Byte(x)`: the value `x` encoded as 8 bits. 1072 | 1073 | ## Authenticated Encryption 1074 | 1075 | ~~~ 1076 | Encrypt(msg, ad, key, nonce) 1077 | ~~~ 1078 | 1079 | The `Encrypt` function of AEGIS-128X resembles that of AEGIS-128L, and similarly, the `Encrypt` function of AEGIS-256X mirrors that of AEGIS-256, but processes `R`-bit input blocks per update. 1080 | 1081 | Steps: 1082 | 1083 | ~~~ 1084 | Init(key, nonce) 1085 | 1086 | ct = {} 1087 | 1088 | ad_blocks = Split(ZeroPad(ad, R), R) 1089 | for ai in ad_blocks: 1090 | Absorb(ai) 1091 | 1092 | msg_blocks = Split(ZeroPad(msg, R), R) 1093 | for xi in msg_blocks: 1094 | ct = ct || Enc(xi) 1095 | 1096 | tag = Finalize(|ad|, |msg|) 1097 | ct = Truncate(ct, |msg|) 1098 | 1099 | return ct and tag 1100 | ~~~ 1101 | 1102 | ## Authenticated Decryption 1103 | 1104 | ~~~ 1105 | Decrypt(ct, tag, ad, key, nonce) 1106 | ~~~ 1107 | 1108 | The `Decrypt` function of AEGIS-128X resembles that of AEGIS-128L, and similarly, the `Decrypt` function of AEGIS-256X mirrors that of AEGIS-256, but processes `R`-bit input blocks per update. 1109 | 1110 | Steps: 1111 | 1112 | ~~~ 1113 | Init(key, nonce) 1114 | 1115 | msg = {} 1116 | 1117 | ad_blocks = Split(ZeroPad(ad, R), R) 1118 | for ai in ad_blocks: 1119 | Absorb(ai) 1120 | 1121 | ct_blocks = Split(ct, R) 1122 | cn = Tail(ct, |ct| mod R) 1123 | 1124 | for ci in ct_blocks: 1125 | msg = msg || Dec(ci) 1126 | 1127 | if cn is not empty: 1128 | msg = msg || DecPartial(cn) 1129 | 1130 | expected_tag = Finalize(|ad|, |msg|) 1131 | 1132 | if CtEq(tag, expected_tag) is False: 1133 | erase msg 1134 | erase expected_tag 1135 | return "verification failed" error 1136 | else: 1137 | return msg 1138 | ~~~ 1139 | 1140 | ## AEGIS-128X 1141 | 1142 | ### The Update Function 1143 | 1144 | ~~~ 1145 | Update(M0, M1) 1146 | ~~~ 1147 | 1148 | The AEGIS-128X `Update` function is similar to the AEGIS-128L `Update` function but absorbs `R` (= `256 * D`) bits at once. `M0` and `M1` are `128 * D` bits instead of 128 bits but are split into 128-bit blocks, each of them updating a different AEGIS-128L state. 1149 | 1150 | Steps: 1151 | 1152 | ~~~ 1153 | m0 = Split(M0, 128) 1154 | m1 = Split(M1, 128) 1155 | 1156 | for i in 0..D: 1157 | V'[0,i] = AESRound(V[7,i], V[0,i] ^ m0[i]) 1158 | V'[1,i] = AESRound(V[0,i], V[1,i]) 1159 | V'[2,i] = AESRound(V[1,i], V[2,i]) 1160 | V'[3,i] = AESRound(V[2,i], V[3,i]) 1161 | V'[4,i] = AESRound(V[3,i], V[4,i] ^ m1[i]) 1162 | V'[5,i] = AESRound(V[4,i], V[5,i]) 1163 | V'[6,i] = AESRound(V[5,i], V[6,i]) 1164 | V'[7,i] = AESRound(V[6,i], V[7,i]) 1165 | 1166 | V[0,i] = V'[0,i] 1167 | V[1,i] = V'[1,i] 1168 | V[2,i] = V'[2,i] 1169 | V[3,i] = V'[3,i] 1170 | V[4,i] = V'[4,i] 1171 | V[5,i] = V'[5,i] 1172 | V[6,i] = V'[6,i] 1173 | V[7,i] = V'[7,i] 1174 | ~~~ 1175 | 1176 | ### The Init Function 1177 | 1178 | ~~~ 1179 | Init(key, nonce) 1180 | ~~~ 1181 | 1182 | The `Init` function initializes a vector of `D` AEGIS-128L states with the same `key` and `nonce` but a different context `ctx[i]`. The context is added to the state before every update. 1183 | 1184 | Steps: 1185 | 1186 | ~~~ 1187 | for i in 0..D: 1188 | V[0,i] = key ^ nonce 1189 | V[1,i] = C1 1190 | V[2,i] = C0 1191 | V[3,i] = C1 1192 | V[4,i] = key ^ nonce 1193 | V[5,i] = key ^ C0 1194 | V[6,i] = key ^ C1 1195 | V[7,i] = key ^ C0 1196 | 1197 | nonce_v = {} 1198 | key_v = {} 1199 | for i in 0..D: 1200 | nonce_v = nonce_v || nonce 1201 | key_v = key_v || key 1202 | 1203 | for i in 0..D: 1204 | ctx[i] = ZeroPad(Byte(i) || Byte(D - 1), 128) 1205 | 1206 | Repeat(10, 1207 | for i in 0..D: 1208 | V[3,i] = V[3,i] ^ ctx[i] 1209 | V[7,i] = V[7,i] ^ ctx[i] 1210 | 1211 | Update(nonce_v, key_v) 1212 | ) 1213 | ~~~ 1214 | 1215 | ### The Absorb Function 1216 | 1217 | ~~~ 1218 | Absorb(ai) 1219 | ~~~ 1220 | 1221 | The `Absorb` function is similar to the AEGIS-128L `Absorb` function but absorbs `R` bits instead of 256 bits. 1222 | 1223 | Steps: 1224 | 1225 | ~~~ 1226 | t0, t1 = Split(ai, R) 1227 | Update(t0, t1) 1228 | ~~~ 1229 | 1230 | ### The Enc Function 1231 | 1232 | ~~~ 1233 | Enc(xi) 1234 | ~~~ 1235 | 1236 | The `Enc` function is similar to the AEGIS-128L `Enc` function but encrypts `R` bits instead of 256 bits. 1237 | 1238 | Steps: 1239 | 1240 | ~~~ 1241 | z0 = {} 1242 | z1 = {} 1243 | for i in 0..D: 1244 | z0 = z0 || (V[6,i] ^ V[1,i] ^ (V[2,i] & V[3,i])) 1245 | z1 = z1 || (V[2,i] ^ V[5,i] ^ (V[6,i] & V[7,i])) 1246 | 1247 | t0, t1 = Split(xi, R) 1248 | out0 = t0 ^ z0 1249 | out1 = t1 ^ z1 1250 | 1251 | Update(t0, t1) 1252 | ci = out0 || out1 1253 | 1254 | return ci 1255 | ~~~ 1256 | 1257 | ### The Dec Function 1258 | 1259 | ~~~ 1260 | Dec(ci) 1261 | ~~~ 1262 | 1263 | The `Dec` function is similar to the AEGIS-128L `Dec` function but decrypts `R` bits instead of 256 bits. 1264 | 1265 | Steps: 1266 | 1267 | ~~~ 1268 | z0 = {} 1269 | z1 = {} 1270 | for i in 0..D: 1271 | z0 = z0 || (V[6,i] ^ V[1,i] ^ (V[2,i] & V[3,i])) 1272 | z1 = z1 || (V[2,i] ^ V[5,i] ^ (V[6,i] & V[7,i])) 1273 | 1274 | t0, t1 = Split(ci, R) 1275 | out0 = t0 ^ z0 1276 | out1 = t1 ^ z1 1277 | 1278 | Update(out0, out1) 1279 | xi = out0 || out1 1280 | 1281 | return xi 1282 | ~~~ 1283 | 1284 | ### The DecPartial Function 1285 | 1286 | ~~~ 1287 | DecPartial(cn) 1288 | ~~~ 1289 | 1290 | The `DecPartial` function is similar to the AEGIS-128L `DecPartial` function but decrypts up to `R` bits instead of 256 bits. 1291 | 1292 | Steps: 1293 | 1294 | ~~~ 1295 | z0 = {} 1296 | z1 = {} 1297 | for i in 0..D: 1298 | z0 = z0 || (V[6,i] ^ V[1,i] ^ (V[2,i] & V[3,i])) 1299 | z1 = z1 || (V[2,i] ^ V[5,i] ^ (V[6,i] & V[7,i])) 1300 | 1301 | t0, t1 = Split(ZeroPad(cn, R), 128 * D) 1302 | out0 = t0 ^ z0 1303 | out1 = t1 ^ z1 1304 | 1305 | xn = Truncate(out0 || out1, |cn|) 1306 | 1307 | v0, v1 = Split(ZeroPad(xn, R), 128 * D) 1308 | Update(v0, v1) 1309 | 1310 | return xn 1311 | ~~~ 1312 | 1313 | ### The Finalize Function 1314 | 1315 | ~~~ 1316 | Finalize(ad_len_bits, msg_len_bits) 1317 | ~~~ 1318 | 1319 | The `Finalize` function finalizes every AEGIS-128L instance and combines the resulting authentication tags using the bitwise exclusive OR operation. 1320 | 1321 | Steps: 1322 | 1323 | ~~~ 1324 | t = {} 1325 | u = LE64(ad_len_bits) || LE64(msg_len_bits) 1326 | for i in 0..D: 1327 | t = t || (V[2,i] ^ u) 1328 | 1329 | Repeat(7, Update(t, t)) 1330 | 1331 | if tag_len_bits == 128: 1332 | tag = ZeroPad({}, 128) 1333 | for i in 0..D: 1334 | ti = V[0,i] ^ V[1,i] ^ V[2,i] ^ V[3,i] ^ V[4,i] ^ V[5,i] ^ V[6,i] 1335 | tag = tag ^ ti 1336 | 1337 | else: # 256 bits 1338 | ti0 = ZeroPad({}, 128) 1339 | ti1 = ZeroPad({}, 128) 1340 | for i in 0..D: 1341 | ti0 = ti0 ^ V[0,i] ^ V[1,i] ^ V[2,i] ^ V[3,i] 1342 | ti1 = ti1 ^ V[4,i] ^ V[5,i] ^ V[6,i] ^ V[7,i] 1343 | tag = ti0 || ti1 1344 | 1345 | return tag 1346 | ~~~ 1347 | 1348 | ## AEGIS-256X 1349 | 1350 | ### The Update Function 1351 | 1352 | ~~~ 1353 | Update(M) 1354 | ~~~ 1355 | 1356 | The AEGIS-256X `Update` function is similar to the AEGIS-256 `Update` function but absorbs `R` (`128 * D`) bits at once. `M` is `128 * D` bits instead of 128 bits and is split into 128-bit blocks, each of them updating a different AEGIS-256 state. 1357 | 1358 | Steps: 1359 | 1360 | ~~~ 1361 | m = Split(M, 128) 1362 | 1363 | for i in 0..D: 1364 | V'[0,i] = AESRound(V[5,i], V[0,i] ^ m[i]) 1365 | V'[1,i] = AESRound(V[0,i], V[1,i]) 1366 | V'[2,i] = AESRound(V[1,i], V[2,i]) 1367 | V'[3,i] = AESRound(V[2,i], V[3,i]) 1368 | V'[4,i] = AESRound(V[3,i], V[4,i]) 1369 | V'[5,i] = AESRound(V[4,i], V[5,i]) 1370 | 1371 | V[0,i] = V'[0,i] 1372 | V[1,i] = V'[1,i] 1373 | V[2,i] = V'[2,i] 1374 | V[3,i] = V'[3,i] 1375 | V[4,i] = V'[4,i] 1376 | V[5,i] = V'[5,i] 1377 | ~~~ 1378 | 1379 | ### The Init Function 1380 | 1381 | ~~~ 1382 | Init(key, nonce) 1383 | ~~~ 1384 | 1385 | The `Init` function initializes a vector of `D` AEGIS-256 states with the same `key` and `nonce` but a different context `ctx[i]`. The context is added to the state before every update. 1386 | 1387 | Steps: 1388 | 1389 | ~~~ 1390 | k0, k1 = Split(key, 128) 1391 | n0, n1 = Split(nonce, 128) 1392 | 1393 | for i in 0..D: 1394 | V[0,i] = k0 ^ n0 1395 | V[1,i] = k1 ^ n1 1396 | V[2,i] = C1 1397 | V[3,i] = C0 1398 | V[4,i] = k0 ^ C0 1399 | V[5,i] = k1 ^ C1 1400 | 1401 | k0_v, k1_v = {}, {} 1402 | k0n0_v, k1n1_v = {}, {} 1403 | for i in 0..D: 1404 | k0_v = k0_v || k0 1405 | k1_v = k1_v || k1 1406 | k0n0_v = k0n0_v || (k0 ^ n0) 1407 | k1n1_v = k1n1_v || (k1 ^ n1) 1408 | 1409 | for i in 0..D: 1410 | ctx[i] = ZeroPad(Byte(i) || Byte(D - 1), 128) 1411 | 1412 | Repeat(4, 1413 | for i in 0..D: 1414 | V[3,i] = V[3,i] ^ ctx[i] 1415 | V[5,i] = V[5,i] ^ ctx[i] 1416 | 1417 | Update(k0_v) 1418 | for i in 0..D: 1419 | V[3,i] = V[3,i] ^ ctx[i] 1420 | V[5,i] = V[5,i] ^ ctx[i] 1421 | 1422 | Update(k1_v) 1423 | for i in 0..D: 1424 | V[3,i] = V[3,i] ^ ctx[i] 1425 | V[5,i] = V[5,i] ^ ctx[i] 1426 | 1427 | Update(k0n0_v) 1428 | for i in 0..D: 1429 | V[3,i] = V[3,i] ^ ctx[i] 1430 | V[5,i] = V[5,i] ^ ctx[i] 1431 | 1432 | Update(k1n1_v) 1433 | ) 1434 | ~~~ 1435 | 1436 | ### The Absorb Function 1437 | 1438 | ~~~ 1439 | Absorb(ai) 1440 | ~~~ 1441 | 1442 | The `Absorb` function is similar to the AEGIS-256 `Absorb` function but absorbs `R` bits instead of 128 bits. 1443 | 1444 | Steps: 1445 | 1446 | ~~~ 1447 | Update(ai) 1448 | ~~~ 1449 | 1450 | ### The Enc Function 1451 | 1452 | ~~~ 1453 | Enc(xi) 1454 | ~~~ 1455 | 1456 | The `Enc` function is similar to the AEGIS-256 `Enc` function but encrypts `R` bits instead of 128 bits. 1457 | 1458 | Steps: 1459 | 1460 | ~~~ 1461 | z = {} 1462 | for i in 0..D: 1463 | z = z || (V[1,i] ^ V[4,i] ^ V[5,i] ^ (V[2,i] & V[3,i])) 1464 | 1465 | Update(xi) 1466 | 1467 | ci = xi ^ z 1468 | 1469 | return ci 1470 | ~~~ 1471 | 1472 | ### The Dec Function 1473 | 1474 | ~~~ 1475 | Dec(ci) 1476 | ~~~ 1477 | 1478 | The `Dec` function is similar to the AEGIS-256 `Dec` function but decrypts `R` bits instead of 128 bits. 1479 | 1480 | Steps: 1481 | 1482 | ~~~ 1483 | z = {} 1484 | for i in 0..D: 1485 | z = z || (V[1,i] ^ V[4,i] ^ V[5,i] ^ (V[2,i] & V[3,i])) 1486 | 1487 | xi = ci ^ z 1488 | 1489 | Update(xi) 1490 | 1491 | return xi 1492 | ~~~ 1493 | 1494 | ### The DecPartial Function 1495 | 1496 | ~~~ 1497 | DecPartial(cn) 1498 | ~~~ 1499 | 1500 | The `DecPartial` function is similar to the AEGIS-256 `DecPartial` function but decrypts up to `R` bits instead of 128 bits. 1501 | 1502 | Steps: 1503 | 1504 | ~~~ 1505 | z = {} 1506 | for i in 0..D: 1507 | z = z || (V[1,i] ^ V[4,i] ^ V[5,i] ^ (V[2,i] & V[3,i])) 1508 | 1509 | t = ZeroPad(cn, R) 1510 | out = t ^ z 1511 | 1512 | xn = Truncate(out, |cn|) 1513 | 1514 | v = ZeroPad(xn, 128 * D) 1515 | Update(v) 1516 | 1517 | return xn 1518 | ~~~ 1519 | 1520 | ### The Finalize Function 1521 | 1522 | ~~~ 1523 | Finalize(ad_len_bits, msg_len_bits) 1524 | ~~~ 1525 | 1526 | The `Finalize` function finalizes every AEGIS-256 instance and combines the resulting authentication tags using the bitwise exclusive OR operation. 1527 | 1528 | Steps: 1529 | 1530 | ~~~ 1531 | t = {} 1532 | u = LE64(ad_len_bits) || LE64(msg_len_bits) 1533 | for i in 0..D: 1534 | t = t || (V[3,i] ^ u) 1535 | 1536 | Repeat(7, Update(t)) 1537 | 1538 | if tag_len_bits == 128: 1539 | tag = ZeroPad({}, 128) 1540 | for i in 0..D: 1541 | ti = V[0,i] ^ V[1,i] ^ V[2,i] ^ V[3,i] ^ V[4,i] ^ V[5,i] 1542 | tag = tag ^ ti 1543 | 1544 | else: # 256 bits 1545 | ti0 = ZeroPad({}, 128) 1546 | ti1 = ZeroPad({}, 128) 1547 | for i in 0..D: 1548 | ti0 = ti0 ^ V[0,i] ^ V[1,i] ^ V[2,i] 1549 | ti1 = ti1 ^ V[3,i] ^ V[4,i] ^ V[5,i] 1550 | tag = ti0 || ti1 1551 | 1552 | return tag 1553 | ~~~ 1554 | 1555 | ## Implementation Considerations 1556 | 1557 | AEGIS-128X and AEGIS-256X with a degree of `1` are identical to AEGIS-128L and AEGIS-256, respectively. This property can be used to reduce the size of a generic implementation. 1558 | 1559 | In AEGIS-128X, `V` can be represented as eight 256-bit registers (when `D = 2`) or eight 512-bit registers (when `D = 4`). In AEGIS-256X, `V` can be represented as six 256-bit registers (when `D = 2`) or six 512-bit registers (when `D = 4`). With this representation, loops over `0..D` in the above pseudocode can be replaced by vector instructions. 1560 | 1561 | ## Operational Considerations 1562 | 1563 | The AEGIS parallel modes are specialized and can only improve performance on specific CPUs. 1564 | 1565 | The degrees of parallelism implementations are encouraged to support are `2` (for CPUs with 256-bit registers) and `4` (for CPUs with 512-bit registers). The resulting algorithms are called `AEGIS-128X2`, `AEGIS-128X4`, `AEGIS-256X2`, and `AEGIS-256X4`. 1566 | 1567 | The following table summarizes how many bits are processed in parallel (rate), the memory requirements (state size), and the minimum vector register size a CPU should support for optimal performance. 1568 | 1569 | | Algorithm | Rate (bits) | Optimal Register Size | State Size (bits) | 1570 | | ----------- | ----------: | :-------------------: | ----------------: | 1571 | | AEGIS-128L | 256 | 128 bits | 1024 | 1572 | | AEGIS-128X2 | 512 | 256 bits | 2048 | 1573 | | AEGIS-128X4 | 1024 | 512 bits | 4096 | 1574 | | AEGIS-256 | 128 | 128 bits | 768 | 1575 | | AEGIS-256X2 | 256 | 256 bits | 1536 | 1576 | | AEGIS-256X4 | 512 | 512 bits | 3072 | 1577 | 1578 | Note that architectures with smaller vector registers but with many registers and large pipelines may still benefit from the parallel modes. 1579 | 1580 | Protocols SHOULD opt for a parallel mode only when all the involved parties agree on a specific variant. AEGIS-128L and AEGIS-256 SHOULD remain the default choices. 1581 | 1582 | Implementations MAY choose not to include the parallel AEGIS modes. 1583 | 1584 | # Encoding (ct, tag) Tuples 1585 | 1586 | Applications MAY keep the ciphertext and the authentication tag in distinct structures or encode both as a single string. 1587 | 1588 | In the latter case, the tag MUST immediately follow the ciphertext: 1589 | 1590 | ~~~ 1591 | combined_ct = ct || tag 1592 | ~~~ 1593 | 1594 | # AEGIS as a Stream Cipher 1595 | 1596 | All AEGIS variants can also be used as stream ciphers. 1597 | 1598 | ~~~ 1599 | Stream(len, key, nonce) 1600 | ~~~ 1601 | 1602 | The `Stream` function expands a key and an optional nonce into a variable-length keystream. 1603 | 1604 | Inputs: 1605 | 1606 | - `len`: the length of the keystream to generate in bits. 1607 | - `key`: the AEGIS key. 1608 | - `nonce`: the AEGIS nonce. If unspecified, it is set to `N_MAX` zero bytes. 1609 | 1610 | Outputs: 1611 | 1612 | - `stream`: the keystream. 1613 | 1614 | Steps: 1615 | 1616 | ~~~ 1617 | if len == 0: 1618 | return {} 1619 | else: 1620 | stream, tag = Encrypt(ZeroPad({ 0 }, len), {}, key, nonce) 1621 | return stream 1622 | ~~~ 1623 | 1624 | This is equivalent to encrypting a `len` all-zero bits message without associated data and discarding the authentication tag. 1625 | 1626 | Instead of relying on the generic `Encrypt` function, implementations can omit the `Finalize` function. 1627 | 1628 | After initialization, the `Update` function is called with constant parameters, allowing further optimizations. 1629 | 1630 | # AEGIS as a Message Authentication Code 1631 | 1632 | All AEGIS variants can be used to construct a Message Authentication Code (MAC). 1633 | 1634 | For all the variants, the `Mac` function takes a key, a nonce, and data as input and produces a 128- or 256-bit tag as output. 1635 | 1636 | ~~~ 1637 | Mac(data, key, nonce) 1638 | ~~~ 1639 | 1640 | Security: 1641 | 1642 | - This is the only function that allows the reuse of `(key, nonce)` pairs with different inputs. 1643 | - AEGIS-based MAC functions MUST NOT be used as hash functions: if the key is known, inputs causing state collisions can easily be crafted. 1644 | - Unlike hash-based MACs, tags MUST NOT be used for key derivation as there is no guarantee that they are uniformly random. 1645 | 1646 | Inputs: 1647 | 1648 | - `data`: the input data to authenticate (length MUST be less than or equal to `A_MAX`). 1649 | - `key`: the secret key. 1650 | - `nonce`: the public nonce. 1651 | 1652 | Outputs: 1653 | 1654 | - `tag`: the authentication tag. 1655 | 1656 | ## AEGISMAC-128L 1657 | 1658 | AEGISMAC-128L refers to the `Mac` function based on the building blocks of AEGIS-128L. 1659 | 1660 | Steps: 1661 | 1662 | ~~~ 1663 | Init(key, nonce) 1664 | data_blocks = Split(ZeroPad(data, 256), 256) 1665 | for di in data_blocks: 1666 | Absorb(di) 1667 | tag = Finalize(|data|, tag_len_bits) 1668 | return tag 1669 | ~~~ 1670 | 1671 | ## AEGISMAC-256 1672 | 1673 | AEGISMAC-256 refers to the `Mac` function based on the building blocks of AEGIS-256. 1674 | 1675 | Steps: 1676 | 1677 | ~~~ 1678 | Init(key, nonce) 1679 | data_blocks = Split(ZeroPad(data, 128), 128) 1680 | for di in data_blocks: 1681 | Absorb(di) 1682 | tag = Finalize(|data|, tag_len_bits) 1683 | return tag 1684 | ~~~ 1685 | 1686 | ## AEGISMAC-128X 1687 | 1688 | AEGISMAC-128X is based on the building blocks of AEGIS-128X but replaces the `Finalize` function with a dedicated `FinalizeMac` function. 1689 | 1690 | ### The Mac Function 1691 | 1692 | Steps: 1693 | 1694 | ~~~ 1695 | Init(key, nonce) 1696 | data_blocks = Split(ZeroPad(data, R), R) 1697 | for di in data_blocks: 1698 | Absorb(di) 1699 | tag = FinalizeMac(|data|) 1700 | return tag 1701 | ~~~ 1702 | 1703 | ### The FinalizeMac Function 1704 | 1705 | ~~~ 1706 | FinalizeMac(data_len_bits) 1707 | ~~~ 1708 | 1709 | The `FinalizeMac` function computes a 128- or 256-bit tag that authenticates the input data. 1710 | 1711 | It finalizes all the instances, absorbs the resulting tags into the first state, and computes the final tag using that single state, as done in AEGIS-128L. 1712 | 1713 | Steps: 1714 | 1715 | ~~~ 1716 | t = {} 1717 | u = LE64(data_len_bits) || LE64(tag_len_bits) 1718 | for i in 0..D: 1719 | t = t || (V[2,i] ^ u) 1720 | 1721 | Repeat(7, Update(t, t)) 1722 | 1723 | tags = {} 1724 | if tag_len_bits == 128: 1725 | for i in 0..D: # tag from state 0 is included 1726 | ti = V[0,i] ^ V[1,i] ^ V[2,i] ^ V[3,i] ^ V[4,i] ^ V[5,i] ^ V[6,i] 1727 | tags = tags || ti 1728 | 1729 | else: # 256 bits 1730 | for i in 1..D: # tag from state 0 is skipped 1731 | ti0 = V[0,i] ^ V[1,i] ^ V[2,i] ^ V[3,i] 1732 | ti1 = V[4,i] ^ V[5,i] ^ V[6,i] ^ V[7,i] 1733 | tags = tags || (ti0 || ti1) 1734 | 1735 | if D > 1: 1736 | # Absorb tags into state 0; other states are not used anymore 1737 | for v in Split(tags, 256): 1738 | x0, x1 = Split(v, 128) 1739 | Absorb(ZeroPad(x0, R / 2) || ZeroPad(x1, R / 2)) 1740 | 1741 | u = LE64(D) || LE64(tag_len_bits) 1742 | t = ZeroPad(V[2,0] ^ u, R) 1743 | Repeat(7, Update(t, t)) 1744 | 1745 | if tag_len_bits == 128: 1746 | tag = V[0,0] ^ V[1,0] ^ V[2,0] ^ V[3,0] ^ V[4,0] ^ V[5,0] ^ V[6,0] 1747 | else: # 256 bits 1748 | t0 = V[0,0] ^ V[1,0] ^ V[2,0] ^ V[3,0] 1749 | t1 = V[4,0] ^ V[5,0] ^ V[6,0] ^ V[7,0] 1750 | tag = t0 || t1 1751 | 1752 | return tag 1753 | ~~~ 1754 | 1755 | ## AEGISMAC-256X 1756 | 1757 | AEGISMAC-256X is based on the building blocks of AEGIS-256X but replaces the `Finalize` function with a dedicated `FinalizeMac` function. 1758 | 1759 | ### The Mac Function 1760 | 1761 | Steps: 1762 | 1763 | ~~~ 1764 | Init(key, nonce) 1765 | data_blocks = Split(ZeroPad(data, R), R) 1766 | for di in data_blocks: 1767 | Absorb(di) 1768 | tag = FinalizeMac(|data|) 1769 | return tag 1770 | ~~~ 1771 | 1772 | ### The FinalizeMac Function 1773 | 1774 | ~~~ 1775 | FinalizeMac(data_len_bits) 1776 | ~~~ 1777 | 1778 | The `FinalizeMac` function computes a 128- or 256-bit tag that authenticates the input data. 1779 | 1780 | It finalizes all the instances, absorbs the resulting tags into the first state, and computes the final tag using that single state, as done in AEGIS-256. 1781 | 1782 | ~~~ 1783 | t = {} 1784 | u = LE64(data_len_bits) || LE64(tag_len_bits) 1785 | for i in 0..D: 1786 | t = t || (V[3,i] ^ u) 1787 | 1788 | Repeat(7, Update(t)) 1789 | 1790 | tags = {} 1791 | if tag_len_bits == 128: 1792 | for i in 1..D: # tag from state 0 is skipped 1793 | ti = V[0,i] ^ V[1,i] ^ V[2,i] ^ V[3,i] ^ V[4,i] ^ V[5,i] 1794 | tags = tags || ti 1795 | 1796 | else: # 256 bits 1797 | for i in 1..D: # tag from state 0 is skipped 1798 | ti0 = V[0,i] ^ V[1,i] ^ V[2,i] 1799 | ti1 = V[3,i] ^ V[4,i] ^ V[5,i] 1800 | tags = tags || (ti0 || ti1) 1801 | 1802 | if D > 1: 1803 | # Absorb tags into state 0; other states are not used anymore 1804 | for v in Split(tags, 128): 1805 | Absorb(ZeroPad(v, R)) 1806 | 1807 | u = LE64(D) || LE64(tag_len_bits) 1808 | t = ZeroPad(V[3,0] ^ u, R) 1809 | Repeat(7, Update(t)) 1810 | 1811 | if tag_len_bits == 128: 1812 | tag = V[0,0] ^ V[1,0] ^ V[2,0] ^ V[3,0] ^ V[4,0] ^ V[5,0] 1813 | else: # 256 bits 1814 | t0 = V[0,0] ^ V[1,0] ^ V[2,0] 1815 | t1 = V[3,0] ^ V[4,0] ^ V[5,0] 1816 | tag = t0 || t1 1817 | 1818 | return tag 1819 | ~~~ 1820 | 1821 | # Implementation Status 1822 | 1823 | *This note is to be removed before publishing as an RFC.* 1824 | 1825 | Multiple implementations of the schemes described in this document have been developed and verified for interoperability. 1826 | 1827 | A comprehensive list of known implementations and integrations can be found at [](https://github.com/cfrg/draft-irtf-cfrg-aegis-aead), which includes reference implementations closely aligned with the pseudocode provided in this document. 1828 | 1829 | # Security Considerations 1830 | 1831 | ## Usage Guidelines 1832 | 1833 | ### Key and Nonce Selection 1834 | 1835 | All AEGIS variants MUST be used in a nonce-respecting setting: for a given `key`, a `nonce` MUST only be used once, even with different `tag` lengths. Failure to do so would immediately reveal the bitwise difference between two messages. 1836 | 1837 | Every key MUST be randomly chosen from a uniform distribution. 1838 | 1839 | The nonce MAY be public or predictable. It can be a counter, the output of a permutation, or a generator with a long period. 1840 | 1841 | With AEGIS-128L and AEGIS-128X, random nonces can safely encrypt up to 248 messages using the same key with negligible (~2-33, to align with NIST guidelines) collision probability. 1842 | 1843 | With AEGIS-256 and AEGIS-256X, random nonces can be used with no practical limits. 1844 | 1845 | ### Committing Security 1846 | 1847 | An authentication tag may verify under multiple keys, nonces, or associated data, but AEGIS is assumed to be key committing in the receiver-binding game. This mitigates common attacks when used with low-entropy keys such as passwords. Finding distinct keys and/or nonces that successfully verify the same `(ad, ct, tag)` tuple is expected to require ~264 attempts with a 128-bit authentication tag and ~2128 attempts with a 256-bit tag. 1848 | 1849 | AEGIS is fully committing in the restricted setting where an adversary cannot control the associated data. As shown in {{IR23}}, with the ability to alter the associated data, it is possible to efficiently find multiple keys that will verify the same authenticated ciphertext. 1850 | 1851 | Protocols mandating a fully committing scheme without that restriction can provide the associated data as input to a cryptographic hash function and use the output as the `ad` parameter of the `Encrypt` and `Decrypt` functions. The selected hash function must ensure a minimum of 128-bit collision and preimage resistance. An instance of such a function is SHA-256 {{!RFC6234}}. 1852 | 1853 | Alternatively, the associated data can be fed into a collision-resistant KDF, such as HKDF {{!RFC5869}}, via the `info` input to derive the `key` parameter. The `ad` parameter can then be left empty. Note that the `salt` input MUST NOT be used since large salts get hashed, which affects commitment. Furthermore, this requires values concatenated to form the `info` input to be unambiguously encoded, like by appending their lengths. 1854 | 1855 | ### Multi-User Security 1856 | 1857 | AEGIS nonces match the size of the key. AEGIS-128L and AEGIS-128X feature 128-bit nonces, offering an extra 32 bits compared to the commonly used AEADs in IETF protocols at the time of writing. The AEGIS-256 and AEGIS-256X variants provide even larger nonces. With 192 random bits, 64 bits remain available to optionally encode additional information. 1858 | 1859 | In all these variants, unused nonce bits can encode a key identifier, enhancing multi-user security. If every key has a unique identifier, multi-target attacks do not provide any advantage over single-target attacks. 1860 | 1861 | ## Implementation Security 1862 | 1863 | If tag verification fails, the unverified plaintext and computed authentication tag MUST NOT be released. As shown in {{VV18}}, even a partial leak of the plaintext without verification facilitates chosen ciphertext attacks. 1864 | 1865 | The security of AEGIS against timing and physical attacks is limited by the implementation of the underlying `AESRound` function. Failure to implement `AESRound` in a fashion safe against timing and physical attacks, such as differential power analysis, timing analysis, or fault injection attacks, may lead to leakage of secret key material or state information. The exact mitigations required for timing and physical attacks depend on the threat model in question. 1866 | 1867 | Regardless of the variant, the `key` and `nonce` are only required by the `Init` function; other functions only depend on the resulting state. Therefore, implementations can overwrite ephemeral keys with zeros right after the last `Update` call of the initialization function. 1868 | 1869 | ## Security Guarantees 1870 | 1871 | AEGIS-256 offers 256-bit security against plaintext and state recovery, whereas AEGIS-128L offers 128-bit security. 1872 | 1873 | Under the assumption that the secret key is unknown to the attacker, all AEGIS variants offer at least 128-bit security against forgery attacks. 1874 | 1875 | Encrypting the same message with the same key and nonce but different associated data generates distinct ciphertexts that do not reveal any additional information about the message. 1876 | However, `(key, nonce)` pairs MUST NOT be reused, even if the associated data differs. 1877 | 1878 | AEGIS has been shown to have reforgeability resilience in {{FLLW17}}. Without the ability to set the associated data, a successful forgery does not increase the probability of subsequent forgeries. 1879 | 1880 | AEGIS-128X and AEGIS-256X share the same security properties and requirements as AEGIS-128L and AEGIS-256, respectively. In particular, the security level and usage limits remain the same {{D23}}. 1881 | 1882 | AEGIS is considered secure against guess-and-determine attacks aimed at recovering the state from observed ciphertexts. 1883 | 1884 | This resilience extends to quantum adversaries operating within the Q1 model, where the attacker has access to a quantum computer but is restricted to classical (non-quantum) communications with the systems under attack. In this model, quantum attacks offer no practical advantage in decrypting previously recorded ciphertexts or in recovering the encryption key. 1885 | 1886 | This document extends the original specification by introducing optional support for 256-bit authentication tags, which are constructed similarly to the 128-bit tags. 1887 | As shown in {{SSI24}}, with 256-bit tags, all AEGIS variants achieve more than 128-bit security against forgery by differential attacks. 1888 | 1889 | Security analyses of AEGIS can be found in {{AEGIS}}, {{M14}}, {{FLLW17}}, {{ENP20}}, {{LIMS21}}, {{JLD22}}, {{STSI23}}, {{IR23}}, {{BS23}}, {{AIKRS24}}, and {{SSI24}}. 1890 | 1891 | # IANA Considerations 1892 | 1893 | IANA has assigned the following identifiers in the AEAD Algorithms Registry: 1894 | 1895 | | Algorithm Name | ID | 1896 | | ---------------- | ---- | 1897 | | `AEAD_AEGIS128L` | `32` | 1898 | | `AEAD_AEGIS256` | `33` | 1899 | {: title="AEGIS entries in the AEAD Algorithms Registry"} 1900 | 1901 | IANA is requested to update the references of these entries to refer to the final version of this document. 1902 | 1903 | IANA is also requested to register the following entries in the AEAD Algorithms Registry: 1904 | 1905 | | Algorithm Name | ID | 1906 | | ----------------- | --- | 1907 | | `AEAD_AEGIS128X2` | | 1908 | | `AEAD_AEGIS128X4` | | 1909 | | `AEAD_AEGIS256X2` | | 1910 | | `AEAD_AEGIS256X4` | | 1911 | {: title="Missing AEGIS entries in the AEAD Algorithms Registry"} 1912 | 1913 | The identifier is left to be assigned by the IANA expert. 1914 | 1915 | --- back 1916 | 1917 | # Test Vectors 1918 | 1919 | The following test vectors are also available in JSON format at {{TEST-VECTORS}}. In this format, byte strings are represented as JSON strings containing their hexadecimal encoding. 1920 | 1921 | ## AESRound Test Vector 1922 | 1923 | ~~~ test-vectors 1924 | in : 000102030405060708090a0b0c0d0e0f 1925 | 1926 | rk : 101112131415161718191a1b1c1d1e1f 1927 | 1928 | out : 7a7b4e5638782546a8c0477a3b813f43 1929 | ~~~ 1930 | 1931 | ## AEGIS-128L Test Vectors 1932 | 1933 | ### Update Test Vector 1934 | 1935 | ~~~ test-vectors 1936 | S0 : 9b7e60b24cc873ea894ecc07911049a3 1937 | S1 : 330be08f35300faa2ebf9a7b0d274658 1938 | S2 : 7bbd5bd2b049f7b9b515cf26fbe7756c 1939 | S3 : c35a00f55ea86c3886ec5e928f87db18 1940 | S4 : 9ebccafce87cab446396c4334592c91f 1941 | S5 : 58d83e31f256371e60fc6bb257114601 1942 | S6 : 1639b56ea322c88568a176585bc915de 1943 | S7 : 640818ffb57dc0fbc2e72ae93457e39a 1944 | 1945 | M0 : 033e6975b94816879e42917650955aa0 1946 | M1 : fcc1968a46b7e97861bd6e89af6aa55f 1947 | 1948 | After Update: 1949 | 1950 | S0 : 596ab773e4433ca0127c73f60536769d 1951 | S1 : 790394041a3d26ab697bde865014652d 1952 | S2 : 38cf49e4b65248acd533041b64dd0611 1953 | S3 : 16d8e58748f437bfff1797f780337cee 1954 | S4 : 9689ecdf08228c74d7e3360cca53d0a5 1955 | S5 : a21746bb193a569e331e1aa985d0d729 1956 | S6 : 09d714e6fcf9177a8ed1cde7e3d259a6 1957 | S7 : 61279ba73167f0ab76f0a11bf203bdff 1958 | ~~~ 1959 | 1960 | ### Test Vector 1 1961 | 1962 | ~~~ test-vectors 1963 | key : 10010000000000000000000000000000 1964 | 1965 | nonce : 10000200000000000000000000000000 1966 | 1967 | ad : 1968 | 1969 | msg : 00000000000000000000000000000000 1970 | 1971 | ct : c1c0e58bd913006feba00f4b3cc3594e 1972 | 1973 | tag128: abe0ece80c24868a226a35d16bdae37a 1974 | 1975 | tag256: 25835bfbb21632176cf03840687cb968 1976 | cace4617af1bd0f7d064c639a5c79ee4 1977 | ~~~ 1978 | 1979 | ### Test Vector 2 1980 | 1981 | ~~~ test-vectors 1982 | key : 10010000000000000000000000000000 1983 | 1984 | nonce : 10000200000000000000000000000000 1985 | 1986 | ad : 1987 | 1988 | msg : 1989 | 1990 | ct : 1991 | 1992 | tag128: c2b879a67def9d74e6c14f708bbcc9b4 1993 | 1994 | tag256: 1360dc9db8ae42455f6e5b6a9d488ea4 1995 | f2184c4e12120249335c4ee84bafe25d 1996 | ~~~ 1997 | 1998 | ### Test Vector 3 1999 | 2000 | ~~~ test-vectors 2001 | key : 10010000000000000000000000000000 2002 | 2003 | nonce : 10000200000000000000000000000000 2004 | 2005 | ad : 0001020304050607 2006 | 2007 | msg : 000102030405060708090a0b0c0d0e0f 2008 | 101112131415161718191a1b1c1d1e1f 2009 | 2010 | ct : 79d94593d8c2119d7e8fd9b8fc77845c 2011 | 5c077a05b2528b6ac54b563aed8efe84 2012 | 2013 | tag128: cc6f3372f6aa1bb82388d695c3962d9a 2014 | 2015 | tag256: 022cb796fe7e0ae1197525ff67e30948 2016 | 4cfbab6528ddef89f17d74ef8ecd82b3 2017 | ~~~ 2018 | 2019 | ### Test Vector 4 2020 | 2021 | ~~~ test-vectors 2022 | key : 10010000000000000000000000000000 2023 | 2024 | nonce : 10000200000000000000000000000000 2025 | 2026 | ad : 0001020304050607 2027 | 2028 | msg : 000102030405060708090a0b0c0d 2029 | 2030 | ct : 79d94593d8c2119d7e8fd9b8fc77 2031 | 2032 | tag128: 5c04b3dba849b2701effbe32c7f0fab7 2033 | 2034 | tag256: 86f1b80bfb463aba711d15405d094baf 2035 | 4a55a15dbfec81a76f35ed0b9c8b04ac 2036 | ~~~ 2037 | 2038 | ### Test Vector 5 2039 | 2040 | ~~~ test-vectors 2041 | key : 10010000000000000000000000000000 2042 | 2043 | nonce : 10000200000000000000000000000000 2044 | 2045 | ad : 000102030405060708090a0b0c0d0e0f 2046 | 101112131415161718191a1b1c1d1e1f 2047 | 20212223242526272829 2048 | 2049 | msg : 101112131415161718191a1b1c1d1e1f 2050 | 202122232425262728292a2b2c2d2e2f 2051 | 3031323334353637 2052 | 2053 | ct : b31052ad1cca4e291abcf2df3502e6bd 2054 | b1bfd6db36798be3607b1f94d34478aa 2055 | 7ede7f7a990fec10 2056 | 2057 | tag128: 7542a745733014f9474417b337399507 2058 | 2059 | tag256: b91e2947a33da8bee89b6794e647baf0 2060 | fc835ff574aca3fc27c33be0db2aff98 2061 | ~~~ 2062 | 2063 | ### Test Vector 6 2064 | 2065 | This test MUST return a "verification failed" error. 2066 | 2067 | ~~~ test-vectors 2068 | key : 10000200000000000000000000000000 2069 | 2070 | nonce : 10010000000000000000000000000000 2071 | 2072 | ad : 0001020304050607 2073 | 2074 | ct : 79d94593d8c2119d7e8fd9b8fc77 2075 | 2076 | tag128: 5c04b3dba849b2701effbe32c7f0fab7 2077 | 2078 | tag256: 86f1b80bfb463aba711d15405d094baf 2079 | 4a55a15dbfec81a76f35ed0b9c8b04ac 2080 | ~~~ 2081 | 2082 | ### Test Vector 7 2083 | 2084 | This test MUST return a "verification failed" error. 2085 | 2086 | ~~~ test-vectors 2087 | key : 10010000000000000000000000000000 2088 | 2089 | nonce : 10000200000000000000000000000000 2090 | 2091 | ad : 0001020304050607 2092 | 2093 | ct : 79d94593d8c2119d7e8fd9b8fc78 2094 | 2095 | tag128: 5c04b3dba849b2701effbe32c7f0fab7 2096 | 2097 | tag256: 86f1b80bfb463aba711d15405d094baf 2098 | 4a55a15dbfec81a76f35ed0b9c8b04ac 2099 | ~~~ 2100 | 2101 | ### Test Vector 8 2102 | 2103 | This test MUST return a "verification failed" error. 2104 | 2105 | ~~~ test-vectors 2106 | key : 10010000000000000000000000000000 2107 | 2108 | nonce : 10000200000000000000000000000000 2109 | 2110 | ad : 0001020304050608 2111 | 2112 | ct : 79d94593d8c2119d7e8fd9b8fc77 2113 | 2114 | tag128: 5c04b3dba849b2701effbe32c7f0fab7 2115 | 2116 | tag256: 86f1b80bfb463aba711d15405d094baf 2117 | 4a55a15dbfec81a76f35ed0b9c8b04ac 2118 | ~~~ 2119 | 2120 | ### Test Vector 9 2121 | 2122 | This test MUST return a "verification failed" error. 2123 | 2124 | ~~~ test-vectors 2125 | key : 10010000000000000000000000000000 2126 | 2127 | nonce : 10000200000000000000000000000000 2128 | 2129 | ad : 0001020304050607 2130 | 2131 | ct : 79d94593d8c2119d7e8fd9b8fc77 2132 | 2133 | tag128: 6c04b3dba849b2701effbe32c7f0fab8 2134 | 2135 | tag256: 86f1b80bfb463aba711d15405d094baf 2136 | 4a55a15dbfec81a76f35ed0b9c8b04ad 2137 | ~~~ 2138 | 2139 | ## AEGIS-256 Test Vectors 2140 | 2141 | ### Update Test Vector 2142 | 2143 | ~~~ test-vectors 2144 | S0 : 1fa1207ed76c86f2c4bb40e8b395b43e 2145 | S1 : b44c375e6c1e1978db64bcd12e9e332f 2146 | S2 : 0dab84bfa9f0226432ff630f233d4e5b 2147 | S3 : d7ef65c9b93e8ee60c75161407b066e7 2148 | S4 : a760bb3da073fbd92bdc24734b1f56fb 2149 | S5 : a828a18d6a964497ac6e7e53c5f55c73 2150 | 2151 | M : b165617ed04ab738afb2612c6d18a1ec 2152 | 2153 | After Update: 2154 | 2155 | S0 : e6bc643bae82dfa3d991b1b323839dcd 2156 | S1 : 648578232ba0f2f0a3677f617dc052c3 2157 | S2 : ea788e0e572044a46059212dd007a789 2158 | S3 : 2f1498ae19b80da13fba698f088a8590 2159 | S4 : a54c2ee95e8c2a2c3dae2ec743ae6b86 2160 | S5 : a3240fceb68e32d5d114df1b5363ab67 2161 | ~~~ 2162 | 2163 | ### Test Vector 1 2164 | 2165 | ~~~ test-vectors 2166 | key : 10010000000000000000000000000000 2167 | 00000000000000000000000000000000 2168 | 2169 | nonce : 10000200000000000000000000000000 2170 | 00000000000000000000000000000000 2171 | 2172 | ad : 2173 | 2174 | msg : 00000000000000000000000000000000 2175 | 2176 | ct : 754fc3d8c973246dcc6d741412a4b236 2177 | 2178 | tag128: 3fe91994768b332ed7f570a19ec5896e 2179 | 2180 | tag256: 1181a1d18091082bf0266f66297d167d 2181 | 2e68b845f61a3b0527d31fc7b7b89f13 2182 | ~~~ 2183 | 2184 | ### Test Vector 2 2185 | 2186 | ~~~ test-vectors 2187 | key : 10010000000000000000000000000000 2188 | 00000000000000000000000000000000 2189 | 2190 | nonce : 10000200000000000000000000000000 2191 | 00000000000000000000000000000000 2192 | 2193 | ad : 2194 | 2195 | msg : 2196 | 2197 | ct : 2198 | 2199 | tag128: e3def978a0f054afd1e761d7553afba3 2200 | 2201 | tag256: 6a348c930adbd654896e1666aad67de9 2202 | 89ea75ebaa2b82fb588977b1ffec864a 2203 | ~~~ 2204 | 2205 | ### Test Vector 3 2206 | 2207 | ~~~ test-vectors 2208 | key : 10010000000000000000000000000000 2209 | 00000000000000000000000000000000 2210 | 2211 | nonce : 10000200000000000000000000000000 2212 | 00000000000000000000000000000000 2213 | 2214 | ad : 0001020304050607 2215 | 2216 | msg : 000102030405060708090a0b0c0d0e0f 2217 | 101112131415161718191a1b1c1d1e1f 2218 | 2219 | ct : f373079ed84b2709faee373584585d60 2220 | accd191db310ef5d8b11833df9dec711 2221 | 2222 | tag128: 8d86f91ee606e9ff26a01b64ccbdd91d 2223 | 2224 | tag256: b7d28d0c3c0ebd409fd22b4416050307 2225 | 3a547412da0854bfb9723020dab8da1a 2226 | ~~~ 2227 | 2228 | ### Test Vector 4 2229 | 2230 | ~~~ test-vectors 2231 | key : 10010000000000000000000000000000 2232 | 00000000000000000000000000000000 2233 | 2234 | nonce : 10000200000000000000000000000000 2235 | 00000000000000000000000000000000 2236 | 2237 | ad : 0001020304050607 2238 | 2239 | msg : 000102030405060708090a0b0c0d 2240 | 2241 | ct : f373079ed84b2709faee37358458 2242 | 2243 | tag128: c60b9c2d33ceb058f96e6dd03c215652 2244 | 2245 | tag256: 8c1cc703c81281bee3f6d9966e14948b 2246 | 4a175b2efbdc31e61a98b4465235c2d9 2247 | ~~~ 2248 | 2249 | ### Test Vector 5 2250 | 2251 | ~~~ test-vectors 2252 | key : 10010000000000000000000000000000 2253 | 00000000000000000000000000000000 2254 | 2255 | nonce : 10000200000000000000000000000000 2256 | 00000000000000000000000000000000 2257 | 2258 | ad : 000102030405060708090a0b0c0d0e0f 2259 | 101112131415161718191a1b1c1d1e1f 2260 | 20212223242526272829 2261 | 2262 | msg : 101112131415161718191a1b1c1d1e1f 2263 | 202122232425262728292a2b2c2d2e2f 2264 | 3031323334353637 2265 | 2266 | ct : 57754a7d09963e7c787583a2e7b859bb 2267 | 24fa1e04d49fd550b2511a358e3bca25 2268 | 2a9b1b8b30cc4a67 2269 | 2270 | tag128: ab8a7d53fd0e98d727accca94925e128 2271 | 2272 | tag256: a3aca270c006094d71c20e6910b5161c 2273 | 0826df233d08919a566ec2c05990f734 2274 | ~~~ 2275 | 2276 | ### Test Vector 6 2277 | 2278 | This test MUST return a "verification failed" error. 2279 | 2280 | ~~~ test-vectors 2281 | key : 10000200000000000000000000000000 2282 | 00000000000000000000000000000000 2283 | 2284 | nonce : 10010000000000000000000000000000 2285 | 00000000000000000000000000000000 2286 | 2287 | ad : 0001020304050607 2288 | 2289 | ct : f373079ed84b2709faee37358458 2290 | 2291 | tag128: c60b9c2d33ceb058f96e6dd03c215652 2292 | 2293 | tag256: 8c1cc703c81281bee3f6d9966e14948b 2294 | 4a175b2efbdc31e61a98b4465235c2d9 2295 | ~~~ 2296 | 2297 | ### Test Vector 7 2298 | 2299 | This test MUST return a "verification failed" error. 2300 | 2301 | ~~~ test-vectors 2302 | key : 10010000000000000000000000000000 2303 | 00000000000000000000000000000000 2304 | 2305 | nonce : 10000200000000000000000000000000 2306 | 00000000000000000000000000000000 2307 | 2308 | ad : 0001020304050607 2309 | 2310 | ct : f373079ed84b2709faee37358459 2311 | 2312 | tag128: c60b9c2d33ceb058f96e6dd03c215652 2313 | 2314 | tag256: 8c1cc703c81281bee3f6d9966e14948b 2315 | 4a175b2efbdc31e61a98b4465235c2d9 2316 | ~~~ 2317 | 2318 | ### Test Vector 8 2319 | 2320 | This test MUST return a "verification failed" error. 2321 | 2322 | ~~~ test-vectors 2323 | key : 10010000000000000000000000000000 2324 | 00000000000000000000000000000000 2325 | 2326 | nonce : 10000200000000000000000000000000 2327 | 00000000000000000000000000000000 2328 | 2329 | ad : 0001020304050608 2330 | 2331 | ct : f373079ed84b2709faee37358458 2332 | 2333 | tag128: c60b9c2d33ceb058f96e6dd03c215652 2334 | 2335 | tag256: 8c1cc703c81281bee3f6d9966e14948b 2336 | 4a175b2efbdc31e61a98b4465235c2d9 2337 | ~~~ 2338 | 2339 | ### Test Vector 9 2340 | 2341 | This test MUST return a "verification failed" error. 2342 | 2343 | ~~~ test-vectors 2344 | key : 10010000000000000000000000000000 2345 | 00000000000000000000000000000000 2346 | 2347 | nonce : 10000200000000000000000000000000 2348 | 00000000000000000000000000000000 2349 | 2350 | ad : 0001020304050607 2351 | 2352 | ct : f373079ed84b2709faee37358458 2353 | 2354 | tag128: c60b9c2d33ceb058f96e6dd03c215653 2355 | 2356 | tag256: 8c1cc703c81281bee3f6d9966e14948b 2357 | 4a175b2efbdc31e61a98b4465235c2da 2358 | ~~~ 2359 | 2360 | ## AEGIS-128X2 Test Vectors 2361 | 2362 | ### Initial State 2363 | 2364 | ~~~ test-vectors 2365 | key : 000102030405060708090a0b0c0d0e0f 2366 | 2367 | nonce : 101112131415161718191a1b1c1d1e1f 2368 | 2369 | ctx[0]: 00010000000000000000000000000000 2370 | ctx[1]: 01010000000000000000000000000000 2371 | ~~~ 2372 | 2373 | After initialization: 2374 | 2375 | ~~~ test-vectors 2376 | V[0,0]: a4fc1ad9a72942fb88bd2cabbba6509a 2377 | V[0,1]: 80a40e392fc71084209b6c3319bdc6cc 2378 | 2379 | V[1,0]: 380f435cf801763b1f0c2a2f7212052d 2380 | V[1,1]: 73796607b59b1b650ee91c152af1f18a 2381 | 2382 | V[2,0]: 6ee1de433ea877fa33bc0782abff2dcb 2383 | V[2,1]: b9fab2ab496e16d1facaffd5453cbf14 2384 | 2385 | V[3,0]: 85f94b0d4263bfa86fdf45a603d8b6ac 2386 | V[3,1]: 90356c8cadbaa2c969001da02e3feca0 2387 | 2388 | V[4,0]: 09bd69ad3730174bcd2ce9a27cd1357e 2389 | V[4,1]: e610b45125796a4fcf1708cef5c4f718 2390 | 2391 | V[5,0]: fcdeb0cf0a87bf442fc82383ddb0f6d6 2392 | V[5,1]: 61ad32a4694d6f3cca313a2d3f4687aa 2393 | 2394 | V[6,0]: 571c207988659e2cdfbdaae77f4f37e3 2395 | V[6,1]: 32e6094e217573bf91fb28c145a3efa8 2396 | 2397 | V[7,0]: ca549badf8faa58222412478598651cf 2398 | V[7,1]: 3407279a54ce76d2e2e8a90ec5d108eb 2399 | ~~~ 2400 | 2401 | ### Test Vector 1 2402 | 2403 | ~~~ test-vectors 2404 | key : 000102030405060708090a0b0c0d0e0f 2405 | 2406 | nonce : 101112131415161718191a1b1c1d1e1f 2407 | 2408 | ad : 2409 | 2410 | msg : 2411 | 2412 | ct : 2413 | 2414 | tag128: 63117dc57756e402819a82e13eca8379 2415 | 2416 | tag256: b92c71fdbd358b8a4de70b27631ace90 2417 | cffd9b9cfba82028412bac41b4f53759 2418 | ~~~ 2419 | 2420 | ### Test Vector 2 2421 | 2422 | ~~~ test-vectors 2423 | key : 000102030405060708090a0b0c0d0e0f 2424 | 2425 | nonce : 101112131415161718191a1b1c1d1e1f 2426 | 2427 | ad : 0102030401020304 2428 | 2429 | msg : 04050607040506070405060704050607 2430 | 04050607040506070405060704050607 2431 | 04050607040506070405060704050607 2432 | 04050607040506070405060704050607 2433 | 04050607040506070405060704050607 2434 | 04050607040506070405060704050607 2435 | 04050607040506070405060704050607 2436 | 0405060704050607 2437 | 2438 | ct : 5795544301997f93621b278809d6331b 2439 | 3bfa6f18e90db12c4aa35965b5e98c5f 2440 | c6fb4e54bcb6111842c20637252eff74 2441 | 7cb3a8f85b37de80919a589fe0f24872 2442 | bc926360696739e05520647e390989e1 2443 | eb5fd42f99678a0276a498f8c454761c 2444 | 9d6aacb647ad56be62b29c22cd4b5761 2445 | b38f43d5a5ee062f 2446 | 2447 | tag128: 1aebc200804f405cab637f2adebb6d77 2448 | 2449 | tag256: c471876f9b4978c44f2ae1ce770cdb11 2450 | a094ee3feca64e7afcd48bfe52c60eca 2451 | ~~~ 2452 | 2453 | ## AEGIS-128X4 Test Vectors 2454 | 2455 | ### Initial State 2456 | 2457 | ~~~ test-vectors 2458 | key : 000102030405060708090a0b0c0d0e0f 2459 | 2460 | nonce : 101112131415161718191a1b1c1d1e1f 2461 | 2462 | ctx[0]: 00030000000000000000000000000000 2463 | ctx[1]: 01030000000000000000000000000000 2464 | ctx[2]: 02030000000000000000000000000000 2465 | ctx[3]: 03030000000000000000000000000000 2466 | ~~~ 2467 | 2468 | After initialization: 2469 | 2470 | ~~~ test-vectors 2471 | V[0,0]: 924eb07635003a37e6c6575ba8ce1929 2472 | V[0,1]: c8b6a5d91475445e936d48e794be0ce2 2473 | V[0,2]: fcd37d050e24084befe3bbb219d64760 2474 | V[0,3]: 2e9f58cfb893a8800220242c373a8b18 2475 | 2476 | V[1,0]: 1a1f60c4fab64e5471dc72edfcf6fe6b 2477 | V[1,1]: c1e525ebea2d6375a9edd045dce96381 2478 | V[1,2]: 97a3e25abd228a44d4a14a6d3fe9185c 2479 | V[1,3]: c2d4cf7f4287a98744645674265d4ca8 2480 | 2481 | V[2,0]: 7bb50c534f6ec4780530ff1cce8a16e8 2482 | V[2,1]: 7b08d57557da0b5ef7b5f7d98b0ba189 2483 | V[2,2]: 6bfcac34ddb68404821a4d665303cb0f 2484 | V[2,3]: d95626f6dfad1aed7467622c38529932 2485 | 2486 | V[3,0]: af339fd2d50ee45fc47665c647cf6586 2487 | V[3,1]: d0669b39d140f0e118a4a511efe2f95a 2488 | V[3,2]: 7a94330f35c194fadda2a87e42cdeccc 2489 | V[3,3]: 233b640d1f4d56e2757e72c1a9d8ecb1 2490 | 2491 | V[4,0]: 9f93737d699ba05c11e94f2b201bef5e 2492 | V[4,1]: 61caf387cf7cfd3f8300ac7680ccfd76 2493 | V[4,2]: 5825a671ecef03b7a9c98a601ae32115 2494 | V[4,3]: 87a1fe4d558161a8f4c38731f3223032 2495 | 2496 | V[5,0]: 7a5aca78d636c05bbc702b2980196ab6 2497 | V[5,1]: 915d868408495d07eb527789f282c575 2498 | V[5,2]: d0947bfbc1d3309cdffc9be1503aea62 2499 | V[5,3]: 8834ea57a15b9fbdc0245464a4b8cbef 2500 | 2501 | V[6,0]: e46f4cf71a95ac45b6f0823e3aba1a86 2502 | V[6,1]: 8c4ecef682fc44a8eba911b3fc7d99f9 2503 | V[6,2]: a4fb61e2c928a2ca760b8772f2ea5f2e 2504 | V[6,3]: 3d34ea89da73caa3016c280500a155a3 2505 | 2506 | V[7,0]: 85075f0080e9d618e7eb40f57c32d9f7 2507 | V[7,1]: d2ab2b320c6e93b155a3787cb83e5281 2508 | V[7,2]: 0b3af0250ae36831a1b072e499929bcb 2509 | V[7,3]: 5cce4d00329d69f1aae36aa541347512 2510 | ~~~ 2511 | 2512 | ### Test Vector 1 2513 | 2514 | ~~~ test-vectors 2515 | key : 000102030405060708090a0b0c0d0e0f 2516 | 2517 | nonce : 101112131415161718191a1b1c1d1e1f 2518 | 2519 | ad : 2520 | 2521 | msg : 2522 | 2523 | ct : 2524 | 2525 | tag128: 5bef762d0947c00455b97bb3af30dfa3 2526 | 2527 | tag256: a4b25437f4be93cfa856a2f27e4416b4 2528 | 2cac79fd4698f2cdbe6af25673e10a68 2529 | ~~~ 2530 | 2531 | ### Test Vector 2 2532 | 2533 | ~~~ test-vectors 2534 | key : 000102030405060708090a0b0c0d0e0f 2535 | 2536 | nonce : 101112131415161718191a1b1c1d1e1f 2537 | 2538 | ad : 0102030401020304 2539 | 2540 | msg : 04050607040506070405060704050607 2541 | 04050607040506070405060704050607 2542 | 04050607040506070405060704050607 2543 | 04050607040506070405060704050607 2544 | 04050607040506070405060704050607 2545 | 04050607040506070405060704050607 2546 | 04050607040506070405060704050607 2547 | 0405060704050607 2548 | 2549 | ct : e836118562f4479c9d35c17356a83311 2550 | 4c21f9aa39e4dda5e5c87f4152a00fce 2551 | 9a7c38f832eafe8b1c12f8a7cf12a81a 2552 | 1ad8a9c24ba9dedfbdaa586ffea67ddc 2553 | 801ea97d9ab4a872f42d0e352e2713da 2554 | cd609f9442c17517c5a29daf3e2a3fac 2555 | 4ff6b1380c4e46df7b086af6ce6bc1ed 2556 | 594b8dd64aed2a7e 2557 | 2558 | tag128: 0e56ab94e2e85db80f9d54010caabfb4 2559 | 2560 | tag256: 69abf0f64a137dd6e122478d777e98bc 2561 | 422823006cf57f5ee822dd78397230b2 2562 | ~~~ 2563 | 2564 | ## AEGIS-256X2 Test Vectors 2565 | 2566 | ### Initial State 2567 | 2568 | ~~~ test-vectors 2569 | key : 000102030405060708090a0b0c0d0e0f 2570 | 101112131415161718191a1b1c1d1e1f 2571 | 2572 | nonce : 101112131415161718191a1b1c1d1e1f 2573 | 202122232425262728292a2b2c2d2e2f 2574 | 2575 | ctx[0]: 00010000000000000000000000000000 2576 | ctx[1]: 01010000000000000000000000000000 2577 | ~~~ 2578 | 2579 | After initialization: 2580 | 2581 | ~~~ test-vectors 2582 | V[0,0]: eca2bf4538442e8712d4972595744039 2583 | V[0,1]: 201405efa9264f07911db58101903087 2584 | 2585 | V[1,0]: 3e536a998799408a97f3479a6f779d48 2586 | V[1,1]: 0d79a7d822a5d215f78c3bf2feb33ae1 2587 | 2588 | V[2,0]: cf8c63d6f2b4563cdd9231107c85950e 2589 | V[2,1]: 78d17ed7d8d563ff11bd202c76864839 2590 | 2591 | V[3,0]: d7e0707e6bfbbad913bc94b6993a9fa0 2592 | V[3,1]: 097e4b1bff40d4c19cb29dfd125d62f2 2593 | 2594 | V[4,0]: a373cf6d537dd66bc0ef0f2f9285359f 2595 | V[4,1]: c0d0ae0c48f9df3faaf0e7be7768c326 2596 | 2597 | V[5,0]: 9f76560dcae1efacabdcce446ae283bc 2598 | V[5,1]: bd52a6b9c8f976a26ec1409df19e8bfe 2599 | ~~~ 2600 | 2601 | ### Test Vector 1 2602 | 2603 | ~~~ test-vectors 2604 | key : 000102030405060708090a0b0c0d0e0f 2605 | 101112131415161718191a1b1c1d1e1f 2606 | 2607 | nonce : 101112131415161718191a1b1c1d1e1f 2608 | 202122232425262728292a2b2c2d2e2f 2609 | 2610 | ad : 2611 | 2612 | msg : 2613 | 2614 | ct : 2615 | 2616 | tag128: 62cdbab084c83dacdb945bb446f049c8 2617 | 2618 | tag256: 25d7e799b49a80354c3f881ac2f1027f 2619 | 471a5d293052bd9997abd3ae84014bb7 2620 | ~~~ 2621 | 2622 | ### Test Vector 2 2623 | 2624 | ~~~ test-vectors 2625 | key : 000102030405060708090a0b0c0d0e0f 2626 | 101112131415161718191a1b1c1d1e1f 2627 | 2628 | nonce : 101112131415161718191a1b1c1d1e1f 2629 | 202122232425262728292a2b2c2d2e2f 2630 | 2631 | ad : 0102030401020304 2632 | 2633 | msg : 04050607040506070405060704050607 2634 | 04050607040506070405060704050607 2635 | 04050607040506070405060704050607 2636 | 04050607040506070405060704050607 2637 | 04050607040506070405060704050607 2638 | 04050607040506070405060704050607 2639 | 04050607040506070405060704050607 2640 | 0405060704050607 2641 | 2642 | ct : 72120c2ea8236180d67859001f472907 2643 | 7b7064c414384fe3a7b52f1571f4f8a7 2644 | d0f01e18db4f3bc0adb150702e5d147a 2645 | 8d36522132761b994c1bd395589e2ccf 2646 | 0790dfe2a3d12d61cd666b2859827739 2647 | db4037dd3124c78424459376f6cac08e 2648 | 1a7223a2a43e398ce6385cd654a19f48 2649 | 1cba3b8f25910b42 2650 | 2651 | tag128: 635d391828520bf1512763f0c8f5cdbd 2652 | 2653 | tag256: b5668d3317159e9cc5d46e4803c3a76a 2654 | d63bb42b3f47956d94f30db8cb366ad7 2655 | ~~~ 2656 | 2657 | ## AEGIS-256X4 Test Vectors 2658 | 2659 | ### Initial State 2660 | 2661 | ~~~ test-vectors 2662 | key : 000102030405060708090a0b0c0d0e0f 2663 | 101112131415161718191a1b1c1d1e1f 2664 | 2665 | nonce : 101112131415161718191a1b1c1d1e1f 2666 | 202122232425262728292a2b2c2d2e2f 2667 | 2668 | ctx[0]: 00030000000000000000000000000000 2669 | ctx[1]: 01030000000000000000000000000000 2670 | ctx[2]: 02030000000000000000000000000000 2671 | ctx[3]: 03030000000000000000000000000000 2672 | ~~~ 2673 | 2674 | After initialization: 2675 | 2676 | ~~~ test-vectors 2677 | V[0,0]: 482a86e8436cd2361063a4b2702769b9 2678 | V[0,1]: d95a2be81c9245b22996f68eea0122f9 2679 | V[0,2]: 0c2a3b348b1a5e256c6751377318c41e 2680 | V[0,3]: f64436a21653fe7cf2e0829a177db383 2681 | 2682 | V[1,0]: e705e8866267717d96092e58e78b574c 2683 | V[1,1]: d1dd412142df9806cc267af2fe1d830e 2684 | V[1,2]: 30e7dfd3c9941b8394e95bdf5bac99d9 2685 | V[1,3]: 9f27186f8a4fab86820689822c3c74d2 2686 | 2687 | V[2,0]: e1aa6af5d9e31dde8d94a48a0810fa89 2688 | V[2,1]: 63555cdf0d98f18fb75b029ad80786c0 2689 | V[2,2]: a3ee0e4a3429a9539e4fcec385475608 2690 | V[2,3]: 28ea527d31ef61df498dc107fe02df99 2691 | 2692 | V[3,0]: 37f06808410c8f3954525ae44584d3be 2693 | V[3,1]: 8fcc23bca2fe2209f93d34e2da35b33d 2694 | V[3,2]: 33156347df89eaa69ab11096362daccf 2695 | V[3,3]: bbe58d9dbe8c5b0469be5a87086db5d4 2696 | 2697 | V[4,0]: d1c9eb37fecbc5ada7b351fa4f501f32 2698 | V[4,1]: 0b9b803283c1538628b507c8f6432434 2699 | V[4,2]: bfb8b6d4f87cce28825c7e92f54b8728 2700 | V[4,3]: 8917bb5b09c32f900c6a5a1d63c46264 2701 | 2702 | V[5,0]: 4f6110c2ef0c3c687e90c1e5532ddf8e 2703 | V[5,1]: 031bd85d99f64684d23728a0453c72a1 2704 | V[5,2]: 10bc7ec34d4119b5bdeb6c7dfc458247 2705 | V[5,3]: 591ece530aeaa5c9867220156f5c25e3 2706 | ~~~ 2707 | 2708 | ### Test Vector 1 2709 | 2710 | ~~~ test-vectors 2711 | key : 000102030405060708090a0b0c0d0e0f 2712 | 101112131415161718191a1b1c1d1e1f 2713 | 2714 | nonce : 101112131415161718191a1b1c1d1e1f 2715 | 202122232425262728292a2b2c2d2e2f 2716 | 2717 | ad : 2718 | 2719 | msg : 2720 | 2721 | ct : 2722 | 2723 | tag128: 3b7fee6cee7bf17888ad11ed2397beb4 2724 | 2725 | tag256: 6093a1a8aab20ec635dc1ca71745b01b 2726 | 5bec4fc444c9ffbebd710d4a34d20eaf 2727 | ~~~ 2728 | 2729 | ### Test Vector 2 2730 | 2731 | ~~~ test-vectors 2732 | key : 000102030405060708090a0b0c0d0e0f 2733 | 101112131415161718191a1b1c1d1e1f 2734 | 2735 | nonce : 101112131415161718191a1b1c1d1e1f 2736 | 202122232425262728292a2b2c2d2e2f 2737 | 2738 | ad : 0102030401020304 2739 | 2740 | msg : 04050607040506070405060704050607 2741 | 04050607040506070405060704050607 2742 | 04050607040506070405060704050607 2743 | 04050607040506070405060704050607 2744 | 04050607040506070405060704050607 2745 | 04050607040506070405060704050607 2746 | 04050607040506070405060704050607 2747 | 0405060704050607 2748 | 2749 | ct : bfc2085b7e8017da99b0b6d646ae4d01 2750 | f4ba8f2e7dfca1d759ae48a135139b9a 2751 | aac6b4f5db810d426be1fdaff4e14541 2752 | 53a34b11da78ed7e418ee2ee9853042e 2753 | 95536aecbb694cea1b16a478eb0d4d1b 2754 | f6509b1ce652a45af58e0e46ffccfa2d 2755 | 0426e702391d2ff5813808b81748a490 2756 | dd656465fed61f09 2757 | 2758 | tag128: b63b611b13975e2f3dc3cb6c2397bfcd 2759 | 2760 | tag256: 7847eace74409ee56c8f4cf63a9c2841 2761 | ce7c8bd567d7c0ca514c879a190b978c 2762 | ~~~ 2763 | 2764 | ## AEGISMAC Test Vectors 2765 | 2766 | ### AEGISMAC-128L Test Vector 2767 | 2768 | ~~~ test-vectors 2769 | key : 10010000000000000000000000000000 2770 | 2771 | nonce : 10000200000000000000000000000000 2772 | 2773 | data : 000102030405060708090a0b0c0d0e0f 2774 | 101112131415161718191a1b1c1d1e1f 2775 | 202122 2776 | 2777 | tag128 : d3f09b2842ad301687d6902c921d7818 2778 | 2779 | tag256 : 9490e7c89d420c9f37417fa625eb38e8 2780 | cad53c5cbec55285e8499ea48377f2a3 2781 | ~~~ 2782 | 2783 | ### AEGISMAC-128X2 Test Vector 2784 | 2785 | ~~~ test-vectors 2786 | key : 10010000000000000000000000000000 2787 | 2788 | nonce : 10000200000000000000000000000000 2789 | 2790 | data : 000102030405060708090a0b0c0d0e0f 2791 | 101112131415161718191a1b1c1d1e1f 2792 | 202122 2793 | 2794 | tags128: 9f5f69928fa481fa86e8a51e072a9b29 2795 | eeaa77a356f796b427f6a54f52ae0e20 2796 | 2797 | tag128 : 6873ee34e6b5c59143b6d35c5e4f2c6e 2798 | 2799 | tags256: 22cdcf558d0338b6ad8fbba4da7307d3 2800 | 0bd685fff23dc9d41f598c2a7ea44055 2801 | 2802 | tag256 : afcba3fc2d63c8d6c7f2d63f3ec8fbbb 2803 | af022e15ac120e78ffa7755abccd959c 2804 | ~~~ 2805 | 2806 | ### AEGISMAC-128X4 Test Vector 2807 | 2808 | ~~~ test-vectors 2809 | key : 10010000000000000000000000000000 2810 | 2811 | nonce : 10000200000000000000000000000000 2812 | 2813 | data : 000102030405060708090a0b0c0d0e0f 2814 | 101112131415161718191a1b1c1d1e1f 2815 | 202122 2816 | 2817 | tags128: 7fecd913a7cb0011b6c4c88e0c6f8578 2818 | 19a98fbeaf21d1092c32953fff82c8a9 2819 | c7b5e6625a5765d04af26cf22adc1282 2820 | 4c8cf3b4dbb85f379e13b04a8d06bca7 2821 | 2822 | tag128 : c45a98fd9ab8956ce616eb008cfe4e53 2823 | 2824 | tags256: d595732bdf230a1441978414cd8cfa39 2825 | ecef6ad0ee1e65ae530006ca5d5f4481 2826 | f9ec5edfa64e9c3d76d3a5eda9fe5bd1 2827 | fb9d842373f7c90bedb8bfe383740b23 2828 | 1264a15143eb8c3d9f17754099f147e3 2829 | 401c83c0d5afc70fd0d68bfd17f9280f 2830 | 2831 | tag256 : 26fdc76f41b1da7aec7779f6e964beae 2832 | 8904e662f05aca8345ae3befb357412a 2833 | ~~~ 2834 | 2835 | ### AEGISMAC-256 Test Vector 2836 | 2837 | ~~~ test-vectors 2838 | key : 10010000000000000000000000000000 2839 | 00000000000000000000000000000000 2840 | 2841 | nonce : 10000200000000000000000000000000 2842 | 00000000000000000000000000000000 2843 | 2844 | data : 000102030405060708090a0b0c0d0e0f 2845 | 101112131415161718191a1b1c1d1e1f 2846 | 202122 2847 | 2848 | tag128 : c08e20cfc56f27195a46c9cef5c162d4 2849 | 2850 | tag256 : a5c906ede3d69545c11e20afa360b221 2851 | f936e946ed2dba3d7c75ad6dc2784126 2852 | ~~~ 2853 | 2854 | ### AEGISMAC-256X2 Test Vector 2855 | 2856 | ~~~ test-vectors 2857 | key : 10010000000000000000000000000000 2858 | 00000000000000000000000000000000 2859 | 2860 | nonce : 10000200000000000000000000000000 2861 | 00000000000000000000000000000000 2862 | 2863 | data : 000102030405060708090a0b0c0d0e0f 2864 | 101112131415161718191a1b1c1d1e1f 2865 | 202122 2866 | 2867 | tags128: db8852ea2c03f22b0d0694ea4e88e4b1 2868 | 2869 | tag128 : fb319cb6dd728a764606fb14d37f2a5e 2870 | 2871 | tags256: b4d124976b34b2aa8bc3fa0b55396cf7 2872 | fb83f4ef5ba607681cddf5ba3e925727 2873 | 2874 | tag256 : 0844b20ed5147ceae89c7a160263afd4 2875 | b1382d6b154ecf560ce8a342cb6a8fd1 2876 | ~~~ 2877 | 2878 | ### AEGISMAC-256X4 Test Vector 2879 | 2880 | ~~~ test-vectors 2881 | key : 10010000000000000000000000000000 2882 | 00000000000000000000000000000000 2883 | 2884 | nonce : 10000200000000000000000000000000 2885 | 00000000000000000000000000000000 2886 | 2887 | data : 000102030405060708090a0b0c0d0e0f 2888 | 101112131415161718191a1b1c1d1e1f 2889 | 202122 2890 | 2891 | tags128: 702d595e74962d073a0d68c883d80deb 2892 | 41ab207e43b16659d556d7467218a9ec 2893 | 113406e7cb56e0f6b63c95c88421dfee 2894 | 2895 | tag128 : a51f9bc5beae60cce77f0dbc60761edd 2896 | 2897 | tags256: a46ebcd10939b42012a3f9b6147172af 2898 | 3b74aec5d0070e8d6a81498ccbcdb41a 2899 | d57cd7a50fa8621dfea2e81cd941def5 2900 | 57094251a24527a4d97fc4c825368180 2901 | 3973129d07cc20811a8b3c34574f6ce0 2902 | 10165dd0e856e797f70731e78e32f764 2903 | 2904 | tag256 : b36a16ef07c36d75a91f437502f24f54 2905 | 5b8dfa88648ed116943c29fead3bf10c 2906 | ~~~ 2907 | 2908 | # Acknowledgments 2909 | {:numbered="false"} 2910 | 2911 | The AEGIS family of authenticated encryption algorithms was invented by Hongjun Wu and Bart Preneel. 2912 | 2913 | The state update function leverages the AES permutation invented by Joan Daemen and Vincent Rijmen. They also authored the Pelican MAC, which partly motivated the design of the AEGIS MAC. 2914 | 2915 | We would like to thank the following individuals for their contributions: 2916 | 2917 | - Eric Lagergren, Daniel Bleichenbacher, and Conrad Ludgate for catching invalid test vectors, and Daniel Bleichenbacher for many helpful suggestions. 2918 | - Soatok Dreamseeker for his early review of the draft and for suggesting the addition of negative test vectors. 2919 | - John Preuß Mattsson for his review of the draft and for suggesting how AEGIS should be used in the context of DTLS and QUIC. 2920 | - Bart Mennink and Charlotte Lefevre, as well as Takanori Isobe and Mostafizar Rahman, for investigating the committing security of the schemes specified in this document. 2921 | - Scott Fluhrer for his review of the draft as a member of the CFRG Crypto Review Panel. 2922 | - Yawning Angel, Chris Barber, and Neil Madden for their review of the draft. 2923 | - Gilles Van Assche for reviewing the draft and providing insightful comments on the implications of nonce reuse in AEGIS-128X and AEGIS-256X. 2924 | -------------------------------------------------------------------------------- /reference-implementations/aegis128l.zig: -------------------------------------------------------------------------------- 1 | const std = @import("std"); 2 | const assert = std.debug.assert; 3 | const crypto = std.crypto; 4 | const mem = std.mem; 5 | const AesBlock = std.crypto.core.aes.Block; 6 | const AuthenticationError = std.crypto.errors.AuthenticationError; 7 | 8 | pub const Aegis128L = Aegis128L_(128); 9 | pub const Aegis128L_256 = Aegis128L_(256); 10 | 11 | fn Aegis128L_(comptime tag_bits: u9) type { 12 | assert(tag_bits == 128 or tag_bits == 256); // tag bits must be 128 or 256 13 | 14 | return struct { 15 | const Self = @This(); 16 | 17 | pub const key_length = 16; 18 | pub const nonce_length = 16; 19 | pub const tag_length: comptime_int = tag_bits / 8; 20 | pub const ad_max_length = 1 << 61; 21 | pub const msg_max_length = 1 << 61; 22 | pub const ct_max_length = msg_max_length + tag_length; 23 | 24 | const State = [8]AesBlock; 25 | 26 | s: State, 27 | 28 | inline fn aesround(in: AesBlock, rk: AesBlock) AesBlock { 29 | return in.encrypt(rk); 30 | } 31 | 32 | fn update(self: *Self, m0: AesBlock, m1: AesBlock) void { 33 | const s = self.s; 34 | self.s = State{ 35 | aesround(s[7], s[0].xorBlocks(m0)), 36 | aesround(s[0], s[1]), 37 | aesround(s[1], s[2]), 38 | aesround(s[2], s[3]), 39 | aesround(s[3], s[4].xorBlocks(m1)), 40 | aesround(s[4], s[5]), 41 | aesround(s[5], s[6]), 42 | aesround(s[6], s[7]), 43 | }; 44 | } 45 | 46 | fn init(key: [key_length]u8, nonce: [nonce_length]u8) Self { 47 | const c0 = AesBlock.fromBytes(&[16]u8{ 0x00, 0x01, 0x01, 0x02, 0x03, 0x05, 0x08, 0x0d, 0x15, 0x22, 0x37, 0x59, 0x90, 0xe9, 0x79, 0x62 }); 48 | const c1 = AesBlock.fromBytes(&[16]u8{ 0xdb, 0x3d, 0x18, 0x55, 0x6d, 0xc2, 0x2f, 0xf1, 0x20, 0x11, 0x31, 0x42, 0x73, 0xb5, 0x28, 0xdd }); 49 | const key_block = AesBlock.fromBytes(&key); 50 | const nonce_block = AesBlock.fromBytes(&nonce); 51 | var self = Self{ .s = State{ 52 | key_block.xorBlocks(nonce_block), 53 | c1, 54 | c0, 55 | c1, 56 | key_block.xorBlocks(nonce_block), 57 | key_block.xorBlocks(c0), 58 | key_block.xorBlocks(c1), 59 | key_block.xorBlocks(c0), 60 | } }; 61 | for (0..10) |_| { 62 | self.update(nonce_block, key_block); 63 | } 64 | return self; 65 | } 66 | 67 | fn absorb(self: *Self, ai: *const [32]u8) void { 68 | const t0 = AesBlock.fromBytes(ai[0..16]); 69 | const t1 = AesBlock.fromBytes(ai[16..32]); 70 | self.update(t0, t1); 71 | } 72 | 73 | fn enc(self: *Self, xi: *const [32]u8) [32]u8 { 74 | const s = self.s; 75 | const z0 = s[1].xorBlocks(s[6]).xorBlocks(s[2].andBlocks(s[3])); 76 | const z1 = s[2].xorBlocks(s[5]).xorBlocks(s[6].andBlocks(s[7])); 77 | const t0 = AesBlock.fromBytes(xi[0..16]); 78 | const t1 = AesBlock.fromBytes(xi[16..32]); 79 | const out0 = t0.xorBlocks(z0); 80 | const out1 = t1.xorBlocks(z1); 81 | self.update(t0, t1); 82 | var ci: [32]u8 = undefined; 83 | ci[0..16].* = out0.toBytes(); 84 | ci[16..32].* = out1.toBytes(); 85 | return ci; 86 | } 87 | 88 | fn dec(self: *Self, ci: *const [32]u8) [32]u8 { 89 | const s = self.s; 90 | const z0 = s[1].xorBlocks(s[6]).xorBlocks(s[2].andBlocks(s[3])); 91 | const z1 = s[2].xorBlocks(s[5]).xorBlocks(s[6].andBlocks(s[7])); 92 | const t0 = AesBlock.fromBytes(ci[0..16]); 93 | const t1 = AesBlock.fromBytes(ci[16..32]); 94 | const out0 = t0.xorBlocks(z0); 95 | const out1 = t1.xorBlocks(z1); 96 | self.update(out0, out1); 97 | var xi: [32]u8 = undefined; 98 | xi[0..16].* = out0.toBytes(); 99 | xi[16..32].* = out1.toBytes(); 100 | return xi; 101 | } 102 | 103 | fn decLast(self: *Self, xn: []u8, cn: []const u8) void { 104 | const s = self.s; 105 | const z0 = s[1].xorBlocks(s[6]).xorBlocks(s[2].andBlocks(s[3])); 106 | const z1 = s[2].xorBlocks(s[5]).xorBlocks(s[6].andBlocks(s[7])); 107 | var pad = [_]u8{0} ** 32; 108 | @memcpy(pad[0..cn.len], cn); 109 | const t0 = AesBlock.fromBytes(pad[0..16]); 110 | const t1 = AesBlock.fromBytes(pad[16..32]); 111 | const out0 = t0.xorBlocks(z0); 112 | const out1 = t1.xorBlocks(z1); 113 | pad[0..16].* = out0.toBytes(); 114 | pad[16..32].* = out1.toBytes(); 115 | @memcpy(xn, pad[0..cn.len]); 116 | @memset(pad[cn.len..], 0); 117 | const v0 = AesBlock.fromBytes(pad[0..16]); 118 | const v1 = AesBlock.fromBytes(pad[16..32]); 119 | self.update(v0, v1); 120 | } 121 | 122 | fn finalize(self: *Self, ad_len: usize, msg_len: usize) [tag_length]u8 { 123 | var s = &self.s; 124 | var b: [16]u8 = undefined; 125 | mem.writeInt(u64, b[0..8], @as(u64, ad_len) * 8, .little); 126 | mem.writeInt(u64, b[8..16], @as(u64, msg_len) * 8, .little); 127 | const t = s[2].xorBlocks(AesBlock.fromBytes(&b)); 128 | for (0..7) |_| { 129 | self.update(t, t); 130 | } 131 | var tag: [tag_length]u8 = undefined; 132 | if (tag_length == 16) { 133 | tag = s[0].xorBlocks(s[1]).xorBlocks(s[2]).xorBlocks(s[3]).xorBlocks(s[4]).xorBlocks(s[5]).xorBlocks(s[6]).toBytes(); 134 | } else { 135 | tag[0..16].* = s[0].xorBlocks(s[1]).xorBlocks(s[2]).xorBlocks(s[3]).toBytes(); 136 | tag[16..].* = s[4].xorBlocks(s[5]).xorBlocks(s[6]).xorBlocks(s[7]).toBytes(); 137 | } 138 | return tag; 139 | } 140 | 141 | pub fn encrypt( 142 | ct: []u8, 143 | msg: []const u8, 144 | ad: []const u8, 145 | key: [key_length]u8, 146 | nonce: [nonce_length]u8, 147 | ) [tag_length]u8 { 148 | assert(msg.len <= msg_max_length); 149 | assert(ad.len <= ad_max_length); 150 | assert(ct.len == msg.len); 151 | var aegis = init(key, nonce); 152 | 153 | var i: usize = 0; 154 | while (i + 32 <= ad.len) : (i += 32) { 155 | aegis.absorb(ad[i..][0..32]); 156 | } 157 | if (ad.len % 32 != 0) { 158 | var pad = [_]u8{0} ** 32; 159 | @memcpy(pad[0 .. ad.len % 32], ad[i..]); 160 | aegis.absorb(&pad); 161 | } 162 | 163 | i = 0; 164 | while (i + 32 <= msg.len) : (i += 32) { 165 | ct[i..][0..32].* = aegis.enc(msg[i..][0..32]); 166 | } 167 | if (msg.len % 32 != 0) { 168 | var pad = [_]u8{0} ** 32; 169 | @memcpy(pad[0 .. msg.len % 32], msg[i..]); 170 | @memcpy(ct[i..], aegis.enc(&pad)[0 .. msg.len % 32]); 171 | } 172 | 173 | return aegis.finalize(ad.len, msg.len); 174 | } 175 | 176 | pub fn decrypt( 177 | msg: []u8, 178 | ct: []const u8, 179 | tag: [tag_length]u8, 180 | ad: []const u8, 181 | key: [key_length]u8, 182 | nonce: [nonce_length]u8, 183 | ) AuthenticationError!void { 184 | assert(ct.len <= ct_max_length); 185 | assert(ad.len <= ad_max_length); 186 | assert(ct.len == msg.len); 187 | var aegis = init(key, nonce); 188 | 189 | var i: usize = 0; 190 | while (i + 32 <= ad.len) : (i += 32) { 191 | aegis.absorb(ad[i..][0..32]); 192 | } 193 | if (ad.len % 32 != 0) { 194 | var pad = [_]u8{0} ** 32; 195 | @memcpy(pad[0 .. ad.len % 32], ad[i..]); 196 | aegis.absorb(&pad); 197 | } 198 | 199 | i = 0; 200 | while (i + 32 <= ct.len) : (i += 32) { 201 | msg[i..][0..32].* = aegis.dec(ct[i..][0..32]); 202 | } 203 | if (ct.len % 32 != 0) { 204 | aegis.decLast(msg[i..], ct[i..]); 205 | } 206 | 207 | const expected_tag = aegis.finalize(ad.len, msg.len); 208 | if (!crypto.utils.timingSafeEql([expected_tag.len]u8, expected_tag, tag)) { 209 | crypto.utils.secureZero(u8, msg); 210 | return error.AuthenticationFailed; 211 | } 212 | } 213 | 214 | pub fn stream( 215 | out: []u8, 216 | key: [key_length]u8, 217 | nonce: ?[nonce_length]u8, 218 | ) void { 219 | assert(out.len <= msg_max_length); 220 | var aegis = init(key, nonce orelse [_]u8{0} ** nonce_length); 221 | 222 | const zero = [_]u8{0} ** 32; 223 | 224 | var i: usize = 0; 225 | while (i + 32 <= out.len) : (i += 32) { 226 | out[i..][0..32].* = aegis.enc(&zero); 227 | } 228 | if (out.len % 32 != 0) { 229 | @memcpy(out[i..], aegis.enc(&zero)[0 .. out.len % 32]); 230 | } 231 | } 232 | 233 | pub fn mac( 234 | data: []const u8, 235 | key: [key_length]u8, 236 | nonce: [nonce_length]u8, 237 | ) [tag_length]u8 { 238 | assert(data.len <= ad_max_length); 239 | var aegis = init(key, nonce); 240 | 241 | var i: usize = 0; 242 | while (i + 32 <= data.len) : (i += 32) { 243 | aegis.absorb(data[i..][0..32]); 244 | } 245 | if (data.len % 32 != 0) { 246 | var pad = [_]u8{0} ** 32; 247 | @memcpy(pad[0 .. data.len % 32], data[i..]); 248 | aegis.absorb(&pad); 249 | } 250 | return aegis.finalize(data.len, tag_length); 251 | } 252 | }; 253 | } 254 | -------------------------------------------------------------------------------- /reference-implementations/aegis128x.zig: -------------------------------------------------------------------------------- 1 | const std = @import("std"); 2 | const assert = std.debug.assert; 3 | const crypto = std.crypto; 4 | const mem = std.mem; 5 | const AesBlockVec = crypto.core.aes.BlockVec; 6 | const AuthenticationError = std.crypto.errors.AuthenticationError; 7 | 8 | pub const Aegis128X2 = Aegis128X_(2, 128); 9 | pub const Aegis128X2_256 = Aegis128X_(2, 256); 10 | pub const Aegis128X4 = Aegis128X_(4, 128); 11 | pub const Aegis128X4_256 = Aegis128X_(4, 256); 12 | 13 | // Let S = { s0, s1, s2, s3, s4, s5, s6, s7 } represent a regular AEGIS-128L state. 14 | // 15 | // An AEGIS-128X2 state uses two AEGIS-128L states { S0, S1 } represented as: 16 | // { { S0_s0, S1_s0 }, { S0_s1, S1_s1 }, { S0_s2, S1_s2 }, { S0_s3, S1_s3 }, 17 | // { S0_s0, S1_s0 }, { S0_s1, S1_s1 }, { S0_s6, S1_s6 }, { S0_s7, S1_s7 } } 18 | // 19 | // This is the native representation when using VAES instructions with 256 bit vectors. 20 | // That can be generalized to other degrees. 21 | // 22 | // The following AEGIS-128X implementation is pretty much identical to the AEGIS-128L 23 | // one, the main difference being that `AesBlock` (a single AES block) is replaced with 24 | // `AesBlockX` (a vector of `degree` AES blocks). 25 | 26 | fn Aegis128X_(comptime degree: u7, comptime tag_bits: u9) type { 27 | assert(tag_bits == 128 or tag_bits == 256); // tag bits must be 128 or 256 28 | assert(degree > 0); // degree can't be 0 29 | 30 | return struct { 31 | const Self = @This(); 32 | 33 | pub const key_length = 16; 34 | pub const nonce_length = 16; 35 | pub const tag_length: comptime_int = tag_bits / 8; 36 | pub const ad_max_length = 1 << 61; 37 | pub const msg_max_length = 1 << 61; 38 | pub const ct_max_length = msg_max_length + tag_length; 39 | 40 | const AesBlockX = AesBlockVec(degree); 41 | const blockx_length = AesBlockX.block_length; 42 | const rate = blockx_length * 2; 43 | 44 | const State = [8]AesBlockX; 45 | 46 | s: State, 47 | 48 | inline fn aesround(in: AesBlockX, rk: AesBlockX) AesBlockX { 49 | return in.encrypt(rk); 50 | } 51 | 52 | fn update(self: *Self, m0: AesBlockX, m1: AesBlockX) void { 53 | const s = self.s; 54 | self.s = State{ 55 | aesround(s[7], s[0].xorBlocks(m0)), 56 | aesround(s[0], s[1]), 57 | aesround(s[1], s[2]), 58 | aesround(s[2], s[3]), 59 | aesround(s[3], s[4].xorBlocks(m1)), 60 | aesround(s[4], s[5]), 61 | aesround(s[5], s[6]), 62 | aesround(s[6], s[7]), 63 | }; 64 | } 65 | 66 | fn init(key: [key_length]u8, nonce: [nonce_length]u8) Self { 67 | const c0_v = AesBlockX.fromBytes(&[16]u8{ 0x00, 0x01, 0x01, 0x02, 0x03, 0x05, 0x08, 0x0d, 0x15, 0x22, 0x37, 0x59, 0x90, 0xe9, 0x79, 0x62 } ** degree); 68 | const c1_v = AesBlockX.fromBytes(&[16]u8{ 0xdb, 0x3d, 0x18, 0x55, 0x6d, 0xc2, 0x2f, 0xf1, 0x20, 0x11, 0x31, 0x42, 0x73, 0xb5, 0x28, 0xdd } ** degree); 69 | const key_v = AesBlockX.fromBytes(&(key ** degree)); 70 | const nonce_v = AesBlockX.fromBytes(&(nonce ** degree)); 71 | const ctx_v = ctx_v: { 72 | var contexts_bytes = [_]u8{0} ** blockx_length; 73 | for (0..degree) |i| { 74 | contexts_bytes[i * 16] = @intCast(i); 75 | contexts_bytes[i * 16 + 1] = @intCast(degree - 1); 76 | } 77 | break :ctx_v AesBlockX.fromBytes(&contexts_bytes); 78 | }; 79 | var self = Self{ .s = State{ 80 | key_v.xorBlocks(nonce_v), 81 | c1_v, 82 | c0_v, 83 | c1_v, 84 | key_v.xorBlocks(nonce_v), 85 | key_v.xorBlocks(c0_v), 86 | key_v.xorBlocks(c1_v), 87 | key_v.xorBlocks(c0_v), 88 | } }; 89 | for (0..10) |_| { 90 | self.s[3] = self.s[3].xorBlocks(ctx_v); 91 | self.s[7] = self.s[7].xorBlocks(ctx_v); 92 | self.update(nonce_v, key_v); 93 | } 94 | return self; 95 | } 96 | 97 | fn absorb(self: *Self, ai: *const [rate]u8) void { 98 | const t0 = AesBlockX.fromBytes(ai[0..blockx_length]); 99 | const t1 = AesBlockX.fromBytes(ai[blockx_length..rate]); 100 | self.update(t0, t1); 101 | } 102 | 103 | fn enc(self: *Self, xi: *const [rate]u8) [rate]u8 { 104 | const s = self.s; 105 | const z0 = s[1].xorBlocks(s[6]).xorBlocks(s[2].andBlocks(s[3])); 106 | const z1 = s[2].xorBlocks(s[5]).xorBlocks(s[6].andBlocks(s[7])); 107 | const t0 = AesBlockX.fromBytes(xi[0..blockx_length]); 108 | const t1 = AesBlockX.fromBytes(xi[blockx_length..rate]); 109 | const out0 = t0.xorBlocks(z0); 110 | const out1 = t1.xorBlocks(z1); 111 | self.update(t0, t1); 112 | var ci: [rate]u8 = undefined; 113 | ci[0..blockx_length].* = out0.toBytes(); 114 | ci[blockx_length..rate].* = out1.toBytes(); 115 | return ci; 116 | } 117 | 118 | fn dec(self: *Self, ci: *const [rate]u8) [rate]u8 { 119 | const s = self.s; 120 | const z0 = s[1].xorBlocks(s[6]).xorBlocks(s[2].andBlocks(s[3])); 121 | const z1 = s[2].xorBlocks(s[5]).xorBlocks(s[6].andBlocks(s[7])); 122 | const t0 = AesBlockX.fromBytes(ci[0..blockx_length]); 123 | const t1 = AesBlockX.fromBytes(ci[blockx_length..rate]); 124 | const out0 = t0.xorBlocks(z0); 125 | const out1 = t1.xorBlocks(z1); 126 | self.update(out0, out1); 127 | var xi: [rate]u8 = undefined; 128 | xi[0..blockx_length].* = out0.toBytes(); 129 | xi[blockx_length..rate].* = out1.toBytes(); 130 | return xi; 131 | } 132 | 133 | fn decLast(self: *Self, xn: []u8, cn: []const u8) void { 134 | const s = self.s; 135 | const z0 = s[1].xorBlocks(s[6]).xorBlocks(s[2].andBlocks(s[3])); 136 | const z1 = s[2].xorBlocks(s[5]).xorBlocks(s[6].andBlocks(s[7])); 137 | var pad = [_]u8{0} ** rate; 138 | @memcpy(pad[0..cn.len], cn); 139 | const t0 = AesBlockX.fromBytes(pad[0..blockx_length]); 140 | const t1 = AesBlockX.fromBytes(pad[blockx_length..rate]); 141 | const out0 = t0.xorBlocks(z0); 142 | const out1 = t1.xorBlocks(z1); 143 | pad[0..blockx_length].* = out0.toBytes(); 144 | pad[blockx_length..rate].* = out1.toBytes(); 145 | @memcpy(xn, pad[0..cn.len]); 146 | @memset(pad[cn.len..], 0); 147 | const v0 = AesBlockX.fromBytes(pad[0..blockx_length]); 148 | const v1 = AesBlockX.fromBytes(pad[blockx_length..rate]); 149 | self.update(v0, v1); 150 | } 151 | 152 | fn finalize(self: *Self, ad_len: usize, msg_len: usize) [tag_length]u8 { 153 | var s = &self.s; 154 | var b: [blockx_length]u8 = undefined; 155 | mem.writeInt(u64, b[0..8], @as(u64, ad_len) * 8, .little); 156 | mem.writeInt(u64, b[8..16], @as(u64, msg_len) * 8, .little); 157 | for (1..degree) |i| { 158 | b[i * 16 ..][0..16].* = b[0..16].*; 159 | } 160 | const t = s[2].xorBlocks(AesBlockX.fromBytes(&b)); 161 | for (0..7) |_| { 162 | self.update(t, t); 163 | } 164 | var tag: [tag_length]u8 = undefined; 165 | if (tag_length == 16) { 166 | var tag_multi = s[0].xorBlocks(s[1]).xorBlocks(s[2]).xorBlocks(s[3]).xorBlocks(s[4]).xorBlocks(s[5]).xorBlocks(s[6]).toBytes(); 167 | tag = tag_multi[0..16].*; 168 | for (1..degree) |d| { 169 | for (0..16) |i| { 170 | tag[i] ^= tag_multi[d * 16 + i]; 171 | } 172 | } 173 | } else { 174 | var tag_multi_0 = s[0].xorBlocks(s[1]).xorBlocks(s[2]).xorBlocks(s[3]).toBytes(); 175 | var tag_multi_1 = s[4].xorBlocks(s[5]).xorBlocks(s[6]).xorBlocks(s[7]).toBytes(); 176 | @memcpy(tag[0..16], tag_multi_0[0..16]); 177 | @memcpy(tag[16..32], tag_multi_1[0..16]); 178 | for (1..degree) |d| { 179 | for (0..16) |i| { 180 | tag[i] ^= tag_multi_0[d * 16 + i]; 181 | tag[i + 16] ^= tag_multi_1[d * 16 + i]; 182 | } 183 | } 184 | } 185 | return tag; 186 | } 187 | 188 | fn finalizeMac(self: *Self, data_len: usize) [tag_length]u8 { 189 | var s = &self.s; 190 | var b: [blockx_length]u8 = undefined; 191 | mem.writeInt(u64, b[0..8], @as(u64, data_len) * 8, .little); 192 | mem.writeInt(u64, b[8..16], tag_bits, .little); 193 | for (1..degree) |i| { 194 | b[i * 16 ..][0..16].* = b[0..16].*; 195 | } 196 | var t = s[2].xorBlocks(AesBlockX.fromBytes(&b)); 197 | for (0..7) |_| { 198 | self.update(t, t); 199 | } 200 | var v = [_]u8{0} ** rate; 201 | if (tag_length == 16) { 202 | const tags = s[0].xorBlocks(s[1]).xorBlocks(s[2]).xorBlocks(s[3]).xorBlocks(s[4]).xorBlocks(s[5]).xorBlocks(s[6]).toBytes(); 203 | for (0..degree / 2) |d| { 204 | v[0..16].* = tags[d * 32 ..][0..16].*; 205 | v[rate / 2 ..][0..16].* = tags[d * 32 ..][16..32].*; 206 | self.absorb(&v); 207 | } 208 | } else { 209 | const tags_0 = s[0].xorBlocks(s[1]).xorBlocks(s[2]).xorBlocks(s[3]).toBytes(); 210 | const tags_1 = s[4].xorBlocks(s[5]).xorBlocks(s[6]).xorBlocks(s[7]).toBytes(); 211 | for (1..degree) |d| { 212 | v[0..16].* = tags_0[d * 16 ..][0..16].*; 213 | v[rate / 2 ..][0..16].* = tags_1[d * 16 ..][0..16].*; 214 | self.absorb(&v); 215 | } 216 | } 217 | if (degree > 1) { 218 | mem.writeInt(u64, b[0..8], degree, .little); 219 | mem.writeInt(u64, b[8..16], tag_bits, .little); 220 | t = s[2].xorBlocks(AesBlockX.fromBytes(&b)); 221 | for (0..7) |_| { 222 | self.update(t, t); 223 | } 224 | } 225 | if (tag_length == 16) { 226 | const tags = s[0].xorBlocks(s[1]).xorBlocks(s[2]).xorBlocks(s[3]).xorBlocks(s[4]).xorBlocks(s[5]).xorBlocks(s[6]).toBytes(); 227 | return tags[0..16].*; 228 | } else { 229 | const tags_0 = s[0].xorBlocks(s[1]).xorBlocks(s[2]).xorBlocks(s[3]).toBytes(); 230 | const tags_1 = s[4].xorBlocks(s[5]).xorBlocks(s[6]).xorBlocks(s[7]).toBytes(); 231 | return tags_0[0..16].* ++ tags_1[0..16].*; 232 | } 233 | } 234 | 235 | pub fn encrypt( 236 | ct: []u8, 237 | msg: []const u8, 238 | ad: []const u8, 239 | key: [key_length]u8, 240 | nonce: [nonce_length]u8, 241 | ) [tag_length]u8 { 242 | assert(msg.len <= msg_max_length); 243 | assert(ad.len <= ad_max_length); 244 | assert(ct.len == msg.len); 245 | var aegis = init(key, nonce); 246 | 247 | var i: usize = 0; 248 | while (i + rate <= ad.len) : (i += rate) { 249 | aegis.absorb(ad[i..][0..rate]); 250 | } 251 | if (ad.len % rate != 0) { 252 | var pad = [_]u8{0} ** rate; 253 | @memcpy(pad[0 .. ad.len % rate], ad[i..]); 254 | aegis.absorb(&pad); 255 | } 256 | 257 | i = 0; 258 | while (i + rate <= msg.len) : (i += rate) { 259 | @memcpy(ct[i..][0..rate], &aegis.enc(msg[i..][0..rate])); 260 | } 261 | if (msg.len % rate != 0) { 262 | var pad = [_]u8{0} ** rate; 263 | @memcpy(pad[0 .. msg.len % rate], msg[i..]); 264 | @memcpy(ct[i..], aegis.enc(&pad)[0 .. msg.len % rate]); 265 | } 266 | 267 | return aegis.finalize(ad.len, msg.len); 268 | } 269 | 270 | pub fn decrypt( 271 | msg: []u8, 272 | ct: []const u8, 273 | tag: [tag_length]u8, 274 | ad: []const u8, 275 | key: [key_length]u8, 276 | nonce: [nonce_length]u8, 277 | ) AuthenticationError!void { 278 | assert(ct.len <= ct_max_length); 279 | assert(ad.len <= ad_max_length); 280 | assert(ct.len == msg.len); 281 | var aegis = init(key, nonce); 282 | 283 | var i: usize = 0; 284 | while (i + rate <= ad.len) : (i += rate) { 285 | aegis.absorb(ad[i..][0..rate]); 286 | } 287 | if (ad.len % rate != 0) { 288 | var pad = [_]u8{0} ** rate; 289 | @memcpy(pad[0 .. ad.len % rate], ad[i..]); 290 | aegis.absorb(&pad); 291 | } 292 | 293 | i = 0; 294 | while (i + rate <= ct.len) : (i += rate) { 295 | @memcpy(msg[i..][0..rate], &aegis.dec(ct[i..][0..rate])); 296 | } 297 | if (ct.len % rate != 0) { 298 | aegis.decLast(msg[i..], ct[i..]); 299 | } 300 | 301 | const expected_tag = aegis.finalize(ad.len, msg.len); 302 | if (!crypto.utils.timingSafeEql([expected_tag.len]u8, expected_tag, tag)) { 303 | crypto.utils.secureZero(u8, msg); 304 | return error.AuthenticationFailed; 305 | } 306 | } 307 | 308 | pub fn stream( 309 | out: []u8, 310 | key: [key_length]u8, 311 | nonce: ?[nonce_length]u8, 312 | ) void { 313 | assert(out.len <= msg_max_length); 314 | var aegis = init(key, nonce orelse [_]u8{0} ** nonce_length); 315 | 316 | const zero = [_]u8{0} ** rate; 317 | 318 | var i: usize = 0; 319 | while (i + rate <= out.len) : (i += rate) { 320 | out[i..][0..rate].* = aegis.enc(&zero); 321 | } 322 | if (out.len % rate != 0) { 323 | @memcpy(out[i..], aegis.enc(&zero)[0 .. out.len % rate]); 324 | } 325 | } 326 | 327 | pub fn mac( 328 | data: []const u8, 329 | key: [key_length]u8, 330 | nonce: [nonce_length]u8, 331 | ) [tag_length]u8 { 332 | assert(data.len <= ad_max_length); 333 | var aegis = init(key, nonce); 334 | var i: usize = 0; 335 | while (i + rate <= data.len) : (i += rate) { 336 | aegis.absorb(data[i..][0..rate]); 337 | } 338 | if (data.len % rate != 0) { 339 | var pad = [_]u8{0} ** rate; 340 | @memcpy(pad[0 .. data.len % rate], data[i..]); 341 | aegis.absorb(&pad); 342 | } 343 | return aegis.finalizeMac(data.len); 344 | } 345 | }; 346 | } 347 | -------------------------------------------------------------------------------- /reference-implementations/aegis256.zig: -------------------------------------------------------------------------------- 1 | const std = @import("std"); 2 | const assert = std.debug.assert; 3 | const crypto = std.crypto; 4 | const mem = std.mem; 5 | const AesBlock = std.crypto.core.aes.Block; 6 | const AuthenticationError = std.crypto.errors.AuthenticationError; 7 | 8 | pub const Aegis256 = Aegis256_(128); 9 | pub const Aegis256_256 = Aegis256_(256); 10 | 11 | fn Aegis256_(comptime tag_bits: u9) type { 12 | assert(tag_bits == 128 or tag_bits == 256); // tag bits must be 128 or 256 13 | 14 | return struct { 15 | const Self = @This(); 16 | 17 | pub const key_length = 32; 18 | pub const nonce_length = 32; 19 | pub const tag_length: comptime_int = tag_bits / 8; 20 | pub const ad_max_length = 1 << 61; 21 | pub const msg_max_length = 1 << 61; 22 | pub const ct_max_length = msg_max_length + tag_length; 23 | 24 | const State = [6]AesBlock; 25 | 26 | s: State, 27 | 28 | inline fn aesround(in: AesBlock, rk: AesBlock) AesBlock { 29 | return in.encrypt(rk); 30 | } 31 | 32 | fn update(self: *Self, m: AesBlock) void { 33 | const s = self.s; 34 | self.s = State{ 35 | aesround(s[5], s[0].xorBlocks(m)), 36 | aesround(s[0], s[1]), 37 | aesround(s[1], s[2]), 38 | aesround(s[2], s[3]), 39 | aesround(s[3], s[4]), 40 | aesround(s[4], s[5]), 41 | }; 42 | } 43 | 44 | fn init(key: [key_length]u8, nonce: [nonce_length]u8) Self { 45 | const c0 = AesBlock.fromBytes(&[16]u8{ 0x00, 0x01, 0x01, 0x02, 0x03, 0x05, 0x08, 0x0d, 0x15, 0x22, 0x37, 0x59, 0x90, 0xe9, 0x79, 0x62 }); 46 | const c1 = AesBlock.fromBytes(&[16]u8{ 0xdb, 0x3d, 0x18, 0x55, 0x6d, 0xc2, 0x2f, 0xf1, 0x20, 0x11, 0x31, 0x42, 0x73, 0xb5, 0x28, 0xdd }); 47 | const k0 = AesBlock.fromBytes(key[0..16]); 48 | const k1 = AesBlock.fromBytes(key[16..32]); 49 | const n0 = AesBlock.fromBytes(nonce[0..16]); 50 | const n1 = AesBlock.fromBytes(nonce[16..32]); 51 | var self = Self{ .s = State{ 52 | k0.xorBlocks(n0), 53 | k1.xorBlocks(n1), 54 | c1, 55 | c0, 56 | k0.xorBlocks(c0), 57 | k1.xorBlocks(c1), 58 | } }; 59 | for (0..4) |_| { 60 | self.update(k0); 61 | self.update(k1); 62 | self.update(k0.xorBlocks(n0)); 63 | self.update(k1.xorBlocks(n1)); 64 | } 65 | return self; 66 | } 67 | 68 | fn absorb(self: *Self, ai: *const [16]u8) void { 69 | const t = AesBlock.fromBytes(ai); 70 | self.update(t); 71 | } 72 | 73 | fn enc(self: *Self, xi: *const [16]u8) [16]u8 { 74 | const s = self.s; 75 | const z = s[1].xorBlocks(s[4]).xorBlocks(s[5]).xorBlocks(s[2].andBlocks(s[3])); 76 | const t = AesBlock.fromBytes(xi); 77 | const ci = t.xorBlocks(z); 78 | self.update(t); 79 | return ci.toBytes(); 80 | } 81 | 82 | fn dec(self: *Self, ci: *const [16]u8) [16]u8 { 83 | const s = self.s; 84 | const z = s[1].xorBlocks(s[4]).xorBlocks(s[5]).xorBlocks(s[2].andBlocks(s[3])); 85 | const t = AesBlock.fromBytes(ci); 86 | const xi = t.xorBlocks(z); 87 | self.update(xi); 88 | return xi.toBytes(); 89 | } 90 | 91 | fn decLast(self: *Self, xn: []u8, cn: []const u8) void { 92 | const s = self.s; 93 | const z = s[1].xorBlocks(s[4]).xorBlocks(s[5]).xorBlocks(s[2].andBlocks(s[3])); 94 | var pad = [_]u8{0} ** 16; 95 | @memcpy(pad[0..cn.len], cn); 96 | const t = AesBlock.fromBytes(&pad); 97 | const out = t.xorBlocks(z); 98 | pad = out.toBytes(); 99 | @memcpy(xn, pad[0..cn.len]); 100 | @memset(pad[cn.len..], 0); 101 | const v = AesBlock.fromBytes(&pad); 102 | self.update(v); 103 | } 104 | 105 | fn finalize(self: *Self, ad_len: usize, msg_len: usize) [tag_length]u8 { 106 | var s = &self.s; 107 | var b: [16]u8 = undefined; 108 | mem.writeInt(u64, b[0..8], @as(u64, ad_len) * 8, .little); 109 | mem.writeInt(u64, b[8..16], @as(u64, msg_len) * 8, .little); 110 | const t = s[3].xorBlocks(AesBlock.fromBytes(&b)); 111 | for (0..7) |_| { 112 | self.update(t); 113 | } 114 | var tag: [tag_length]u8 = undefined; 115 | if (tag_length == 16) { 116 | tag = s[0].xorBlocks(s[1]).xorBlocks(s[2]).xorBlocks(s[3]).xorBlocks(s[4]).xorBlocks(s[5]).toBytes(); 117 | } else { 118 | tag[0..16].* = s[0].xorBlocks(s[1]).xorBlocks(s[2]).toBytes(); 119 | tag[16..].* = s[3].xorBlocks(s[4]).xorBlocks(s[5]).toBytes(); 120 | } 121 | return tag; 122 | } 123 | 124 | pub fn encrypt( 125 | ct: []u8, 126 | msg: []const u8, 127 | ad: []const u8, 128 | key: [key_length]u8, 129 | nonce: [nonce_length]u8, 130 | ) [tag_length]u8 { 131 | assert(msg.len <= msg_max_length); 132 | assert(ad.len <= ad_max_length); 133 | assert(ct.len == msg.len); 134 | var aegis = init(key, nonce); 135 | 136 | var i: usize = 0; 137 | while (i + 16 <= ad.len) : (i += 16) { 138 | aegis.absorb(ad[i..][0..16]); 139 | } 140 | if (ad.len % 16 != 0) { 141 | var pad = [_]u8{0} ** 16; 142 | @memcpy(pad[0 .. ad.len % 16], ad[i..]); 143 | aegis.absorb(&pad); 144 | } 145 | 146 | i = 0; 147 | while (i + 16 <= msg.len) : (i += 16) { 148 | ct[i..][0..16].* = aegis.enc(msg[i..][0..16]); 149 | } 150 | if (msg.len % 16 != 0) { 151 | var pad = [_]u8{0} ** 16; 152 | @memcpy(pad[0 .. msg.len % 16], msg[i..]); 153 | @memcpy(ct[i..], aegis.enc(&pad)[0 .. msg.len % 16]); 154 | } 155 | 156 | return aegis.finalize(ad.len, msg.len); 157 | } 158 | 159 | pub fn decrypt( 160 | msg: []u8, 161 | ct: []const u8, 162 | tag: [tag_length]u8, 163 | ad: []const u8, 164 | key: [key_length]u8, 165 | nonce: [nonce_length]u8, 166 | ) AuthenticationError!void { 167 | assert(ct.len <= ct_max_length); 168 | assert(ad.len <= ad_max_length); 169 | assert(ct.len == msg.len); 170 | var aegis = init(key, nonce); 171 | 172 | var i: usize = 0; 173 | while (i + 16 <= ad.len) : (i += 16) { 174 | aegis.absorb(ad[i..][0..16]); 175 | } 176 | if (ad.len % 16 != 0) { 177 | var pad = [_]u8{0} ** 16; 178 | @memcpy(pad[0 .. ad.len % 16], ad[i..]); 179 | aegis.absorb(&pad); 180 | } 181 | 182 | i = 0; 183 | while (i + 16 <= ct.len) : (i += 16) { 184 | msg[i..][0..16].* = aegis.dec(ct[i..][0..16]); 185 | } 186 | if (ct.len % 16 != 0) { 187 | aegis.decLast(msg[i..], ct[i..]); 188 | } 189 | 190 | const expected_tag = aegis.finalize(ad.len, msg.len); 191 | if (!crypto.utils.timingSafeEql([expected_tag.len]u8, expected_tag, tag)) { 192 | crypto.utils.secureZero(u8, msg); 193 | return error.AuthenticationFailed; 194 | } 195 | } 196 | 197 | pub fn stream( 198 | out: []u8, 199 | key: [key_length]u8, 200 | nonce: ?[nonce_length]u8, 201 | ) void { 202 | assert(out.len <= msg_max_length); 203 | var aegis = init(key, nonce orelse [_]u8{0} ** nonce_length); 204 | 205 | const zero = [_]u8{0} ** 16; 206 | 207 | var i: usize = 0; 208 | while (i + 16 <= out.len) : (i += 16) { 209 | out[i..][0..16].* = aegis.enc(&zero); 210 | } 211 | if (out.len % 16 != 0) { 212 | @memcpy(out[i..], aegis.enc(&zero)[0 .. out.len % 16]); 213 | } 214 | } 215 | 216 | pub fn mac( 217 | data: []const u8, 218 | key: [key_length]u8, 219 | nonce: [nonce_length]u8, 220 | ) [tag_length]u8 { 221 | assert(data.len <= ad_max_length); 222 | var aegis = init(key, nonce); 223 | 224 | var i: usize = 0; 225 | while (i + 16 <= data.len) : (i += 16) { 226 | aegis.absorb(data[i..][0..16]); 227 | } 228 | if (data.len % 16 != 0) { 229 | var pad = [_]u8{0} ** 16; 230 | @memcpy(pad[0 .. data.len % 16], data[i..]); 231 | aegis.absorb(&pad); 232 | } 233 | return aegis.finalize(data.len, tag_length); 234 | } 235 | }; 236 | } 237 | -------------------------------------------------------------------------------- /reference-implementations/aegis256x.zig: -------------------------------------------------------------------------------- 1 | const std = @import("std"); 2 | const assert = std.debug.assert; 3 | const crypto = std.crypto; 4 | const mem = std.mem; 5 | const AesBlockVec = crypto.core.aes.BlockVec; 6 | const AuthenticationError = std.crypto.errors.AuthenticationError; 7 | 8 | pub const Aegis256X2 = Aegis256_(2, 128); 9 | pub const Aegis256X2_256 = Aegis256_(2, 256); 10 | pub const Aegis256X4 = Aegis256_(4, 128); 11 | pub const Aegis256X4_256 = Aegis256_(4, 256); 12 | 13 | // Let S = { s0, s1, s2, s3, s4, s5 } represent a regular AEGIS-256L state. 14 | // 15 | // An AEGIS-128X2 state uses two AEGIS-256 states { S0, S1 } represented as: 16 | // { { S0_s0, S1_s0 }, { S0_s1, S1_s1 }, { S0_s2, S1_s2 }, 17 | // { S0_s3, S1_s3 }, { S0_s4, S1_s4 }, { S0_s5, S1_s5 } } 18 | // 19 | // This is the native representation when using VAES instructions with 256 bit vectors. 20 | // That can be generalized to other degrees. 21 | // 22 | // The following AEGIS-256X implementation is pretty much identical to the AEGIS-256 23 | // one, the main difference being that `AesBlock` (a single AES block) is replaced with 24 | // `AesBlockX` (a vector of `degree` AES blocks). 25 | 26 | fn Aegis256_(comptime degree: u7, comptime tag_bits: u9) type { 27 | assert(tag_bits == 128 or tag_bits == 256); // tag bits must be 128 or 256 28 | assert(degree > 0); // degree can't be 0 29 | 30 | return struct { 31 | const Self = @This(); 32 | 33 | pub const key_length = 32; 34 | pub const nonce_length = 32; 35 | pub const tag_length: comptime_int = tag_bits / 8; 36 | pub const ad_max_length = 1 << 61; 37 | pub const msg_max_length = 1 << 61; 38 | pub const ct_max_length = msg_max_length + tag_length; 39 | 40 | const AesBlockX = AesBlockVec(degree); 41 | const blockx_length = AesBlockX.block_length; 42 | const rate = blockx_length; 43 | 44 | const State = [6]AesBlockX; 45 | 46 | s: State, 47 | 48 | inline fn aesround(in: AesBlockX, rk: AesBlockX) AesBlockX { 49 | return in.encrypt(rk); 50 | } 51 | 52 | fn update(self: *Self, m: AesBlockX) void { 53 | const s = self.s; 54 | self.s = State{ 55 | aesround(s[5], s[0].xorBlocks(m)), 56 | aesround(s[0], s[1]), 57 | aesround(s[1], s[2]), 58 | aesround(s[2], s[3]), 59 | aesround(s[3], s[4]), 60 | aesround(s[4], s[5]), 61 | }; 62 | } 63 | 64 | fn init(key: [key_length]u8, nonce: [nonce_length]u8) Self { 65 | const c0_v = AesBlockX.fromBytes(&[16]u8{ 0x00, 0x01, 0x01, 0x02, 0x03, 0x05, 0x08, 0x0d, 0x15, 0x22, 0x37, 0x59, 0x90, 0xe9, 0x79, 0x62 } ** degree); 66 | const c1_v = AesBlockX.fromBytes(&[16]u8{ 0xdb, 0x3d, 0x18, 0x55, 0x6d, 0xc2, 0x2f, 0xf1, 0x20, 0x11, 0x31, 0x42, 0x73, 0xb5, 0x28, 0xdd } ** degree); 67 | const k0_v = AesBlockX.fromBytes(key[0..16] ** degree); 68 | const k1_v = AesBlockX.fromBytes(key[16..32] ** degree); 69 | const k0n0_v = k0_v.xorBlocks(AesBlockX.fromBytes(nonce[0..16] ** degree)); 70 | const k1n1_v = k1_v.xorBlocks(AesBlockX.fromBytes(nonce[16..32] ** degree)); 71 | const ctx_v = ctx_v: { 72 | var contexts_bytes = [_]u8{0} ** (blockx_length); 73 | for (0..degree) |i| { 74 | contexts_bytes[i * 16] = @intCast(i); 75 | contexts_bytes[i * 16 + 1] = @intCast(degree - 1); 76 | } 77 | break :ctx_v AesBlockX.fromBytes(&contexts_bytes); 78 | }; 79 | var self = Self{ .s = State{ 80 | k0n0_v, 81 | k1n1_v, 82 | c1_v, 83 | c0_v, 84 | k0_v.xorBlocks(c0_v), 85 | k1_v.xorBlocks(c1_v), 86 | } }; 87 | for (0..4) |_| { 88 | self.s[3] = self.s[3].xorBlocks(ctx_v); 89 | self.s[5] = self.s[5].xorBlocks(ctx_v); 90 | self.update(k0_v); 91 | self.s[3] = self.s[3].xorBlocks(ctx_v); 92 | self.s[5] = self.s[5].xorBlocks(ctx_v); 93 | self.update(k1_v); 94 | self.s[3] = self.s[3].xorBlocks(ctx_v); 95 | self.s[5] = self.s[5].xorBlocks(ctx_v); 96 | self.update(k0n0_v); 97 | self.s[3] = self.s[3].xorBlocks(ctx_v); 98 | self.s[5] = self.s[5].xorBlocks(ctx_v); 99 | self.update(k1n1_v); 100 | } 101 | return self; 102 | } 103 | 104 | fn absorb(self: *Self, ai: *const [rate]u8) void { 105 | const t = AesBlockX.fromBytes(ai); 106 | self.update(t); 107 | } 108 | 109 | fn enc(self: *Self, xi: *const [rate]u8) [rate]u8 { 110 | const s = self.s; 111 | const z = s[1].xorBlocks(s[4]).xorBlocks(s[5]).xorBlocks(s[2].andBlocks(s[3])); 112 | const t = AesBlockX.fromBytes(xi); 113 | const ci = t.xorBlocks(z); 114 | self.update(t); 115 | return ci.toBytes(); 116 | } 117 | 118 | fn dec(self: *Self, ci: *const [rate]u8) [rate]u8 { 119 | const s = self.s; 120 | const z = s[1].xorBlocks(s[4]).xorBlocks(s[5]).xorBlocks(s[2].andBlocks(s[3])); 121 | const t = AesBlockX.fromBytes(ci); 122 | const xi = t.xorBlocks(z); 123 | self.update(xi); 124 | return xi.toBytes(); 125 | } 126 | 127 | fn decLast(self: *Self, xn: []u8, cn: []const u8) void { 128 | const s = self.s; 129 | const z = s[1].xorBlocks(s[4]).xorBlocks(s[5]).xorBlocks(s[2].andBlocks(s[3])); 130 | var pad = [_]u8{0} ** rate; 131 | @memcpy(pad[0..cn.len], cn); 132 | const t = AesBlockX.fromBytes(&pad); 133 | const out = t.xorBlocks(z); 134 | pad = out.toBytes(); 135 | @memcpy(xn, pad[0..cn.len]); 136 | @memset(pad[cn.len..], 0); 137 | const v = AesBlockX.fromBytes(&pad); 138 | self.update(v); 139 | } 140 | 141 | fn finalize(self: *Self, ad_len: usize, msg_len: usize) [tag_length]u8 { 142 | var s = &self.s; 143 | var b: [blockx_length]u8 = undefined; 144 | mem.writeInt(u64, b[0..8], @as(u64, ad_len) * 8, .little); 145 | mem.writeInt(u64, b[8..16], @as(u64, msg_len) * 8, .little); 146 | for (1..degree) |i| { 147 | b[i * 16 ..][0..16].* = b[0..16].*; 148 | } 149 | const t = s[3].xorBlocks(AesBlockX.fromBytes(&b)); 150 | for (0..7) |_| { 151 | self.update(t); 152 | } 153 | var tag: [tag_length]u8 = undefined; 154 | if (tag_length == 16) { 155 | var tag_multi = s[0].xorBlocks(s[1]).xorBlocks(s[2]).xorBlocks(s[3]).xorBlocks(s[4]).xorBlocks(s[5]).toBytes(); 156 | tag = tag_multi[0..16].*; 157 | for (1..degree) |d| { 158 | for (0..16) |i| { 159 | tag[i] ^= tag_multi[d * 16 + i]; 160 | } 161 | } 162 | } else { 163 | var tag_multi_0 = s[0].xorBlocks(s[1]).xorBlocks(s[2]).toBytes(); 164 | var tag_multi_1 = s[3].xorBlocks(s[4]).xorBlocks(s[5]).toBytes(); 165 | tag[0..16].* = tag_multi_0[0..16].*; 166 | tag[16..32].* = tag_multi_1[0..16].*; 167 | for (1..degree) |d| { 168 | for (0..16) |i| { 169 | tag[i] ^= tag_multi_0[d * 16 + i]; 170 | tag[i + 16] ^= tag_multi_1[d * 16 + i]; 171 | } 172 | } 173 | } 174 | return tag; 175 | } 176 | 177 | fn finalizeMac(self: *Self, data_len: usize) [tag_length]u8 { 178 | var s = &self.s; 179 | var b: [blockx_length]u8 = undefined; 180 | mem.writeInt(u64, b[0..8], @as(u64, data_len) * 8, .little); 181 | mem.writeInt(u64, b[8..16], tag_bits, .little); 182 | for (1..degree) |i| { 183 | b[i * 16 ..][0..16].* = b[0..16].*; 184 | } 185 | var t = s[3].xorBlocks(AesBlockX.fromBytes(&b)); 186 | for (0..7) |_| { 187 | self.update(t); 188 | } 189 | var v = [_]u8{0} ** rate; 190 | if (tag_length == 16) { 191 | const tags = s[0].xorBlocks(s[1]).xorBlocks(s[2]).xorBlocks(s[3]).xorBlocks(s[4]).xorBlocks(s[5]).toBytes(); 192 | for (1..degree) |d| { 193 | v[0..16].* = tags[d * 16 ..][0..16].*; 194 | self.absorb(&v); 195 | } 196 | } else { 197 | const tags_0 = s[0].xorBlocks(s[1]).xorBlocks(s[2]).toBytes(); 198 | const tags_1 = s[3].xorBlocks(s[4]).xorBlocks(s[5]).toBytes(); 199 | for (1..degree) |d| { 200 | v[0..16].* = tags_0[d * 16 ..][0..16].*; 201 | self.absorb(&v); 202 | v[0..16].* = tags_1[d * 16 ..][0..16].*; 203 | self.absorb(&v); 204 | } 205 | } 206 | if (degree > 1) { 207 | mem.writeInt(u64, b[0..8], degree, .little); 208 | mem.writeInt(u64, b[8..16], tag_bits, .little); 209 | t = s[3].xorBlocks(AesBlockX.fromBytes(&b)); 210 | for (0..7) |_| { 211 | self.update(t); 212 | } 213 | } 214 | if (tag_length == 16) { 215 | const tags = s[0].xorBlocks(s[1]).xorBlocks(s[2]).xorBlocks(s[3]).xorBlocks(s[4]).xorBlocks(s[5]).toBytes(); 216 | return tags[0..16].*; 217 | } else { 218 | const tags_0 = s[0].xorBlocks(s[1]).xorBlocks(s[2]).toBytes(); 219 | const tags_1 = s[3].xorBlocks(s[4]).xorBlocks(s[5]).toBytes(); 220 | return tags_0[0..16].* ++ tags_1[0..16].*; 221 | } 222 | } 223 | 224 | pub fn encrypt( 225 | ct: []u8, 226 | msg: []const u8, 227 | ad: []const u8, 228 | key: [key_length]u8, 229 | nonce: [nonce_length]u8, 230 | ) [tag_length]u8 { 231 | assert(msg.len <= msg_max_length); 232 | assert(ad.len <= ad_max_length); 233 | assert(ct.len == msg.len); 234 | var aegis = init(key, nonce); 235 | 236 | var i: usize = 0; 237 | while (i + rate <= ad.len) : (i += rate) { 238 | aegis.absorb(ad[i..][0..rate]); 239 | } 240 | if (ad.len % rate != 0) { 241 | var pad = [_]u8{0} ** rate; 242 | @memcpy(pad[0 .. ad.len % rate], ad[i..]); 243 | aegis.absorb(&pad); 244 | } 245 | 246 | i = 0; 247 | while (i + rate <= msg.len) : (i += rate) { 248 | ct[i..][0..rate].* = aegis.enc(msg[i..][0..rate]); 249 | } 250 | if (msg.len % rate != 0) { 251 | var pad = [_]u8{0} ** rate; 252 | @memcpy(pad[0 .. msg.len % rate], msg[i..]); 253 | @memcpy(ct[i..], aegis.enc(&pad)[0 .. msg.len % rate]); 254 | } 255 | 256 | return aegis.finalize(ad.len, msg.len); 257 | } 258 | 259 | pub fn decrypt( 260 | msg: []u8, 261 | ct: []const u8, 262 | tag: [tag_length]u8, 263 | ad: []const u8, 264 | key: [key_length]u8, 265 | nonce: [nonce_length]u8, 266 | ) AuthenticationError!void { 267 | assert(ct.len <= ct_max_length); 268 | assert(ad.len <= ad_max_length); 269 | assert(ct.len == msg.len); 270 | var aegis = init(key, nonce); 271 | 272 | var i: usize = 0; 273 | while (i + rate <= ad.len) : (i += rate) { 274 | aegis.absorb(ad[i..][0..rate]); 275 | } 276 | if (ad.len % rate != 0) { 277 | var pad = [_]u8{0} ** rate; 278 | @memcpy(pad[0 .. ad.len % rate], ad[i..]); 279 | aegis.absorb(&pad); 280 | } 281 | 282 | i = 0; 283 | while (i + rate <= ct.len) : (i += rate) { 284 | msg[i..][0..rate].* = aegis.dec(ct[i..][0..rate]); 285 | } 286 | if (ct.len % rate != 0) { 287 | aegis.decLast(msg[i..], ct[i..]); 288 | } 289 | 290 | const expected_tag = aegis.finalize(ad.len, msg.len); 291 | if (!crypto.utils.timingSafeEql([expected_tag.len]u8, expected_tag, tag)) { 292 | crypto.utils.secureZero(u8, msg); 293 | return error.AuthenticationFailed; 294 | } 295 | } 296 | 297 | pub fn stream( 298 | out: []u8, 299 | key: [key_length]u8, 300 | nonce: ?[nonce_length]u8, 301 | ) void { 302 | assert(out.len <= msg_max_length); 303 | var aegis = init(key, nonce orelse [_]u8{0} ** nonce_length); 304 | 305 | const zero = [_]u8{0} ** rate; 306 | 307 | var i: usize = 0; 308 | while (i + rate <= out.len) : (i += rate) { 309 | out[i..][0..rate].* = aegis.enc(&zero); 310 | } 311 | if (out.len % rate != 0) { 312 | @memcpy(out[i..], aegis.enc(&zero)[0 .. out.len % rate]); 313 | } 314 | } 315 | 316 | pub fn mac( 317 | data: []const u8, 318 | key: [key_length]u8, 319 | nonce: [nonce_length]u8, 320 | ) [tag_length]u8 { 321 | assert(data.len <= ad_max_length); 322 | var aegis = init(key, nonce); 323 | 324 | var i: usize = 0; 325 | while (i + rate <= data.len) : (i += rate) { 326 | aegis.absorb(data[i..][0..rate]); 327 | } 328 | if (data.len % rate != 0) { 329 | var pad = [_]u8{0} ** rate; 330 | @memcpy(pad[0 .. data.len % rate], data[i..]); 331 | aegis.absorb(&pad); 332 | } 333 | return aegis.finalizeMac(data.len); 334 | } 335 | }; 336 | } 337 | -------------------------------------------------------------------------------- /reference-implementations/build.zig: -------------------------------------------------------------------------------- 1 | const std = @import("std"); 2 | 3 | pub fn build(b: *std.Build) void { 4 | const target = b.standardTargetOptions(.{}); 5 | const optimize = b.standardOptimizeOption(.{}); 6 | 7 | const lib_unit_tests = b.addTest(.{ 8 | .root_source_file = b.path("tests.zig"), 9 | .target = target, 10 | .optimize = optimize, 11 | }); 12 | const run_lib_unit_tests = b.addRunArtifact(lib_unit_tests); 13 | const test_step = b.step("test", "Run unit tests"); 14 | test_step.dependOn(&run_lib_unit_tests.step); 15 | } 16 | -------------------------------------------------------------------------------- /reference-implementations/tests.zig: -------------------------------------------------------------------------------- 1 | const std = @import("std"); 2 | 3 | const aegis128l = @import("aegis128l.zig"); 4 | const aegis128x = @import("aegis128x.zig"); 5 | const aegis256 = @import("aegis256.zig"); 6 | const aegis256x = @import("aegis256x.zig"); 7 | 8 | test { 9 | const aegis_variants = [_]type{ 10 | aegis128l.Aegis128L, aegis128l.Aegis128L_256, 11 | aegis128x.Aegis128X2, aegis128x.Aegis128X2_256, 12 | aegis128x.Aegis128X4, aegis128x.Aegis128X4_256, 13 | aegis256.Aegis256, aegis256.Aegis256_256, 14 | aegis256x.Aegis256X2, aegis256x.Aegis256X2_256, 15 | aegis256x.Aegis256X4, aegis256x.Aegis256X4_256, 16 | }; 17 | inline for (aegis_variants) |Aegis| { 18 | const key = [_]u8{0x01} ** Aegis.key_length; 19 | const nonce = [_]u8{0x02} ** Aegis.nonce_length; 20 | const ad = [_]u8{0x03} ** 1000; 21 | const msg = [_]u8{0x04} ** 1000; 22 | var msg2: [msg.len]u8 = undefined; 23 | var ct: [msg.len]u8 = undefined; 24 | const tag = Aegis.encrypt(&ct, &msg, &ad, key, nonce); 25 | try Aegis.decrypt(&msg2, &ct, tag, &ad, key, nonce); 26 | try std.testing.expectEqualSlices(u8, &msg, &msg2); 27 | } 28 | } 29 | 30 | test { 31 | const aegis_variants = [_]type{ 32 | aegis128l.Aegis128L, aegis128l.Aegis128L_256, 33 | aegis128x.Aegis128X2, aegis128x.Aegis128X2_256, 34 | aegis128x.Aegis128X4, aegis128x.Aegis128X4_256, 35 | aegis256.Aegis256, aegis256.Aegis256_256, 36 | aegis256x.Aegis256X2, aegis256x.Aegis256X2_256, 37 | aegis256x.Aegis256X4, aegis256x.Aegis256X4_256, 38 | }; 39 | inline for (aegis_variants) |Aegis| { 40 | const key = [_]u8{ 0x10, 0x01 } ++ [_]u8{0x00} ** (Aegis.key_length - 2); 41 | const nonce = [_]u8{ 0x10, 0x00, 0x02 } ++ [_]u8{0x00} ** (Aegis.nonce_length - 3); 42 | var msg: [35]u8 = undefined; 43 | for (&msg, 0..) |*byte, i| byte.* = @truncate(i); 44 | _ = Aegis.mac(&msg, key, nonce); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /test-vectors/aegis-128l-test-vectors.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "name": "Update Test Vector", 4 | "S0": "9b7e60b24cc873ea894ecc07911049a3", 5 | "S1": "330be08f35300faa2ebf9a7b0d274658", 6 | "S2": "7bbd5bd2b049f7b9b515cf26fbe7756c", 7 | "S3": "c35a00f55ea86c3886ec5e928f87db18", 8 | "S4": "9ebccafce87cab446396c4334592c91f", 9 | "S5": "58d83e31f256371e60fc6bb257114601", 10 | "S6": "1639b56ea322c88568a176585bc915de", 11 | "S7": "640818ffb57dc0fbc2e72ae93457e39a", 12 | "M0": "033e6975b94816879e42917650955aa0", 13 | "M1": "fcc1968a46b7e97861bd6e89af6aa55f", 14 | "S0_2": "596ab773e4433ca0127c73f60536769d", 15 | "S1_2": "790394041a3d26ab697bde865014652d", 16 | "S2_2": "38cf49e4b65248acd533041b64dd0611", 17 | "S3_2": "16d8e58748f437bfff1797f780337cee", 18 | "S4_2": "9689ecdf08228c74d7e3360cca53d0a5", 19 | "S5_2": "a21746bb193a569e331e1aa985d0d729", 20 | "S6_2": "09d714e6fcf9177a8ed1cde7e3d259a6", 21 | "S7_2": "61279ba73167f0ab76f0a11bf203bdff" 22 | }, 23 | { 24 | "name": "Test Vector 1", 25 | "key": "10010000000000000000000000000000", 26 | "nonce": "10000200000000000000000000000000", 27 | "ad": "", 28 | "msg": "00000000000000000000000000000000", 29 | "ct": "c1c0e58bd913006feba00f4b3cc3594e", 30 | "tag128": "abe0ece80c24868a226a35d16bdae37a", 31 | "tag256": "25835bfbb21632176cf03840687cb968cace4617af1bd0f7d064c639a5c79ee4" 32 | }, 33 | { 34 | "name": "Test Vector 2", 35 | "key": "10010000000000000000000000000000", 36 | "nonce": "10000200000000000000000000000000", 37 | "ad": "", 38 | "msg": "", 39 | "ct": "", 40 | "tag128": "c2b879a67def9d74e6c14f708bbcc9b4", 41 | "tag256": "1360dc9db8ae42455f6e5b6a9d488ea4f2184c4e12120249335c4ee84bafe25d" 42 | }, 43 | { 44 | "name": "Test Vector 3", 45 | "key": "10010000000000000000000000000000", 46 | "nonce": "10000200000000000000000000000000", 47 | "ad": "0001020304050607", 48 | "msg": "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", 49 | "ct": "79d94593d8c2119d7e8fd9b8fc77845c5c077a05b2528b6ac54b563aed8efe84", 50 | "tag128": "cc6f3372f6aa1bb82388d695c3962d9a", 51 | "tag256": "022cb796fe7e0ae1197525ff67e309484cfbab6528ddef89f17d74ef8ecd82b3" 52 | }, 53 | { 54 | "name": "Test Vector 4", 55 | "key": "10010000000000000000000000000000", 56 | "nonce": "10000200000000000000000000000000", 57 | "ad": "0001020304050607", 58 | "msg": "000102030405060708090a0b0c0d", 59 | "ct": "79d94593d8c2119d7e8fd9b8fc77", 60 | "tag128": "5c04b3dba849b2701effbe32c7f0fab7", 61 | "tag256": "86f1b80bfb463aba711d15405d094baf4a55a15dbfec81a76f35ed0b9c8b04ac" 62 | }, 63 | { 64 | "name": "Test Vector 5", 65 | "key": "10010000000000000000000000000000", 66 | "nonce": "10000200000000000000000000000000", 67 | "ad": "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20212223242526272829", 68 | "msg": "101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f3031323334353637", 69 | "ct": "b31052ad1cca4e291abcf2df3502e6bdb1bfd6db36798be3607b1f94d34478aa7ede7f7a990fec10", 70 | "tag128": "7542a745733014f9474417b337399507", 71 | "tag256": "b91e2947a33da8bee89b6794e647baf0fc835ff574aca3fc27c33be0db2aff98" 72 | }, 73 | { 74 | "name": "Test Vector 6", 75 | "error": "verification failed", 76 | "key": "10000200000000000000000000000000", 77 | "nonce": "10010000000000000000000000000000", 78 | "ad": "0001020304050607", 79 | "ct": "79d94593d8c2119d7e8fd9b8fc77", 80 | "tag128": "5c04b3dba849b2701effbe32c7f0fab7", 81 | "tag256": "86f1b80bfb463aba711d15405d094baf4a55a15dbfec81a76f35ed0b9c8b04ac" 82 | }, 83 | { 84 | "name": "Test Vector 7", 85 | "error": "verification failed", 86 | "key": "10010000000000000000000000000000", 87 | "nonce": "10000200000000000000000000000000", 88 | "ad": "0001020304050607", 89 | "ct": "79d94593d8c2119d7e8fd9b8fc78", 90 | "tag128": "5c04b3dba849b2701effbe32c7f0fab7", 91 | "tag256": "86f1b80bfb463aba711d15405d094baf4a55a15dbfec81a76f35ed0b9c8b04ac" 92 | }, 93 | { 94 | "name": "Test Vector 8", 95 | "error": "verification failed", 96 | "key": "10010000000000000000000000000000", 97 | "nonce": "10000200000000000000000000000000", 98 | "ad": "0001020304050608", 99 | "ct": "79d94593d8c2119d7e8fd9b8fc77", 100 | "tag128": "5c04b3dba849b2701effbe32c7f0fab7", 101 | "tag256": "86f1b80bfb463aba711d15405d094baf4a55a15dbfec81a76f35ed0b9c8b04ac" 102 | }, 103 | { 104 | "name": "Test Vector 9", 105 | "error": "verification failed", 106 | "key": "10010000000000000000000000000000", 107 | "nonce": "10000200000000000000000000000000", 108 | "ad": "0001020304050607", 109 | "ct": "79d94593d8c2119d7e8fd9b8fc77", 110 | "tag128": "6c04b3dba849b2701effbe32c7f0fab8", 111 | "tag256": "86f1b80bfb463aba711d15405d094baf4a55a15dbfec81a76f35ed0b9c8b04ad" 112 | } 113 | ] -------------------------------------------------------------------------------- /test-vectors/aegis-128x2-test-vectors.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "name": "Initial State", 4 | "key": "000102030405060708090a0b0c0d0e0f", 5 | "nonce": "101112131415161718191a1b1c1d1e1f", 6 | "ctx[0]": "00010000000000000000000000000000", 7 | "ctx[1]": "01010000000000000000000000000000" 8 | }, 9 | { 10 | "name": "Initial State (after initialization)", 11 | "V[0,0]": "a4fc1ad9a72942fb88bd2cabbba6509a", 12 | "V[0,1]": "80a40e392fc71084209b6c3319bdc6cc", 13 | "V[1,0]": "380f435cf801763b1f0c2a2f7212052d", 14 | "V[1,1]": "73796607b59b1b650ee91c152af1f18a", 15 | "V[2,0]": "6ee1de433ea877fa33bc0782abff2dcb", 16 | "V[2,1]": "b9fab2ab496e16d1facaffd5453cbf14", 17 | "V[3,0]": "85f94b0d4263bfa86fdf45a603d8b6ac", 18 | "V[3,1]": "90356c8cadbaa2c969001da02e3feca0", 19 | "V[4,0]": "09bd69ad3730174bcd2ce9a27cd1357e", 20 | "V[4,1]": "e610b45125796a4fcf1708cef5c4f718", 21 | "V[5,0]": "fcdeb0cf0a87bf442fc82383ddb0f6d6", 22 | "V[5,1]": "61ad32a4694d6f3cca313a2d3f4687aa", 23 | "V[6,0]": "571c207988659e2cdfbdaae77f4f37e3", 24 | "V[6,1]": "32e6094e217573bf91fb28c145a3efa8", 25 | "V[7,0]": "ca549badf8faa58222412478598651cf", 26 | "V[7,1]": "3407279a54ce76d2e2e8a90ec5d108eb" 27 | }, 28 | { 29 | "name": "Test Vector 1", 30 | "key": "000102030405060708090a0b0c0d0e0f", 31 | "nonce": "101112131415161718191a1b1c1d1e1f", 32 | "ad": "", 33 | "msg": "", 34 | "ct": "", 35 | "tag128": "63117dc57756e402819a82e13eca8379", 36 | "tag256": "b92c71fdbd358b8a4de70b27631ace90cffd9b9cfba82028412bac41b4f53759" 37 | }, 38 | { 39 | "name": "Test Vector 2", 40 | "key": "000102030405060708090a0b0c0d0e0f", 41 | "nonce": "101112131415161718191a1b1c1d1e1f", 42 | "ad": "0102030401020304", 43 | "msg": "040506070405060704050607040506070405060704050607040506070405060704050607040506070405060704050607040506070405060704050607040506070405060704050607040506070405060704050607040506070405060704050607040506070405060704050607040506070405060704050607", 44 | "ct": "5795544301997f93621b278809d6331b3bfa6f18e90db12c4aa35965b5e98c5fc6fb4e54bcb6111842c20637252eff747cb3a8f85b37de80919a589fe0f24872bc926360696739e05520647e390989e1eb5fd42f99678a0276a498f8c454761c9d6aacb647ad56be62b29c22cd4b5761b38f43d5a5ee062f", 45 | "tag128": "1aebc200804f405cab637f2adebb6d77", 46 | "tag256": "c471876f9b4978c44f2ae1ce770cdb11a094ee3feca64e7afcd48bfe52c60eca" 47 | } 48 | ] -------------------------------------------------------------------------------- /test-vectors/aegis-128x4-test-vectors.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "name": "Initial State", 4 | "key": "000102030405060708090a0b0c0d0e0f", 5 | "nonce": "101112131415161718191a1b1c1d1e1f", 6 | "ctx[0]": "00030000000000000000000000000000", 7 | "ctx[1]": "01030000000000000000000000000000", 8 | "ctx[2]": "02030000000000000000000000000000", 9 | "ctx[3]": "03030000000000000000000000000000" 10 | }, 11 | { 12 | "name": "Initial State (after initialization)", 13 | "V[0,0]": "924eb07635003a37e6c6575ba8ce1929", 14 | "V[0,1]": "c8b6a5d91475445e936d48e794be0ce2", 15 | "V[0,2]": "fcd37d050e24084befe3bbb219d64760", 16 | "V[0,3]": "2e9f58cfb893a8800220242c373a8b18", 17 | "V[1,0]": "1a1f60c4fab64e5471dc72edfcf6fe6b", 18 | "V[1,1]": "c1e525ebea2d6375a9edd045dce96381", 19 | "V[1,2]": "97a3e25abd228a44d4a14a6d3fe9185c", 20 | "V[1,3]": "c2d4cf7f4287a98744645674265d4ca8", 21 | "V[2,0]": "7bb50c534f6ec4780530ff1cce8a16e8", 22 | "V[2,1]": "7b08d57557da0b5ef7b5f7d98b0ba189", 23 | "V[2,2]": "6bfcac34ddb68404821a4d665303cb0f", 24 | "V[2,3]": "d95626f6dfad1aed7467622c38529932", 25 | "V[3,0]": "af339fd2d50ee45fc47665c647cf6586", 26 | "V[3,1]": "d0669b39d140f0e118a4a511efe2f95a", 27 | "V[3,2]": "7a94330f35c194fadda2a87e42cdeccc", 28 | "V[3,3]": "233b640d1f4d56e2757e72c1a9d8ecb1", 29 | "V[4,0]": "9f93737d699ba05c11e94f2b201bef5e", 30 | "V[4,1]": "61caf387cf7cfd3f8300ac7680ccfd76", 31 | "V[4,2]": "5825a671ecef03b7a9c98a601ae32115", 32 | "V[4,3]": "87a1fe4d558161a8f4c38731f3223032", 33 | "V[5,0]": "7a5aca78d636c05bbc702b2980196ab6", 34 | "V[5,1]": "915d868408495d07eb527789f282c575", 35 | "V[5,2]": "d0947bfbc1d3309cdffc9be1503aea62", 36 | "V[5,3]": "8834ea57a15b9fbdc0245464a4b8cbef", 37 | "V[6,0]": "e46f4cf71a95ac45b6f0823e3aba1a86", 38 | "V[6,1]": "8c4ecef682fc44a8eba911b3fc7d99f9", 39 | "V[6,2]": "a4fb61e2c928a2ca760b8772f2ea5f2e", 40 | "V[6,3]": "3d34ea89da73caa3016c280500a155a3", 41 | "V[7,0]": "85075f0080e9d618e7eb40f57c32d9f7", 42 | "V[7,1]": "d2ab2b320c6e93b155a3787cb83e5281", 43 | "V[7,2]": "0b3af0250ae36831a1b072e499929bcb", 44 | "V[7,3]": "5cce4d00329d69f1aae36aa541347512" 45 | }, 46 | { 47 | "name": "Test Vector 1", 48 | "key": "000102030405060708090a0b0c0d0e0f", 49 | "nonce": "101112131415161718191a1b1c1d1e1f", 50 | "ad": "", 51 | "msg": "", 52 | "ct": "", 53 | "tag128": "5bef762d0947c00455b97bb3af30dfa3", 54 | "tag256": "a4b25437f4be93cfa856a2f27e4416b42cac79fd4698f2cdbe6af25673e10a68" 55 | }, 56 | { 57 | "name": "Test Vector 2", 58 | "key": "000102030405060708090a0b0c0d0e0f", 59 | "nonce": "101112131415161718191a1b1c1d1e1f", 60 | "ad": "0102030401020304", 61 | "msg": "040506070405060704050607040506070405060704050607040506070405060704050607040506070405060704050607040506070405060704050607040506070405060704050607040506070405060704050607040506070405060704050607040506070405060704050607040506070405060704050607", 62 | "ct": "e836118562f4479c9d35c17356a833114c21f9aa39e4dda5e5c87f4152a00fce9a7c38f832eafe8b1c12f8a7cf12a81a1ad8a9c24ba9dedfbdaa586ffea67ddc801ea97d9ab4a872f42d0e352e2713dacd609f9442c17517c5a29daf3e2a3fac4ff6b1380c4e46df7b086af6ce6bc1ed594b8dd64aed2a7e", 63 | "tag128": "0e56ab94e2e85db80f9d54010caabfb4", 64 | "tag256": "69abf0f64a137dd6e122478d777e98bc422823006cf57f5ee822dd78397230b2" 65 | } 66 | ] -------------------------------------------------------------------------------- /test-vectors/aegis-256-test-vectors.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "name": "Update Test Vector", 4 | "S0": "1fa1207ed76c86f2c4bb40e8b395b43e", 5 | "S1": "b44c375e6c1e1978db64bcd12e9e332f", 6 | "S2": "0dab84bfa9f0226432ff630f233d4e5b", 7 | "S3": "d7ef65c9b93e8ee60c75161407b066e7", 8 | "S4": "a760bb3da073fbd92bdc24734b1f56fb", 9 | "S5": "a828a18d6a964497ac6e7e53c5f55c73", 10 | "M": "b165617ed04ab738afb2612c6d18a1ec", 11 | "S0_2": "e6bc643bae82dfa3d991b1b323839dcd", 12 | "S1_2": "648578232ba0f2f0a3677f617dc052c3", 13 | "S2_2": "ea788e0e572044a46059212dd007a789", 14 | "S3_2": "2f1498ae19b80da13fba698f088a8590", 15 | "S4_2": "a54c2ee95e8c2a2c3dae2ec743ae6b86", 16 | "S5_2": "a3240fceb68e32d5d114df1b5363ab67" 17 | }, 18 | { 19 | "name": "Test Vector 1", 20 | "key": "1001000000000000000000000000000000000000000000000000000000000000", 21 | "nonce": "1000020000000000000000000000000000000000000000000000000000000000", 22 | "ad": "", 23 | "msg": "00000000000000000000000000000000", 24 | "ct": "754fc3d8c973246dcc6d741412a4b236", 25 | "tag128": "3fe91994768b332ed7f570a19ec5896e", 26 | "tag256": "1181a1d18091082bf0266f66297d167d2e68b845f61a3b0527d31fc7b7b89f13" 27 | }, 28 | { 29 | "name": "Test Vector 2", 30 | "key": "1001000000000000000000000000000000000000000000000000000000000000", 31 | "nonce": "1000020000000000000000000000000000000000000000000000000000000000", 32 | "ad": "", 33 | "msg": "", 34 | "ct": "", 35 | "tag128": "e3def978a0f054afd1e761d7553afba3", 36 | "tag256": "6a348c930adbd654896e1666aad67de989ea75ebaa2b82fb588977b1ffec864a" 37 | }, 38 | { 39 | "name": "Test Vector 3", 40 | "key": "1001000000000000000000000000000000000000000000000000000000000000", 41 | "nonce": "1000020000000000000000000000000000000000000000000000000000000000", 42 | "ad": "0001020304050607", 43 | "msg": "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", 44 | "ct": "f373079ed84b2709faee373584585d60accd191db310ef5d8b11833df9dec711", 45 | "tag128": "8d86f91ee606e9ff26a01b64ccbdd91d", 46 | "tag256": "b7d28d0c3c0ebd409fd22b44160503073a547412da0854bfb9723020dab8da1a" 47 | }, 48 | { 49 | "name": "Test Vector 4", 50 | "key": "1001000000000000000000000000000000000000000000000000000000000000", 51 | "nonce": "1000020000000000000000000000000000000000000000000000000000000000", 52 | "ad": "0001020304050607", 53 | "msg": "000102030405060708090a0b0c0d", 54 | "ct": "f373079ed84b2709faee37358458", 55 | "tag128": "c60b9c2d33ceb058f96e6dd03c215652", 56 | "tag256": "8c1cc703c81281bee3f6d9966e14948b4a175b2efbdc31e61a98b4465235c2d9" 57 | }, 58 | { 59 | "name": "Test Vector 5", 60 | "key": "1001000000000000000000000000000000000000000000000000000000000000", 61 | "nonce": "1000020000000000000000000000000000000000000000000000000000000000", 62 | "ad": "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20212223242526272829", 63 | "msg": "101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f3031323334353637", 64 | "ct": "57754a7d09963e7c787583a2e7b859bb24fa1e04d49fd550b2511a358e3bca252a9b1b8b30cc4a67", 65 | "tag128": "ab8a7d53fd0e98d727accca94925e128", 66 | "tag256": "a3aca270c006094d71c20e6910b5161c0826df233d08919a566ec2c05990f734" 67 | }, 68 | { 69 | "name": "Test Vector 6", 70 | "error": "verification failed", 71 | "key": "1000020000000000000000000000000000000000000000000000000000000000", 72 | "nonce": "1001000000000000000000000000000000000000000000000000000000000000", 73 | "ad": "0001020304050607", 74 | "ct": "f373079ed84b2709faee37358458", 75 | "tag128": "c60b9c2d33ceb058f96e6dd03c215652", 76 | "tag256": "8c1cc703c81281bee3f6d9966e14948b4a175b2efbdc31e61a98b4465235c2d9" 77 | }, 78 | { 79 | "name": "Test Vector 7", 80 | "error": "verification failed", 81 | "key": "1001000000000000000000000000000000000000000000000000000000000000", 82 | "nonce": "1000020000000000000000000000000000000000000000000000000000000000", 83 | "ad": "0001020304050607", 84 | "ct": "f373079ed84b2709faee37358459", 85 | "tag128": "c60b9c2d33ceb058f96e6dd03c215652", 86 | "tag256": "8c1cc703c81281bee3f6d9966e14948b4a175b2efbdc31e61a98b4465235c2d9" 87 | }, 88 | { 89 | "name": "Test Vector 8", 90 | "error": "verification failed", 91 | "key": "1001000000000000000000000000000000000000000000000000000000000000", 92 | "nonce": "1000020000000000000000000000000000000000000000000000000000000000", 93 | "ad": "0001020304050608", 94 | "ct": "f373079ed84b2709faee37358458", 95 | "tag128": "c60b9c2d33ceb058f96e6dd03c215652", 96 | "tag256": "8c1cc703c81281bee3f6d9966e14948b4a175b2efbdc31e61a98b4465235c2d9" 97 | }, 98 | { 99 | "name": "Test Vector 9", 100 | "error": "verification failed", 101 | "key": "1001000000000000000000000000000000000000000000000000000000000000", 102 | "nonce": "1000020000000000000000000000000000000000000000000000000000000000", 103 | "ad": "0001020304050607", 104 | "ct": "f373079ed84b2709faee37358458", 105 | "tag128": "c60b9c2d33ceb058f96e6dd03c215653", 106 | "tag256": "8c1cc703c81281bee3f6d9966e14948b4a175b2efbdc31e61a98b4465235c2da" 107 | } 108 | ] -------------------------------------------------------------------------------- /test-vectors/aegis-256x2-test-vectors.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "name": "Initial State", 4 | "key": "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", 5 | "nonce": "101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f", 6 | "ctx[0]": "00010000000000000000000000000000", 7 | "ctx[1]": "01010000000000000000000000000000" 8 | }, 9 | { 10 | "name": "Initial State (after initialization)", 11 | "V[0,0]": "eca2bf4538442e8712d4972595744039", 12 | "V[0,1]": "201405efa9264f07911db58101903087", 13 | "V[1,0]": "3e536a998799408a97f3479a6f779d48", 14 | "V[1,1]": "0d79a7d822a5d215f78c3bf2feb33ae1", 15 | "V[2,0]": "cf8c63d6f2b4563cdd9231107c85950e", 16 | "V[2,1]": "78d17ed7d8d563ff11bd202c76864839", 17 | "V[3,0]": "d7e0707e6bfbbad913bc94b6993a9fa0", 18 | "V[3,1]": "097e4b1bff40d4c19cb29dfd125d62f2", 19 | "V[4,0]": "a373cf6d537dd66bc0ef0f2f9285359f", 20 | "V[4,1]": "c0d0ae0c48f9df3faaf0e7be7768c326", 21 | "V[5,0]": "9f76560dcae1efacabdcce446ae283bc", 22 | "V[5,1]": "bd52a6b9c8f976a26ec1409df19e8bfe" 23 | }, 24 | { 25 | "name": "Test Vector 1", 26 | "key": "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", 27 | "nonce": "101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f", 28 | "ad": "", 29 | "msg": "", 30 | "ct": "", 31 | "tag128": "62cdbab084c83dacdb945bb446f049c8", 32 | "tag256": "25d7e799b49a80354c3f881ac2f1027f471a5d293052bd9997abd3ae84014bb7" 33 | }, 34 | { 35 | "name": "Test Vector 2", 36 | "key": "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", 37 | "nonce": "101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f", 38 | "ad": "0102030401020304", 39 | "msg": "040506070405060704050607040506070405060704050607040506070405060704050607040506070405060704050607040506070405060704050607040506070405060704050607040506070405060704050607040506070405060704050607040506070405060704050607040506070405060704050607", 40 | "ct": "72120c2ea8236180d67859001f4729077b7064c414384fe3a7b52f1571f4f8a7d0f01e18db4f3bc0adb150702e5d147a8d36522132761b994c1bd395589e2ccf0790dfe2a3d12d61cd666b2859827739db4037dd3124c78424459376f6cac08e1a7223a2a43e398ce6385cd654a19f481cba3b8f25910b42", 41 | "tag128": "635d391828520bf1512763f0c8f5cdbd", 42 | "tag256": "b5668d3317159e9cc5d46e4803c3a76ad63bb42b3f47956d94f30db8cb366ad7" 43 | } 44 | ] -------------------------------------------------------------------------------- /test-vectors/aegis-256x4-test-vectors.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "name": "Initial State", 4 | "key": "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", 5 | "nonce": "101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f", 6 | "ctx[0]": "00030000000000000000000000000000", 7 | "ctx[1]": "01030000000000000000000000000000", 8 | "ctx[2]": "02030000000000000000000000000000", 9 | "ctx[3]": "03030000000000000000000000000000" 10 | }, 11 | { 12 | "name": "Initial State (after initialization)", 13 | "V[0,0]": "482a86e8436cd2361063a4b2702769b9", 14 | "V[0,1]": "d95a2be81c9245b22996f68eea0122f9", 15 | "V[0,2]": "0c2a3b348b1a5e256c6751377318c41e", 16 | "V[0,3]": "f64436a21653fe7cf2e0829a177db383", 17 | "V[1,0]": "e705e8866267717d96092e58e78b574c", 18 | "V[1,1]": "d1dd412142df9806cc267af2fe1d830e", 19 | "V[1,2]": "30e7dfd3c9941b8394e95bdf5bac99d9", 20 | "V[1,3]": "9f27186f8a4fab86820689822c3c74d2", 21 | "V[2,0]": "e1aa6af5d9e31dde8d94a48a0810fa89", 22 | "V[2,1]": "63555cdf0d98f18fb75b029ad80786c0", 23 | "V[2,2]": "a3ee0e4a3429a9539e4fcec385475608", 24 | "V[2,3]": "28ea527d31ef61df498dc107fe02df99", 25 | "V[3,0]": "37f06808410c8f3954525ae44584d3be", 26 | "V[3,1]": "8fcc23bca2fe2209f93d34e2da35b33d", 27 | "V[3,2]": "33156347df89eaa69ab11096362daccf", 28 | "V[3,3]": "bbe58d9dbe8c5b0469be5a87086db5d4", 29 | "V[4,0]": "d1c9eb37fecbc5ada7b351fa4f501f32", 30 | "V[4,1]": "0b9b803283c1538628b507c8f6432434", 31 | "V[4,2]": "bfb8b6d4f87cce28825c7e92f54b8728", 32 | "V[4,3]": "8917bb5b09c32f900c6a5a1d63c46264", 33 | "V[5,0]": "4f6110c2ef0c3c687e90c1e5532ddf8e", 34 | "V[5,1]": "031bd85d99f64684d23728a0453c72a1", 35 | "V[5,2]": "10bc7ec34d4119b5bdeb6c7dfc458247", 36 | "V[5,3]": "591ece530aeaa5c9867220156f5c25e3" 37 | }, 38 | { 39 | "name": "Test Vector 1", 40 | "key": "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", 41 | "nonce": "101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f", 42 | "ad": "", 43 | "msg": "", 44 | "ct": "", 45 | "tag128": "3b7fee6cee7bf17888ad11ed2397beb4", 46 | "tag256": "6093a1a8aab20ec635dc1ca71745b01b5bec4fc444c9ffbebd710d4a34d20eaf" 47 | }, 48 | { 49 | "name": "Test Vector 2", 50 | "key": "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", 51 | "nonce": "101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f", 52 | "ad": "0102030401020304", 53 | "msg": "040506070405060704050607040506070405060704050607040506070405060704050607040506070405060704050607040506070405060704050607040506070405060704050607040506070405060704050607040506070405060704050607040506070405060704050607040506070405060704050607", 54 | "ct": "bfc2085b7e8017da99b0b6d646ae4d01f4ba8f2e7dfca1d759ae48a135139b9aaac6b4f5db810d426be1fdaff4e1454153a34b11da78ed7e418ee2ee9853042e95536aecbb694cea1b16a478eb0d4d1bf6509b1ce652a45af58e0e46ffccfa2d0426e702391d2ff5813808b81748a490dd656465fed61f09", 55 | "tag128": "b63b611b13975e2f3dc3cb6c2397bfcd", 56 | "tag256": "7847eace74409ee56c8f4cf63a9c2841ce7c8bd567d7c0ca514c879a190b978c" 57 | } 58 | ] -------------------------------------------------------------------------------- /test-vectors/aegismac-test-vectors.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "name": "AEGISMAC-128L Test Vector", 4 | "key": "10010000000000000000000000000000", 5 | "nonce": "10000200000000000000000000000000", 6 | "data": "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122", 7 | "tag128": "d3f09b2842ad301687d6902c921d7818", 8 | "tag256": "9490e7c89d420c9f37417fa625eb38e8cad53c5cbec55285e8499ea48377f2a3" 9 | }, 10 | { 11 | "name": "AEGISMAC-128X2 Test Vector", 12 | "key": "10010000000000000000000000000000", 13 | "nonce": "10000200000000000000000000000000", 14 | "data": "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122", 15 | "tags128": "9f5f69928fa481fa86e8a51e072a9b29eeaa77a356f796b427f6a54f52ae0e20", 16 | "tag128": "6873ee34e6b5c59143b6d35c5e4f2c6e", 17 | "tags256": "22cdcf558d0338b6ad8fbba4da7307d30bd685fff23dc9d41f598c2a7ea44055", 18 | "tag256": "afcba3fc2d63c8d6c7f2d63f3ec8fbbbaf022e15ac120e78ffa7755abccd959c" 19 | }, 20 | { 21 | "name": "AEGISMAC-128X4 Test Vector", 22 | "key": "10010000000000000000000000000000", 23 | "nonce": "10000200000000000000000000000000", 24 | "data": "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122", 25 | "tags128": "7fecd913a7cb0011b6c4c88e0c6f857819a98fbeaf21d1092c32953fff82c8a9c7b5e6625a5765d04af26cf22adc12824c8cf3b4dbb85f379e13b04a8d06bca7", 26 | "tag128": "c45a98fd9ab8956ce616eb008cfe4e53", 27 | "tags256": "d595732bdf230a1441978414cd8cfa39ecef6ad0ee1e65ae530006ca5d5f4481f9ec5edfa64e9c3d76d3a5eda9fe5bd1fb9d842373f7c90bedb8bfe383740b231264a15143eb8c3d9f17754099f147e3401c83c0d5afc70fd0d68bfd17f9280f", 28 | "tag256": "26fdc76f41b1da7aec7779f6e964beae8904e662f05aca8345ae3befb357412a" 29 | }, 30 | { 31 | "name": "AEGISMAC-256 Test Vector", 32 | "key": "1001000000000000000000000000000000000000000000000000000000000000", 33 | "nonce": "1000020000000000000000000000000000000000000000000000000000000000", 34 | "data": "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122", 35 | "tag128": "c08e20cfc56f27195a46c9cef5c162d4", 36 | "tag256": "a5c906ede3d69545c11e20afa360b221f936e946ed2dba3d7c75ad6dc2784126" 37 | }, 38 | { 39 | "name": "AEGISMAC-256X2 Test Vector", 40 | "key": "1001000000000000000000000000000000000000000000000000000000000000", 41 | "nonce": "1000020000000000000000000000000000000000000000000000000000000000", 42 | "data": "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122", 43 | "tags128": "db8852ea2c03f22b0d0694ea4e88e4b1", 44 | "tag128": "fb319cb6dd728a764606fb14d37f2a5e", 45 | "tags256": "b4d124976b34b2aa8bc3fa0b55396cf7fb83f4ef5ba607681cddf5ba3e925727", 46 | "tag256": "0844b20ed5147ceae89c7a160263afd4b1382d6b154ecf560ce8a342cb6a8fd1" 47 | }, 48 | { 49 | "name": "AEGISMAC-256X4 Test Vector", 50 | "key": "1001000000000000000000000000000000000000000000000000000000000000", 51 | "nonce": "1000020000000000000000000000000000000000000000000000000000000000", 52 | "data": "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122", 53 | "tags128": "702d595e74962d073a0d68c883d80deb41ab207e43b16659d556d7467218a9ec113406e7cb56e0f6b63c95c88421dfee", 54 | "tag128": "a51f9bc5beae60cce77f0dbc60761edd", 55 | "tags256": "a46ebcd10939b42012a3f9b6147172af3b74aec5d0070e8d6a81498ccbcdb41ad57cd7a50fa8621dfea2e81cd941def557094251a24527a4d97fc4c8253681803973129d07cc20811a8b3c34574f6ce010165dd0e856e797f70731e78e32f764", 56 | "tag256": "b36a16ef07c36d75a91f437502f24f545b8dfa88648ed116943c29fead3bf10c" 57 | } 58 | ] -------------------------------------------------------------------------------- /test-vectors/aesround-test-vector.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "name": "AESRound Test Vector", 4 | "in": "000102030405060708090a0b0c0d0e0f", 5 | "rk": "101112131415161718191a1b1c1d1e1f", 6 | "out": "7a7b4e5638782546a8c0477a3b813f43" 7 | } 8 | ] -------------------------------------------------------------------------------- /test-vectors/gen.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python3 2 | 3 | import json 4 | import re 5 | 6 | 7 | def tvdump(topic, tvs): 8 | with open(filename(topic), "w") as f: 9 | f.write(json.dumps(tvs, indent=2)) 10 | 11 | print(json.dumps(tvs, indent=2)) 12 | 13 | 14 | def filename(topic): 15 | return re.sub(r"[^a-z0-9]+", "-", topic.lower()) + ".json" 16 | 17 | 18 | header = True 19 | in_tv = False 20 | tv = {} 21 | tvs = [] 22 | must_fail = False 23 | with open("../draft-irtf-cfrg-aegis-aead.md") as f: 24 | for line in f: 25 | line = line.strip() 26 | if line == "": 27 | continue 28 | if line.startswith("# Test Vectors"): 29 | header = False 30 | continue 31 | if header: 32 | continue 33 | 34 | if line.startswith("## "): 35 | if len(tvs) > 0: 36 | tvdump(topic, tvs) 37 | topic = line[3:] 38 | tv_name = topic 39 | tvs = [] 40 | continue 41 | 42 | if line.startswith("### "): 43 | tv_name = line[4:] 44 | tv = {"test": tv_name} 45 | in_tv = False 46 | continue 47 | 48 | if line == "~~~ test-vectors": 49 | in_tv = True 50 | tv = {"name": tv_name} 51 | if must_fail: 52 | tv["error"] = "verification failed" 53 | must_fail = False 54 | continue 55 | 56 | if line == "~~~": 57 | tvs.append(tv) 58 | in_tv = False 59 | current_key = None 60 | continue 61 | 62 | if line.find("verification failed") != -1: 63 | must_fail = True 64 | continue 65 | 66 | if line == "After initialization:": 67 | tv_name = tv_name + " (after initialization)" 68 | 69 | if not in_tv: 70 | continue 71 | 72 | parts = line.split(":") 73 | if len(parts) == 2: 74 | key = parts[0].strip() 75 | value = parts[1].strip() 76 | if key == "After Update": 77 | continue 78 | if key in tv: 79 | key = key + "_2" 80 | tv[key] = value 81 | current_key = key 82 | continue 83 | 84 | if not current_key: 85 | continue 86 | 87 | tv[key] += line.strip() 88 | 89 | tvdump(topic, tvs) 90 | --------------------------------------------------------------------------------