├── .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 | [](https://crates.io/crates/serde-encrypt)
4 | [](https://crates.io/crates/serde-encrypt)
5 | [](https://docs.rs/serde-encrypt)
6 | 
7 | [](https://github.com/laysakura/serde-encrypt/actions/workflows/ci.yml)
8 | [](https://codecov.io/gh/laysakura/serde-encrypt)
9 | [](https://github.com/laysakura/serde-encrypt/blob/master/LICENSE-MIT)
10 | [](https://github.com/laysakura/serde-encrypt/blob/master/LICENSE-APACHE)
11 |
12 | 
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 |
--------------------------------------------------------------------------------