├── .github ├── FUNDING.yml ├── dependabot.yml └── workflows │ └── ci.yml ├── .gitignore ├── .idea ├── .gitignore ├── modules.xml ├── serde-encrypt.iml └── vcs.xml ├── CHANGELOG.md ├── Cargo.toml ├── LICENSE-APACHE ├── LICENSE-MIT ├── Makefile.toml ├── README.md ├── rust-toolchain ├── serde-encrypt-core ├── Cargo.toml ├── src │ ├── encrypt.rs │ ├── encrypt │ │ ├── encrypted_message.rs │ │ ├── plain_message_public_key.rs │ │ ├── plain_message_shared_key.rs │ │ └── plain_message_shared_key │ │ │ ├── shared_key_core.rs │ │ │ └── shared_key_deterministic_core.rs │ ├── error.rs │ ├── error │ │ └── error_kind.rs │ ├── key.rs │ ├── key │ │ ├── as_shared_key.rs │ │ ├── combined_key.rs │ │ ├── key_pair.rs │ │ └── key_pair │ │ │ ├── private_key.rs │ │ │ └── public_key.rs │ ├── lib.rs │ └── random.rs └── tests │ ├── feat_serde_encrypt_std_error.rs │ ├── feat_shared_key_distribution.rs │ └── test_util │ ├── mod.rs │ └── random │ └── mod.rs └── serde-encrypt ├── Cargo.toml ├── src ├── encrypt.rs ├── encrypt │ ├── plain_message_public_key.rs │ ├── plain_message_shared_key.rs │ └── plain_message_shared_key_deterministic.rs ├── key.rs ├── key │ └── key_pair.rs ├── lib.rs ├── random.rs ├── serialize.rs ├── serialize │ ├── impls.rs │ └── impls │ │ ├── bincode_serializer.rs │ │ ├── cbor_serializer.rs │ │ └── postcard_serializer.rs ├── shared_key.rs ├── traits.rs └── traits │ ├── serde_encrypt_public_key.rs │ ├── serde_encrypt_shared_key.rs │ └── serde_encrypt_shared_key_deterministic.rs └── tests ├── example_serde_encrypt_public_key_owned_data.rs ├── example_serde_encrypt_public_key_struct_with_reference.rs ├── example_serde_encrypt_shared_key_encryption_with_key_exchange.rs ├── example_serde_encrypt_shared_key_owned_data.rs ├── feat_different_cipher_from_same_plain.rs ├── feat_large_message.rs ├── feat_nostd.rs ├── feat_same_cipher_from_same_plain.rs ├── feat_serde_types.rs ├── feat_serializers.rs ├── test_util ├── mod.rs ├── serde_encrypt_public_key │ └── mod.rs └── serde_encrypt_shared_key │ └── mod.rs └── unit_plain_message_xxx_key.rs /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: [laysakura] 4 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: "cargo" 4 | directory: "/" 5 | schedule: 6 | interval: "daily" 7 | open-pull-requests-limit: 99 8 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: ci 2 | 3 | on: 4 | pull_request: 5 | types: 6 | - opened 7 | - synchronize 8 | push: 9 | branches: 10 | - main 11 | workflow_dispatch: 12 | 13 | jobs: 14 | job-matrix: 15 | name: ${{ matrix.make.name }} (${{ matrix.rust }}; ${{ matrix.os }}) 16 | runs-on: ${{ matrix.os }} 17 | strategy: 18 | fail-fast: false 19 | matrix: 20 | os: 21 | - ubuntu-latest 22 | rust: 23 | - nightly 24 | - stable 25 | - 1.49.0 # MSRV 26 | make: 27 | - name: format 28 | task: format 29 | - name: lint 30 | task: lint 31 | - name: test 32 | task: build test 33 | - name: doc 34 | task: doc 35 | - name: deadlink 36 | task: deadlink 37 | rust-free: true 38 | install-cargo-deadlinks: true 39 | install-mlc: true 40 | - name: codecov 41 | task: lcov 42 | install-grcov: true 43 | - name: os-less-build 44 | task: os-less-build 45 | rust-free: true # Rust is installed inside task 46 | - name: build-core-sgx 47 | task: build-core-sgx 48 | rust-free: true # sgx-rust docker image has Rust inside 49 | exclude: 50 | - rust: nightly 51 | make: 52 | name: format 53 | - rust: 1.49.0 54 | make: 55 | name: format 56 | - rust: nightly 57 | make: 58 | name: lint 59 | - rust: 1.49.0 60 | make: 61 | name: lint 62 | - rust: nightly 63 | make: 64 | name: doc 65 | - rust: 1.49.0 66 | make: 67 | name: doc 68 | - rust: nightly 69 | make: 70 | name: deadlink 71 | - rust: 1.49.0 72 | make: 73 | name: deadlink 74 | - rust: stable 75 | make: 76 | name: codecov 77 | - rust: 1.49.0 78 | make: 79 | name: codecov 80 | - rust: nightly 81 | make: 82 | name: build-core-sgx 83 | - rust: 1.49.0 84 | make: 85 | name: build-core-sgx 86 | env: 87 | RUST_BACKTRACE: full 88 | CACHE_RESET_KEY: 20210611-01 89 | steps: 90 | - uses: actions/checkout@v2 91 | 92 | - name: Install Rust ${{ matrix.rust }} 93 | if: ${{ ! matrix.make.rust-free }} 94 | uses: actions-rs/toolchain@v1 95 | with: 96 | toolchain: ${{ matrix.rust }} 97 | profile: minimal 98 | components: rustfmt, clippy, llvm-tools-preview 99 | override: true 100 | 101 | - name: Cache cargo registry 102 | if: ${{ ! matrix.make.rust-free }} 103 | uses: actions/cache@v2 104 | continue-on-error: false 105 | with: 106 | path: | 107 | ~/.cargo/registry 108 | ~/.cargo/git 109 | key: ${{ env.CACHE_RESET_KEY }}-${{ runner.os }}-${{ matrix.rust }}-cargo-${{ matrix.make.name }}-${{ hashFiles('**/Cargo.lock') }} 110 | restore-keys: | 111 | ${{ env.CACHE_RESET_KEY }}-${{ runner.os }}-${{ matrix.rust }}-cargo-${{ matrix.make.name }}- 112 | ${{ env.CACHE_RESET_KEY }}-${{ runner.os }}-${{ matrix.rust }}-cargo- 113 | 114 | - name: Install cargo-make 115 | env: 116 | BASE_URL: https://github.com/sagiegurari/cargo-make/releases/download 117 | VERSION: 0.34.0 118 | run: | 119 | FILE_BASE=cargo-make-v${VERSION}-x86_64-unknown-linux-musl 120 | mkdir -p ${HOME}/.local/bin 121 | curl -L "${BASE_URL}/${VERSION}/${FILE_BASE}.zip" --output /tmp/cargo-make.zip 122 | unzip /tmp/cargo-make.zip -d /tmp/cargo-make 123 | mv -f /tmp/cargo-make/${FILE_BASE}/cargo-make $HOME/.local/bin/cargo-make 124 | echo "$HOME/.local/bin" >> $GITHUB_PATH 125 | 126 | - name: Install cargo-deadlinks 127 | if: ${{ matrix.make.install-cargo-deadlinks }} 128 | env: 129 | BASE_URL: https://github.com/deadlinks/cargo-deadlinks/releases/download 130 | VERSION: 0.8.0 131 | run: | 132 | FILE_BASE=cargo-deadlinks-linux 133 | curl -L "${BASE_URL}/${VERSION}/${FILE_BASE}" --output $HOME/.local/bin/cargo-deadlinks 134 | chmod +x $HOME/.local/bin/cargo-deadlinks 135 | cargo deadlinks --version 136 | rustup override set 1.52.1 # FIXME: https://github.com/deadlinks/cargo-deadlinks/issues/147 137 | 138 | - name: Install mlc 139 | if: ${{ matrix.make.install-mlc }} 140 | env: 141 | BASE_URL: https://github.com/becheran/mlc/releases/download 142 | VERSION: 0.14.3 143 | run: | 144 | FILE_BASE=mlc-x86_64-linux 145 | curl -L "${BASE_URL}/v${VERSION}/${FILE_BASE}" --output $HOME/.local/bin/mlc 146 | chmod +x $HOME/.local/bin/mlc 147 | mlc --version 148 | 149 | - name: Install grcov 150 | if: ${{ matrix.make.install-grcov }} 151 | env: 152 | BASE_URL: https://github.com/mozilla/grcov/releases/download 153 | VERSION: 0.8.0 154 | run: | 155 | FILE_BASE=grcov-linux-x86_64 156 | curl -L "${BASE_URL}/v${VERSION}/${FILE_BASE}.tar.bz2" --output /tmp/grcov.tar.bz2 157 | tar xvf /tmp/grcov.tar.bz2 --directory=$HOME/.local/bin/ 158 | grcov --version 159 | 160 | - name: ${{ matrix.make.name }} 161 | run: | 162 | for task in ${{ matrix.make.task }} ; do 163 | cargo make ${task} 164 | done 165 | 166 | - name: Upload lcov to codecov 167 | if: ${{ matrix.make.install-grcov }} 168 | uses: codecov/codecov-action@v1 169 | with: 170 | token: ${{ secrets.CODECOV_SECRET }} 171 | files: ./lcov.info 172 | 173 | slack-notify: 174 | if: always() 175 | needs: 176 | - job-matrix 177 | name: workflow notification to slack 178 | runs-on: ubuntu-latest 179 | steps: 180 | - uses: Gamesight/slack-workflow-status@master 181 | with: 182 | repo_token: ${{ secrets.GITHUB_TOKEN }} 183 | slack_webhook_url: ${{ secrets.SLACK_WEBHOOK_URL }} 184 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /**/target 2 | Cargo.lock 3 | -------------------------------------------------------------------------------- /.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # Default ignored files 2 | /shelf/ 3 | /workspace.xml 4 | # Editor-based HTTP Client requests 5 | /httpRequests/ 6 | # Datasource local storage ignored files 7 | /dataSources/ 8 | /dataSources.local.xml 9 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /.idea/serde-encrypt.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes to this project will be documented in this file. 4 | 5 | The format is based on [Keep a Changelog][Keep a Changelog] and this project adheres to [Semantic Versioning][Semantic Versioning]. 6 | 7 | ## [Unreleased] 8 | 9 | ## [v0.7.0] - 2022-04-14 10 | 11 | ### Added 12 | 13 | - `SharedKey::new()` and `SharedKey::new_const()` to generate a shared key from array (runtime / compile-time). [#105](https://github.com/laysakura/serde-encrypt/pull/105) 14 | - Thanks: @kurikomoe 15 | 16 | ### Fixed 17 | 18 | - Codes in README didn't compile. [#105](https://github.com/laysakura/serde-encrypt/pull/105) 19 | - Thanks: @kurikomoe 20 | 21 | ## [v0.6.0] - 2021-06-22 22 | 23 | ### Added 24 | 25 | - `SerdeEncryptSharedKeyDeterministic` for deterministic encryption. [#95](https://github.com/laysakura/serde-encrypt/pull/95) 26 | 27 | ## [v0.5.0] - 2021-06-19 28 | 29 | ### Changed 30 | 31 | - `SharedKey` serializer - `BincodeSerializer` for std; `PostcardSerilizer` for no_std. [#94](https://github.com/laysakura/serde-encrypt/pull/90) 32 | 33 | ### Fixed 34 | 35 | - Documentation about serializers. Although `BincodeSerializer` or `PostcardSerializer` show better performance, `CborSerializer` serializes more complex serde types. [#94](https://github.com/laysakura/serde-encrypt/pull/90) 36 | 37 | ## [v0.4.1] - 2021-06-19 38 | 39 | ### Fixed 40 | 41 | - Dead links in documents. [#90](https://github.com/laysakura/serde-encrypt/pull/90), [#93](https://github.com/laysakura/serde-encrypt/pull/93) 42 | 43 | ## [v0.4.0] - 2021-06-17 44 | 45 | ### Added 46 | 47 | - New built-in serializers: 48 | - `PostcardSerializer`, which uses [`postcard` crate](https://docs.rs/postcard) for serialization. 49 | - `BincodeSerializer` for `std` feature, which uses [`bincode` crate](https://docs.rs/bincode) for serialization. 50 | 51 | - `EncryptedMessage::len()` function to return cipher-text's payload size. 52 | 53 | ## [v0.3.2] - 2021-06-16 54 | 55 | ### Added 56 | 57 | - [`serde-encrypt-sgx` crate](https://github.com/laysakura/serde-encrypt-sgx) for crates using [Rust SGX SDK](https://github.com/apache/incubator-teaclave-sgx-sdk). 58 | 59 | - Minimum Supported Rust Version decreases to 1.49.0. 60 | 61 | ### Changed 62 | 63 | - `serde-encrypt` crate is split into `serde-encrypt-core` (no dependencies to serde) and `serde-encrypt` (serde dependent layer). Users should depend only on `serde-encrypt` (structures from `-core` are re-exported). 64 | 65 | - `SerdeEncryptPublicKey` and `SerdeEncryptSharedKey` takes associated type `S` (serializer). Currently `CborSerializer` is available. Crate users can implement serializers by themselves if necessary. 66 | 67 | - Some `struct`s/`enum`s moved into differently named modules. Shows where into they are moved. 68 | - `serde_encrypt::Error` 69 | - `serde_encrypt::ErrorKind` 70 | - `serde_encrypt::EncryptedMessages` 71 | - `serde_encrypt::SenderCombinedKey` 72 | - `serde_encrypt::ReceiverCombinedKey` 73 | - `serde_encrypt::AsSharedKey` 74 | 75 | ## [v0.2.0] - 2021-06-14 76 | 77 | ### Added 78 | 79 | - `EncryptedMessage::nonce()` getter method. 80 | - `EncryptedMessage::encrypted()` getter method. 81 | 82 | ## [v0.1.1] - 2021-06-14 83 | 84 | ### Added 85 | 86 | - Initial release (0.1.0 yanked) 87 | 88 | --- 89 | 90 | 91 | [Keep a Changelog]: https://keepachangelog.com/ 92 | [Semantic Versioning]: https://semver.org/ 93 | 94 | 95 | [Unreleased]: https://github.com/laysakura/serde-encrypt/compare/v0.7.0...HEAD 96 | [Released]: https://github.com/laysakura/serde-encrypt/releases 97 | [v0.7.0]: https://github.com/laysakura/serde-encrypt/compare/v0.6.0...v0.7.0 98 | [v0.6.0]: https://github.com/laysakura/serde-encrypt/compare/v0.5.0...v0.6.0 99 | [v0.5.0]: https://github.com/laysakura/serde-encrypt/compare/v0.4.1...v0.5.0 100 | [v0.4.1]: https://github.com/laysakura/serde-encrypt/compare/v0.4.0...v0.4.1 101 | [v0.4.0]: https://github.com/laysakura/serde-encrypt/compare/v0.3.2...v0.4.0 102 | [v0.3.2]: https://github.com/laysakura/serde-encrypt/compare/0.2.0...v0.3.2 103 | [v0.2.0]: https://github.com/laysakura/serde-encrypt/compare/0.1.1...0.2.0 104 | [v0.1.1]: https://github.com/laysakura/serde-encrypt/releases/0.1.1 105 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | 3 | members = [ 4 | "serde-encrypt", 5 | "serde-encrypt-core", 6 | ] 7 | -------------------------------------------------------------------------------- /LICENSE-APACHE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /LICENSE-MIT: -------------------------------------------------------------------------------- 1 | Permission is hereby granted, free of charge, to any 2 | person obtaining a copy of this software and associated 3 | documentation files (the "Software"), to deal in the 4 | Software without restriction, including without 5 | limitation the rights to use, copy, modify, merge, 6 | publish, distribute, sublicense, and/or sell copies of 7 | the Software, and to permit persons to whom the Software 8 | is furnished to do so, subject to the following 9 | conditions: 10 | 11 | The above copyright notice and this permission notice 12 | shall be included in all copies or substantial portions 13 | of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 16 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 17 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 18 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT 19 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 20 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 22 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 23 | DEALINGS IN THE SOFTWARE. 24 | -------------------------------------------------------------------------------- /Makefile.toml: -------------------------------------------------------------------------------- 1 | [config] 2 | default_to_workspace = false 3 | skip_core_tasks = true 4 | 5 | [env] 6 | PROJ_NAME = "serde-encrypt" 7 | 8 | [tasks.format] 9 | script = [''' 10 | #!/usr/bin/env bash -eux 11 | cargo fmt --all 12 | '''] 13 | 14 | [tasks.lint] 15 | script = [''' 16 | #!/usr/bin/env bash -eux 17 | RUSTFLAGS='-D warnings' cargo clippy --workspace --all-targets --all-features 18 | '''] 19 | 20 | [tasks.build] 21 | script = [''' 22 | #!/usr/bin/env bash -eux 23 | RUSTFLAGS='-D warnings' cargo build --workspace --all-targets --all-features 24 | '''] 25 | 26 | [tasks.test] 27 | script = [''' 28 | #!/usr/bin/env bash -eux 29 | cargo test --workspace --all-targets --all-features 30 | '''] 31 | 32 | [tasks.doc] 33 | script = [''' 34 | #!/usr/bin/env bash -eux 35 | cargo clean --doc 36 | cargo doc --workspace --no-deps --all-features 37 | '''] 38 | 39 | [tasks.deadlink] 40 | script = [''' 41 | #!/usr/bin/env bash -eux 42 | cargo deadlinks --check-http 43 | mlc --ignore-path target 44 | '''] 45 | 46 | [tasks.os-less-build] 47 | script = [ 48 | ''' 49 | #!/usr/bin/env bash -eux 50 | rustup target add aarch64-unknown-none 51 | RUSTFLAGS='-D warnings' cargo build --workspace --no-default-features --target=aarch64-unknown-none 52 | ''', 53 | ] 54 | 55 | [tasks.build-core-sgx] 56 | script = [ 57 | ''' 58 | #!/usr/bin/env bash -eux 59 | docker run --rm -v `pwd`:/root/serde-encrypt baiduxlab/sgx-rust:1804-1.1.3 bash -c ' 60 | export PATH=/root/.cargo/bin:$PATH 61 | cd /root/serde-encrypt/serde-encrypt-core 62 | rustup show 63 | RUSTFLAGS="-D warnings" cargo build --all-features 64 | ' 65 | ''', 66 | ] 67 | 68 | [tasks.publish] 69 | script = [ 70 | ''' 71 | #!/usr/bin/env bash -eux 72 | cargo workspaces publish 73 | ''', 74 | ] 75 | 76 | [tasks.lcov] 77 | script = [ 78 | ''' 79 | #!/usr/bin/env bash -eux 80 | rm -rf target/debug/deps/${PROJ_NAME}-* 81 | 82 | export CARGO_INCREMENTAL=0 83 | export RUSTFLAGS="-Zinstrument-coverage" 84 | export LLVM_PROFILE_FILE="${PROJ_NAME}-%p-%m.profraw" 85 | 86 | cargo +nightly build --workspace --verbose 87 | cargo +nightly test --workspace --verbose 88 | 89 | grcov . -s . --binary-path ./target/debug/ -t lcov --branch --ignore-not-existing -o lcov.info 90 | ''', 91 | ] 92 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # serde-encrypt 2 | 3 | [![crates.io](https://img.shields.io/crates/v/serde-encrypt.svg)](https://crates.io/crates/serde-encrypt) 4 | [![Crates.io](https://img.shields.io/crates/d/serde-encrypt?label=cargo%20installs)](https://crates.io/crates/serde-encrypt) 5 | [![docs.rs](https://img.shields.io/badge/API%20doc-docs.rs-blueviolet)](https://docs.rs/serde-encrypt) 6 | ![MSRV](https://img.shields.io/badge/rustc-1.49+-lightgray.svg) 7 | [![ci](https://github.com/laysakura/serde-encrypt/actions/workflows/ci.yml/badge.svg?branch=main&event=push)](https://github.com/laysakura/serde-encrypt/actions/workflows/ci.yml) 8 | [![codecov](https://codecov.io/gh/laysakura/serde-encrypt/branch/main/graph/badge.svg?token=XI0IR5QVU3)](https://codecov.io/gh/laysakura/serde-encrypt) 9 | [![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/laysakura/serde-encrypt/blob/master/LICENSE-MIT) 10 | [![License: Apache 2.0](https://img.shields.io/badge/license-Apache_2.0-blue.svg)](https://github.com/laysakura/serde-encrypt/blob/master/LICENSE-APACHE) 11 | 12 | ![serde-encrypt logo](https://user-images.githubusercontent.com/498788/122903416-58946580-d38a-11eb-836d-58ef02128334.png) 13 | 14 | 🔐 **Encrypts all the `Serialize`.** 15 | 16 | ```text 17 | Alice Bob 18 | +-----------------------------------+ +-----------------------------------+ 19 | | #[derive(Serialize, Deserialize)] | | #[derive(Serialize, Deserialize)] | 20 | | struct Message | | struct Message | 21 | +-----------------------------------+ +-----------------------------------+ 22 | | .encrypt() ^ 23 | v | ::decrypt() 24 | +-----------------------------------+ +-----------------------------------+ 25 | | struct EncryptedMessage | | struct EncryptedMessage | 26 | +-----------------------------------+ +-----------------------------------+ 27 | | .serialize() ^ 28 | v | ::deserialize() 29 | +-----------------------------------+ +-----------------------------------+ 30 | | struct Vec | -----> | struct Vec | 31 | +-----------------------------------+ +-----------------------------------+ 32 | ``` 33 | 34 | ## Overview 35 | 36 | serde-encrypt encrypts/decrypts any `struct`s and `enum`s that implements `serde::{Serialize, Deserialize`}. 37 | 38 | serde-encrypt supports both **shared-key encryption** (XChaCha20-Poly1305) and **public-key encryption** (XChaCha20-Poly1305 with X25519 key-exchange), both of which are considered to be secure enough. 39 | 40 | serde-encrypt is optionally available in **no_std** environments. 41 | 42 | ```toml Cargo.toml 43 | [dependencies] 44 | serde-encrypt = "(version)" # If you use std 45 | serde-encrypt = {version = "(version)", default-features = false} # If you need no_std 46 | ``` 47 | 48 | ## Example 49 | 50 | Good first example from [shared key encryption test](https://github.com/laysakura/serde-encrypt/blob/main/serde-encrypt/tests/example_serde_encrypt_shared_key_owned_data.rs). 51 | 52 | If you and your peer already have shared-key, just implement `SerdeEncryptSharedKey` trait to your `Serialize` and `Deserialize` data types. 53 | 54 | ```rust 55 | #[derive(Debug, Serialize, Deserialize)] 56 | struct Message { 57 | content: String, 58 | sender: String, 59 | } 60 | 61 | impl SerdeEncryptSharedKey for Message { 62 | type S = BincodeSerializer; // you can specify serializer implementation (or implement it by yourself). 63 | } 64 | ``` 65 | 66 | Then, you can serialize the `Message` into `Vec` in encrypted form. 67 | 68 | ```rust 69 | // Alternative: 70 | // const SHARED_KEY: SharedKey = SharedKey::new_const([0u8; 32]); 71 | let shared_key = SharedKey::new([0u8; 32]); // or your peer reads from elsewhere. 72 | 73 | let msg = Message { 74 | content: "I ❤️ you.".to_string(), 75 | sender: "Alice".to_string(), 76 | }; 77 | let encrypted_message = msg.encrypt(&shared_key)?; 78 | let serialized_encrypted_message: Vec = encrypted_message.serialize(); 79 | ``` 80 | 81 | After your peer gets the binary, they can decrypt and deserialize it to `Message`. 82 | 83 | ```rust 84 | let shared_key = SharedKey::new([0u8; 32]); 85 | 86 | let encrypted_message = EncryptedMessage::deserialize(serialized_encrypted_message)?; 87 | let msg = Message::decrypt_owned(&encrypted_message, &shared_key); 88 | ``` 89 | 90 | ### Further examples... 91 | 92 | - 👀 [Encrypts struct with reference fields](https://github.com/laysakura/serde-encrypt/blob/main/serde-encrypt/tests/example_serde_encrypt_public_key_struct_with_reference.rs) 93 | - 🔑 [Generates shared-key and safely exchange it to your peer. And then, encrypt/decrypt messages using the shared-key.](https://github.com/laysakura/serde-encrypt/blob/main/serde-encrypt/tests/example_serde_encrypt_shared_key_encryption_with_key_exchange.rs) 94 | - 📚 [Encrypts/Decrypts complex serde types](https://github.com/laysakura/serde-encrypt/blob/main/serde-encrypt/tests/feat_serde_types.rs) 95 | 96 | ## Features and uses cases 97 | 98 | ### Feature comparison 99 | 100 | | | `SerdeEncryptSharedKey` | `SerdeEncryptSharedKeyDeterministic` | `SerdeEncryptPublicKey` | 101 | | --------------------- | ----------------------- | ------------------------------------ | ----------------------- | 102 | | (a)symmetric? | symmetric | symmetric | asymmetric | 103 | | deterministic? _(*1)_ | no | yes | no | 104 | | performance | high | high | low | 105 | 106 | _(*1) Deterministic encryptions always produce the same cipher-text from a given plain-text. More vulnerable but useful for equal-matching in cipher-text (e.g. RDBMS's encrypted index eq-search)._ 107 | 108 | ### Encryption algorithm 109 | 110 | | | `SerdeEncryptSharedKey` | `SerdeEncryptSharedKeyDeterministic` | `SerdeEncryptPublicKey` | 111 | | -------------------- | ---------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------ | 112 | | key exchange | - | - | X25519 | 113 | | encryption | XChaCha20 | XChaCha20 | XChaCha20 | 114 | | message auth | Poly1305 | Poly1305 | Poly1305 | 115 | | nonce _(*2)_ | XSalsa20 (random 24-byte) | Fixed 24-byte | XSalsa20 (random 24-byte) | 116 | | Rng _(*3)_ for nonce | [ChaCha20Rng](https://docs.rs/rand_chacha/0.3.1/rand_chacha/struct.ChaCha12Rng.html) | - | [ChaCha20Rng](https://docs.rs/rand_chacha/0.3.1/rand_chacha/struct.ChaCha12Rng.html) | 117 | | Implementation | [XChaCha20Poly1305](https://docs.rs/chacha20poly1305/0.8.0/chacha20poly1305/struct.XChaCha20Poly1305.html) | [XChaCha20Poly1305](https://docs.rs/chacha20poly1305/0.8.0/chacha20poly1305/struct.XChaCha20Poly1305.html) | [ChaChaBox](https://docs.rs/crypto_box/0.6.0/crypto_box/struct.ChaChaBox.html) | 118 | 119 | _(*2) "Number used once": to make encryption non-deterministic. Although nonce for each encryption is not secret, nonce among different encryption must be different in order for attackers to get harder to guess plain-text._ 120 | 121 | _(*3) Random number generator._ 122 | 123 | ### Serializer 124 | 125 | Crate users can choose and even implement by themselves serialize representations in design. 126 | 127 | Currently, the following serializers are built-in. 128 | 129 | - `BincodeSerializer` (only `std` feature) 130 | - Best choice for `std` to reduce message size in most cases. 131 | - `PostcardSerializer` 132 | - Best choice for no_std to reduce message size in most cases. 133 | - `CborSerializer` 134 | - Has large message size but deals with complex serde types. See [Encrypts/Decrypts complex serde types example](https://github.com/laysakura/serde-encrypt/blob/main/serde-encrypt/tests/feat_serde_types.rs) to check kind of serde types only `CborSerializer` can serialize. 135 | - Single available choice in `serde-encrypt-sgx`. 136 | - Both bincode and postcard crates cannot compile with Rust SGX SDK 137 | 138 | ### Use cases 139 | 140 | - `SerdeEncryptSharedKey` 141 | - Both message sender and receiver already hold shared key. 142 | - Needs shared-key exchange via any safe way but wants high-speed encryption/decryption (e.g. communicates large amounts of messages). 143 | - `SerdeEncryptSharedKeyDeterministic` 144 | - Only when you need deterministic encryption for equal-matching in cipher-text. 145 | - Note that this is more vulnerable than `SerdeEncryptSharedKey` because, for example, attackers can find repeated patterns in cipher-text and then guess repeated patterns in plain-text. 146 | - `SerdeEncryptPublicKey` 147 | - To exchange `SharedKey`. 148 | - Quickly sends/receive small amounts of messages without secret shared key. 149 | 150 | ### [Rust SGX SDK](https://github.com/apache/incubator-teaclave-sgx-sdk) support 151 | 152 | Use [serde-encrypt-sgx](https://github.com/laysakura/serde-encrypt-sgx) crate. 153 | 154 | ### Feature flags 155 | 156 | - `std` (`serde-encrypt` [default] ; `serde-encrypt-core` [default]) 157 | - `std::error::Error` trait implementation to `serde_encrypt::Error`. 158 | - Random number generator is created via [`SeedableRng::from_entropy()`](https://rust-random.github.io/rand/rand_core/trait.SeedableRng.html#method.from_entropy), which is considered to be more secure in OS-available environments. 159 | - `BincodeSerializer` available. 160 | 161 | ## Implementation 162 | 163 | ### Crates 164 | 165 | `serde-encrypt` is a cargo workspace project and two crates are inside: 166 | 167 | - `serde-encrypt-core` 168 | - Encryption / Decryption implementations. 169 | - Traits for serialization / deserialization. 170 | - Traits for RNG (Random Number Generator) singleton. 171 | - `serde-encrypt` (depends on `serde-encrypt-core`) 172 | - Serialization / Deserialization impls. 173 | - RNG singleton impls. 174 | 175 | [`serde-encrypt-sgx` crate](https://github.com/laysakura/serde-encrypt-sgx) is also available in separate repository. 176 | It's in the same layer as `serde-encrypt`. 177 | 178 | In order to use serde with Rust SGX SDK, people should use forked version [serde-sgx](https://github.com/mesalock-linux/serde-sgx/). 179 | Also, Rust SGX SDK compiles with only old version of rustc ([nightly-2020-10-25, currently](https://github.com/apache/incubator-teaclave-sgx-sdk/blob/ed9e7cce4fd40efd7a256d5c4be1c5f00778a5bb/dockerfile/Dockerfile.1804.nightly#L34)), 180 | even simple no_std crate cannot build sometimes (e.g. [spin crate](https://docs.rs/spin) cannot). 181 | 182 | It is another choice to make `serde-encrypt-sgx` inside this repository using feature flags but it breaks `cargo build --all-features` in latest rustc. 183 | 184 | ### Encryption 185 | 186 | [crypto_box crate](https://docs.rs/crypto_box) is used both for public-key encryption and shared-key encryption. 187 | 188 | > Pure Rust implementation of the crypto_box public-key authenticated encryption scheme from NaCl-family libraries (e.g. libsodium, TweetNaCl) which combines the X25519 Diffie-Hellman function and the XSalsa20Poly1305 authenticated encryption cipher into an Elliptic Curve Integrated Encryption Scheme (ECIES). 189 | 190 | ### Serialization 191 | 192 | `struct`s and `enum`s to encrypt are serialized before encrypted. 193 | Built-in serializers are listed [here](#serializer). 194 | 195 | Users can also implement [TypedSerialized trait](https://docs.rs/serde-encrypt/0.3.2/serde_encrypt/serialize/trait.TypedSerialized.html) by themselves 196 | to get better serialization. 197 | 198 | ## Changelog 199 | 200 | See [CHANGELOG.md](https://github.com/laysakura/serde-encrypt/blob/master/CHANGELOG.md). 201 | 202 | ## License 203 | 204 | Licensed under either of [Apache License, Version 2.0](LICENSE-APACHE) or [MIT license](LICENSE-MIT) at your option. 205 | 206 | Unless you explicitly state otherwise, any contribution intentionally submitted 207 | for inclusion in serde-encrypt by you, as defined in the Apache-2.0 license, shall be 208 | dual licensed as above, without any additional terms or conditions. 209 | -------------------------------------------------------------------------------- /rust-toolchain: -------------------------------------------------------------------------------- 1 | stable 2 | -------------------------------------------------------------------------------- /serde-encrypt-core/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | authors = ["Sho Nakatani "] 3 | categories = ["no-std", "cryptography", "encoding"] 4 | description = "Encrypts all the Serialize" 5 | documentation = "https://docs.rs/serde-encrypt-core" 6 | edition = "2018" 7 | keywords = ["libsodium", "xsalsa20poly1305", "x25519", "serde", "serde-encrypt"] # up to 5 keywords, each keyword should have <= 20 chars 8 | license = "MIT OR Apache-2.0" 9 | name = "serde-encrypt-core" 10 | readme = "../README.md" 11 | repository = "https://github.com/laysakura/serde-encrypt" 12 | version = "0.7.0" 13 | 14 | [dependencies] 15 | chacha20poly1305 = {version = "0.8", default-features = false, features = ["alloc", "xchacha20poly1305"]} 16 | crypto_box = {version = "0.6"} 17 | 18 | rand = {version = "0.8", default-features = false} 19 | rand_chacha = {version = "0.3", default-features = false} 20 | 21 | [dev-dependencies] 22 | spin = {version = "0.9", default-features = false, features = ["spin_mutex", "lazy"]} 23 | 24 | [features] 25 | default = ["std"] 26 | 27 | std = [ 28 | "chacha20poly1305/std", 29 | "rand_chacha/std", 30 | ] 31 | -------------------------------------------------------------------------------- /serde-encrypt-core/src/encrypt.rs: -------------------------------------------------------------------------------- 1 | //! Encryption/Decryption implementations. 2 | 3 | pub mod encrypted_message; 4 | pub mod plain_message_public_key; 5 | pub mod plain_message_shared_key; 6 | -------------------------------------------------------------------------------- /serde-encrypt-core/src/encrypt/encrypted_message.rs: -------------------------------------------------------------------------------- 1 | //! Encrypted message structure. 2 | 3 | use core::convert::TryInto; 4 | 5 | use alloc::vec::Vec; 6 | 7 | use crate::error::Error; 8 | 9 | /// 192-bit / 24-byte nonce used in XChaCha20 / XSalsa20 10 | const NONCE_SIZE: usize = 24; 11 | 12 | /// Encrypted message structure. 13 | /// 14 | /// This struct is serialized into `Vec` (and deserialized from `Vec`). 15 | /// In order to send an EncryptedMessage to a remote receiver, use `let bin = encrypted_message.serialize();`. 16 | /// Then, the receiver should deserialize it by `let encrypted_message = EncryptedMessage::deserialize(bin);`. 17 | /// 18 | /// This struct includes Nonce, which is internally used when a receiver decrypt the encrypted message. 19 | #[derive(Clone, Eq, PartialEq, Debug)] 20 | pub struct EncryptedMessage { 21 | encrypted: Vec, 22 | 23 | /// XChaCha20 nonce (192-bit / 24-byte) 24 | nonce: [u8; NONCE_SIZE], 25 | } 26 | 27 | impl EncryptedMessage { 28 | #[doc(hidden)] 29 | pub fn new(encrypted: Vec, nonce: [u8; 24]) -> Self { 30 | Self { encrypted, nonce } 31 | } 32 | 33 | /// Serialize this encrypted message into binary in order to send it to a remote receiver. 34 | pub fn serialize(mut self) -> Vec { 35 | let mut serialized: Vec = self.nonce.to_vec(); 36 | serialized.append(&mut self.encrypted); 37 | serialized 38 | } 39 | 40 | /// Deserializer function for a receiver. 41 | /// 42 | /// # Failures 43 | /// 44 | /// - [DeserializationError](crate::error::ErrorKind::DeserializationError) when: 45 | /// - binary data does not have nonce. 46 | pub fn deserialize(mut serialized_encrypted_message: Vec) -> Result { 47 | if serialized_encrypted_message.len() >= NONCE_SIZE { 48 | let encrypted = serialized_encrypted_message.split_off(NONCE_SIZE); 49 | Ok(Self { 50 | encrypted, 51 | nonce: serialized_encrypted_message 52 | .try_into() 53 | .expect("length already checked"), 54 | }) 55 | } else { 56 | Err(Error::decryption_error( 57 | "binary data to decrypt (and then deserialize) does not seem to have nonce data", 58 | )) 59 | } 60 | } 61 | 62 | /// Ref to XChaCha20 nonce (192-bit / 24-byte) used to create this encrypted message. 63 | pub fn nonce(&self) -> &[u8] { 64 | &self.nonce 65 | } 66 | 67 | /// Ref to encrypted message. 68 | pub fn encrypted(&self) -> &[u8] { 69 | &self.encrypted 70 | } 71 | 72 | /// Payload size in bytes. 73 | #[allow(clippy::len_without_is_empty)] 74 | pub fn len(&self) -> usize { 75 | self.encrypted().len() + self.nonce().len() 76 | } 77 | } 78 | 79 | #[cfg(test)] 80 | mod tests { 81 | use alloc::vec; 82 | 83 | use crate::error::ErrorKind; 84 | 85 | use super::*; 86 | 87 | #[test] 88 | fn test_serialization() -> Result<(), Error> { 89 | let encrypted_message = EncryptedMessage::new(b"*ENCRYPTED*".to_vec(), [42u8; 24]); 90 | let bin = encrypted_message.clone().serialize(); 91 | assert_eq!(EncryptedMessage::deserialize(bin)?, encrypted_message); 92 | Ok(()) 93 | } 94 | 95 | #[test] 96 | fn test_decryption_error_on_no_nonce() { 97 | let bin = vec![42u8; NONCE_SIZE - 1]; 98 | let e = EncryptedMessage::deserialize(bin).unwrap_err(); 99 | assert_eq!(e.kind(), &ErrorKind::DecryptionError); 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /serde-encrypt-core/src/encrypt/plain_message_public_key.rs: -------------------------------------------------------------------------------- 1 | //! Shared key encryption. 2 | 3 | use core::ops::DerefMut; 4 | 5 | use crate::{ 6 | error::Error, 7 | key::combined_key::{ReceiverCombinedKey, SenderCombinedKey}, 8 | random::RngSingleton, 9 | }; 10 | use alloc::vec::Vec; 11 | use chacha20poly1305::{aead::Payload, XNonce}; 12 | use crypto_box::{aead::Aead, ChaChaBox}; 13 | 14 | use super::encrypted_message::EncryptedMessage; 15 | 16 | /// Plain message structure serialized via serde. 17 | pub trait PlainMessagePublicKeyCore { 18 | /// RNG singleton 19 | type R: RngSingleton; 20 | 21 | /// Constructor 22 | fn new(plain_message: Vec) -> Self 23 | where 24 | Self: Sized; 25 | 26 | /// Raw representation 27 | fn into_vec(self) -> Vec; 28 | 29 | /// Ref to raw representation 30 | fn as_slice(&self) -> &[u8]; 31 | 32 | /// Encrypt into EncryptedMessage 33 | fn encrypt(&self, combined_key: &SenderCombinedKey) -> Result { 34 | let nonce = Self::generate_nonce(); 35 | let sender_box = ChaChaBox::new( 36 | combined_key.receiver_public_key().as_ref(), 37 | combined_key.sender_private_key().as_ref(), 38 | ); 39 | 40 | // TODO https://github.com/laysakura/serde-encrypt/issues/19 41 | let aad = b"".as_ref(); 42 | 43 | let encrypted = sender_box 44 | .encrypt( 45 | &nonce, 46 | Payload { 47 | msg: self.as_slice(), 48 | aad, 49 | }, 50 | ) 51 | .map_err(|_| { 52 | Error::encryption_error("failed to encrypt serialized data into ChaChaBox") 53 | })?; 54 | 55 | Ok(EncryptedMessage::new(encrypted, nonce.into())) 56 | } 57 | 58 | /// Decrypt from EncryptedMessage 59 | fn decrypt( 60 | encrypted_message: &EncryptedMessage, 61 | combined_key: &ReceiverCombinedKey, 62 | ) -> Result 63 | where 64 | Self: Sized, 65 | { 66 | let receiver_box = ChaChaBox::new( 67 | combined_key.sender_public_key().as_ref(), 68 | combined_key.receiver_private_key().as_ref(), 69 | ); 70 | 71 | let nonce = encrypted_message.nonce(); 72 | let encrypted = encrypted_message.encrypted(); 73 | 74 | let serial_plain = receiver_box 75 | .decrypt(nonce.into(), encrypted) 76 | .map_err(|_| Error::decryption_error("error on decryption of ChaChaBox"))?; 77 | 78 | Ok(Self::new(serial_plain)) 79 | } 80 | 81 | /// Generate random nonce which is large enough (24-byte) to rarely conflict. 82 | fn generate_nonce() -> XNonce { 83 | let mut rng = Self::R::instance(); 84 | crypto_box::generate_nonce(rng.deref_mut()) 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /serde-encrypt-core/src/encrypt/plain_message_shared_key.rs: -------------------------------------------------------------------------------- 1 | //! Shared key encryption. 2 | 3 | mod shared_key_core; 4 | mod shared_key_deterministic_core; 5 | 6 | pub use shared_key_core::PlainMessageSharedKeyCore; 7 | pub use shared_key_deterministic_core::PlainMessageSharedKeyDeterministicCore; 8 | 9 | use super::encrypted_message::EncryptedMessage; 10 | use crate::{error::Error, key::as_shared_key::AsSharedKey}; 11 | use alloc::{format, vec::Vec}; 12 | use chacha20poly1305::{XChaCha20Poly1305, XNonce}; 13 | use crypto_box::aead::{Aead, NewAead}; 14 | 15 | /// Encrypt into EncryptedMessage 16 | fn encrypt( 17 | plain_message: &[u8], 18 | shared_key: &S, 19 | nonce: XNonce, 20 | ) -> Result 21 | where 22 | S: AsSharedKey, 23 | { 24 | let chacha = XChaCha20Poly1305::new(shared_key.to_chacha_key()); 25 | 26 | let encrypted = chacha.encrypt(&nonce, plain_message).map_err(|e| { 27 | Error::encryption_error(&format!( 28 | "failed to encrypt serialized data by XChaCha20: {:?}", 29 | e 30 | )) 31 | })?; 32 | 33 | Ok(EncryptedMessage::new(encrypted, nonce.into())) 34 | } 35 | 36 | /// Decrypt from EncryptedMessage 37 | fn decrypt(encrypted_message: &EncryptedMessage, shared_key: &S) -> Result, Error> 38 | where 39 | S: AsSharedKey, 40 | { 41 | let nonce = encrypted_message.nonce(); 42 | let chacha = XChaCha20Poly1305::new(shared_key.to_chacha_key()); 43 | 44 | let encrypted = encrypted_message.encrypted(); 45 | 46 | chacha.decrypt(nonce.into(), encrypted).map_err(|e| { 47 | Error::decryption_error(&format!( 48 | "error on decryption of XChaCha20 cipher-text: {:?}", 49 | e 50 | )) 51 | }) 52 | } 53 | -------------------------------------------------------------------------------- /serde-encrypt-core/src/encrypt/plain_message_shared_key/shared_key_core.rs: -------------------------------------------------------------------------------- 1 | //! Shared key encryption. 2 | 3 | use crate::encrypt::encrypted_message::EncryptedMessage; 4 | use crate::random::RngSingleton; 5 | use crate::{error::Error, key::as_shared_key::AsSharedKey}; 6 | use alloc::vec::Vec; 7 | use chacha20poly1305::XNonce; 8 | use core::ops::DerefMut; 9 | 10 | use super::{decrypt, encrypt}; 11 | 12 | /// Plain message structure serialized via serde. 13 | pub trait PlainMessageSharedKeyCore { 14 | /// RNG singleton 15 | type R: RngSingleton; 16 | 17 | /// Constructor 18 | fn new(plain_message: Vec) -> Self 19 | where 20 | Self: Sized; 21 | 22 | /// Raw representation 23 | fn into_vec(self) -> Vec; 24 | 25 | /// Ref to raw representation 26 | fn as_slice(&self) -> &[u8]; 27 | 28 | /// Encrypt into EncryptedMessage 29 | fn encrypt(&self, shared_key: &S) -> Result 30 | where 31 | S: AsSharedKey, 32 | { 33 | let nonce = Self::generate_nonce(); 34 | encrypt(self.as_slice(), shared_key, nonce) 35 | } 36 | 37 | /// Decrypt from EncryptedMessage 38 | fn decrypt(encrypted_message: &EncryptedMessage, shared_key: &S) -> Result 39 | where 40 | Self: Sized, 41 | S: AsSharedKey, 42 | { 43 | let plain = decrypt(encrypted_message, shared_key)?; 44 | Ok(Self::new(plain)) 45 | } 46 | 47 | /// Generate random nonce which is large enough (24-byte) to rarely conflict. 48 | fn generate_nonce() -> XNonce { 49 | let mut rng = Self::R::instance(); 50 | crypto_box::generate_nonce(rng.deref_mut()) 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /serde-encrypt-core/src/encrypt/plain_message_shared_key/shared_key_deterministic_core.rs: -------------------------------------------------------------------------------- 1 | //! Shared key deterministic encryption. 2 | 3 | use crate::{ 4 | encrypt::encrypted_message::EncryptedMessage, error::Error, key::as_shared_key::AsSharedKey, 5 | }; 6 | use alloc::vec::Vec; 7 | use chacha20poly1305::XNonce; 8 | 9 | use super::{decrypt, encrypt}; 10 | 11 | const FIXED_NONCE: [u8; 24] = [255; 24]; 12 | 13 | /// Plain message structure serialized via serde. 14 | pub trait PlainMessageSharedKeyDeterministicCore { 15 | /// Constructor 16 | fn new(plain_message: Vec) -> Self 17 | where 18 | Self: Sized; 19 | 20 | /// Raw representation 21 | fn into_vec(self) -> Vec; 22 | 23 | /// Ref to raw representation 24 | fn as_slice(&self) -> &[u8]; 25 | 26 | /// Encrypt into EncryptedMessage 27 | fn encrypt(&self, shared_key: &S) -> Result 28 | where 29 | S: AsSharedKey, 30 | { 31 | let nonce = Self::generate_nonce(); 32 | encrypt(self.as_slice(), shared_key, nonce) 33 | } 34 | 35 | /// Decrypt from EncryptedMessage 36 | fn decrypt(encrypted_message: &EncryptedMessage, shared_key: &S) -> Result 37 | where 38 | Self: Sized, 39 | S: AsSharedKey, 40 | { 41 | let plain = decrypt(encrypted_message, shared_key)?; 42 | Ok(Self::new(plain)) 43 | } 44 | 45 | /// Generate fixed nonce to enable eq-match in cipher-text. 46 | /// Note that is more vulnerable than generating random nonce (which [PlainMessageSharedKeyCore](crate::encrypt::plain_message_shared_key::PlainMessageSharedKeyCore) does). 47 | fn generate_nonce() -> XNonce { 48 | *XNonce::from_slice(&FIXED_NONCE) 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /serde-encrypt-core/src/error.rs: -------------------------------------------------------------------------------- 1 | //! Error type. 2 | 3 | mod error_kind; 4 | 5 | pub use self::error_kind::ErrorKind; 6 | 7 | use alloc::string::{String, ToString}; 8 | use core::fmt::Display; 9 | 10 | /// Error type. 11 | #[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)] 12 | pub struct Error { 13 | /// Machine-readable error type. 14 | kind: ErrorKind, 15 | 16 | /// Human-readable error reason. 17 | reason: String, 18 | } 19 | 20 | impl Display for Error { 21 | fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { 22 | write!(f, "{}: {}", self.kind, self.reason) 23 | } 24 | } 25 | 26 | #[cfg(feature = "std")] 27 | impl std::error::Error for Error {} 28 | 29 | impl Error { 30 | /// Ref to error kind. 31 | pub fn kind(&self) -> &ErrorKind { 32 | &self.kind 33 | } 34 | 35 | fn new(kind: ErrorKind, reason: &str) -> Self { 36 | Self { 37 | kind, 38 | reason: reason.to_string(), 39 | } 40 | } 41 | 42 | #[doc(hidden)] 43 | pub fn serialization_error(reason: &str) -> Self { 44 | Self::new(ErrorKind::SerializationError, reason) 45 | } 46 | 47 | #[doc(hidden)] 48 | pub fn deserialization_error(reason: &str) -> Self { 49 | Self::new(ErrorKind::DeserializationError, reason) 50 | } 51 | 52 | #[doc(hidden)] 53 | pub fn encryption_error(reason: &str) -> Self { 54 | Self::new(ErrorKind::EncryptionError, reason) 55 | } 56 | 57 | #[doc(hidden)] 58 | pub fn decryption_error(reason: &str) -> Self { 59 | Self::new(ErrorKind::DecryptionError, reason) 60 | } 61 | } 62 | 63 | #[cfg(test)] 64 | mod tests { 65 | use super::*; 66 | use alloc::format; 67 | 68 | #[test] 69 | fn test_display() { 70 | let e = Error::serialization_error("x"); 71 | let _s = format!("{}", e); 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /serde-encrypt-core/src/error/error_kind.rs: -------------------------------------------------------------------------------- 1 | //! Kinds of errors. 2 | 3 | use core::fmt::Display; 4 | 5 | /// Kinds of errors. 6 | #[allow(missing_docs)] 7 | #[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)] 8 | pub enum ErrorKind { 9 | SerializationError, 10 | DeserializationError, 11 | 12 | EncryptionError, 13 | DecryptionError, 14 | } 15 | 16 | impl Display for ErrorKind { 17 | fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { 18 | let s = match self { 19 | ErrorKind::SerializationError => "SerializationError: Failed to serialize data to send", 20 | ErrorKind::DeserializationError => { 21 | "DeserializationError: Failed to deserialize data received" 22 | } 23 | ErrorKind::EncryptionError => { 24 | "EncryptionError: Failed to encrypt serialized data to send" 25 | } 26 | ErrorKind::DecryptionError => "DecryptionError: Failed to decrypt data received", 27 | }; 28 | write!(f, "{}", s) 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /serde-encrypt-core/src/key.rs: -------------------------------------------------------------------------------- 1 | #![allow(missing_docs)] 2 | 3 | #[deny(missing_docs)] 4 | pub mod combined_key; 5 | #[deny(missing_docs)] 6 | pub mod key_pair; 7 | 8 | pub mod as_shared_key; 9 | -------------------------------------------------------------------------------- /serde-encrypt-core/src/key/as_shared_key.rs: -------------------------------------------------------------------------------- 1 | //! Keys for common key cryptosystem. 2 | 3 | use crate::random::RngSingleton; 4 | use chacha20poly1305::Key as ChaChaKey; 5 | use core::{convert::TryInto, ops::DerefMut}; 6 | use rand::RngCore; 7 | 8 | /// 32-byte key shared among sender and receiver secretly. 9 | /// 10 | /// The reason why this is not a struct but a trait is: 11 | /// 12 | /// - shared key should be serialized and encrypted in order to be shared among peers 13 | /// - but this -core trait is serialization agnostic. 14 | /// 15 | /// So, implementators of this trait is expected to have `serde::{Serialize, Deserialize}` and `SerdeSerializePublicKey` trait bounds. 16 | pub trait AsSharedKey { 17 | /// RNG singleton 18 | type R: RngSingleton; 19 | 20 | /// Constructor from secret bytes. 21 | fn from_array(key: [u8; 32]) -> Self 22 | where 23 | Self: Sized; 24 | 25 | /// Ref to 32-byte slice 26 | fn as_slice(&self) -> &[u8]; 27 | 28 | /// Generates secure random key. 29 | /// 30 | /// Random number generator which implements `CryptRng` is used internally. 31 | fn generate() -> Self 32 | where 33 | Self: Sized, 34 | { 35 | let mut rng = Self::R::instance(); 36 | 37 | let r0 = rng.deref_mut().next_u64(); 38 | let r1 = rng.deref_mut().next_u64(); 39 | let r2 = rng.deref_mut().next_u64(); 40 | let r3 = rng.deref_mut().next_u64(); 41 | 42 | let key = [ 43 | r0.to_le_bytes(), 44 | r1.to_le_bytes(), 45 | r2.to_le_bytes(), 46 | r3.to_le_bytes(), 47 | ] 48 | .concat() 49 | .try_into() 50 | .expect("must be 32 bytes"); 51 | 52 | Self::from_array(key) 53 | } 54 | 55 | /// Makes `chacha20poly1305::Key` 56 | fn to_chacha_key(&self) -> &ChaChaKey { 57 | ChaChaKey::from_slice(self.as_slice()) 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /serde-encrypt-core/src/key/combined_key.rs: -------------------------------------------------------------------------------- 1 | //! "Combined key" for Diffie-Hellman key exchange. 2 | //! A combined key consists of either: 3 | //! 4 | //! - (`Alice's private key`, `Bob's public key`) pair 5 | //! - (`Alice's public key`, `Bob's private key`) pair 6 | 7 | use super::key_pair::{ 8 | private_key::{ReceiverPrivateKey, SenderPrivateKey}, 9 | public_key::{ReceiverPublicKey, SenderPublicKey}, 10 | }; 11 | 12 | /// (`Alice's private key`, `Bob's public key`) pair. 13 | /// 14 | /// (Alice is a sender and Bob a receiver.) 15 | #[derive(Clone, Debug)] 16 | pub struct SenderCombinedKey<'s, 'r> { 17 | sender_private_key: &'s SenderPrivateKey, 18 | receiver_public_key: &'r ReceiverPublicKey, 19 | } 20 | 21 | impl<'s, 'r> SenderCombinedKey<'s, 'r> { 22 | /// Constructor. 23 | pub fn new( 24 | sender_private_key: &'s SenderPrivateKey, 25 | receiver_public_key: &'r ReceiverPublicKey, 26 | ) -> Self { 27 | Self { 28 | sender_private_key, 29 | receiver_public_key, 30 | } 31 | } 32 | 33 | pub(crate) fn sender_private_key(&self) -> &SenderPrivateKey { 34 | self.sender_private_key 35 | } 36 | 37 | pub(crate) fn receiver_public_key(&self) -> &ReceiverPublicKey { 38 | self.receiver_public_key 39 | } 40 | } 41 | 42 | /// (`Alice's public key`, `Bob's private key`) pair. 43 | /// 44 | /// (Alice is a sender and Bob a receiver.) 45 | #[derive(Clone, Debug)] 46 | pub struct ReceiverCombinedKey<'s, 'r> { 47 | sender_public_key: &'s SenderPublicKey, 48 | receiver_private_key: &'r ReceiverPrivateKey, 49 | } 50 | 51 | impl<'s, 'r> ReceiverCombinedKey<'s, 'r> { 52 | /// Constructor. 53 | pub fn new( 54 | sender_public_key: &'s SenderPublicKey, 55 | receiver_private_key: &'r ReceiverPrivateKey, 56 | ) -> Self { 57 | Self { 58 | sender_public_key, 59 | receiver_private_key, 60 | } 61 | } 62 | 63 | pub(crate) fn receiver_private_key(&self) -> &ReceiverPrivateKey { 64 | self.receiver_private_key 65 | } 66 | 67 | pub(crate) fn sender_public_key(&self) -> &SenderPublicKey { 68 | self.sender_public_key 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /serde-encrypt-core/src/key/key_pair.rs: -------------------------------------------------------------------------------- 1 | //! X25519 key-pair (public-key and private-key). 2 | 3 | pub mod private_key; 4 | pub mod public_key; 5 | 6 | use core::ops::DerefMut; 7 | 8 | use self::{ 9 | private_key::{ReceiverPrivateKey, SenderPrivateKey}, 10 | public_key::{ReceiverPublicKey, SenderPublicKey}, 11 | }; 12 | use crate::random::RngSingleton; 13 | use crypto_box::{PublicKey, SecretKey}; 14 | 15 | /// X25519 Key-pair generated by sender. 16 | pub trait SenderKeyPairCore { 17 | /// RNG singleton 18 | type R: RngSingleton; 19 | 20 | /// Constructor 21 | fn new(sender_private_key: SenderPrivateKey, sender_public_key: SenderPublicKey) -> Self 22 | where 23 | Self: Sized; 24 | 25 | /// Generates a key-pair for message sender. 26 | fn generate() -> Self 27 | where 28 | Self: Sized, 29 | { 30 | let (private_key, public_key) = gen_key_pair::(); 31 | let sender_private_key = SenderPrivateKey::from(private_key); 32 | let sender_public_key = SenderPublicKey::from(public_key); 33 | Self::new(sender_private_key, sender_public_key) 34 | } 35 | 36 | /// Ref to private key. 37 | fn private_key(&self) -> &SenderPrivateKey; 38 | 39 | /// Ref to public key. 40 | fn public_key(&self) -> &SenderPublicKey; 41 | } 42 | 43 | /// X25519 Key-pair generated by receiver. 44 | pub trait ReceiverKeyPairCore { 45 | /// RNG singleton 46 | type R: RngSingleton; 47 | 48 | /// Constructor 49 | fn new( 50 | receiver_private_key: ReceiverPrivateKey, 51 | receiver_public_key: ReceiverPublicKey, 52 | ) -> Self 53 | where 54 | Self: Sized; 55 | 56 | /// Generates a key-pair for message receiver. 57 | fn generate() -> Self 58 | where 59 | Self: Sized, 60 | { 61 | let (private_key, public_key) = gen_key_pair::(); 62 | let receiver_private_key = ReceiverPrivateKey::from(private_key); 63 | let receiver_public_key = ReceiverPublicKey::from(public_key); 64 | Self::new(receiver_private_key, receiver_public_key) 65 | } 66 | 67 | /// Ref to private key. 68 | fn private_key(&self) -> &ReceiverPrivateKey; 69 | 70 | /// Ref to public key. 71 | fn public_key(&self) -> &ReceiverPublicKey; 72 | } 73 | 74 | fn gen_key_pair() -> (SecretKey, PublicKey) 75 | where 76 | R: RngSingleton, 77 | { 78 | let mut rng = R::instance(); 79 | 80 | let secret_key = SecretKey::generate(rng.deref_mut()); 81 | let public_key = secret_key.public_key(); 82 | 83 | (secret_key, public_key) 84 | } 85 | -------------------------------------------------------------------------------- /serde-encrypt-core/src/key/key_pair/private_key.rs: -------------------------------------------------------------------------------- 1 | //! X25519 private-key. 2 | 3 | use crypto_box::SecretKey; 4 | 5 | /// Message sender's private key 6 | #[derive(Clone, Debug)] 7 | pub struct SenderPrivateKey(SecretKey); 8 | 9 | impl AsRef for SenderPrivateKey { 10 | fn as_ref(&self) -> &SecretKey { 11 | &self.0 12 | } 13 | } 14 | 15 | impl From for SenderPrivateKey { 16 | fn from(s: SecretKey) -> Self { 17 | Self(s) 18 | } 19 | } 20 | 21 | /// Message receiver's private key 22 | #[derive(Clone, Debug)] 23 | pub struct ReceiverPrivateKey(SecretKey); 24 | 25 | impl AsRef for ReceiverPrivateKey { 26 | fn as_ref(&self) -> &SecretKey { 27 | &self.0 28 | } 29 | } 30 | 31 | impl From for ReceiverPrivateKey { 32 | fn from(s: SecretKey) -> Self { 33 | Self(s) 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /serde-encrypt-core/src/key/key_pair/public_key.rs: -------------------------------------------------------------------------------- 1 | //! X25519 public-key. 2 | 3 | use crypto_box::PublicKey; 4 | 5 | /// Message sender's public key 6 | #[derive(Clone, Debug)] 7 | pub struct SenderPublicKey(PublicKey); 8 | 9 | impl AsRef for SenderPublicKey { 10 | fn as_ref(&self) -> &PublicKey { 11 | &self.0 12 | } 13 | } 14 | 15 | impl From for SenderPublicKey { 16 | fn from(p: PublicKey) -> Self { 17 | Self(p) 18 | } 19 | } 20 | 21 | /// Message receiver's public key 22 | #[derive(Clone, Debug)] 23 | pub struct ReceiverPublicKey(PublicKey); 24 | 25 | impl AsRef for ReceiverPublicKey { 26 | fn as_ref(&self) -> &PublicKey { 27 | &self.0 28 | } 29 | } 30 | 31 | impl From for ReceiverPublicKey { 32 | fn from(p: PublicKey) -> Self { 33 | Self(p) 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /serde-encrypt-core/src/lib.rs: -------------------------------------------------------------------------------- 1 | //! Core implementation of serde-encrypt crate. 2 | //! 3 | //! This crate is serde agnostic because: 4 | //! 5 | //! - serde cannot be easily build in some environment (e.g. rust-sgx-sdk), 6 | //! - so it is nice to manage serde dependency in thin layer (serde-encrypt crate here) in order to build core logic easily. 7 | //! 8 | //! Normally, users do not depend on this crate directly. 9 | 10 | #![deny(missing_debug_implementations, missing_docs)] 11 | #![cfg_attr(not(feature = "std"), no_std)] 12 | 13 | extern crate alloc; 14 | 15 | pub mod encrypt; 16 | pub mod error; 17 | pub mod key; 18 | pub mod random; 19 | -------------------------------------------------------------------------------- /serde-encrypt-core/src/random.rs: -------------------------------------------------------------------------------- 1 | //! RNG abstract 2 | 3 | use core::ops::DerefMut; 4 | 5 | use rand_chacha::ChaCha12Rng; 6 | 7 | /// RNG singleton 8 | pub trait RngSingleton { 9 | /// &mut ChaCha12Rng 10 | type D: DerefMut; 11 | 12 | /// Singleton instance 13 | fn instance() -> Self::D; 14 | } 15 | -------------------------------------------------------------------------------- /serde-encrypt-core/tests/feat_serde_encrypt_std_error.rs: -------------------------------------------------------------------------------- 1 | //! serde_encrypt::error::Error implements std::error::Error in `std` feature. 2 | 3 | #![cfg(feature = "std")] 4 | 5 | mod test_util; 6 | 7 | // https://rust-lang.github.io/api-guidelines/interoperability.html#error-types-are-meaningful-and-well-behaved-c-good-err 8 | #[test] 9 | fn test_api_guidelines_c_good_err() { 10 | use std::fmt::Display; 11 | 12 | fn assert_error() {} 13 | assert_error::(); 14 | 15 | fn assert_display() {} 16 | assert_display::(); 17 | } 18 | -------------------------------------------------------------------------------- /serde-encrypt-core/tests/feat_shared_key_distribution.rs: -------------------------------------------------------------------------------- 1 | //! Test if SharedKey::generates() emits different key every time. 2 | 3 | mod test_util; 4 | 5 | use serde_encrypt_core::key::as_shared_key::AsSharedKey; 6 | use test_util::*; 7 | 8 | #[test] 9 | fn test_shared_key_distribution() { 10 | #[derive(PartialEq, Debug)] 11 | struct MySharedKey([u8; 32]); 12 | 13 | impl AsSharedKey for MySharedKey { 14 | type R = TestRngSingleton; 15 | 16 | fn from_array(key: [u8; 32]) -> Self 17 | where 18 | Self: Sized, 19 | { 20 | Self(key) 21 | } 22 | 23 | fn as_slice(&self) -> &[u8] { 24 | &self.0 25 | } 26 | } 27 | 28 | assert_no_duplicate(MySharedKey::generate, 100); 29 | } 30 | -------------------------------------------------------------------------------- /serde-encrypt-core/tests/test_util/mod.rs: -------------------------------------------------------------------------------- 1 | #![allow(dead_code)] 2 | 3 | extern crate alloc; 4 | 5 | mod random; 6 | 7 | pub use random::TestRngSingleton; 8 | 9 | use alloc::vec::Vec; 10 | use core::fmt::Debug; 11 | 12 | pub fn assert_no_duplicate(generator: impl Fn() -> T, n_generate: usize) 13 | where 14 | T: PartialEq + Debug, 15 | { 16 | let mut vs = Vec::::new(); 17 | for _ in 0..n_generate { 18 | let v = generator(); 19 | vs.push(v); 20 | } 21 | 22 | for i in 0..n_generate { 23 | let v_i = vs.get(i).unwrap(); 24 | for j in (i + 1)..n_generate { 25 | let v_j = vs.get(j).unwrap(); 26 | assert_ne!(v_i, v_j); 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /serde-encrypt-core/tests/test_util/random/mod.rs: -------------------------------------------------------------------------------- 1 | use rand::SeedableRng; 2 | use rand_chacha::ChaCha12Rng; 3 | use serde_encrypt_core::random::RngSingleton; 4 | use spin::{Lazy, Mutex, MutexGuard}; 5 | 6 | static GLOBAL_RNG: Lazy> = 7 | Lazy::new(|| Mutex::new(ChaCha12Rng::from_seed([0u8; 32]))); 8 | 9 | #[derive(Clone, Debug)] 10 | pub struct TestRngSingleton; 11 | impl RngSingleton for TestRngSingleton { 12 | type D = MutexGuard<'static, ChaCha12Rng>; 13 | 14 | fn instance() -> Self::D { 15 | GLOBAL_RNG.lock() 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /serde-encrypt/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | authors = ["Sho Nakatani "] 3 | categories = ["no-std", "cryptography", "encoding"] 4 | description = "Encrypts all the Serialize" 5 | documentation = "https://docs.rs/serde-encrypt" 6 | edition = "2018" 7 | keywords = ["libsodium", "xsalsa20poly1305", "x25519", "serde", "serde-encrypt"] # up to 5 keywords, each keyword should have <= 20 chars 8 | license = "MIT OR Apache-2.0" 9 | name = "serde-encrypt" 10 | readme = "../README.md" 11 | repository = "https://github.com/laysakura/serde-encrypt" 12 | version = "0.7.0" 13 | 14 | [dependencies] 15 | serde-encrypt-core = {version = "0.7.0", path = "../serde-encrypt-core", default-features = false} 16 | 17 | bincode = {version = "1.3", optional = true} 18 | postcard = {version = "0.7", default-features = false, features = ["alloc"]} 19 | serde = {version = "1.0", default-features = false} 20 | serde_cbor = {version = "0.11", default-features = false, features = ["alloc"]} 21 | 22 | rand_chacha = {version = "0.3", default-features = false} 23 | rand_core = {version = "0.6", default-features = false} 24 | 25 | cfg-if = "1.0" 26 | 27 | # Lazy static options 28 | once_cell = {version = "1.8", optional = true} 29 | spin = {version = "0.9.8", default-features = false, features = ["spin_mutex", "lazy"]}# default (available w/o std) 30 | 31 | [dev-dependencies] 32 | serde = {version = "1.0", default-features = false, features = ["derive", "alloc"]}# alloc for Vec, String 33 | serde_json = {version = "1.0", default-features = false, features = ["alloc"]} 34 | serde_repr = "0.1" 35 | 36 | pretty_assertions = "1.0" 37 | 38 | void = "1.0" 39 | 40 | [features] 41 | default = ["std"] 42 | std = [ 43 | "serde-encrypt-core/std", 44 | "serde/std", 45 | "bincode", 46 | "serde_cbor/std", 47 | "once_cell", 48 | "rand_chacha/std", 49 | "rand_core/getrandom", # from_entropy() 50 | ] 51 | -------------------------------------------------------------------------------- /serde-encrypt/src/encrypt.rs: -------------------------------------------------------------------------------- 1 | //! Encryption implementation 2 | 3 | pub mod plain_message_public_key; 4 | pub mod plain_message_shared_key; 5 | pub mod plain_message_shared_key_deterministic; 6 | -------------------------------------------------------------------------------- /serde-encrypt/src/encrypt/plain_message_public_key.rs: -------------------------------------------------------------------------------- 1 | //! Public key encryption 2 | 3 | use alloc::vec::Vec; 4 | use serde_encrypt_core::encrypt::plain_message_public_key::PlainMessagePublicKeyCore; 5 | 6 | use crate::random::RngSingletonImpl; 7 | 8 | /// Plain message structure serialized via serde. 9 | #[derive(Clone, Eq, PartialEq, Debug)] 10 | pub struct PlainMessagePublicKey(Vec); 11 | 12 | impl PlainMessagePublicKeyCore for PlainMessagePublicKey { 13 | type R = RngSingletonImpl; 14 | 15 | fn new(plain_message: Vec) -> Self 16 | where 17 | Self: Sized, 18 | { 19 | Self(plain_message) 20 | } 21 | 22 | fn into_vec(self) -> Vec { 23 | self.0 24 | } 25 | 26 | fn as_slice(&self) -> &[u8] { 27 | &self.0 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /serde-encrypt/src/encrypt/plain_message_shared_key.rs: -------------------------------------------------------------------------------- 1 | //! Shared key encryption 2 | 3 | use alloc::vec::Vec; 4 | use serde_encrypt_core::encrypt::plain_message_shared_key::PlainMessageSharedKeyCore; 5 | 6 | use crate::random::RngSingletonImpl; 7 | 8 | /// Plain message structure serialized via serde. 9 | #[derive(Clone, Eq, PartialEq, Debug)] 10 | pub struct PlainMessageSharedKey(Vec); 11 | 12 | impl PlainMessageSharedKeyCore for PlainMessageSharedKey { 13 | type R = RngSingletonImpl; 14 | 15 | fn new(plain_message: Vec) -> Self 16 | where 17 | Self: Sized, 18 | { 19 | Self(plain_message) 20 | } 21 | 22 | fn into_vec(self) -> Vec { 23 | self.0 24 | } 25 | 26 | fn as_slice(&self) -> &[u8] { 27 | &self.0 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /serde-encrypt/src/encrypt/plain_message_shared_key_deterministic.rs: -------------------------------------------------------------------------------- 1 | //! Shared key deterministic encryption 2 | 3 | use alloc::vec::Vec; 4 | use serde_encrypt_core::encrypt::plain_message_shared_key::PlainMessageSharedKeyDeterministicCore; 5 | 6 | /// Plain message structure serialized via serde. 7 | #[derive(Clone, Eq, PartialEq, Debug)] 8 | pub struct PlainMessageSharedKeyDeterministic(Vec); 9 | 10 | impl PlainMessageSharedKeyDeterministicCore for PlainMessageSharedKeyDeterministic { 11 | fn new(plain_message: Vec) -> Self 12 | where 13 | Self: Sized, 14 | { 15 | Self(plain_message) 16 | } 17 | 18 | fn into_vec(self) -> Vec { 19 | self.0 20 | } 21 | 22 | fn as_slice(&self) -> &[u8] { 23 | &self.0 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /serde-encrypt/src/key.rs: -------------------------------------------------------------------------------- 1 | #![allow(missing_docs)] 2 | 3 | #[deny(missing_docs)] 4 | pub mod key_pair; 5 | -------------------------------------------------------------------------------- /serde-encrypt/src/key/key_pair.rs: -------------------------------------------------------------------------------- 1 | //! X25519 key-pair (public-key and private-key). 2 | 3 | use serde_encrypt_core::key::key_pair::{ 4 | private_key::{ReceiverPrivateKey, SenderPrivateKey}, 5 | public_key::{ReceiverPublicKey, SenderPublicKey}, 6 | ReceiverKeyPairCore, SenderKeyPairCore, 7 | }; 8 | 9 | use crate::random::RngSingletonImpl; 10 | 11 | /// Message sender's key pair 12 | #[derive(Clone, Debug)] 13 | pub struct SenderKeyPair { 14 | sender_private_key: SenderPrivateKey, 15 | sender_public_key: SenderPublicKey, 16 | } 17 | 18 | impl SenderKeyPairCore for SenderKeyPair { 19 | type R = RngSingletonImpl; 20 | 21 | fn new(sender_private_key: SenderPrivateKey, sender_public_key: SenderPublicKey) -> Self 22 | where 23 | Self: Sized, 24 | { 25 | Self { 26 | sender_private_key, 27 | sender_public_key, 28 | } 29 | } 30 | 31 | fn private_key(&self) -> &SenderPrivateKey { 32 | &self.sender_private_key 33 | } 34 | 35 | fn public_key(&self) -> &SenderPublicKey { 36 | &self.sender_public_key 37 | } 38 | } 39 | 40 | /// Message receiver's key pair 41 | #[derive(Clone, Debug)] 42 | pub struct ReceiverKeyPair { 43 | receiver_private_key: ReceiverPrivateKey, 44 | receiver_public_key: ReceiverPublicKey, 45 | } 46 | 47 | impl ReceiverKeyPairCore for ReceiverKeyPair { 48 | type R = RngSingletonImpl; 49 | 50 | fn new(receiver_private_key: ReceiverPrivateKey, receiver_public_key: ReceiverPublicKey) -> Self 51 | where 52 | Self: Sized, 53 | { 54 | Self { 55 | receiver_private_key, 56 | receiver_public_key, 57 | } 58 | } 59 | 60 | fn private_key(&self) -> &ReceiverPrivateKey { 61 | &self.receiver_private_key 62 | } 63 | 64 | fn public_key(&self) -> &ReceiverPublicKey { 65 | &self.receiver_public_key 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /serde-encrypt/src/lib.rs: -------------------------------------------------------------------------------- 1 | //! serde-encrypt encrypts/decrypts any `strct`s and `enum`s that implement `serde::{Serialize, Deserialize`}. 2 | //! 3 | //! See [README.md](https://github.com/laysakura/serde-encrypt) for basic usage and implementation details. 4 | 5 | #![deny(missing_debug_implementations, missing_docs)] 6 | #![cfg_attr(not(feature = "std"), no_std)] 7 | 8 | extern crate alloc; 9 | 10 | pub mod encrypt; 11 | pub mod key; 12 | pub mod serialize; 13 | pub mod shared_key; 14 | pub mod traits; 15 | 16 | mod random; 17 | 18 | cfg_if::cfg_if! { 19 | if #[cfg(feature = "std")] { 20 | use once_cell::sync::Lazy; 21 | use std::sync::{MutexGuard, Mutex}; 22 | } else { 23 | use spin::{Lazy, MutexGuard, Mutex}; 24 | } 25 | } 26 | 27 | pub use serde_encrypt_core::{ 28 | encrypt::encrypted_message::EncryptedMessage, 29 | error::{Error, ErrorKind}, 30 | key::{ 31 | as_shared_key::AsSharedKey, 32 | combined_key::{ReceiverCombinedKey, SenderCombinedKey}, 33 | key_pair::{ReceiverKeyPairCore, SenderKeyPairCore}, 34 | }, 35 | }; 36 | -------------------------------------------------------------------------------- /serde-encrypt/src/random.rs: -------------------------------------------------------------------------------- 1 | //! RNG 2 | 3 | #[cfg(not(feature = "std"))] 4 | use alloc::format; 5 | #[cfg(not(feature = "std"))] 6 | use core::convert::TryInto; 7 | 8 | use crate::{Lazy, Mutex, MutexGuard}; 9 | use rand_chacha::ChaCha12Rng; 10 | use rand_core::SeedableRng; 11 | use serde_encrypt_core::random::RngSingleton; 12 | 13 | static GLOBAL_RNG: Lazy> = 14 | Lazy::new(|| Mutex::new(RngSingletonImpl::chacha12_rng())); 15 | 16 | /// RNG singleton implementation 17 | #[derive(Clone, Debug)] 18 | pub struct RngSingletonImpl; 19 | impl RngSingleton for RngSingletonImpl { 20 | type D = MutexGuard<'static, ChaCha12Rng>; 21 | 22 | #[cfg(feature = "std")] 23 | fn instance() -> Self::D { 24 | GLOBAL_RNG 25 | .lock() 26 | .expect("Panic occurred in another MutexGuard scope") 27 | } 28 | #[cfg(not(feature = "std"))] 29 | fn instance() -> Self::D { 30 | GLOBAL_RNG.lock() 31 | } 32 | } 33 | impl RngSingletonImpl { 34 | #[cfg(feature = "std")] 35 | fn chacha12_rng() -> ChaCha12Rng { 36 | ChaCha12Rng::from_entropy() 37 | } 38 | 39 | #[cfg(not(feature = "std"))] 40 | fn chacha12_rng() -> ChaCha12Rng { 41 | ChaCha12Rng::from_seed(Self::gen_seed()) 42 | } 43 | 44 | #[cfg(not(feature = "std"))] 45 | /// Generate random seed from memory address. 46 | /// 47 | /// Note that this is for no_std env. 48 | /// If you use `SeedableRng::from_entropy` would more secure. 49 | /// E.g. Single process environments may have deterministic memory address. 50 | fn gen_seed() -> [u8; 32] { 51 | let a0 = Self::gen_rand_u64_mem_addr(); 52 | let a1 = a0 ^ a0.rotate_right(13); 53 | let a2 = a1 ^ a1.rotate_right(17); 54 | let a3 = a2 ^ a2.rotate_right(5); 55 | 56 | let a0 = a0.to_le_bytes(); 57 | let a1 = a1.to_le_bytes(); 58 | let a2 = a2.to_le_bytes(); 59 | let a3 = a3.to_le_bytes(); 60 | 61 | [a0, a1, a2, a3] 62 | .concat() 63 | .try_into() 64 | .expect("must be 32 bytes") 65 | } 66 | 67 | /// Poorly distributed numbers to use themselves as rand. 68 | /// Just use as seed. 69 | #[cfg(not(feature = "std"))] 70 | fn gen_rand_u64_mem_addr() -> u64 { 71 | let x = 123; 72 | let x_addr = &x as *const i32; 73 | let x_addr_s = format!("{:p}", x_addr); 74 | let x_addr_s = x_addr_s.trim_start_matches("0x"); 75 | u64::from_str_radix(x_addr_s, 16).expect("must be a hex string") 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /serde-encrypt/src/serialize.rs: -------------------------------------------------------------------------------- 1 | //! Serializer trait and default implementation. 2 | 3 | pub mod impls; 4 | 5 | use crate::Error; 6 | use alloc::vec::Vec; 7 | use serde::{Deserialize, Serialize}; 8 | 9 | /// Serialization abstract with type to serialize. 10 | /// 11 | /// Serializer implementations must implement this trait. 12 | pub trait TypedSerialized { 13 | /// Type to serialize 14 | type T; 15 | 16 | /// Constructor 17 | fn new(serialized: Vec) -> Self 18 | where 19 | Self: Sized; 20 | 21 | /// Ref to serialized. 22 | fn as_slice(&self) -> &[u8]; 23 | 24 | /// Into serialized. 25 | fn into_vec(self) -> Vec; 26 | 27 | /// # Failures 28 | /// 29 | /// - [SerializationError](serde_encrypt_core::error::ErrorKind::SerializationError) when failed to serialize message. 30 | fn serialize(v: &Self::T) -> Result 31 | where 32 | Self: Sized, 33 | Self::T: Serialize; 34 | 35 | /// # Failures 36 | /// 37 | /// - [DeserializationError](serde_encrypt_core::error::ErrorKind::DeserializationError) when failed to deserialize decrypted message. 38 | fn deserialize<'de>(&'de self) -> Result 39 | where 40 | Self::T: Deserialize<'de>; 41 | } 42 | -------------------------------------------------------------------------------- /serde-encrypt/src/serialize/impls.rs: -------------------------------------------------------------------------------- 1 | //! Serializer implementations. 2 | 3 | mod postcard_serializer; 4 | pub use postcard_serializer::PostcardSerializer; 5 | 6 | mod cbor_serializer; 7 | pub use cbor_serializer::CborSerializer; 8 | 9 | cfg_if::cfg_if! { 10 | if #[cfg(feature = "std")] { 11 | mod bincode_serializer; 12 | pub use bincode_serializer::BincodeSerializer; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /serde-encrypt/src/serialize/impls/bincode_serializer.rs: -------------------------------------------------------------------------------- 1 | use crate::{serialize::TypedSerialized, Error}; 2 | use alloc::{format, vec::Vec}; 3 | use core::marker::PhantomData; 4 | use serde::{Deserialize, Serialize}; 5 | 6 | /// [bincode](https://docs.rs/bincode) serializer 7 | #[derive(Debug)] 8 | pub struct BincodeSerializer { 9 | serialized: Vec, 10 | _type: PhantomData, 11 | } 12 | 13 | impl TypedSerialized for BincodeSerializer { 14 | type T = T; 15 | 16 | fn new(serialized: Vec) -> Self 17 | where 18 | Self: Sized, 19 | { 20 | Self { 21 | serialized, 22 | _type: PhantomData::default(), 23 | } 24 | } 25 | 26 | fn as_slice(&self) -> &[u8] { 27 | &self.serialized 28 | } 29 | 30 | fn into_vec(self) -> Vec { 31 | self.serialized 32 | } 33 | 34 | fn serialize(v: &Self::T) -> Result 35 | where 36 | Self: Sized, 37 | Self::T: Serialize, 38 | { 39 | let serialized = bincode::serialize(v).map_err(|e| { 40 | Error::serialization_error(&format!("failed to serialize data by bincode: {:?}", e)) 41 | })?; 42 | Ok(Self::new(serialized)) 43 | } 44 | 45 | fn deserialize<'de>(&'de self) -> Result 46 | where 47 | Self::T: Deserialize<'de>, 48 | { 49 | bincode::deserialize(self.as_slice()).map_err(|e| { 50 | Error::deserialization_error(&format!( 51 | "error on bincode deserialization after decryption: {:?}", 52 | e 53 | )) 54 | }) 55 | } 56 | } 57 | 58 | #[cfg(test)] 59 | mod tests { 60 | use super::*; 61 | 62 | #[test] 63 | fn test_bincode_serializer() -> Result<(), Error> { 64 | #[derive(PartialEq, Debug, Serialize, Deserialize)] 65 | struct Message(i32); 66 | 67 | let msg = Message(42); 68 | 69 | let serialized_msg = BincodeSerializer::serialize(&msg)?; 70 | let deserialized_msg = serialized_msg.deserialize()?; 71 | 72 | assert_eq!(msg, deserialized_msg); 73 | 74 | Ok(()) 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /serde-encrypt/src/serialize/impls/cbor_serializer.rs: -------------------------------------------------------------------------------- 1 | use crate::{serialize::TypedSerialized, Error}; 2 | use alloc::{format, vec::Vec}; 3 | use core::marker::PhantomData; 4 | use serde::{Deserialize, Serialize}; 5 | 6 | /// [CBOR](https://docs.rs/serde_cbor) serializer 7 | #[derive(Debug)] 8 | pub struct CborSerializer { 9 | serialized: Vec, 10 | _type: PhantomData, 11 | } 12 | 13 | impl TypedSerialized for CborSerializer { 14 | type T = T; 15 | 16 | fn new(serialized: Vec) -> Self 17 | where 18 | Self: Sized, 19 | { 20 | Self { 21 | serialized, 22 | _type: PhantomData::default(), 23 | } 24 | } 25 | 26 | fn as_slice(&self) -> &[u8] { 27 | &self.serialized 28 | } 29 | 30 | fn into_vec(self) -> Vec { 31 | self.serialized 32 | } 33 | 34 | /// # Failures 35 | /// 36 | /// - [SerializationError](serde_encrypt_core::error::ErrorKind::SerializationError) when failed to serialize message. 37 | fn serialize(v: &Self::T) -> Result 38 | where 39 | Self: Sized, 40 | Self::T: Serialize, 41 | { 42 | let serialized = serde_cbor::to_vec(v).map_err(|e| { 43 | Error::serialization_error(&format!("failed to serialize data by serde_cbor: {:?}", e)) 44 | })?; 45 | Ok(Self::new(serialized)) 46 | } 47 | 48 | /// # Failures 49 | /// 50 | /// - [DeserializationError](serde_encrypt_core::error::ErrorKind::DeserializationError) when failed to deserialize decrypted message. 51 | fn deserialize<'de>(&'de self) -> Result 52 | where 53 | Self::T: Deserialize<'de>, 54 | { 55 | serde_cbor::from_slice(self.as_slice()).map_err(|e| { 56 | Error::deserialization_error(&format!( 57 | "error on serde_cbor deserialization after decryption: {:?}", 58 | e 59 | )) 60 | }) 61 | } 62 | } 63 | 64 | #[cfg(test)] 65 | mod tests { 66 | use super::*; 67 | 68 | #[test] 69 | fn test_cbor_serializer() -> Result<(), Error> { 70 | #[derive(PartialEq, Debug, Serialize, Deserialize)] 71 | struct Message(i32); 72 | 73 | let msg = Message(42); 74 | 75 | let serialized_msg = CborSerializer::serialize(&msg)?; 76 | let deserialized_msg = serialized_msg.deserialize()?; 77 | 78 | assert_eq!(msg, deserialized_msg); 79 | 80 | Ok(()) 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /serde-encrypt/src/serialize/impls/postcard_serializer.rs: -------------------------------------------------------------------------------- 1 | use crate::{serialize::TypedSerialized, Error}; 2 | use alloc::{format, vec::Vec}; 3 | use core::marker::PhantomData; 4 | use serde::{Deserialize, Serialize}; 5 | 6 | /// [postcard](https://docs.rs/postcard) serializer 7 | #[derive(Debug)] 8 | pub struct PostcardSerializer { 9 | serialized: Vec, 10 | _type: PhantomData, 11 | } 12 | 13 | impl TypedSerialized for PostcardSerializer { 14 | type T = T; 15 | 16 | fn new(serialized: Vec) -> Self 17 | where 18 | Self: Sized, 19 | { 20 | Self { 21 | serialized, 22 | _type: PhantomData::default(), 23 | } 24 | } 25 | 26 | fn as_slice(&self) -> &[u8] { 27 | &self.serialized 28 | } 29 | 30 | fn into_vec(self) -> Vec { 31 | self.serialized 32 | } 33 | 34 | /// # Failures 35 | /// 36 | /// - [SerializationError](serde_encrypt_core::error::ErrorKind::SerializationError) when failed to serialize message. 37 | fn serialize(v: &Self::T) -> Result 38 | where 39 | Self: Sized, 40 | Self::T: Serialize, 41 | { 42 | let serialized = postcard::to_allocvec(v).map_err(|e| { 43 | Error::serialization_error(&format!("failed to serialize data by postcard: {:?}", e)) 44 | })?; 45 | Ok(Self::new(serialized)) 46 | } 47 | 48 | /// # Failures 49 | /// 50 | /// - [DeserializationError](serde_encrypt_core::error::ErrorKind::DeserializationError) when failed to deserialize decrypted message. 51 | fn deserialize<'de>(&'de self) -> Result 52 | where 53 | Self::T: Deserialize<'de>, 54 | { 55 | postcard::from_bytes(self.as_slice()).map_err(|e| { 56 | Error::deserialization_error(&format!( 57 | "error on postcard deserialization after decryption: {:?}", 58 | e 59 | )) 60 | }) 61 | } 62 | } 63 | 64 | #[cfg(test)] 65 | mod tests { 66 | use super::*; 67 | 68 | #[test] 69 | fn test_postcard_serializer() -> Result<(), Error> { 70 | #[derive(PartialEq, Debug, Serialize, Deserialize)] 71 | struct Message(i32); 72 | 73 | let msg = Message(42); 74 | 75 | let serialized_msg = PostcardSerializer::serialize(&msg)?; 76 | let deserialized_msg = serialized_msg.deserialize()?; 77 | 78 | assert_eq!(msg, deserialized_msg); 79 | 80 | Ok(()) 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /serde-encrypt/src/shared_key.rs: -------------------------------------------------------------------------------- 1 | //! serde-serializable shared key. 2 | 3 | use serde::{Deserialize, Serialize}; 4 | 5 | use crate::{AsSharedKey, random::RngSingletonImpl}; 6 | use crate::traits::SerdeEncryptPublicKey; 7 | 8 | /// 32-byte key shared among sender and receiver secretly. 9 | /// 10 | /// It is a good practice to use [SerdeEncryptPublicKey](crate::traits::SerdeEncryptPublicKey) 11 | /// to exchange this shared key. 12 | #[derive(Clone, Eq, PartialEq, Hash, Debug, Serialize, Deserialize)] 13 | pub struct SharedKey([u8; 32]); 14 | 15 | impl SharedKey { 16 | /// Build SharedKey from static `[u8; 32]` data at compile time. 17 | pub const fn new_const(data: [u8; 32]) -> Self { 18 | Self(data) 19 | } 20 | 21 | /// Build SharedKey from `[u8; 32]` data. 22 | pub fn new(data: [u8; 32]) -> Self { 23 | Self(data) 24 | } 25 | } 26 | 27 | impl AsSharedKey for SharedKey { 28 | type R = RngSingletonImpl; 29 | 30 | fn from_array(key: [u8; 32]) -> Self { 31 | Self(key) 32 | } 33 | 34 | fn as_slice(&self) -> &[u8] { 35 | &self.0 36 | } 37 | } 38 | 39 | cfg_if::cfg_if! { 40 | if #[cfg(feature = "std")] { 41 | use crate::serialize::impls::BincodeSerializer; 42 | impl SerdeEncryptPublicKey for SharedKey { 43 | type S = BincodeSerializer; 44 | } 45 | } else { 46 | use crate::serialize::impls::PostcardSerializer; 47 | impl SerdeEncryptPublicKey for SharedKey { 48 | type S = PostcardSerializer; 49 | } 50 | } 51 | } 52 | 53 | #[cfg(test)] 54 | mod test { 55 | use std::convert::TryInto; 56 | use super::*; 57 | 58 | #[test] 59 | fn build_sharedkey_from_array() { 60 | const STATIC_ARRAY: [u8; 32] = [1, 1, 4, 5, 1, 4, 61 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; 62 | 63 | let runtime_array: [u8; 32] = Vec::from(STATIC_ARRAY).try_into().unwrap(); 64 | 65 | // Building SharedKey directly from static_array only works in the same mod. 66 | const SHAREDKEY_CONST_INTERNAL: SharedKey = SharedKey(STATIC_ARRAY); 67 | 68 | // Test `const fn new`, which build SharedKey in compile time 69 | const SHARED_KEY_CONST: SharedKey = SharedKey::new_const(STATIC_ARRAY); 70 | 71 | // Test `fn new`, which build SharedKey in runtime. 72 | let shared_key = SharedKey::new(runtime_array); 73 | 74 | assert_eq!(shared_key, SHAREDKEY_CONST_INTERNAL); 75 | assert_eq!(SHARED_KEY_CONST, SHAREDKEY_CONST_INTERNAL); 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /serde-encrypt/src/traits.rs: -------------------------------------------------------------------------------- 1 | //! Traits to enable encrypted-serialization to your struct/enum. 2 | 3 | mod serde_encrypt_public_key; 4 | mod serde_encrypt_shared_key; 5 | mod serde_encrypt_shared_key_deterministic; 6 | 7 | pub use serde_encrypt_public_key::SerdeEncryptPublicKey; 8 | pub use serde_encrypt_shared_key::SerdeEncryptSharedKey; 9 | pub use serde_encrypt_shared_key_deterministic::SerdeEncryptSharedKeyDeterministic; 10 | -------------------------------------------------------------------------------- /serde-encrypt/src/traits/serde_encrypt_public_key.rs: -------------------------------------------------------------------------------- 1 | use crate::encrypt::plain_message_public_key::PlainMessagePublicKey; 2 | use crate::serialize::TypedSerialized; 3 | use crate::{EncryptedMessage, Error, ReceiverCombinedKey, SenderCombinedKey}; 4 | use serde::{de::DeserializeOwned, Deserialize, Serialize}; 5 | use serde_encrypt_core::encrypt::plain_message_public_key::PlainMessagePublicKeyCore; 6 | 7 | /// Public-key authenticated encryption for serde-serializable types. 8 | /// 9 | /// # Features 10 | /// 11 | /// - Safe and bidirectional public-key exchange. 12 | /// - Message authentication. 13 | /// - Different cipher-text for the same plain-text to avoid attacks such as statistical analysis of cipher-text. 14 | /// 15 | /// # Anti-features 16 | /// 17 | /// - Identity authentication of sender nor receiver. 18 | /// 19 | /// # Popular use cases 20 | /// 21 | /// - Shared-key exchange. 22 | /// - Encryption for relatively small and non-frequent messages (shared-key encryption is faster than public-key). 23 | /// 24 | /// # Examples 25 | /// 26 | /// ## Encrypting owned data 27 | /// 28 | /// See [this example](https://github.com/laysakura/serde-encrypt/blob/main/serde-encrypt/tests/example_serde_encrypt_public_key_owned_data.rs). 29 | /// 30 | /// ## Encrypting struct with reference fields 31 | /// 32 | /// See [this example](https://github.com/laysakura/serde-encrypt/blob/main/serde-encrypt/tests/example_serde_encrypt_public_key_struct_with_reference.rs). 33 | /// 34 | /// # Algorithm 35 | /// 36 | /// - Public-key exchange: X25519 37 | /// - Encryption: XChaCha20 38 | /// - Message authentication: Poly1305 MAC 39 | pub trait SerdeEncryptPublicKey { 40 | /// Serializer implementation 41 | type S: TypedSerialized; 42 | 43 | /// Serialize and encrypt. 44 | /// 45 | /// # Failures 46 | /// 47 | /// - [SerializationError](serde_encrypt_core::error::ErrorKind::SerializationError) when failed to serialize message. 48 | /// - [EncryptionError](serde_encrypt_core::error::ErrorKind::EncryptionError) when failed to encrypt serialized message. 49 | fn encrypt(&self, combined_key: &SenderCombinedKey) -> Result 50 | where 51 | Self: Serialize, 52 | { 53 | let serialized = Self::S::serialize(self)?; 54 | let plain_msg = PlainMessagePublicKey::new(serialized.into_vec()); 55 | plain_msg.encrypt(combined_key) 56 | } 57 | 58 | /// Decrypt and deserialize into DeserializeOwned type. 59 | /// 60 | /// # Failures 61 | /// 62 | /// - [DecryptionError](serde_encrypt_core::error::ErrorKind::DecryptionError) when failed to decrypt message. 63 | /// - [DeserializationError](serde_encrypt_core::error::ErrorKind::DeserializationError) when failed to deserialize decrypted message. 64 | fn decrypt_owned( 65 | encrypted_message: &EncryptedMessage, 66 | combined_key: &ReceiverCombinedKey, 67 | ) -> Result 68 | where 69 | Self: DeserializeOwned, 70 | { 71 | let serialized = Self::decrypt_ref(encrypted_message, combined_key)?; 72 | serialized.deserialize() 73 | } 74 | 75 | /// Just decrypts cipher-text. Returned data must be deserialized later. 76 | /// Types implementing `serde::Deserialize<'de>` (not `serde::de::DeserializeOwned`) should use 77 | /// this function to resolve lifetime. 78 | /// 79 | /// # Failures 80 | /// 81 | /// - [DecryptionError](serde_encrypt_core::error::ErrorKind::DecryptionError) when failed to decrypt message. 82 | fn decrypt_ref<'de>( 83 | encrypted_message: &EncryptedMessage, 84 | combined_key: &ReceiverCombinedKey, 85 | ) -> Result 86 | where 87 | Self: Deserialize<'de>, 88 | { 89 | let plain_msg = PlainMessagePublicKey::decrypt(encrypted_message, combined_key)?; 90 | Ok(Self::S::new(plain_msg.into_vec())) 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /serde-encrypt/src/traits/serde_encrypt_shared_key.rs: -------------------------------------------------------------------------------- 1 | use crate::{ 2 | encrypt::plain_message_shared_key::PlainMessageSharedKey, serialize::TypedSerialized, 3 | shared_key::SharedKey, EncryptedMessage, Error, 4 | }; 5 | use serde::{de::DeserializeOwned, Deserialize, Serialize}; 6 | use serde_encrypt_core::encrypt::plain_message_shared_key::PlainMessageSharedKeyCore; 7 | 8 | /// Shared-key authenticated encryption for serde-serializable types. 9 | /// 10 | /// # Features 11 | /// 12 | /// - Message authentication. 13 | /// - Different cipher-text for the same plain-text to avoid attacks such as statistical analysis of cipher-text. 14 | /// - Uses small (32-byte) key. 15 | /// 16 | /// # Anti-features 17 | /// 18 | /// - Identity authentication of sender nor receiver. 19 | /// 20 | /// # Popular use cases 21 | /// 22 | /// Good for both large and small message encryption / decryption. 23 | /// 24 | /// ## when sender and receiver does not hold shared key yet: 25 | /// 26 | /// First, message sender or receiver should generate [SharedKey](crate::shared_key::SharedKey). 27 | /// 28 | /// And then sender or receiver who generated the key should give it to another using safe communication. 29 | /// [SerdeEncryptPublicKey](crate::traits::SerdeEncryptPublicKey) is recommended for it. 30 | /// 31 | /// # Examples 32 | /// 33 | /// ## Encrypting owned data with already-shared key 34 | /// 35 | /// See [this example](https://github.com/laysakura/serde-encrypt/blob/main/serde-encrypt/tests/example_serde_encrypt_shared_key_owned_data.rs). 36 | /// 37 | /// ## Generate and exchange shared key and encrypt struct with reference fields 38 | /// 39 | /// See [this example](https://github.com/laysakura/serde-encrypt/blob/main/serde-encrypt/tests/example_serde_encrypt_shared_key_encryption_with_key_exchange.rs). 40 | /// 41 | /// # Algorithm 42 | /// 43 | /// - Encryption: XChaCha20 44 | /// - Message authentication: Poly1305 MAC 45 | pub trait SerdeEncryptSharedKey { 46 | /// Serializer implementation 47 | type S: TypedSerialized; 48 | 49 | /// Serialize and encrypt. 50 | /// 51 | /// # Failures 52 | /// 53 | /// - [SerializationError](serde_encrypt_core::error::ErrorKind::SerializationError) when failed to serialize message. 54 | /// - [EncryptionError](serde_encrypt_core::error::ErrorKind::EncryptionError) when failed to encrypt serialized message. 55 | fn encrypt(&self, shared_key: &SharedKey) -> Result 56 | where 57 | Self: Serialize, 58 | { 59 | let serialized = Self::S::serialize(self)?; 60 | let plain_msg = PlainMessageSharedKey::new(serialized.into_vec()); 61 | plain_msg.encrypt(shared_key) 62 | } 63 | 64 | /// Decrypt and deserialize into DeserializeOwned type. 65 | /// 66 | /// # Failures 67 | /// 68 | /// - [DecryptionError](serde_encrypt_core::error::ErrorKind::DecryptionError) when failed to decrypt message. 69 | /// - [DeserializationError](serde_encrypt_core::error::ErrorKind::DeserializationError) when failed to deserialize decrypted message. 70 | fn decrypt_owned( 71 | encrypted_message: &EncryptedMessage, 72 | shared_key: &SharedKey, 73 | ) -> Result 74 | where 75 | Self: DeserializeOwned, 76 | { 77 | let serialized = Self::decrypt_ref(encrypted_message, shared_key)?; 78 | serialized.deserialize() 79 | } 80 | 81 | /// Just decrypts cipher-text. Returned data must be deserialized later. 82 | /// Types implementing `serde::Deserialize<'de>` (not `serde::de::DeserializeOwned`) should use 83 | /// this function to resolve lifetime. 84 | /// 85 | /// # Failures 86 | /// 87 | /// - [DecryptionError](serde_encrypt_core::error::ErrorKind::DecryptionError) when failed to decrypt message. 88 | fn decrypt_ref<'de>( 89 | encrypted_message: &EncryptedMessage, 90 | shared_key: &SharedKey, 91 | ) -> Result 92 | where 93 | Self: Deserialize<'de>, 94 | { 95 | let plain_msg = PlainMessageSharedKey::decrypt(encrypted_message, shared_key)?; 96 | Ok(Self::S::new(plain_msg.into_vec())) 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /serde-encrypt/src/traits/serde_encrypt_shared_key_deterministic.rs: -------------------------------------------------------------------------------- 1 | use crate::{ 2 | encrypt::plain_message_shared_key_deterministic::PlainMessageSharedKeyDeterministic, 3 | serialize::TypedSerialized, shared_key::SharedKey, EncryptedMessage, Error, 4 | }; 5 | use serde::{de::DeserializeOwned, Deserialize, Serialize}; 6 | use serde_encrypt_core::encrypt::plain_message_shared_key::PlainMessageSharedKeyDeterministicCore; 7 | 8 | /// Shared-key authenticated **deterministic** encryption for serde-serializable types. 9 | /// 10 | /// # Features 11 | /// 12 | /// - Message authentication. 13 | /// - Same cipher-text for the same plain-text for eq-match in cipher-text. 14 | /// Note that this is more vulnerable than [SerdeEncryptSharedKey](crate::traits::SerdeEncryptSharedKey) 15 | /// because, for example, attackers can find repeated patterns in cipher-text and then guess 16 | /// repeated patterns in plain-text. 17 | /// - Uses small (32-byte) key. 18 | /// 19 | /// # Anti-features 20 | /// 21 | /// - Identity authentication of sender nor receiver. 22 | /// 23 | /// # Popular use cases 24 | /// 25 | /// Good for both large and small message encryption / decryption. 26 | /// 27 | /// Eq-match feature is used in encrypted indexes in RDBMS, for example. 28 | /// 29 | /// # Examples 30 | /// 31 | /// See: [SerdeEncryptSharedKey](crate::traits::SerdeEncryptSharedKey), who has nearly the same usage. 32 | /// 33 | /// # Algorithm 34 | /// 35 | /// - Encryption: XChaCha20 36 | /// - Message authentication: Poly1305 MAC 37 | /// - Fixed nonce. 38 | pub trait SerdeEncryptSharedKeyDeterministic { 39 | /// Serializer implementation 40 | type S: TypedSerialized; 41 | 42 | /// Serialize and encrypt. 43 | /// 44 | /// # Failures 45 | /// 46 | /// - [SerializationError](serde_encrypt_core::error::ErrorKind::SerializationError) when failed to serialize message. 47 | /// - [EncryptionError](serde_encrypt_core::error::ErrorKind::EncryptionError) when failed to encrypt serialized message. 48 | fn encrypt(&self, shared_key: &SharedKey) -> Result 49 | where 50 | Self: Serialize, 51 | { 52 | let serialized = Self::S::serialize(self)?; 53 | let plain_msg = PlainMessageSharedKeyDeterministic::new(serialized.into_vec()); 54 | plain_msg.encrypt(shared_key) 55 | } 56 | 57 | /// Decrypt and deserialize into DeserializeOwned type. 58 | /// 59 | /// # Failures 60 | /// 61 | /// - [DecryptionError](serde_encrypt_core::error::ErrorKind::DecryptionError) when failed to decrypt message. 62 | /// - [DeserializationError](serde_encrypt_core::error::ErrorKind::DeserializationError) when failed to deserialize decrypted message. 63 | fn decrypt_owned( 64 | encrypted_message: &EncryptedMessage, 65 | shared_key: &SharedKey, 66 | ) -> Result 67 | where 68 | Self: DeserializeOwned, 69 | { 70 | let serialized = Self::decrypt_ref(encrypted_message, shared_key)?; 71 | serialized.deserialize() 72 | } 73 | 74 | /// Just decrypts cipher-text. Returned data must be deserialized later. 75 | /// Types implementing `serde::Deserialize<'de>` (not `serde::de::DeserializeOwned`) should use 76 | /// this function to resolve lifetime. 77 | /// 78 | /// # Failures 79 | /// 80 | /// - [DecryptionError](serde_encrypt_core::error::ErrorKind::DecryptionError) when failed to decrypt message. 81 | fn decrypt_ref<'de>( 82 | encrypted_message: &EncryptedMessage, 83 | shared_key: &SharedKey, 84 | ) -> Result 85 | where 86 | Self: Deserialize<'de>, 87 | { 88 | let plain_msg = PlainMessageSharedKeyDeterministic::decrypt(encrypted_message, shared_key)?; 89 | Ok(Self::S::new(plain_msg.into_vec())) 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /serde-encrypt/tests/example_serde_encrypt_public_key_owned_data.rs: -------------------------------------------------------------------------------- 1 | //! Shows how to use SerdeEncryptPublicKey. 2 | 3 | use serde::{Deserialize, Serialize}; 4 | use serde_encrypt::{ 5 | key::key_pair::{ReceiverKeyPair, SenderKeyPair}, 6 | serialize::impls::BincodeSerializer, 7 | traits::SerdeEncryptPublicKey, 8 | EncryptedMessage, Error, ReceiverCombinedKey, ReceiverKeyPairCore, SenderCombinedKey, 9 | SenderKeyPairCore, 10 | }; 11 | 12 | #[derive(Debug, Serialize, Deserialize)] 13 | struct Message { 14 | content: String, 15 | sender: String, 16 | } 17 | 18 | impl SerdeEncryptPublicKey for Message { 19 | type S = BincodeSerializer; 20 | } 21 | 22 | fn alice_sends_secret_message(combined_key: &SenderCombinedKey) -> Result, Error> { 23 | let msg = Message { 24 | content: "I ❤️ you.".to_string(), 25 | sender: "Alice".to_string(), 26 | }; 27 | let encrypted_message = msg.encrypt(combined_key)?; 28 | Ok(encrypted_message.serialize()) 29 | } 30 | 31 | fn bob_receives_secret_message( 32 | encrypted_serialized: Vec, 33 | combined_key: &ReceiverCombinedKey, 34 | ) -> Result { 35 | let encrypted_message = EncryptedMessage::deserialize(encrypted_serialized)?; 36 | Message::decrypt_owned(&encrypted_message, combined_key) 37 | } 38 | 39 | #[test] 40 | fn test_serde_encrypt_public_key() -> Result<(), Error> { 41 | let alice_key_pair = SenderKeyPair::generate(); 42 | let bob_key_pair = ReceiverKeyPair::generate(); 43 | 44 | let alice_combined_key = 45 | SenderCombinedKey::new(alice_key_pair.private_key(), bob_key_pair.public_key()); 46 | let bob_combined_key = 47 | ReceiverCombinedKey::new(alice_key_pair.public_key(), bob_key_pair.private_key()); 48 | 49 | let secret_message = alice_sends_secret_message(&alice_combined_key)?; 50 | let revealed_message = bob_receives_secret_message(secret_message, &bob_combined_key)?; 51 | 52 | // Congrats 🎉👏 53 | assert_eq!(revealed_message.content, "I ❤️ you."); 54 | assert_eq!(revealed_message.sender, "Alice"); 55 | 56 | Ok(()) 57 | } 58 | -------------------------------------------------------------------------------- /serde-encrypt/tests/example_serde_encrypt_public_key_struct_with_reference.rs: -------------------------------------------------------------------------------- 1 | //! Shows how to use SerdeEncryptPublicKey for struct with reference fields. 2 | 3 | use serde::{Deserialize, Serialize}; 4 | use serde_encrypt::{ 5 | key::key_pair::{ReceiverKeyPair, SenderKeyPair}, 6 | serialize::{impls::BincodeSerializer, TypedSerialized}, 7 | traits::SerdeEncryptPublicKey, 8 | EncryptedMessage, Error, ReceiverCombinedKey, ReceiverKeyPairCore, SenderCombinedKey, 9 | SenderKeyPairCore, 10 | }; 11 | 12 | #[derive(Debug, Serialize, Deserialize)] 13 | struct Content<'a> { 14 | title: &'a str, 15 | sentence: &'a str, 16 | } 17 | 18 | #[derive(Debug, Serialize, Deserialize)] 19 | struct Message<'a> { 20 | content: Content<'a>, 21 | sender: &'a str, 22 | } 23 | 24 | impl<'a> SerdeEncryptPublicKey for Message<'a> { 25 | type S = BincodeSerializer; 26 | } 27 | 28 | fn alice_sends_secret_message(combined_key: &SenderCombinedKey) -> Result, Error> { 29 | let msg = Message { 30 | content: Content { 31 | title: "my heart", 32 | sentence: "I ❤️ you.", 33 | }, 34 | sender: "Alice", 35 | }; 36 | let encrypted_message = msg.encrypt(combined_key)?; 37 | Ok(encrypted_message.serialize()) 38 | } 39 | 40 | fn bob_reads_secret_message( 41 | encrypted_serialized: Vec, 42 | combined_key: &ReceiverCombinedKey, 43 | ) -> Result<(), Error> { 44 | let encrypted_message = EncryptedMessage::deserialize(encrypted_serialized)?; 45 | 46 | let decrypted = Message::decrypt_ref(&encrypted_message, combined_key)?; 47 | let revealed_message = decrypted.deserialize()?; 48 | 49 | // Note that you cannot return `revealed_message` from this function 50 | // because it has the same lifetime as local-scoped `x`. 51 | 52 | // Congrats 🎉👏 53 | assert_eq!(revealed_message.content.title, "my heart"); 54 | assert_eq!(revealed_message.content.sentence, "I ❤️ you."); 55 | assert_eq!(revealed_message.sender, "Alice"); 56 | 57 | Ok(()) 58 | } 59 | 60 | #[test] 61 | fn test_serde_encrypt_public_key() -> Result<(), Error> { 62 | let alice_key_pair = SenderKeyPair::generate(); 63 | let bob_key_pair = ReceiverKeyPair::generate(); 64 | 65 | let alice_combined_key = 66 | SenderCombinedKey::new(alice_key_pair.private_key(), bob_key_pair.public_key()); 67 | let bob_combined_key = 68 | ReceiverCombinedKey::new(alice_key_pair.public_key(), bob_key_pair.private_key()); 69 | 70 | let secret_message = alice_sends_secret_message(&alice_combined_key)?; 71 | bob_reads_secret_message(secret_message, &bob_combined_key) 72 | } 73 | -------------------------------------------------------------------------------- /serde-encrypt/tests/example_serde_encrypt_shared_key_encryption_with_key_exchange.rs: -------------------------------------------------------------------------------- 1 | //! Shows typical use case of "Shared-key exchange by public-key encryption": 2 | //! 3 | //! 1. Bob (message receiver) generates shared key. 4 | //! 2. Bob encrypts the shared key using one-time public-key encryption. 5 | //! 3. Bob serializes the encrypted key into binary and gives it to Bob (message sender). 6 | //! 4. Alice decrypts the binary into the shared key. 7 | //! 5. Then Alice encrypts her secret message using the shared key and sends it to Bob. 8 | //! 6. Bob gets the secret and decrypts it using the shared key. 9 | //! 10 | //! Bob generates the shared key in this example, however, it is also OK for Alice to generate the key. 11 | //! (Both sides can start key exchange.) 12 | //! 13 | //! Also, note that Alice (or Bob) can continue to send secret messages to the other using the secret key. 14 | //! In other words, public-key encryption is used only at the start of communication. 15 | //! This achieves good performance compared to repeated public-key encryption. 16 | 17 | use serde::{Deserialize, Serialize}; 18 | use serde_encrypt::{ 19 | key::key_pair::{ReceiverKeyPair, SenderKeyPair}, 20 | serialize::{impls::BincodeSerializer, TypedSerialized}, 21 | shared_key::SharedKey, 22 | traits::{SerdeEncryptPublicKey, SerdeEncryptSharedKey}, 23 | AsSharedKey, EncryptedMessage, Error, ReceiverCombinedKey, ReceiverKeyPairCore, 24 | SenderCombinedKey, SenderKeyPairCore, 25 | }; 26 | 27 | impl<'a> SerdeEncryptSharedKey for Message<'a> { 28 | type S = BincodeSerializer; 29 | } 30 | 31 | fn bob_generates_shared_key() -> SharedKey { 32 | SharedKey::generate() 33 | } 34 | 35 | fn bob_sends_shared_key( 36 | shared_key: &SharedKey, 37 | combined_key: &SenderCombinedKey, 38 | ) -> Result, Error> { 39 | let encrypted_shared_key = shared_key.encrypt(combined_key)?; 40 | Ok(encrypted_shared_key.serialize()) 41 | } 42 | 43 | fn alice_receives_shared_key( 44 | encrypted_serialized_shared_key: Vec, 45 | combined_key: &ReceiverCombinedKey, 46 | ) -> Result { 47 | let encrypted_shared_key = EncryptedMessage::deserialize(encrypted_serialized_shared_key)?; 48 | SharedKey::decrypt_owned(&encrypted_shared_key, combined_key) 49 | } 50 | 51 | #[derive(Debug, Serialize, Deserialize)] 52 | struct Content<'a> { 53 | title: &'a str, 54 | sentence: &'a str, 55 | } 56 | 57 | #[derive(Debug, Serialize, Deserialize)] 58 | struct Message<'a> { 59 | content: Content<'a>, 60 | sender: &'a str, 61 | } 62 | 63 | fn alice_sends_secret_message(shared_key: &SharedKey) -> Result, Error> { 64 | let msg = Message { 65 | content: Content { 66 | title: "my heart", 67 | sentence: "I ❤️ you.", 68 | }, 69 | sender: "Alice", 70 | }; 71 | let encrypted_message = msg.encrypt(shared_key)?; 72 | Ok(encrypted_message.serialize()) 73 | } 74 | 75 | fn bob_reads_secret_message( 76 | encrypted_serialized: Vec, 77 | shared_key: &SharedKey, 78 | ) -> Result<(), Error> { 79 | let encrypted_message = EncryptedMessage::deserialize(encrypted_serialized)?; 80 | 81 | let decrypted = Message::decrypt_ref(&encrypted_message, shared_key)?; 82 | let revealed_message = decrypted.deserialize()?; 83 | 84 | // Note that you cannot return `revealed_message` from this function 85 | // because it has the same lifetime as local-scoped `x`. 86 | 87 | // Congrats 🎉👏 88 | assert_eq!(revealed_message.content.title, "my heart"); 89 | assert_eq!(revealed_message.content.sentence, "I ❤️ you."); 90 | assert_eq!(revealed_message.sender, "Alice"); 91 | 92 | Ok(()) 93 | } 94 | 95 | #[test] 96 | fn test_serde_encrypt_public_key() -> Result<(), Error> { 97 | // public/private key generation to start key exchange 98 | let alice_key_pair = ReceiverKeyPair::generate(); 99 | let bob_key_pair = SenderKeyPair::generate(); 100 | 101 | let alice_combined_key = 102 | ReceiverCombinedKey::new(bob_key_pair.public_key(), alice_key_pair.private_key()); 103 | let bob_combined_key = 104 | SenderCombinedKey::new(bob_key_pair.private_key(), alice_key_pair.public_key()); 105 | 106 | // key exchange 107 | let bob_shared_key = bob_generates_shared_key(); 108 | let encrypted_shared_key = bob_sends_shared_key(&bob_shared_key, &bob_combined_key)?; 109 | let alice_shared_key = alice_receives_shared_key(encrypted_shared_key, &alice_combined_key)?; 110 | assert_eq!(alice_shared_key, bob_shared_key); 111 | 112 | // message exchange using shared key 113 | let secret_message = alice_sends_secret_message(&alice_shared_key)?; 114 | bob_reads_secret_message(secret_message, &bob_shared_key) 115 | } 116 | -------------------------------------------------------------------------------- /serde-encrypt/tests/example_serde_encrypt_shared_key_owned_data.rs: -------------------------------------------------------------------------------- 1 | //! Shows how to use SerdeEncryptSharedKey. 2 | 3 | use serde::{Deserialize, Serialize}; 4 | use serde_encrypt::{ 5 | serialize::impls::BincodeSerializer, shared_key::SharedKey, traits::SerdeEncryptSharedKey, 6 | AsSharedKey, EncryptedMessage, Error, 7 | }; 8 | 9 | #[derive(Debug, Serialize, Deserialize)] 10 | struct Message { 11 | content: String, 12 | sender: String, 13 | } 14 | 15 | impl SerdeEncryptSharedKey for Message { 16 | type S = BincodeSerializer; 17 | } 18 | 19 | fn alice_sends_secret_message(shared_key: &SharedKey) -> Result, Error> { 20 | let msg = Message { 21 | content: "I ❤️ you.".to_string(), 22 | sender: "Alice".to_string(), 23 | }; 24 | let encrypted_message = msg.encrypt(shared_key)?; 25 | Ok(encrypted_message.serialize()) 26 | } 27 | 28 | fn bob_receives_secret_message( 29 | encrypted_serialized: Vec, 30 | shared_key: &SharedKey, 31 | ) -> Result { 32 | let encrypted_message = EncryptedMessage::deserialize(encrypted_serialized)?; 33 | Message::decrypt_owned(&encrypted_message, shared_key) 34 | } 35 | 36 | #[test] 37 | fn test_serde_encrypt_shared_key() -> Result<(), Error> { 38 | // Both Alice and Bob have this key secretly. 39 | const SHARED_KEY: [u8; 32] = [42; 32]; 40 | let shared_key = SharedKey::from_array(SHARED_KEY); 41 | 42 | let secret_message = alice_sends_secret_message(&shared_key)?; 43 | let revealed_message = bob_receives_secret_message(secret_message, &shared_key)?; 44 | 45 | // Congrats 🎉👏 46 | assert_eq!(revealed_message.content, "I ❤️ you."); 47 | assert_eq!(revealed_message.sender, "Alice"); 48 | 49 | Ok(()) 50 | } 51 | -------------------------------------------------------------------------------- /serde-encrypt/tests/feat_different_cipher_from_same_plain.rs: -------------------------------------------------------------------------------- 1 | //! Test if: 2 | //! 3 | //! - SerdeEncryptPublicKey 4 | //! - SerdeEncryptSharedKey 5 | //! 6 | //! emit different cipher-text for the same plain-text to avoid attacks such as statistical analysis of cipher-text. 7 | 8 | mod test_util; 9 | 10 | use serde::{Deserialize, Serialize}; 11 | use serde_encrypt::serialize::impls::BincodeSerializer; 12 | use serde_encrypt::shared_key::SharedKey; 13 | use serde_encrypt::traits::SerdeEncryptPublicKey; 14 | use serde_encrypt::traits::SerdeEncryptSharedKey; 15 | use serde_encrypt::AsSharedKey; 16 | use test_util::serde_encrypt_public_key::*; 17 | use test_util::*; 18 | 19 | #[derive(PartialEq, Debug, Serialize, Deserialize)] 20 | struct Message(String); 21 | 22 | #[test] 23 | fn test_serde_encrypt_public_key_in_a_process() { 24 | combined_keys_gen!(sender_combined_key, _x); 25 | 26 | impl SerdeEncryptPublicKey for Message { 27 | type S = BincodeSerializer; 28 | } 29 | assert_no_duplicate( 30 | || { 31 | let msg = Message("same message".into()); 32 | let encrypted = SerdeEncryptPublicKey::encrypt(&msg, &sender_combined_key).unwrap(); 33 | encrypted.serialize() 34 | }, 35 | 100, 36 | ); 37 | } 38 | 39 | #[test] 40 | fn test_serde_encrypt_shared_key_in_a_process() { 41 | let shared_key = SharedKey::generate(); 42 | 43 | impl SerdeEncryptSharedKey for Message { 44 | type S = BincodeSerializer; 45 | } 46 | assert_no_duplicate( 47 | || { 48 | let msg = Message("same message".into()); 49 | let encrypted = SerdeEncryptSharedKey::encrypt(&msg, &shared_key).unwrap(); 50 | encrypted.serialize() 51 | }, 52 | 100, 53 | ); 54 | } 55 | 56 | // TODO Test "separate processes produce different cipher-text". 57 | -------------------------------------------------------------------------------- /serde-encrypt/tests/feat_large_message.rs: -------------------------------------------------------------------------------- 1 | //! Test if: 2 | //! 3 | //! - SerdeEncryptPublicKey 4 | //! - SerdeEncryptSharedKey 5 | //! 6 | //! can encrypt/decrypt large message. 7 | 8 | mod test_util; 9 | 10 | use serde::{Deserialize, Serialize}; 11 | use serde_encrypt::serialize::impls::BincodeSerializer; 12 | use serde_encrypt::shared_key::SharedKey; 13 | use serde_encrypt::traits::{SerdeEncryptPublicKey, SerdeEncryptSharedKey}; 14 | use serde_encrypt::AsSharedKey; 15 | use test_util::*; 16 | 17 | const SIZE: usize = 1_000_000; 18 | 19 | #[derive(PartialEq, Debug, Serialize, Deserialize)] 20 | struct Message(Vec); 21 | 22 | #[test] 23 | fn test_serde_encrypt_public_key_large_message() { 24 | combined_keys_gen!(sender_combined_key, receiver_combined_key); 25 | 26 | impl SerdeEncryptPublicKey for Message { 27 | type S = BincodeSerializer; 28 | } 29 | 30 | let msg = Message(vec![42u8; SIZE]); 31 | public_key_enc_dec_assert_eq(&msg, &sender_combined_key, &receiver_combined_key).unwrap(); 32 | } 33 | 34 | #[test] 35 | fn test_serde_encrypt_shared_key_large_message() { 36 | let shared_key = SharedKey::generate(); 37 | 38 | impl SerdeEncryptSharedKey for Message { 39 | type S = BincodeSerializer; 40 | } 41 | 42 | let msg = Message(vec![42u8; SIZE]); 43 | shared_key_enc_dec_assert_eq(&msg, &shared_key).unwrap(); 44 | } 45 | -------------------------------------------------------------------------------- /serde-encrypt/tests/feat_nostd.rs: -------------------------------------------------------------------------------- 1 | //! Runtime check for no_std mode. 2 | 3 | #![no_std] 4 | 5 | extern crate alloc; 6 | 7 | mod test_util; 8 | 9 | use alloc::{string::String, vec, vec::Vec}; 10 | use serde::{Deserialize, Serialize}; 11 | use serde_encrypt::{ 12 | serialize::impls::PostcardSerializer, 13 | shared_key::SharedKey, 14 | traits::{SerdeEncryptPublicKey, SerdeEncryptSharedKey}, 15 | AsSharedKey, Error, 16 | }; 17 | use test_util::{serde_encrypt_public_key::*, serde_encrypt_shared_key::*}; 18 | 19 | #[derive(PartialEq, Debug, Serialize, Deserialize)] 20 | struct Pagination { 21 | limit: u64, 22 | offset: u64, 23 | total: u64, 24 | } 25 | 26 | #[derive(PartialEq, Debug, Serialize, Deserialize)] 27 | struct User { 28 | id: String, 29 | username: String, 30 | } 31 | 32 | #[derive(PartialEq, Debug, Serialize, Deserialize)] 33 | struct Users { 34 | users: Vec, 35 | 36 | // #[serde(flatten)]: https://github.com/jamesmunns/postcard/issues/29 37 | pagination: Pagination, 38 | } 39 | 40 | #[test] 41 | fn test_serde_encrypt_public_key_nostd() -> Result<(), Error> { 42 | combined_keys_gen!(sender_combined_key, receiver_combined_key); 43 | 44 | impl SerdeEncryptPublicKey for Users { 45 | type S = PostcardSerializer; 46 | } 47 | 48 | let msg = Users { 49 | users: vec![ 50 | User { 51 | id: "1".into(), 52 | username: "John".into(), 53 | }, 54 | User { 55 | id: "2".into(), 56 | username: "Jane".into(), 57 | }, 58 | ], 59 | pagination: Pagination { 60 | limit: 100, 61 | offset: 200, 62 | total: 256, 63 | }, 64 | }; 65 | public_key_enc_dec_assert_eq(&msg, &sender_combined_key, &receiver_combined_key)?; 66 | Ok(()) 67 | } 68 | 69 | #[test] 70 | fn test_serde_encrypt_shared_key_nostd() -> Result<(), Error> { 71 | let shared_key = SharedKey::generate(); 72 | 73 | impl SerdeEncryptSharedKey for Users { 74 | type S = PostcardSerializer; 75 | } 76 | 77 | let msg = Users { 78 | users: vec![ 79 | User { 80 | id: "1".into(), 81 | username: "John".into(), 82 | }, 83 | User { 84 | id: "2".into(), 85 | username: "Jane".into(), 86 | }, 87 | ], 88 | pagination: Pagination { 89 | limit: 100, 90 | offset: 200, 91 | total: 256, 92 | }, 93 | }; 94 | shared_key_enc_dec_assert_eq(&msg, &shared_key)?; 95 | Ok(()) 96 | } 97 | -------------------------------------------------------------------------------- /serde-encrypt/tests/feat_same_cipher_from_same_plain.rs: -------------------------------------------------------------------------------- 1 | //! Test if: 2 | //! 3 | //! - SerdeEncryptSharedKeyDeterministic 4 | //! 5 | //! emit the same cipher-text for the same plain-text for eq-match in cipher-text. 6 | 7 | mod test_util; 8 | 9 | use serde::{Deserialize, Serialize}; 10 | use serde_encrypt::serialize::impls::BincodeSerializer; 11 | use serde_encrypt::shared_key::SharedKey; 12 | use serde_encrypt::traits::SerdeEncryptSharedKeyDeterministic; 13 | use serde_encrypt::AsSharedKey; 14 | 15 | #[derive(PartialEq, Debug, Serialize, Deserialize)] 16 | struct Message(String); 17 | 18 | #[test] 19 | fn test_serde_encrypt_shared_key_deterministic() { 20 | let shared_key = SharedKey::generate(); 21 | 22 | impl SerdeEncryptSharedKeyDeterministic for Message { 23 | type S = BincodeSerializer; 24 | } 25 | 26 | let msg1 = Message("same message".into()); 27 | let msg2 = Message("same message".into()); 28 | let msg3 = Message("same? message".into()); 29 | 30 | let encrypted1 = Message::encrypt(&msg1, &shared_key).unwrap(); 31 | let encrypted2 = Message::encrypt(&msg2, &shared_key).unwrap(); 32 | let encrypted3 = Message::encrypt(&msg3, &shared_key).unwrap(); 33 | 34 | assert_eq!(encrypted1, encrypted2); 35 | assert_ne!(encrypted2, encrypted3); 36 | } 37 | -------------------------------------------------------------------------------- /serde-encrypt/tests/feat_serde_types.rs: -------------------------------------------------------------------------------- 1 | //! Encrypt/Decrypt various serde types. 2 | //! 3 | //! Some types are from [Examples in Serde document](https://serde.rs/examples.html). 4 | 5 | mod test_util; 6 | 7 | use std::{fmt, marker::PhantomData, str::FromStr}; 8 | 9 | use pretty_assertions::assert_eq; 10 | use serde::{ 11 | de::{self, MapAccess, Visitor}, 12 | Deserialize, Deserializer, Serialize, 13 | }; 14 | use serde_encrypt::{ 15 | serialize::{ 16 | impls::{BincodeSerializer, CborSerializer}, 17 | TypedSerialized, 18 | }, 19 | shared_key::SharedKey, 20 | traits::{SerdeEncryptPublicKey, SerdeEncryptSharedKey}, 21 | AsSharedKey, Error, ErrorKind, 22 | }; 23 | use test_util::*; 24 | use void::Void; 25 | 26 | #[test] 27 | fn test_unit_struct() -> Result<(), Error> { 28 | combined_keys_gen!(sender_combined_key, receiver_combined_key); 29 | let shared_key = SharedKey::generate(); 30 | 31 | #[derive(PartialEq, Debug, Serialize, Deserialize)] 32 | struct Unit; 33 | impl SerdeEncryptPublicKey for Unit { 34 | type S = BincodeSerializer; 35 | } 36 | impl SerdeEncryptSharedKey for Unit { 37 | type S = BincodeSerializer; 38 | } 39 | 40 | let msg = Unit; 41 | public_key_enc_dec_assert_eq(&msg, &sender_combined_key, &receiver_combined_key)?; 42 | shared_key_enc_dec_assert_eq(&msg, &shared_key)?; 43 | Ok(()) 44 | } 45 | 46 | #[test] 47 | fn test_primitive_type_fixed_len() -> Result<(), Error> { 48 | combined_keys_gen!(sender_combined_key, receiver_combined_key); 49 | let shared_key = SharedKey::generate(); 50 | 51 | #[derive(PartialEq, Debug, Serialize, Deserialize)] 52 | struct I32(i32); 53 | impl SerdeEncryptPublicKey for I32 { 54 | type S = BincodeSerializer; 55 | } 56 | impl SerdeEncryptSharedKey for I32 { 57 | type S = BincodeSerializer; 58 | } 59 | 60 | let msg = I32(42); 61 | public_key_enc_dec_assert_eq(&msg, &sender_combined_key, &receiver_combined_key)?; 62 | shared_key_enc_dec_assert_eq(&msg, &shared_key)?; 63 | Ok(()) 64 | } 65 | 66 | #[test] 67 | fn test_primitive_type_unbound_len() -> Result<(), Error> { 68 | combined_keys_gen!(sender_combined_key, receiver_combined_key); 69 | let shared_key = SharedKey::generate(); 70 | 71 | #[derive(PartialEq, Debug, Serialize, Deserialize)] 72 | struct MyString(String); 73 | impl SerdeEncryptPublicKey for MyString { 74 | type S = BincodeSerializer; 75 | } 76 | impl SerdeEncryptSharedKey for MyString { 77 | type S = BincodeSerializer; 78 | } 79 | 80 | let msg = MyString("MyString".to_string()); 81 | public_key_enc_dec_assert_eq(&msg, &sender_combined_key, &receiver_combined_key)?; 82 | shared_key_enc_dec_assert_eq(&msg, &shared_key)?; 83 | Ok(()) 84 | } 85 | 86 | #[test] 87 | fn test_tuple_struct() -> Result<(), Error> { 88 | combined_keys_gen!(sender_combined_key, receiver_combined_key); 89 | let shared_key = SharedKey::generate(); 90 | 91 | #[derive(PartialEq, Debug, Serialize, Deserialize)] 92 | struct Tuple(i16, i32, i64); 93 | impl SerdeEncryptPublicKey for Tuple { 94 | type S = BincodeSerializer; 95 | } 96 | impl SerdeEncryptSharedKey for Tuple { 97 | type S = BincodeSerializer; 98 | } 99 | 100 | let msg = Tuple(42, 4242, 424242); 101 | public_key_enc_dec_assert_eq(&msg, &sender_combined_key, &receiver_combined_key)?; 102 | shared_key_enc_dec_assert_eq(&msg, &shared_key)?; 103 | Ok(()) 104 | } 105 | 106 | #[test] 107 | fn test_enum() -> Result<(), Error> { 108 | combined_keys_gen!(sender_combined_key, receiver_combined_key); 109 | let shared_key = SharedKey::generate(); 110 | 111 | #[derive(PartialEq, Debug, Serialize, Deserialize)] 112 | struct Params; 113 | 114 | #[derive(PartialEq, Debug, Serialize, Deserialize)] 115 | struct Value; 116 | 117 | #[derive(PartialEq, Debug, Serialize, Deserialize)] 118 | enum Message { 119 | Request { 120 | id: String, 121 | method: String, 122 | params: Params, 123 | }, 124 | Response { 125 | id: String, 126 | result: Value, 127 | }, 128 | } 129 | impl SerdeEncryptPublicKey for Message { 130 | type S = BincodeSerializer; 131 | } 132 | impl SerdeEncryptSharedKey for Message { 133 | type S = BincodeSerializer; 134 | } 135 | 136 | let msg_request = Message::Request { 137 | id: "1".into(), 138 | method: "get_foo".into(), 139 | params: Params, 140 | }; 141 | public_key_enc_dec_assert_eq(&msg_request, &sender_combined_key, &receiver_combined_key)?; 142 | shared_key_enc_dec_assert_eq(&msg_request, &shared_key)?; 143 | 144 | let msg_response = Message::Response { 145 | id: "1".into(), 146 | result: Value, 147 | }; 148 | public_key_enc_dec_assert_eq(&msg_response, &sender_combined_key, &receiver_combined_key)?; 149 | shared_key_enc_dec_assert_eq(&msg_response, &shared_key)?; 150 | Ok(()) 151 | } 152 | 153 | #[test] 154 | fn test_enum_tagged() -> Result<(), Error> { 155 | combined_keys_gen!(sender_combined_key, receiver_combined_key); 156 | let shared_key = SharedKey::generate(); 157 | 158 | #[derive(PartialEq, Debug, Serialize, Deserialize)] 159 | struct Params; 160 | 161 | #[derive(PartialEq, Debug, Serialize, Deserialize)] 162 | struct Value; 163 | 164 | #[derive(PartialEq, Debug, Serialize, Deserialize)] 165 | #[serde(tag = "type")] 166 | enum Message { 167 | Request { 168 | id: String, 169 | method: String, 170 | params: Params, 171 | }, 172 | Response { 173 | id: String, 174 | result: Value, 175 | }, 176 | } 177 | impl SerdeEncryptPublicKey for Message { 178 | // [NG] BincodeSerializer for tagged enum: https://github.com/bincode-org/bincode/issues/272 179 | // [NG] PostcardSerializer emits `WontImplement` err: https://github.com/jamesmunns/postcard/blob/96db753865b195948fcbd9c69815028adee9579c/src/de/deserializer.rs#L126 180 | type S = CborSerializer; 181 | } 182 | impl SerdeEncryptSharedKey for Message { 183 | type S = CborSerializer; 184 | } 185 | 186 | let msg_request = Message::Request { 187 | id: "1".into(), 188 | method: "get_foo".into(), 189 | params: Params, 190 | }; 191 | public_key_enc_dec_assert_eq(&msg_request, &sender_combined_key, &receiver_combined_key)?; 192 | shared_key_enc_dec_assert_eq(&msg_request, &shared_key)?; 193 | 194 | let msg_response = Message::Response { 195 | id: "1".into(), 196 | result: Value, 197 | }; 198 | public_key_enc_dec_assert_eq(&msg_response, &sender_combined_key, &receiver_combined_key)?; 199 | shared_key_enc_dec_assert_eq(&msg_response, &shared_key)?; 200 | Ok(()) 201 | } 202 | 203 | #[test] 204 | fn test_enum_adjacently_tagged() -> Result<(), Error> { 205 | combined_keys_gen!(sender_combined_key, receiver_combined_key); 206 | let shared_key = SharedKey::generate(); 207 | 208 | #[derive(PartialEq, Debug, Serialize, Deserialize)] 209 | struct Params; 210 | 211 | #[derive(PartialEq, Debug, Serialize, Deserialize)] 212 | struct Value; 213 | 214 | #[derive(PartialEq, Debug, Serialize, Deserialize)] 215 | #[serde(tag = "t", content = "c")] 216 | enum Message { 217 | Request { 218 | id: String, 219 | method: String, 220 | params: Params, 221 | }, 222 | Response { 223 | id: String, 224 | result: Value, 225 | }, 226 | } 227 | impl SerdeEncryptPublicKey for Message { 228 | // [NG] BincodeSerializer for tagged enum: https://github.com/bincode-org/bincode/issues/272 229 | // [NG] PostcardSerializer emits `WontImplement` err: https://github.com/jamesmunns/postcard/blob/96db753865b195948fcbd9c69815028adee9579c/src/de/deserializer.rs#L126 230 | type S = CborSerializer; 231 | } 232 | impl SerdeEncryptSharedKey for Message { 233 | type S = CborSerializer; 234 | } 235 | 236 | let msg_request = Message::Request { 237 | id: "1".into(), 238 | method: "get_foo".into(), 239 | params: Params, 240 | }; 241 | public_key_enc_dec_assert_eq(&msg_request, &sender_combined_key, &receiver_combined_key)?; 242 | shared_key_enc_dec_assert_eq(&msg_request, &shared_key)?; 243 | 244 | let msg_response = Message::Response { 245 | id: "1".into(), 246 | result: Value, 247 | }; 248 | public_key_enc_dec_assert_eq(&msg_response, &sender_combined_key, &receiver_combined_key)?; 249 | shared_key_enc_dec_assert_eq(&msg_response, &shared_key)?; 250 | Ok(()) 251 | } 252 | 253 | #[test] 254 | fn test_enum_untagged() -> Result<(), Error> { 255 | combined_keys_gen!(sender_combined_key, receiver_combined_key); 256 | let shared_key = SharedKey::generate(); 257 | 258 | #[derive(PartialEq, Debug, Serialize, Deserialize)] 259 | struct Params; 260 | 261 | #[derive(PartialEq, Debug, Serialize, Deserialize)] 262 | struct Value; 263 | 264 | #[derive(PartialEq, Debug, Serialize, Deserialize)] 265 | #[serde(untagged)] 266 | enum Message { 267 | Request { 268 | id: String, 269 | method: String, 270 | params: Params, 271 | }, 272 | Response { 273 | id: String, 274 | result: Value, 275 | }, 276 | } 277 | impl SerdeEncryptPublicKey for Message { 278 | // [NG] BincodeSerializer for tagged enum: https://github.com/bincode-org/bincode/issues/272 279 | // [NG] PostcardSerializer emits `WontImplement` err: https://github.com/jamesmunns/postcard/blob/96db753865b195948fcbd9c69815028adee9579c/src/de/deserializer.rs#L126 280 | type S = CborSerializer; 281 | } 282 | impl SerdeEncryptSharedKey for Message { 283 | type S = CborSerializer; 284 | } 285 | 286 | let msg_request = Message::Request { 287 | id: "1".into(), 288 | method: "get_foo".into(), 289 | params: Params, 290 | }; 291 | public_key_enc_dec_assert_eq(&msg_request, &sender_combined_key, &receiver_combined_key)?; 292 | shared_key_enc_dec_assert_eq(&msg_request, &shared_key)?; 293 | 294 | let msg_response = Message::Response { 295 | id: "1".into(), 296 | result: Value, 297 | }; 298 | public_key_enc_dec_assert_eq(&msg_response, &sender_combined_key, &receiver_combined_key)?; 299 | shared_key_enc_dec_assert_eq(&msg_response, &shared_key)?; 300 | Ok(()) 301 | } 302 | 303 | #[test] 304 | fn test_skip_deserializing() -> Result<(), Error> { 305 | combined_keys_gen!(sender_combined_key, receiver_combined_key); 306 | let shared_key = SharedKey::generate(); 307 | 308 | #[derive(PartialEq, Debug, Serialize, Deserialize)] 309 | struct Struct { 310 | a: i32, 311 | b: i32, 312 | #[serde(skip_deserializing)] 313 | c: i32, 314 | } 315 | impl SerdeEncryptPublicKey for Struct { 316 | type S = BincodeSerializer; 317 | } 318 | impl SerdeEncryptSharedKey for Struct { 319 | type S = BincodeSerializer; 320 | } 321 | 322 | let msg = Struct { 323 | a: 42, 324 | b: 42, 325 | c: 42, 326 | }; 327 | 328 | let receive_msg = public_key_enc_dec(&msg, &sender_combined_key, &receiver_combined_key)?; 329 | assert_eq!(msg.a, receive_msg.a); 330 | assert_eq!(msg.b, receive_msg.b); 331 | assert_eq!( 332 | receive_msg.c, 0, 333 | "deserialization skipped and got default value" 334 | ); 335 | 336 | let receive_msg = shared_key_enc_dec(&msg, &shared_key)?; 337 | assert_eq!(msg.a, receive_msg.a); 338 | assert_eq!(msg.b, receive_msg.b); 339 | assert_eq!( 340 | receive_msg.c, 0, 341 | "deserialization skipped and got default value" 342 | ); 343 | 344 | Ok(()) 345 | } 346 | 347 | #[test] 348 | fn test_skip_deserializing_and_custom_default() -> Result<(), Error> { 349 | combined_keys_gen!(sender_combined_key, receiver_combined_key); 350 | let shared_key = SharedKey::generate(); 351 | 352 | #[derive(PartialEq, Debug, Serialize, Deserialize)] 353 | struct Request { 354 | #[serde(skip_deserializing)] 355 | #[serde(default = "default_resource")] 356 | resource: String, 357 | 358 | #[serde(skip_deserializing)] 359 | #[serde(default)] 360 | timeout: Timeout, 361 | 362 | #[serde(skip_deserializing)] 363 | #[serde(default = "Priority::lowest")] 364 | priority: Priority, 365 | } 366 | 367 | fn default_resource() -> String { 368 | "/".to_string() 369 | } 370 | impl SerdeEncryptPublicKey for Request { 371 | type S = BincodeSerializer; 372 | } 373 | impl SerdeEncryptSharedKey for Request { 374 | type S = BincodeSerializer; 375 | } 376 | 377 | /// Timeout in seconds. 378 | #[derive(PartialEq, Debug, Serialize, Deserialize)] 379 | struct Timeout(u32); 380 | impl Default for Timeout { 381 | fn default() -> Self { 382 | Timeout(30) 383 | } 384 | } 385 | 386 | #[derive(PartialEq, Debug, Serialize, Deserialize)] 387 | enum Priority { 388 | ExtraHigh, 389 | High, 390 | Normal, 391 | Low, 392 | ExtraLow, 393 | } 394 | impl Priority { 395 | fn lowest() -> Self { 396 | Priority::ExtraLow 397 | } 398 | } 399 | 400 | let msg = Request { 401 | resource: "ignored".into(), 402 | timeout: Timeout(12345), 403 | priority: Priority::ExtraHigh, 404 | }; 405 | 406 | let receive_msg = public_key_enc_dec(&msg, &sender_combined_key, &receiver_combined_key)?; 407 | // all fields from sender are skipped deserialization 408 | assert_eq!(receive_msg.resource, default_resource()); 409 | assert_eq!(receive_msg.timeout, Timeout::default()); 410 | assert_eq!(receive_msg.priority, Priority::lowest()); 411 | 412 | let receive_msg = shared_key_enc_dec(&msg, &shared_key)?; 413 | // all fields from sender are skipped deserialization 414 | assert_eq!(receive_msg.resource, default_resource()); 415 | assert_eq!(receive_msg.timeout, Timeout::default()); 416 | assert_eq!(receive_msg.priority, Priority::lowest()); 417 | 418 | Ok(()) 419 | } 420 | 421 | #[test] 422 | fn test_flatten() -> Result<(), Error> { 423 | combined_keys_gen!(sender_combined_key, receiver_combined_key); 424 | let shared_key = SharedKey::generate(); 425 | 426 | #[derive(PartialEq, Debug, Serialize, Deserialize)] 427 | struct Pagination { 428 | limit: u64, 429 | offset: u64, 430 | total: u64, 431 | } 432 | 433 | #[derive(PartialEq, Debug, Serialize, Deserialize)] 434 | struct User { 435 | id: String, 436 | username: String, 437 | } 438 | 439 | #[derive(PartialEq, Debug, Serialize, Deserialize)] 440 | struct Users { 441 | users: Vec, 442 | 443 | #[serde(flatten)] 444 | pagination: Pagination, 445 | } 446 | impl SerdeEncryptPublicKey for Users { 447 | // [NG] BincodeSerializer for #[flatten]: https://github.com/bincode-org/bincode/issues/245 448 | // [NG] PostcardSerializer for #[flatten]: https://github.com/jamesmunns/postcard/issues/29 449 | type S = CborSerializer; 450 | } 451 | impl SerdeEncryptSharedKey for Users { 452 | type S = CborSerializer; 453 | } 454 | 455 | let msg = Users { 456 | users: vec![ 457 | User { 458 | id: "1".into(), 459 | username: "John".into(), 460 | }, 461 | User { 462 | id: "2".into(), 463 | username: "Jane".into(), 464 | }, 465 | ], 466 | pagination: Pagination { 467 | limit: 100, 468 | offset: 200, 469 | total: 256, 470 | }, 471 | }; 472 | public_key_enc_dec_assert_eq(&msg, &sender_combined_key, &receiver_combined_key)?; 473 | shared_key_enc_dec_assert_eq(&msg, &shared_key)?; 474 | Ok(()) 475 | } 476 | 477 | #[test] 478 | fn test_struct_with_reference_shared_key() -> Result<(), Error> { 479 | let shared_key = SharedKey::generate(); 480 | 481 | #[derive(PartialEq, Debug, Serialize, Deserialize)] 482 | struct Str<'a>(&'a str); 483 | impl<'a> SerdeEncryptSharedKey for Str<'a> { 484 | type S = BincodeSerializer; 485 | } 486 | 487 | let msg = Str("Str"); 488 | 489 | let encrypted_msg = msg.encrypt(&shared_key)?; 490 | let decrypted = Str::decrypt_ref(&encrypted_msg, &shared_key)?; 491 | let r_msg = decrypted.deserialize()?; 492 | pretty_assertions::assert_eq!(msg, r_msg); 493 | 494 | Ok(()) 495 | } 496 | 497 | #[test] 498 | fn test_struct_with_reference_public_key() -> Result<(), Error> { 499 | combined_keys_gen!(sender_combined_key, receiver_combined_key); 500 | 501 | #[derive(PartialEq, Debug, Serialize, Deserialize)] 502 | struct Str<'a>(&'a str); 503 | impl<'a> SerdeEncryptPublicKey for Str<'a> { 504 | type S = BincodeSerializer; 505 | } 506 | 507 | let msg = Str("Str"); 508 | 509 | let encrypted_msg = msg.encrypt(&sender_combined_key)?; 510 | let decrypted = Str::decrypt_ref(&encrypted_msg, &receiver_combined_key)?; 511 | let r_msg = decrypted.deserialize()?; 512 | pretty_assertions::assert_eq!(msg, r_msg); 513 | 514 | Ok(()) 515 | } 516 | 517 | #[test] 518 | fn test_serialize_enum_as_number() -> Result<(), Error> { 519 | combined_keys_gen!(sender_combined_key, receiver_combined_key); 520 | let shared_key = SharedKey::generate(); 521 | 522 | use serde_repr::*; 523 | 524 | #[derive(Serialize_repr, Deserialize_repr, PartialEq, Debug)] 525 | #[repr(u8)] 526 | enum SmallPrime { 527 | Two = 2, 528 | Three = 3, 529 | Five = 5, 530 | Seven = 7, 531 | } 532 | impl SerdeEncryptPublicKey for SmallPrime { 533 | type S = BincodeSerializer; 534 | } 535 | impl SerdeEncryptSharedKey for SmallPrime { 536 | type S = BincodeSerializer; 537 | } 538 | 539 | let msg_two = SmallPrime::Two; 540 | public_key_enc_dec_assert_eq(&msg_two, &sender_combined_key, &receiver_combined_key)?; 541 | shared_key_enc_dec_assert_eq(&msg_two, &shared_key)?; 542 | 543 | let msg_seven = SmallPrime::Seven; 544 | public_key_enc_dec_assert_eq(&msg_seven, &sender_combined_key, &receiver_combined_key)?; 545 | shared_key_enc_dec_assert_eq(&msg_seven, &shared_key)?; 546 | 547 | Ok(()) 548 | } 549 | 550 | #[test] 551 | fn test_serialize_field_as_camel_case() -> Result<(), Error> { 552 | combined_keys_gen!(sender_combined_key, receiver_combined_key); 553 | let shared_key = SharedKey::generate(); 554 | 555 | #[derive(PartialEq, Debug, Serialize, Deserialize)] 556 | #[serde(rename_all = "camelCase")] 557 | struct Person { 558 | first_name: String, 559 | last_name: String, 560 | } 561 | impl SerdeEncryptPublicKey for Person { 562 | type S = BincodeSerializer; 563 | } 564 | impl SerdeEncryptSharedKey for Person { 565 | type S = BincodeSerializer; 566 | } 567 | 568 | let msg = Person { 569 | first_name: "John".into(), 570 | last_name: "Doe".into(), 571 | }; 572 | public_key_enc_dec_assert_eq(&msg, &sender_combined_key, &receiver_combined_key)?; 573 | shared_key_enc_dec_assert_eq(&msg, &shared_key)?; 574 | Ok(()) 575 | } 576 | 577 | #[test] 578 | fn test_skip_serializing_without_default() -> Result<(), Error> { 579 | combined_keys_gen!(sender_combined_key, receiver_combined_key); 580 | let shared_key = SharedKey::generate(); 581 | 582 | #[derive(PartialEq, Debug, Serialize, Deserialize)] 583 | struct Resource { 584 | #[serde(skip_serializing)] 585 | // #[serde(default)] here prevents DeserializationError 586 | hash: String, 587 | } 588 | impl SerdeEncryptPublicKey for Resource { 589 | type S = BincodeSerializer; 590 | } 591 | impl SerdeEncryptSharedKey for Resource { 592 | type S = BincodeSerializer; 593 | } 594 | 595 | let msg_with_metadata = Resource { 596 | hash: "deadc0de".into(), 597 | }; 598 | 599 | let e = public_key_enc_dec( 600 | &msg_with_metadata, 601 | &sender_combined_key, 602 | &receiver_combined_key, 603 | ) 604 | .unwrap_err(); 605 | assert_eq!(e.kind(), &ErrorKind::DeserializationError); 606 | 607 | let e = shared_key_enc_dec(&msg_with_metadata, &shared_key).unwrap_err(); 608 | assert_eq!(e.kind(), &ErrorKind::DeserializationError); 609 | 610 | Ok(()) 611 | } 612 | 613 | #[test] 614 | fn test_skip_serializing_if() -> Result<(), Error> { 615 | use std::collections::BTreeMap as Map; 616 | 617 | combined_keys_gen!(sender_combined_key, receiver_combined_key); 618 | let shared_key = SharedKey::generate(); 619 | 620 | #[derive(PartialEq, Debug, Serialize, Deserialize)] 621 | struct Resource { 622 | name: String, 623 | 624 | #[serde(skip_serializing_if = "Map::is_empty")] 625 | metadata: Map, 626 | } 627 | impl SerdeEncryptPublicKey for Resource { 628 | type S = BincodeSerializer; 629 | } 630 | impl SerdeEncryptSharedKey for Resource { 631 | type S = BincodeSerializer; 632 | } 633 | 634 | let msg_with_metadata = Resource { 635 | name: "a.txt".into(), 636 | metadata: vec![("size".into(), "123".into())].into_iter().collect(), 637 | }; 638 | public_key_enc_dec_assert_eq( 639 | &msg_with_metadata, 640 | &sender_combined_key, 641 | &receiver_combined_key, 642 | )?; 643 | 644 | let msg_without_metadata = Resource { 645 | name: "a.txt".into(), 646 | metadata: Map::new(), 647 | }; 648 | 649 | let e = public_key_enc_dec( 650 | &msg_without_metadata, 651 | &sender_combined_key, 652 | &receiver_combined_key, 653 | ) 654 | .unwrap_err(); 655 | assert_eq!(e.kind(), &ErrorKind::DeserializationError); 656 | 657 | let e = shared_key_enc_dec(&msg_without_metadata, &shared_key).unwrap_err(); 658 | assert_eq!(e.kind(), &ErrorKind::DeserializationError); 659 | 660 | Ok(()) 661 | } 662 | 663 | #[test] 664 | fn test_remote_crate() -> Result<(), Error> { 665 | combined_keys_gen!(sender_combined_key, receiver_combined_key); 666 | let shared_key = SharedKey::generate(); 667 | 668 | // Pretend that this is somebody else's crate, not a module. 669 | mod other_crate { 670 | // Neither Serde nor the other crate provides Serialize and Deserialize 671 | // impls for this struct. 672 | #[derive(PartialEq, Debug)] 673 | pub struct Duration { 674 | pub secs: i64, 675 | pub nanos: i32, 676 | } 677 | } 678 | 679 | use other_crate::Duration; 680 | 681 | // Serde calls this the definition of the remote type. It is just a copy of the 682 | // remote data structure. The `remote` attribute gives the path to the actual 683 | // type we intend to derive code for. 684 | #[derive(PartialEq, Debug, Serialize, Deserialize)] 685 | #[serde(remote = "Duration")] 686 | struct DurationDef { 687 | secs: i64, 688 | nanos: i32, 689 | } 690 | 691 | // Now the remote type can be used almost like it had its own Serialize and 692 | // Deserialize impls all along. The `with` attribute gives the path to the 693 | // definition for the remote type. Note that the real type of the field is the 694 | // remote type, not the definition type. 695 | #[derive(PartialEq, Debug, Serialize, Deserialize)] 696 | struct Process { 697 | command_line: String, 698 | 699 | #[serde(with = "DurationDef")] 700 | wall_time: Duration, 701 | } 702 | 703 | impl SerdeEncryptPublicKey for Process { 704 | type S = BincodeSerializer; 705 | } 706 | impl SerdeEncryptSharedKey for Process { 707 | type S = BincodeSerializer; 708 | } 709 | 710 | let msg = Process { 711 | command_line: "sl".into(), 712 | wall_time: Duration { secs: 33, nanos: 4 }, 713 | }; 714 | public_key_enc_dec_assert_eq(&msg, &sender_combined_key, &receiver_combined_key)?; 715 | shared_key_enc_dec_assert_eq(&msg, &shared_key)?; 716 | Ok(()) 717 | } 718 | 719 | #[test] 720 | fn test_remote_crate_with_priv_fields() -> Result<(), Error> { 721 | combined_keys_gen!(sender_combined_key, receiver_combined_key); 722 | let shared_key = SharedKey::generate(); 723 | 724 | // Pretend that this is somebody else's crate, not a module. 725 | mod other_crate { 726 | // Neither Serde nor the other crate provides Serialize and Deserialize 727 | // impls for this struct. Oh, and the fields are private. 728 | #[derive(PartialEq, Debug)] 729 | pub struct Duration { 730 | secs: i64, 731 | nanos: i32, 732 | } 733 | 734 | impl Duration { 735 | pub fn new(secs: i64, nanos: i32) -> Self { 736 | Duration { secs, nanos } 737 | } 738 | 739 | pub fn seconds(&self) -> i64 { 740 | self.secs 741 | } 742 | 743 | pub fn subsec_nanos(&self) -> i32 { 744 | self.nanos 745 | } 746 | } 747 | } 748 | 749 | use other_crate::Duration; 750 | 751 | // Provide getters for every private field of the remote struct. The getter must 752 | // return either `T` or `&T` where `T` is the type of the field. 753 | #[derive(PartialEq, Debug, Serialize, Deserialize)] 754 | #[serde(remote = "Duration")] 755 | struct DurationDef { 756 | #[serde(getter = "Duration::seconds")] 757 | secs: i64, 758 | #[serde(getter = "Duration::subsec_nanos")] 759 | nanos: i32, 760 | } 761 | 762 | // Provide a conversion to construct the remote type. 763 | impl From for Duration { 764 | fn from(def: DurationDef) -> Duration { 765 | Duration::new(def.secs, def.nanos) 766 | } 767 | } 768 | 769 | #[derive(PartialEq, Debug, Serialize, Deserialize)] 770 | struct Process { 771 | command_line: String, 772 | 773 | #[serde(with = "DurationDef")] 774 | wall_time: Duration, 775 | } 776 | impl SerdeEncryptPublicKey for Process { 777 | type S = BincodeSerializer; 778 | } 779 | impl SerdeEncryptSharedKey for Process { 780 | type S = BincodeSerializer; 781 | } 782 | 783 | let msg = Process { 784 | command_line: "sl".into(), 785 | wall_time: Duration::new(33, 4), 786 | }; 787 | public_key_enc_dec_assert_eq(&msg, &sender_combined_key, &receiver_combined_key)?; 788 | shared_key_enc_dec_assert_eq(&msg, &shared_key)?; 789 | Ok(()) 790 | } 791 | 792 | #[test] 793 | fn test_remote_crate_with_helper() -> Result<(), Error> { 794 | combined_keys_gen!(sender_combined_key, receiver_combined_key); 795 | let shared_key = SharedKey::generate(); 796 | 797 | // Pretend that this is somebody else's crate, not a module. 798 | mod other_crate { 799 | // Neither Serde nor the other crate provides Serialize and Deserialize 800 | // impls for this struct. Oh, and the fields are private. 801 | #[derive(PartialEq, Debug)] 802 | pub struct Duration { 803 | secs: i64, 804 | nanos: i32, 805 | } 806 | 807 | impl Duration { 808 | pub fn new(secs: i64, nanos: i32) -> Self { 809 | Duration { secs, nanos } 810 | } 811 | 812 | pub fn seconds(&self) -> i64 { 813 | self.secs 814 | } 815 | 816 | pub fn subsec_nanos(&self) -> i32 { 817 | self.nanos 818 | } 819 | } 820 | } 821 | 822 | use other_crate::Duration; 823 | 824 | // Provide getters for every private field of the remote struct. The getter must 825 | // return either `T` or `&T` where `T` is the type of the field. 826 | #[derive(PartialEq, Debug, Serialize, Deserialize)] 827 | #[serde(remote = "Duration")] 828 | struct DurationDef { 829 | #[serde(getter = "Duration::seconds")] 830 | secs: i64, 831 | #[serde(getter = "Duration::subsec_nanos")] 832 | nanos: i32, 833 | } 834 | 835 | // Provide a conversion to construct the remote type. 836 | impl From for Duration { 837 | fn from(def: DurationDef) -> Duration { 838 | Duration::new(def.secs, def.nanos) 839 | } 840 | } 841 | 842 | #[derive(PartialEq, Debug, Serialize, Deserialize)] 843 | struct Helper(#[serde(with = "DurationDef")] Duration); 844 | 845 | #[derive(PartialEq, Debug, Serialize, Deserialize)] 846 | struct Process { 847 | command_line: String, 848 | wall_time: Helper, 849 | } 850 | impl SerdeEncryptPublicKey for Process { 851 | type S = BincodeSerializer; 852 | } 853 | impl SerdeEncryptSharedKey for Process { 854 | type S = BincodeSerializer; 855 | } 856 | 857 | let msg = Process { 858 | command_line: "sl".into(), 859 | wall_time: Helper(Duration::new(33, 4)), 860 | }; 861 | public_key_enc_dec_assert_eq(&msg, &sender_combined_key, &receiver_combined_key)?; 862 | shared_key_enc_dec_assert_eq(&msg, &shared_key)?; 863 | Ok(()) 864 | } 865 | 866 | #[test] 867 | fn test_string_or_struct() -> Result<(), Error> { 868 | use std::collections::BTreeMap as Map; 869 | 870 | combined_keys_gen!(sender_combined_key, receiver_combined_key); 871 | let shared_key = SharedKey::generate(); 872 | 873 | #[derive(PartialEq, Debug, Serialize, Deserialize)] 874 | struct Service { 875 | // The `string_or_struct` function delegates deserialization to a type's 876 | // `FromStr` impl if given a string, and to the type's `Deserialize` impl if 877 | // given a struct. The function is generic over the field type T (here T is 878 | // `Build`) so it can be reused for any field that implements both `FromStr` 879 | // and `Deserialize`. 880 | #[serde(deserialize_with = "string_or_struct")] 881 | build: Build, 882 | } 883 | impl SerdeEncryptPublicKey for Service { 884 | // [NG] BincodeSerializer emits DeserializeAnyNotSupported err 885 | // [NG] PostcardSerializer emits `WontImplement` err: https://github.com/jamesmunns/postcard/blob/96db753865b195948fcbd9c69815028adee9579c/src/de/deserializer.rs#L126 886 | type S = CborSerializer; 887 | } 888 | impl SerdeEncryptSharedKey for Service { 889 | type S = CborSerializer; 890 | } 891 | 892 | #[derive(PartialEq, Debug, Serialize, Deserialize)] 893 | struct Build { 894 | // This is the only required field. 895 | context: String, 896 | 897 | dockerfile: Option, 898 | 899 | // When `args` is not present in the input, this attribute tells Serde to 900 | // use `Default::default()` which in this case is an empty map. See the 901 | // "default value for a field" example for more about `#[serde(default)]`. 902 | #[serde(default)] 903 | args: Map, 904 | } 905 | 906 | // The `string_or_struct` function uses this impl to instantiate a `Build` if 907 | // the input file contains a string and not a struct. According to the 908 | // docker-compose.yml documentation, a string by itself represents a `Build` 909 | // with just the `context` field set. 910 | // 911 | // > `build` can be specified either as a string containing a path to the build 912 | // > context, or an object with the path specified under context and optionally 913 | // > dockerfile and args. 914 | impl FromStr for Build { 915 | // This implementation of `from_str` can never fail, so use the impossible 916 | // `Void` type as the error type. 917 | type Err = Void; 918 | 919 | fn from_str(s: &str) -> Result { 920 | Ok(Build { 921 | context: s.to_string(), 922 | dockerfile: None, 923 | args: Map::new(), 924 | }) 925 | } 926 | } 927 | 928 | fn string_or_struct<'de, T, D>(deserializer: D) -> Result 929 | where 930 | T: Deserialize<'de> + FromStr, 931 | D: Deserializer<'de>, 932 | { 933 | // This is a Visitor that forwards string types to T's `FromStr` impl and 934 | // forwards map types to T's `Deserialize` impl. The `PhantomData` is to 935 | // keep the compiler from complaining about T being an unused generic type 936 | // parameter. We need T in order to know the Value type for the Visitor 937 | // impl. 938 | struct StringOrStruct(PhantomData T>); 939 | 940 | impl<'de, T> Visitor<'de> for StringOrStruct 941 | where 942 | T: Deserialize<'de> + FromStr, 943 | { 944 | type Value = T; 945 | 946 | fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { 947 | formatter.write_str("string or map") 948 | } 949 | 950 | fn visit_str(self, value: &str) -> Result 951 | where 952 | E: de::Error, 953 | { 954 | Ok(FromStr::from_str(value).unwrap()) 955 | } 956 | 957 | fn visit_map(self, map: M) -> Result 958 | where 959 | M: MapAccess<'de>, 960 | { 961 | // `MapAccessDeserializer` is a wrapper that turns a `MapAccess` 962 | // into a `Deserializer`, allowing it to be used as the input to T's 963 | // `Deserialize` implementation. T then deserializes itself using 964 | // the entries from the map visitor. 965 | Deserialize::deserialize(de::value::MapAccessDeserializer::new(map)) 966 | } 967 | } 968 | 969 | deserializer.deserialize_any(StringOrStruct(PhantomData)) 970 | } 971 | 972 | let msg = Service { 973 | build: Build { 974 | context: "./dir".into(), 975 | dockerfile: Some("Dockerfile".into()), 976 | args: vec![("buildno".into(), "1".into())].into_iter().collect(), 977 | }, 978 | }; 979 | public_key_enc_dec_assert_eq(&msg, &sender_combined_key, &receiver_combined_key)?; 980 | shared_key_enc_dec_assert_eq(&msg, &shared_key)?; 981 | Ok(()) 982 | } 983 | 984 | #[test] 985 | fn test_convert_error_types() -> Result<(), Error> { 986 | combined_keys_gen!(sender_combined_key, receiver_combined_key); 987 | let shared_key = SharedKey::generate(); 988 | 989 | #[derive(PartialEq, Debug, Serialize, Deserialize)] 990 | struct Resource { 991 | name: String, 992 | 993 | #[serde(with = "as_json_string")] 994 | policy: Policy, 995 | } 996 | 997 | impl SerdeEncryptPublicKey for Resource { 998 | type S = BincodeSerializer; 999 | } 1000 | impl SerdeEncryptSharedKey for Resource { 1001 | type S = BincodeSerializer; 1002 | } 1003 | 1004 | #[derive(PartialEq, Debug, Serialize, Deserialize)] 1005 | struct Policy { 1006 | effect: String, 1007 | action: String, 1008 | resource: String, 1009 | } 1010 | 1011 | // Serialize and deserialize logic for dealing with nested values represented as 1012 | // JSON strings. 1013 | mod as_json_string { 1014 | use serde::de::{Deserialize, DeserializeOwned, Deserializer}; 1015 | use serde::ser::{Serialize, Serializer}; 1016 | 1017 | // Serialize to a JSON string, then serialize the string to the output 1018 | // format. 1019 | pub fn serialize(value: &T, serializer: S) -> Result 1020 | where 1021 | T: Serialize, 1022 | S: Serializer, 1023 | { 1024 | use serde::ser::Error; 1025 | let j = serde_json::to_string(value).map_err(Error::custom)?; 1026 | j.serialize(serializer) 1027 | } 1028 | 1029 | // Deserialize a string from the input format, then deserialize the content 1030 | // of that string as JSON. 1031 | pub fn deserialize<'de, T, D>(deserializer: D) -> Result 1032 | where 1033 | T: DeserializeOwned, 1034 | D: Deserializer<'de>, 1035 | { 1036 | use serde::de::Error; 1037 | let j = String::deserialize(deserializer)?; 1038 | serde_json::from_str(&j).map_err(Error::custom) 1039 | } 1040 | } 1041 | 1042 | let msg = Resource { 1043 | name: "a.txt".into(), 1044 | policy: Policy { 1045 | effect: "Allow".to_owned(), 1046 | action: "s3:ListBucket".to_owned(), 1047 | resource: "arn:aws:s3:::example_bucket".to_owned(), 1048 | }, 1049 | }; 1050 | public_key_enc_dec_assert_eq(&msg, &sender_combined_key, &receiver_combined_key)?; 1051 | shared_key_enc_dec_assert_eq(&msg, &shared_key)?; 1052 | Ok(()) 1053 | } 1054 | -------------------------------------------------------------------------------- /serde-encrypt/tests/feat_serializers.rs: -------------------------------------------------------------------------------- 1 | //! Serializers available in `feature = "std"`. 2 | 3 | use serde::{Deserialize, Serialize}; 4 | use serde_encrypt::{ 5 | serialize::impls::CborSerializer, shared_key::SharedKey, traits::SerdeEncryptSharedKey, 6 | AsSharedKey, Error, 7 | }; 8 | 9 | const RAW_MSG: [u8; 1000] = [42; 1000]; 10 | 11 | #[test] 12 | fn test_cbor_serializer() -> Result<(), Error> { 13 | #[derive(PartialEq, Debug, Serialize, Deserialize)] 14 | struct Message(Vec); 15 | 16 | impl SerdeEncryptSharedKey for Message { 17 | type S = CborSerializer; 18 | } 19 | 20 | let shared_key = SharedKey::generate(); 21 | 22 | let msg = Message(RAW_MSG.to_vec()); 23 | 24 | let enc_msg = msg.encrypt(&shared_key)?; 25 | let dec_msg = Message::decrypt_owned(&enc_msg, &shared_key)?; 26 | 27 | eprintln!( 28 | "[CborSerializer] {} bytes in plain-text ; {} bytes in cipher-text.", 29 | msg.0.len(), 30 | enc_msg.len() 31 | ); 32 | 33 | assert_eq!(dec_msg, msg); 34 | 35 | Ok(()) 36 | } 37 | 38 | cfg_if::cfg_if! { 39 | if #[cfg(feature = "std")] { 40 | use serde_encrypt::serialize::impls::BincodeSerializer; 41 | 42 | #[test] 43 | fn test_bincode_serializer() -> Result<(), Error> { 44 | #[derive(PartialEq, Debug, Serialize, Deserialize)] 45 | struct Message(Vec); 46 | 47 | impl SerdeEncryptSharedKey for Message { 48 | type S = BincodeSerializer; 49 | } 50 | 51 | let shared_key = SharedKey::generate(); 52 | 53 | let msg = Message(RAW_MSG.to_vec()); 54 | 55 | let enc_msg = msg.encrypt(&shared_key)?; 56 | let dec_msg = Message::decrypt_owned(&enc_msg, &shared_key)?; 57 | 58 | eprintln!( 59 | "[BincodeSerializer] {} bytes in plain-text ; {} bytes in cipher-text.", 60 | msg.0.len(), 61 | enc_msg.len() 62 | ); 63 | 64 | assert_eq!(dec_msg, msg); 65 | 66 | Ok(()) 67 | } 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /serde-encrypt/tests/test_util/mod.rs: -------------------------------------------------------------------------------- 1 | #![allow(dead_code)] 2 | 3 | extern crate alloc; 4 | 5 | use alloc::vec::Vec; 6 | use core::fmt::Debug; 7 | 8 | pub mod serde_encrypt_public_key; 9 | pub mod serde_encrypt_shared_key; 10 | 11 | pub use serde_encrypt_public_key::*; 12 | pub use serde_encrypt_shared_key::*; 13 | 14 | pub fn assert_no_duplicate(generator: impl Fn() -> T, n_generate: usize) 15 | where 16 | T: PartialEq + Debug, 17 | { 18 | let mut vs = Vec::::new(); 19 | for _ in 0..n_generate { 20 | let v = generator(); 21 | vs.push(v); 22 | } 23 | 24 | for i in 0..n_generate { 25 | let v_i = vs.get(i).unwrap(); 26 | for j in (i + 1)..n_generate { 27 | let v_j = vs.get(j).unwrap(); 28 | assert_ne!(v_i, v_j); 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /serde-encrypt/tests/test_util/serde_encrypt_public_key/mod.rs: -------------------------------------------------------------------------------- 1 | #![allow(dead_code)] 2 | 3 | use core::fmt; 4 | 5 | use serde::{de::DeserializeOwned, Serialize}; 6 | use serde_encrypt::{ 7 | key::key_pair::{ReceiverKeyPair, SenderKeyPair}, 8 | traits::SerdeEncryptPublicKey, 9 | Error, ReceiverCombinedKey, ReceiverKeyPairCore, SenderCombinedKey, SenderKeyPairCore, 10 | }; 11 | 12 | #[macro_export] 13 | macro_rules! combined_keys_gen { 14 | ($sender_combined_key:ident, $receiver_combined_key:ident) => { 15 | let (sender_key_pair, receiver_key_pair) = gen_key_pairs(); 16 | let ($sender_combined_key, $receiver_combined_key) = 17 | mk_combined_keys(&sender_key_pair, &receiver_key_pair); 18 | }; 19 | } 20 | 21 | pub fn gen_key_pairs() -> (SenderKeyPair, ReceiverKeyPair) { 22 | let sender_key_pair = SenderKeyPair::generate(); 23 | let receiver_key_pair = ReceiverKeyPair::generate(); 24 | (sender_key_pair, receiver_key_pair) 25 | } 26 | 27 | pub fn mk_combined_keys<'s, 'r>( 28 | sender_key_pair: &'s SenderKeyPair, 29 | receiver_key_pair: &'r ReceiverKeyPair, 30 | ) -> (SenderCombinedKey<'s, 'r>, ReceiverCombinedKey<'s, 'r>) { 31 | let sender_combined_key = SenderCombinedKey::new( 32 | sender_key_pair.private_key(), 33 | receiver_key_pair.public_key(), 34 | ); 35 | let receiver_combined_key = ReceiverCombinedKey::new( 36 | sender_key_pair.public_key(), 37 | receiver_key_pair.private_key(), 38 | ); 39 | 40 | (sender_combined_key, receiver_combined_key) 41 | } 42 | 43 | pub fn public_key_enc_dec( 44 | sender_msg: &T, 45 | sender_combined_key: &SenderCombinedKey, 46 | receiver_combined_key: &ReceiverCombinedKey, 47 | ) -> Result 48 | where 49 | T: SerdeEncryptPublicKey + Sized + Serialize + DeserializeOwned, 50 | { 51 | let enc = sender_msg.encrypt(sender_combined_key)?; 52 | T::decrypt_owned(&enc, receiver_combined_key) 53 | } 54 | 55 | pub fn public_key_enc_dec_assert_eq( 56 | sender_msg: &T, 57 | sender_combined_key: &SenderCombinedKey, 58 | receiver_combined_key: &ReceiverCombinedKey, 59 | ) -> Result<(), Error> 60 | where 61 | T: SerdeEncryptPublicKey + Sized + Serialize + DeserializeOwned + PartialEq + fmt::Debug, 62 | { 63 | let receiver_msg = public_key_enc_dec(sender_msg, sender_combined_key, receiver_combined_key)?; 64 | assert_eq!(sender_msg, &receiver_msg); 65 | Ok(()) 66 | } 67 | -------------------------------------------------------------------------------- /serde-encrypt/tests/test_util/serde_encrypt_shared_key/mod.rs: -------------------------------------------------------------------------------- 1 | #![allow(dead_code)] 2 | 3 | use core::fmt; 4 | 5 | use serde::{de::DeserializeOwned, Serialize}; 6 | use serde_encrypt::{shared_key::SharedKey, traits::SerdeEncryptSharedKey, Error}; 7 | 8 | pub fn shared_key_enc_dec(sender_msg: &T, shared_key: &SharedKey) -> Result 9 | where 10 | T: SerdeEncryptSharedKey + Sized + Serialize + DeserializeOwned, 11 | { 12 | let enc = sender_msg.encrypt(shared_key)?; 13 | T::decrypt_owned(&enc, shared_key) 14 | } 15 | 16 | pub fn shared_key_enc_dec_assert_eq(sender_msg: &T, shared_key: &SharedKey) -> Result<(), Error> 17 | where 18 | T: SerdeEncryptSharedKey + Sized + Serialize + DeserializeOwned + PartialEq + fmt::Debug, 19 | { 20 | let receiver_msg = shared_key_enc_dec(sender_msg, shared_key)?; 21 | assert_eq!(sender_msg, &receiver_msg); 22 | Ok(()) 23 | } 24 | -------------------------------------------------------------------------------- /serde-encrypt/tests/unit_plain_message_xxx_key.rs: -------------------------------------------------------------------------------- 1 | //! Unit test to PlainMessagePublicKey and PlainMessageSharedKey 2 | 3 | mod test_util; 4 | 5 | use serde_encrypt::{ 6 | encrypt::{ 7 | plain_message_public_key::PlainMessagePublicKey, 8 | plain_message_shared_key::PlainMessageSharedKey, 9 | }, 10 | shared_key::SharedKey, 11 | AsSharedKey, Error, ErrorKind, 12 | }; 13 | use serde_encrypt_core::encrypt::{ 14 | plain_message_public_key::PlainMessagePublicKeyCore, 15 | plain_message_shared_key::PlainMessageSharedKeyCore, 16 | }; 17 | use test_util::*; 18 | 19 | #[test] 20 | fn test_decrypt_with_wrong_public_key() -> Result<(), Error> { 21 | combined_keys_gen!(sender_combined_key1, _r); 22 | combined_keys_gen!(_s, receiver_combined_key2); 23 | 24 | let plain_msg = PlainMessagePublicKey::new(b"abc".to_vec()); 25 | let enc_msg = plain_msg.encrypt(&sender_combined_key1)?; 26 | let e = PlainMessagePublicKey::decrypt(&enc_msg, &receiver_combined_key2).unwrap_err(); 27 | assert_eq!(e.kind(), &ErrorKind::DecryptionError); 28 | 29 | Ok(()) 30 | } 31 | 32 | #[test] 33 | fn test_decrypt_with_wrong_shared_key() -> Result<(), Error> { 34 | let shared_key1 = SharedKey::generate(); 35 | let shared_key2 = SharedKey::generate(); 36 | 37 | let plain_msg = PlainMessageSharedKey::new(b"abc".to_vec()); 38 | let enc_msg = plain_msg.encrypt(&shared_key1)?; 39 | let e = PlainMessageSharedKey::decrypt(&enc_msg, &shared_key2).unwrap_err(); 40 | assert_eq!(e.kind(), &ErrorKind::DecryptionError); 41 | 42 | Ok(()) 43 | } 44 | --------------------------------------------------------------------------------