From f730dc41ed5b669885ba8dc6bc6c76401dcf2789 Mon Sep 17 00:00:00 2001
From: Shun Sakai <sorairolake@protonmail.ch>
Date: Sun, 12 Dec 2021 05:32:40 +0900
Subject: [PATCH] Add implementation of Camellia

---
 .github/workflows/camellia.yml      |  64 +++++
 Cargo.lock                          |   8 +
 Cargo.toml                          |   1 +
 README.md                           |   1 +
 camellia/Cargo.toml                 |  26 ++
 camellia/LICENSE-APACHE             | 201 ++++++++++++++++
 camellia/LICENSE-MIT                |  25 ++
 camellia/README.md                  |  71 ++++++
 camellia/benches/mod.rs             |  38 +++
 camellia/src/camellia.rs            | 352 ++++++++++++++++++++++++++++
 camellia/src/consts.rs              | 103 ++++++++
 camellia/src/lib.rs                 |  51 ++++
 camellia/tests/data/camellia128.blb | Bin 0 -> 27418 bytes
 camellia/tests/data/camellia192.blb | Bin 0 -> 41322 bytes
 camellia/tests/data/camellia256.blb | Bin 0 -> 49594 bytes
 camellia/tests/mod.rs               |   6 +
 16 files changed, 947 insertions(+)
 create mode 100644 .github/workflows/camellia.yml
 create mode 100644 camellia/Cargo.toml
 create mode 100644 camellia/LICENSE-APACHE
 create mode 100644 camellia/LICENSE-MIT
 create mode 100644 camellia/README.md
 create mode 100644 camellia/benches/mod.rs
 create mode 100644 camellia/src/camellia.rs
 create mode 100644 camellia/src/consts.rs
 create mode 100644 camellia/src/lib.rs
 create mode 100644 camellia/tests/data/camellia128.blb
 create mode 100644 camellia/tests/data/camellia192.blb
 create mode 100644 camellia/tests/data/camellia256.blb
 create mode 100644 camellia/tests/mod.rs

diff --git a/.github/workflows/camellia.yml b/.github/workflows/camellia.yml
new file mode 100644
index 00000000..d98a10dd
--- /dev/null
+++ b/.github/workflows/camellia.yml
@@ -0,0 +1,64 @@
+name: camellia
+
+on:
+  pull_request:
+    paths:
+      - "camellia/**"
+      - "Cargo.*"
+  push:
+    branches: master
+
+defaults:
+  run:
+    working-directory: camellia
+
+env:
+  CARGO_INCREMENTAL: 0
+  RUSTFLAGS: "-Dwarnings"
+
+jobs:
+  build:
+    runs-on: ubuntu-latest
+    strategy:
+      matrix:
+        rust:
+          - 1.56.0 # MSRV
+          - stable
+        target:
+          - thumbv7em-none-eabi
+          - wasm32-unknown-unknown
+    steps:
+      - uses: actions/checkout@v2
+      - uses: RustCrypto/actions/cargo-cache@master
+      - uses: actions-rs/toolchain@v1
+        with:
+          profile: minimal
+          toolchain: ${{ matrix.rust }}
+          target: ${{ matrix.target }}
+          override: true
+      - run: cargo build --no-default-features --release --target ${{ matrix.target }}
+
+  minimal-versions:
+    uses: RustCrypto/actions/.github/workflows/minimal-versions.yml@master
+    with:
+        working-directory: ${{ github.workflow }}
+
+  test:
+    runs-on: ubuntu-latest
+    strategy:
+      matrix:
+        rust:
+          - 1.56.0 # MSRV
+          - stable
+    steps:
+      - uses: actions/checkout@v2
+      - uses: RustCrypto/actions/cargo-cache@master
+      - uses: actions-rs/toolchain@v1
+        with:
+          toolchain: ${{ matrix.rust }}
+          override: true
+          profile: minimal
+      - run: cargo check --all-features
+      - run: cargo test --no-default-features
+      - run: cargo test
+      - run: cargo test --all-features
diff --git a/Cargo.lock b/Cargo.lock
index 4e8a895d..17f3ad1b 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -33,6 +33,14 @@ version = "1.4.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
 
+[[package]]
+name = "camellia"
+version = "0.1.0"
+dependencies = [
+ "byteorder",
+ "cipher",
+]
+
 [[package]]
 name = "cast5"
 version = "0.11.1"
diff --git a/Cargo.toml b/Cargo.toml
index 34d21596..7f523bd7 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -2,6 +2,7 @@
 members = [
     "aes",
     "blowfish",
+    "camellia",
     "cast5",
     "des",
     "idea",
diff --git a/README.md b/README.md
index 4327b701..06207878 100644
--- a/README.md
+++ b/README.md
@@ -23,6 +23,7 @@ It's generally recommended not to use other cipher implementations in this repos
 |------|------------|-----------|------|------|
 | [AES](https://en.wikipedia.org/wiki/Advanced_Encryption_Standard) (Rijndael) | `aes` | [![crates.io](https://img.shields.io/crates/v/aes.svg)](https://crates.io/crates/aes) | [![Documentation](https://docs.rs/aes/badge.svg)](https://docs.rs/aes) | ![MSRV 1.56][msrv-1.56] |
 | [Blowfish](https://en.wikipedia.org/wiki/Blowfish_(cipher)) | `blowfish` | [![crates.io](https://img.shields.io/crates/v/blowfish.svg)](https://crates.io/crates/blowfish) | [![Documentation](https://docs.rs/blowfish/badge.svg)](https://docs.rs/blowfish) | ![MSRV 1.56][msrv-1.56] |
+| [Camellia](https://en.wikipedia.org/wiki/Camellia_(cipher)) | `camellia` | [![crates.io](https://img.shields.io/crates/v/camellia.svg)](https://crates.io/crates/camellia) | [![Documentation](https://docs.rs/camellia/badge.svg)](https://docs.rs/camellia) | ![MSRV 1.56][msrv-1.56] |
 | [CAST5](https://en.wikipedia.org/wiki/CAST-128) (CAST-128) | `cast5` | [![crates.io](https://img.shields.io/crates/v/cast5.svg)](https://crates.io/crates/cast5) | [![Documentation](https://docs.rs/cast5/badge.svg)](https://docs.rs/cast5) | ![MSRV 1.56][msrv-1.56] |
 | [DES](https://en.wikipedia.org/wiki/Data_Encryption_Standard) + [3DES](https://en.wikipedia.org/wiki/Triple_DES) (DEA, 3DEA) | `des` | [![crates.io](https://img.shields.io/crates/v/des.svg)](https://crates.io/crates/des) | [![Documentation](https://docs.rs/des/badge.svg)](https://docs.rs/des) | ![MSRV 1.56][msrv-1.56] |
 | [IDEA](https://simple.wikipedia.org/wiki/International_Data_Encryption_Algorithm) | `idea` | [![crates.io](https://img.shields.io/crates/v/idea.svg)](https://crates.io/crates/idea) | [![Documentation](https://docs.rs/idea/badge.svg)](https://docs.rs/idea) | ![MSRV 1.56][msrv-1.56] |
diff --git a/camellia/Cargo.toml b/camellia/Cargo.toml
new file mode 100644
index 00000000..fd771160
--- /dev/null
+++ b/camellia/Cargo.toml
@@ -0,0 +1,26 @@
+[package]
+name = "camellia"
+version = "0.1.0" # Also update html_root_url in lib.rs when bumping this
+description = "Camellia block cipher"
+authors = ["RustCrypto Developers"]
+license = "MIT OR Apache-2.0"
+edition = "2021"
+rust-version = "1.56"
+readme = "README.md"
+documentation = "https://docs.rs/camellia"
+repository = "https://github.com/RustCrypto/block-ciphers"
+keywords = ["crypto", "camellia", "block-cipher"]
+categories = ["cryptography", "no-std"]
+
+[dependencies]
+byteorder = { version = "1.1", default-features = false }
+cipher = "0.4.2"
+
+[dev-dependencies]
+cipher = { version = "0.4.2", features = ["dev"] }
+
+[features]
+zeroize = ["cipher/zeroize"]
+
+[package.metadata.docs.rs]
+rustdoc-args = ["--cfg", "docsrs"]
diff --git a/camellia/LICENSE-APACHE b/camellia/LICENSE-APACHE
new file mode 100644
index 00000000..78173fa2
--- /dev/null
+++ b/camellia/LICENSE-APACHE
@@ -0,0 +1,201 @@
+                              Apache License
+                        Version 2.0, January 2004
+                     http://www.apache.org/licenses/
+
+TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+1. Definitions.
+
+   "License" shall mean the terms and conditions for use, reproduction,
+   and distribution as defined by Sections 1 through 9 of this document.
+
+   "Licensor" shall mean the copyright owner or entity authorized by
+   the copyright owner that is granting the License.
+
+   "Legal Entity" shall mean the union of the acting entity and all
+   other entities that control, are controlled by, or are under common
+   control with that entity. For the purposes of this definition,
+   "control" means (i) the power, direct or indirect, to cause the
+   direction or management of such entity, whether by contract or
+   otherwise, or (ii) ownership of fifty percent (50%) or more of the
+   outstanding shares, or (iii) beneficial ownership of such entity.
+
+   "You" (or "Your") shall mean an individual or Legal Entity
+   exercising permissions granted by this License.
+
+   "Source" form shall mean the preferred form for making modifications,
+   including but not limited to software source code, documentation
+   source, and configuration files.
+
+   "Object" form shall mean any form resulting from mechanical
+   transformation or translation of a Source form, including but
+   not limited to compiled object code, generated documentation,
+   and conversions to other media types.
+
+   "Work" shall mean the work of authorship, whether in Source or
+   Object form, made available under the License, as indicated by a
+   copyright notice that is included in or attached to the work
+   (an example is provided in the Appendix below).
+
+   "Derivative Works" shall mean any work, whether in Source or Object
+   form, that is based on (or derived from) the Work and for which the
+   editorial revisions, annotations, elaborations, or other modifications
+   represent, as a whole, an original work of authorship. For the purposes
+   of this License, Derivative Works shall not include works that remain
+   separable from, or merely link (or bind by name) to the interfaces of,
+   the Work and Derivative Works thereof.
+
+   "Contribution" shall mean any work of authorship, including
+   the original version of the Work and any modifications or additions
+   to that Work or Derivative Works thereof, that is intentionally
+   submitted to Licensor for inclusion in the Work by the copyright owner
+   or by an individual or Legal Entity authorized to submit on behalf of
+   the copyright owner. For the purposes of this definition, "submitted"
+   means any form of electronic, verbal, or written communication sent
+   to the Licensor or its representatives, including but not limited to
+   communication on electronic mailing lists, source code control systems,
+   and issue tracking systems that are managed by, or on behalf of, the
+   Licensor for the purpose of discussing and improving the Work, but
+   excluding communication that is conspicuously marked or otherwise
+   designated in writing by the copyright owner as "Not a Contribution."
+
+   "Contributor" shall mean Licensor and any individual or Legal Entity
+   on behalf of whom a Contribution has been received by Licensor and
+   subsequently incorporated within the Work.
+
+2. Grant of Copyright License. Subject to the terms and conditions of
+   this License, each Contributor hereby grants to You a perpetual,
+   worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+   copyright license to reproduce, prepare Derivative Works of,
+   publicly display, publicly perform, sublicense, and distribute the
+   Work and such Derivative Works in Source or Object form.
+
+3. Grant of Patent License. Subject to the terms and conditions of
+   this License, each Contributor hereby grants to You a perpetual,
+   worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+   (except as stated in this section) patent license to make, have made,
+   use, offer to sell, sell, import, and otherwise transfer the Work,
+   where such license applies only to those patent claims licensable
+   by such Contributor that are necessarily infringed by their
+   Contribution(s) alone or by combination of their Contribution(s)
+   with the Work to which such Contribution(s) was submitted. If You
+   institute patent litigation against any entity (including a
+   cross-claim or counterclaim in a lawsuit) alleging that the Work
+   or a Contribution incorporated within the Work constitutes direct
+   or contributory patent infringement, then any patent licenses
+   granted to You under this License for that Work shall terminate
+   as of the date such litigation is filed.
+
+4. Redistribution. You may reproduce and distribute copies of the
+   Work or Derivative Works thereof in any medium, with or without
+   modifications, and in Source or Object form, provided that You
+   meet the following conditions:
+
+   (a) You must give any other recipients of the Work or
+       Derivative Works a copy of this License; and
+
+   (b) You must cause any modified files to carry prominent notices
+       stating that You changed the files; and
+
+   (c) You must retain, in the Source form of any Derivative Works
+       that You distribute, all copyright, patent, trademark, and
+       attribution notices from the Source form of the Work,
+       excluding those notices that do not pertain to any part of
+       the Derivative Works; and
+
+   (d) If the Work includes a "NOTICE" text file as part of its
+       distribution, then any Derivative Works that You distribute must
+       include a readable copy of the attribution notices contained
+       within such NOTICE file, excluding those notices that do not
+       pertain to any part of the Derivative Works, in at least one
+       of the following places: within a NOTICE text file distributed
+       as part of the Derivative Works; within the Source form or
+       documentation, if provided along with the Derivative Works; or,
+       within a display generated by the Derivative Works, if and
+       wherever such third-party notices normally appear. The contents
+       of the NOTICE file are for informational purposes only and
+       do not modify the License. You may add Your own attribution
+       notices within Derivative Works that You distribute, alongside
+       or as an addendum to the NOTICE text from the Work, provided
+       that such additional attribution notices cannot be construed
+       as modifying the License.
+
+   You may add Your own copyright statement to Your modifications and
+   may provide additional or different license terms and conditions
+   for use, reproduction, or distribution of Your modifications, or
+   for any such Derivative Works as a whole, provided Your use,
+   reproduction, and distribution of the Work otherwise complies with
+   the conditions stated in this License.
+
+5. Submission of Contributions. Unless You explicitly state otherwise,
+   any Contribution intentionally submitted for inclusion in the Work
+   by You to the Licensor shall be under the terms and conditions of
+   this License, without any additional terms or conditions.
+   Notwithstanding the above, nothing herein shall supersede or modify
+   the terms of any separate license agreement you may have executed
+   with Licensor regarding such Contributions.
+
+6. Trademarks. This License does not grant permission to use the trade
+   names, trademarks, service marks, or product names of the Licensor,
+   except as required for reasonable and customary use in describing the
+   origin of the Work and reproducing the content of the NOTICE file.
+
+7. Disclaimer of Warranty. Unless required by applicable law or
+   agreed to in writing, Licensor provides the Work (and each
+   Contributor provides its Contributions) on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+   implied, including, without limitation, any warranties or conditions
+   of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+   PARTICULAR PURPOSE. You are solely responsible for determining the
+   appropriateness of using or redistributing the Work and assume any
+   risks associated with Your exercise of permissions under this License.
+
+8. Limitation of Liability. In no event and under no legal theory,
+   whether in tort (including negligence), contract, or otherwise,
+   unless required by applicable law (such as deliberate and grossly
+   negligent acts) or agreed to in writing, shall any Contributor be
+   liable to You for damages, including any direct, indirect, special,
+   incidental, or consequential damages of any character arising as a
+   result of this License or out of the use or inability to use the
+   Work (including but not limited to damages for loss of goodwill,
+   work stoppage, computer failure or malfunction, or any and all
+   other commercial damages or losses), even if such Contributor
+   has been advised of the possibility of such damages.
+
+9. Accepting Warranty or Additional Liability. While redistributing
+   the Work or Derivative Works thereof, You may choose to offer,
+   and charge a fee for, acceptance of support, warranty, indemnity,
+   or other liability obligations and/or rights consistent with this
+   License. However, in accepting such obligations, You may act only
+   on Your own behalf and on Your sole responsibility, not on behalf
+   of any other Contributor, and only if You agree to indemnify,
+   defend, and hold each Contributor harmless for any liability
+   incurred by, or claims asserted against, such Contributor by reason
+   of your accepting any such warranty or additional liability.
+
+END OF TERMS AND CONDITIONS
+
+APPENDIX: How to apply the Apache License to your work.
+
+   To apply the Apache License to your work, attach the following
+   boilerplate notice, with the fields enclosed by brackets "[]"
+   replaced with your own identifying information. (Don't include
+   the brackets!)  The text should be enclosed in the appropriate
+   comment syntax for the file format. We also recommend that a
+   file or class name and description of purpose be included on the
+   same "printed page" as the copyright notice for easier
+   identification within third-party archives.
+
+Copyright [yyyy] [name of copyright owner]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+   http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
diff --git a/camellia/LICENSE-MIT b/camellia/LICENSE-MIT
new file mode 100644
index 00000000..f8eccd8c
--- /dev/null
+++ b/camellia/LICENSE-MIT
@@ -0,0 +1,25 @@
+Copyright (c) 2021 Shun Sakai
+
+Permission is hereby granted, free of charge, to any
+person obtaining a copy of this software and associated
+documentation files (the "Software"), to deal in the
+Software without restriction, including without
+limitation the rights to use, copy, modify, merge,
+publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the Software
+is furnished to do so, subject to the following
+conditions:
+
+The above copyright notice and this permission notice
+shall be included in all copies or substantial portions
+of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
+ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
+TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
+PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
+SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
+IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
diff --git a/camellia/README.md b/camellia/README.md
new file mode 100644
index 00000000..2eeb6885
--- /dev/null
+++ b/camellia/README.md
@@ -0,0 +1,71 @@
+# RustCrypto: Camellia Cipher
+
+[![crate][crate-image]][crate-link]
+[![Docs][docs-image]][docs-link]
+![Apache2/MIT licensed][license-image]
+![Rust Version][rustc-image]
+[![Project Chat][chat-image]][chat-link]
+[![Build Status][build-image]][build-link]
+[![HAZMAT][hazmat-image]][hazmat-link]
+
+Pure Rust implementation of the [Camellia block cipher][1].
+
+[Documentation][docs-link]
+
+## ⚠️ Security Warning: [Hazmat!][hazmat-link]
+
+This crate does not ensure ciphertexts are authentic (i.e. by using a MAC to
+verify ciphertext integrity), which can lead to serious vulnerabilities
+if used incorrectly!
+
+No security audits of this crate have ever been performed, and it has not been
+thoroughly assessed to ensure its operation is constant-time on common CPU
+architectures.
+
+USE AT YOUR OWN RISK!
+
+## Minimum Supported Rust Version
+
+Rust **1.56** or higher.
+
+Minimum supported Rust version can be changed in the future, but it will be
+done with a minor version bump.
+
+## SemVer Policy
+
+- All on-by-default features of this library are covered by SemVer
+- MSRV is considered exempt from SemVer as noted above
+
+## License
+
+Licensed under either of:
+
+ * [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0)
+ * [MIT license](http://opensource.org/licenses/MIT)
+
+at your option.
+
+### Contribution
+
+Unless you explicitly state otherwise, any contribution intentionally submitted
+for inclusion in the work by you, as defined in the Apache-2.0 license, shall be
+dual licensed as above, without any additional terms or conditions.
+
+[//]: # (badges)
+
+[crate-image]: https://img.shields.io/crates/v/camellia.svg
+[crate-link]: https://crates.io/crates/camellia
+[docs-image]: https://docs.rs/camellia/badge.svg
+[docs-link]: https://docs.rs/camellia/
+[license-image]: https://img.shields.io/badge/license-Apache2.0/MIT-blue.svg
+[rustc-image]: https://img.shields.io/badge/rustc-1.56+-blue.svg
+[hazmat-image]: https://img.shields.io/badge/crypto-hazmat%E2%9A%A0-red.svg
+[hazmat-link]: https://github.com/RustCrypto/meta/blob/master/HAZMAT.md
+[chat-image]: https://img.shields.io/badge/zulip-join_chat-blue.svg
+[chat-link]: https://rustcrypto.zulipchat.com/#narrow/stream/260039-block-ciphers
+[build-image]: https://github.com/RustCrypto/block-ciphers/workflows/camellia/badge.svg?branch=master&event=push
+[build-link]: https://github.com/RustCrypto/block-ciphers/actions?query=workflow%3Acamellia
+
+[//]: # (general links)
+
+[1]: https://en.wikipedia.org/wiki/Camellia_(cipher)
diff --git a/camellia/benches/mod.rs b/camellia/benches/mod.rs
new file mode 100644
index 00000000..6de73b7d
--- /dev/null
+++ b/camellia/benches/mod.rs
@@ -0,0 +1,38 @@
+#![feature(test)]
+extern crate test;
+
+use camellia::{Camellia128, Camellia192, Camellia256};
+use cipher::{block_decryptor_bench, block_encryptor_bench};
+
+block_encryptor_bench!(
+    Key: Camellia128,
+    camellia128_encrypt_block,
+    camellia128_encrypt_blocks
+);
+block_decryptor_bench!(
+    Key: Camellia128,
+    camellia128_decrypt_block,
+    camellia128_decrypt_blocks
+);
+
+block_encryptor_bench!(
+    Key: Camellia192,
+    camellia192_encrypt_block,
+    camellia192_encrypt_blocks
+);
+block_decryptor_bench!(
+    Key: Camellia192,
+    camellia192_decrypt_block,
+    camellia192_decrypt_blocks
+);
+
+block_encryptor_bench!(
+    Key: Camellia256,
+    camellia256_encrypt_block,
+    camellia256_encrypt_blocks
+);
+block_decryptor_bench!(
+    Key: Camellia256,
+    camellia256_decrypt_block,
+    camellia256_decrypt_blocks
+);
diff --git a/camellia/src/camellia.rs b/camellia/src/camellia.rs
new file mode 100644
index 00000000..7557b922
--- /dev/null
+++ b/camellia/src/camellia.rs
@@ -0,0 +1,352 @@
+//
+// Based on src/lib/block/camellia/camellia.cpp from https://github.com/randombit/botan
+// Revision: 32bf9784bd6ee29cb3ffa173f0a734e9edce2dac
+//
+
+/*
+ * Camellia
+ * (C) 2012,2020 Jack Lloyd
+ *
+ * Botan is released under the Simplified BSD License (see license.txt)
+ */
+
+use core::fmt;
+
+use byteorder::{ByteOrder, BE};
+use cipher::{
+    consts::{U16, U24, U32},
+    AlgorithmName, BlockCipher, Key, KeyInit, KeySizeUser,
+};
+
+#[cfg(feature = "zeroize")]
+use cipher::zeroize::{Zeroize, ZeroizeOnDrop};
+
+use crate::consts::{SBOXES, SIGMAS};
+
+/// F-function of component of Camellia defined in RFC 3713.
+fn f(input: u64, key: u64) -> u64 {
+    let x = (input ^ key).to_be_bytes();
+
+    let z1 = 0x0101_0100_0100_0001 * u64::from(SBOXES[0][usize::from(x[0])]);
+    let z2 = 0x0001_0101_0101_0000 * u64::from(SBOXES[1][usize::from(x[1])]);
+    let z3 = 0x0100_0101_0001_0100 * u64::from(SBOXES[2][usize::from(x[2])]);
+    let z4 = 0x0101_0001_0000_0101 * u64::from(SBOXES[3][usize::from(x[3])]);
+    let z5 = 0x0001_0101_0001_0101 * u64::from(SBOXES[1][usize::from(x[4])]);
+    let z6 = 0x0100_0101_0100_0101 * u64::from(SBOXES[2][usize::from(x[5])]);
+    let z7 = 0x0101_0001_0101_0001 * u64::from(SBOXES[3][usize::from(x[6])]);
+    let z8 = 0x0101_0100_0101_0100 * u64::from(SBOXES[0][usize::from(x[7])]);
+
+    z1 ^ z2 ^ z3 ^ z4 ^ z5 ^ z6 ^ z7 ^ z8
+}
+
+/// FL-function of component of Camellia defined in RFC 3713.
+fn fl(input: u64, key: u64) -> u64 {
+    let mut x1 = u32::try_from(input >> 32).unwrap();
+    let mut x2 = u32::try_from(input & 0xffff_ffff).unwrap();
+
+    let k1 = u32::try_from(key >> 32).unwrap();
+    let k2 = u32::try_from(key & 0xffff_ffff).unwrap();
+
+    x2 ^= (x1 & k1).rotate_left(1);
+    x1 ^= x2 | k2;
+
+    (u64::from(x1) << 32) | u64::from(x2)
+}
+
+/// FLINV-function of component of Camellia defined in RFC 3713.
+fn flinv(input: u64, key: u64) -> u64 {
+    let mut y1 = u32::try_from(input >> 32).unwrap();
+    let mut y2 = u32::try_from(input & 0xffff_ffff).unwrap();
+
+    let k1 = u32::try_from(key >> 32).unwrap();
+    let k2 = u32::try_from(key & 0xffff_ffff).unwrap();
+
+    y1 ^= y2 | k2;
+    y2 ^= (y1 & k1).rotate_left(1);
+
+    (u64::from(y1) << 32) | u64::from(y2)
+}
+
+macro_rules! set_kl {
+    ($key:expr) => {
+        (
+            u64::from_be_bytes($key[0..8].try_into().unwrap()),
+            u64::from_be_bytes($key[8..16].try_into().unwrap()),
+        )
+    };
+}
+
+fn set_ka(kl: (u64, u64), kr: (u64, u64)) -> (u64, u64) {
+    let mut d1 = kl.0 ^ kr.0;
+    let mut d2 = kl.1 ^ kr.1;
+    d2 ^= f(d1, SIGMAS[0]);
+    d1 ^= f(d2, SIGMAS[1]);
+    d1 ^= kl.0;
+    d2 ^= kl.1;
+    d2 ^= f(d1, SIGMAS[2]);
+    d1 ^= f(d2, SIGMAS[3]);
+
+    (d1, d2)
+}
+
+fn set_kb(ka: (u64, u64), kr: (u64, u64)) -> (u64, u64) {
+    let mut d1 = ka.0 ^ kr.0;
+    let mut d2 = ka.1 ^ kr.1;
+    d2 ^= f(d1, SIGMAS[4]);
+    d1 ^= f(d2, SIGMAS[5]);
+
+    (d1, d2)
+}
+
+/// Performs rotate left and taking the higher-half of it.
+fn rotate_left_high(val: (u64, u64), mut shift: u8) -> u64 {
+    if shift >= 64 {
+        shift -= 64;
+    }
+
+    (val.0 << shift) | (val.1 >> (64 - shift))
+}
+
+/// Performs rotate left and taking the lower-half of it.
+fn rotate_left_low(val: (u64, u64), mut shift: u8) -> u64 {
+    if shift >= 64 {
+        shift -= 64;
+    }
+
+    (val.0 >> (64 - shift)) | (val.1 << shift)
+}
+
+impl Camellia128 {
+    fn gen_subkeys(kl: (u64, u64), ka: (u64, u64)) -> Self {
+        let mut k = [u64::default(); 26];
+
+        k[0] = kl.0;
+        k[1] = kl.1;
+
+        k[2] = ka.0;
+        k[3] = ka.1;
+        k[4] = rotate_left_high(kl, 15);
+        k[5] = rotate_left_low(kl, 15);
+        k[6] = rotate_left_high(ka, 15);
+        k[7] = rotate_left_low(ka, 15);
+
+        k[8] = rotate_left_high(ka, 30);
+        k[9] = rotate_left_low(ka, 30);
+
+        k[10] = rotate_left_high(kl, 45);
+        k[11] = rotate_left_low(kl, 45);
+        k[12] = rotate_left_high(ka, 45);
+        k[13] = rotate_left_low(kl, 60);
+        k[14] = rotate_left_high(ka, 60);
+        k[15] = rotate_left_low(ka, 60);
+
+        k[16] = rotate_left_low(kl, 77);
+        k[17] = rotate_left_high(kl, 77);
+
+        k[18] = rotate_left_low(kl, 94);
+        k[19] = rotate_left_high(kl, 94);
+        k[20] = rotate_left_low(ka, 94);
+        k[21] = rotate_left_high(ka, 94);
+        k[22] = rotate_left_low(kl, 111);
+        k[23] = rotate_left_high(kl, 111);
+
+        k[24] = rotate_left_low(ka, 111);
+        k[25] = rotate_left_high(ka, 111);
+
+        Self { k }
+    }
+}
+
+macro_rules! impl_gen_subkeys {
+    ($name:ident) => {
+        impl $name {
+            fn gen_subkeys(kl: (u64, u64), kr: (u64, u64), ka: (u64, u64), kb: (u64, u64)) -> Self {
+                let mut k = [u64::default(); 34];
+
+                k[0] = kl.0;
+                k[1] = kl.1;
+
+                k[2] = kb.0;
+                k[3] = kb.1;
+                k[4] = rotate_left_high(kr, 15);
+                k[5] = rotate_left_low(kr, 15);
+                k[6] = rotate_left_high(ka, 15);
+                k[7] = rotate_left_low(ka, 15);
+
+                k[8] = rotate_left_high(kr, 30);
+                k[9] = rotate_left_low(kr, 30);
+
+                k[10] = rotate_left_high(kb, 30);
+                k[11] = rotate_left_low(kb, 30);
+                k[12] = rotate_left_high(kl, 45);
+                k[13] = rotate_left_low(kl, 45);
+                k[14] = rotate_left_high(ka, 45);
+                k[15] = rotate_left_low(ka, 45);
+
+                k[16] = rotate_left_high(kl, 60);
+                k[17] = rotate_left_low(kl, 60);
+
+                k[18] = rotate_left_high(kr, 60);
+                k[19] = rotate_left_low(kr, 60);
+                k[20] = rotate_left_high(kb, 60);
+                k[21] = rotate_left_low(kb, 60);
+                k[22] = rotate_left_low(kl, 77);
+                k[23] = rotate_left_high(kl, 77);
+
+                k[24] = rotate_left_low(ka, 77);
+                k[25] = rotate_left_high(ka, 77);
+
+                k[26] = rotate_left_low(kr, 94);
+                k[27] = rotate_left_high(kr, 94);
+                k[28] = rotate_left_low(ka, 94);
+                k[29] = rotate_left_high(ka, 94);
+                k[30] = rotate_left_low(kl, 111);
+                k[31] = rotate_left_high(kl, 111);
+
+                k[32] = rotate_left_low(kb, 111);
+                k[33] = rotate_left_high(kb, 111);
+
+                Self { k }
+            }
+        }
+    };
+}
+
+impl_gen_subkeys!(Camellia192);
+impl_gen_subkeys!(Camellia256);
+
+impl KeyInit for Camellia128 {
+    fn new(key: &Key<Self>) -> Self {
+        let kl = set_kl!(key);
+        let kr = (u64::default(), u64::default());
+
+        let ka = set_ka(kl, kr);
+
+        Self::gen_subkeys(kl, ka)
+    }
+}
+
+impl KeyInit for Camellia192 {
+    fn new(key: &Key<Self>) -> Self {
+        let kl = set_kl!(key);
+        let kr = u64::from_be_bytes(key[16..24].try_into().unwrap());
+        let kr = (kr, !kr);
+
+        let ka = set_ka(kl, kr);
+        let kb = set_kb(ka, kr);
+
+        Self::gen_subkeys(kl, kr, ka, kb)
+    }
+}
+
+impl KeyInit for Camellia256 {
+    fn new(key: &Key<Self>) -> Self {
+        let kl = set_kl!(key);
+        let kr = (
+            u64::from_be_bytes(key[16..24].try_into().unwrap()),
+            u64::from_be_bytes(key[24..32].try_into().unwrap()),
+        );
+
+        let ka = set_ka(kl, kr);
+        let kb = set_kb(ka, kr);
+
+        Self::gen_subkeys(kl, kr, ka, kb)
+    }
+}
+
+macro_rules! impl_camellia {
+    ($name:ident, $subkey_size:literal, $key_size:ty, $doc:literal) => {
+        #[doc = $doc]
+        #[derive(Clone)]
+        pub struct $name {
+            /// Subkeys.
+            k: [u64; $subkey_size],
+        }
+
+        impl BlockCipher for $name {}
+
+        impl KeySizeUser for $name {
+            type KeySize = $key_size;
+        }
+
+        impl fmt::Debug for $name {
+            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+                f.write_str(concat!(stringify!($name), " { ... }"))
+            }
+        }
+
+        impl AlgorithmName for $name {
+            fn write_alg_name(f: &mut fmt::Formatter<'_>) -> fmt::Result {
+                f.write_str(stringify!($name))
+            }
+        }
+
+        #[cfg(feature = "zeroize")]
+        #[cfg_attr(docsrs, doc(cfg(feature = "zeroize")))]
+        impl Drop for $name {
+            fn drop(&mut self){
+                self.k.zeroize();
+            }
+        }
+
+        #[cfg(feature = "zeroize")]
+        #[cfg_attr(docsrs, doc(cfg(feature = "zeroize")))]
+        impl ZeroizeOnDrop for $name {}
+
+        cipher::impl_simple_block_encdec!(
+            $name, U16, cipher, block,
+            encrypt: {
+                let b = block.get_in();
+                let mut d1 = u64::from_be_bytes(b[0..8].try_into().unwrap());
+                let mut d2 = u64::from_be_bytes(b[8..16].try_into().unwrap());
+
+                d1 ^= cipher.k[0];
+                d2 ^= cipher.k[1];
+
+                for i in (2..$subkey_size - 2).step_by(2) {
+                    if i % 8 == 0 {
+                        d1 = fl(d1, cipher.k[i]);
+                        d2 = flinv(d2, cipher.k[i + 1]);
+
+                        continue;
+                    }
+                    d2 ^= f(d1, cipher.k[i]);
+                    d1 ^= f(d2, cipher.k[i + 1]);
+                }
+
+                d2 ^= cipher.k[$subkey_size - 2];
+                d1 ^= cipher.k[$subkey_size - 1];
+
+                BE::write_u64_into(&[d2, d1], block.get_out());
+            }
+            decrypt: {
+                let b = block.get_in();
+                let mut d1 = u64::from_be_bytes(b[0..8].try_into().unwrap());
+                let mut d2 = u64::from_be_bytes(b[8..16].try_into().unwrap());
+
+                d2 ^= cipher.k[$subkey_size - 1];
+                d1 ^= cipher.k[$subkey_size - 2];
+
+                for i in (2..$subkey_size - 2).rev().step_by(2) {
+                    if (i - 1) % 8 == 0 {
+                        d1 = fl(d1, cipher.k[i]);
+                        d2 = flinv(d2, cipher.k[i - 1]);
+
+                        continue;
+                    }
+                    d2 ^= f(d1, cipher.k[i]);
+                    d1 ^= f(d2, cipher.k[i - 1]);
+                }
+
+                d1 ^= cipher.k[1];
+                d2 ^= cipher.k[0];
+
+                BE::write_u64_into(&[d2, d1], block.get_out());
+            }
+        );
+    };
+}
+
+impl_camellia!(Camellia128, 26, U16, "Camellia-128 block cipher instance.");
+impl_camellia!(Camellia192, 34, U24, "Camellia-192 block cipher instance.");
+impl_camellia!(Camellia256, 34, U32, "Camellia-256 block cipher instance.");
diff --git a/camellia/src/consts.rs b/camellia/src/consts.rs
new file mode 100644
index 00000000..d6f7f30f
--- /dev/null
+++ b/camellia/src/consts.rs
@@ -0,0 +1,103 @@
+/// Constants used as "keys" in the F-function in the key schedule part.
+pub const SIGMAS: [u64; 6] = [
+    // Sigma1
+    0xa09e_667f_3bcc_908b,
+    // Sigma2
+    0xb67a_e858_4caa_73b2,
+    // Sigma3
+    0xc6ef_372f_e94f_82be,
+    // Sigma4
+    0x54ff_53a5_f1d3_6f1c,
+    // Sigma5
+    0x10e5_27fa_de68_2d1d,
+    // Sigma6
+    0xb056_88c2_b3e6_c1fd,
+];
+
+/// Sboxes of Camellia defined in RFC 3713.
+pub const SBOXES: [[u8; 256]; 4] = [
+    // SBOX1
+    [
+        0x70, 0x82, 0x2c, 0xec, 0xb3, 0x27, 0xc0, 0xe5, 0xe4, 0x85, 0x57, 0x35, 0xea, 0x0c, 0xae,
+        0x41, 0x23, 0xef, 0x6b, 0x93, 0x45, 0x19, 0xa5, 0x21, 0xed, 0x0e, 0x4f, 0x4e, 0x1d, 0x65,
+        0x92, 0xbd, 0x86, 0xb8, 0xaf, 0x8f, 0x7c, 0xeb, 0x1f, 0xce, 0x3e, 0x30, 0xdc, 0x5f, 0x5e,
+        0xc5, 0x0b, 0x1a, 0xa6, 0xe1, 0x39, 0xca, 0xd5, 0x47, 0x5d, 0x3d, 0xd9, 0x01, 0x5a, 0xd6,
+        0x51, 0x56, 0x6c, 0x4d, 0x8b, 0x0d, 0x9a, 0x66, 0xfb, 0xcc, 0xb0, 0x2d, 0x74, 0x12, 0x2b,
+        0x20, 0xf0, 0xb1, 0x84, 0x99, 0xdf, 0x4c, 0xcb, 0xc2, 0x34, 0x7e, 0x76, 0x05, 0x6d, 0xb7,
+        0xa9, 0x31, 0xd1, 0x17, 0x04, 0xd7, 0x14, 0x58, 0x3a, 0x61, 0xde, 0x1b, 0x11, 0x1c, 0x32,
+        0x0f, 0x9c, 0x16, 0x53, 0x18, 0xf2, 0x22, 0xfe, 0x44, 0xcf, 0xb2, 0xc3, 0xb5, 0x7a, 0x91,
+        0x24, 0x08, 0xe8, 0xa8, 0x60, 0xfc, 0x69, 0x50, 0xaa, 0xd0, 0xa0, 0x7d, 0xa1, 0x89, 0x62,
+        0x97, 0x54, 0x5b, 0x1e, 0x95, 0xe0, 0xff, 0x64, 0xd2, 0x10, 0xc4, 0x00, 0x48, 0xa3, 0xf7,
+        0x75, 0xdb, 0x8a, 0x03, 0xe6, 0xda, 0x09, 0x3f, 0xdd, 0x94, 0x87, 0x5c, 0x83, 0x02, 0xcd,
+        0x4a, 0x90, 0x33, 0x73, 0x67, 0xf6, 0xf3, 0x9d, 0x7f, 0xbf, 0xe2, 0x52, 0x9b, 0xd8, 0x26,
+        0xc8, 0x37, 0xc6, 0x3b, 0x81, 0x96, 0x6f, 0x4b, 0x13, 0xbe, 0x63, 0x2e, 0xe9, 0x79, 0xa7,
+        0x8c, 0x9f, 0x6e, 0xbc, 0x8e, 0x29, 0xf5, 0xf9, 0xb6, 0x2f, 0xfd, 0xb4, 0x59, 0x78, 0x98,
+        0x06, 0x6a, 0xe7, 0x46, 0x71, 0xba, 0xd4, 0x25, 0xab, 0x42, 0x88, 0xa2, 0x8d, 0xfa, 0x72,
+        0x07, 0xb9, 0x55, 0xf8, 0xee, 0xac, 0x0a, 0x36, 0x49, 0x2a, 0x68, 0x3c, 0x38, 0xf1, 0xa4,
+        0x40, 0x28, 0xd3, 0x7b, 0xbb, 0xc9, 0x43, 0xc1, 0x15, 0xe3, 0xad, 0xf4, 0x77, 0xc7, 0x80,
+        0x9e,
+    ],
+    // SBOX2
+    [
+        0xe0, 0x05, 0x58, 0xd9, 0x67, 0x4e, 0x81, 0xcb, 0xc9, 0x0b, 0xae, 0x6a, 0xd5, 0x18, 0x5d,
+        0x82, 0x46, 0xdf, 0xd6, 0x27, 0x8a, 0x32, 0x4b, 0x42, 0xdb, 0x1c, 0x9e, 0x9c, 0x3a, 0xca,
+        0x25, 0x7b, 0x0d, 0x71, 0x5f, 0x1f, 0xf8, 0xd7, 0x3e, 0x9d, 0x7c, 0x60, 0xb9, 0xbe, 0xbc,
+        0x8b, 0x16, 0x34, 0x4d, 0xc3, 0x72, 0x95, 0xab, 0x8e, 0xba, 0x7a, 0xb3, 0x02, 0xb4, 0xad,
+        0xa2, 0xac, 0xd8, 0x9a, 0x17, 0x1a, 0x35, 0xcc, 0xf7, 0x99, 0x61, 0x5a, 0xe8, 0x24, 0x56,
+        0x40, 0xe1, 0x63, 0x09, 0x33, 0xbf, 0x98, 0x97, 0x85, 0x68, 0xfc, 0xec, 0x0a, 0xda, 0x6f,
+        0x53, 0x62, 0xa3, 0x2e, 0x08, 0xaf, 0x28, 0xb0, 0x74, 0xc2, 0xbd, 0x36, 0x22, 0x38, 0x64,
+        0x1e, 0x39, 0x2c, 0xa6, 0x30, 0xe5, 0x44, 0xfd, 0x88, 0x9f, 0x65, 0x87, 0x6b, 0xf4, 0x23,
+        0x48, 0x10, 0xd1, 0x51, 0xc0, 0xf9, 0xd2, 0xa0, 0x55, 0xa1, 0x41, 0xfa, 0x43, 0x13, 0xc4,
+        0x2f, 0xa8, 0xb6, 0x3c, 0x2b, 0xc1, 0xff, 0xc8, 0xa5, 0x20, 0x89, 0x00, 0x90, 0x47, 0xef,
+        0xea, 0xb7, 0x15, 0x06, 0xcd, 0xb5, 0x12, 0x7e, 0xbb, 0x29, 0x0f, 0xb8, 0x07, 0x04, 0x9b,
+        0x94, 0x21, 0x66, 0xe6, 0xce, 0xed, 0xe7, 0x3b, 0xfe, 0x7f, 0xc5, 0xa4, 0x37, 0xb1, 0x4c,
+        0x91, 0x6e, 0x8d, 0x76, 0x03, 0x2d, 0xde, 0x96, 0x26, 0x7d, 0xc6, 0x5c, 0xd3, 0xf2, 0x4f,
+        0x19, 0x3f, 0xdc, 0x79, 0x1d, 0x52, 0xeb, 0xf3, 0x6d, 0x5e, 0xfb, 0x69, 0xb2, 0xf0, 0x31,
+        0x0c, 0xd4, 0xcf, 0x8c, 0xe2, 0x75, 0xa9, 0x4a, 0x57, 0x84, 0x11, 0x45, 0x1b, 0xf5, 0xe4,
+        0x0e, 0x73, 0xaa, 0xf1, 0xdd, 0x59, 0x14, 0x6c, 0x92, 0x54, 0xd0, 0x78, 0x70, 0xe3, 0x49,
+        0x80, 0x50, 0xa7, 0xf6, 0x77, 0x93, 0x86, 0x83, 0x2a, 0xc7, 0x5b, 0xe9, 0xee, 0x8f, 0x01,
+        0x3d,
+    ],
+    // SBOX3
+    [
+        0x38, 0x41, 0x16, 0x76, 0xd9, 0x93, 0x60, 0xf2, 0x72, 0xc2, 0xab, 0x9a, 0x75, 0x06, 0x57,
+        0xa0, 0x91, 0xf7, 0xb5, 0xc9, 0xa2, 0x8c, 0xd2, 0x90, 0xf6, 0x07, 0xa7, 0x27, 0x8e, 0xb2,
+        0x49, 0xde, 0x43, 0x5c, 0xd7, 0xc7, 0x3e, 0xf5, 0x8f, 0x67, 0x1f, 0x18, 0x6e, 0xaf, 0x2f,
+        0xe2, 0x85, 0x0d, 0x53, 0xf0, 0x9c, 0x65, 0xea, 0xa3, 0xae, 0x9e, 0xec, 0x80, 0x2d, 0x6b,
+        0xa8, 0x2b, 0x36, 0xa6, 0xc5, 0x86, 0x4d, 0x33, 0xfd, 0x66, 0x58, 0x96, 0x3a, 0x09, 0x95,
+        0x10, 0x78, 0xd8, 0x42, 0xcc, 0xef, 0x26, 0xe5, 0x61, 0x1a, 0x3f, 0x3b, 0x82, 0xb6, 0xdb,
+        0xd4, 0x98, 0xe8, 0x8b, 0x02, 0xeb, 0x0a, 0x2c, 0x1d, 0xb0, 0x6f, 0x8d, 0x88, 0x0e, 0x19,
+        0x87, 0x4e, 0x0b, 0xa9, 0x0c, 0x79, 0x11, 0x7f, 0x22, 0xe7, 0x59, 0xe1, 0xda, 0x3d, 0xc8,
+        0x12, 0x04, 0x74, 0x54, 0x30, 0x7e, 0xb4, 0x28, 0x55, 0x68, 0x50, 0xbe, 0xd0, 0xc4, 0x31,
+        0xcb, 0x2a, 0xad, 0x0f, 0xca, 0x70, 0xff, 0x32, 0x69, 0x08, 0x62, 0x00, 0x24, 0xd1, 0xfb,
+        0xba, 0xed, 0x45, 0x81, 0x73, 0x6d, 0x84, 0x9f, 0xee, 0x4a, 0xc3, 0x2e, 0xc1, 0x01, 0xe6,
+        0x25, 0x48, 0x99, 0xb9, 0xb3, 0x7b, 0xf9, 0xce, 0xbf, 0xdf, 0x71, 0x29, 0xcd, 0x6c, 0x13,
+        0x64, 0x9b, 0x63, 0x9d, 0xc0, 0x4b, 0xb7, 0xa5, 0x89, 0x5f, 0xb1, 0x17, 0xf4, 0xbc, 0xd3,
+        0x46, 0xcf, 0x37, 0x5e, 0x47, 0x94, 0xfa, 0xfc, 0x5b, 0x97, 0xfe, 0x5a, 0xac, 0x3c, 0x4c,
+        0x03, 0x35, 0xf3, 0x23, 0xb8, 0x5d, 0x6a, 0x92, 0xd5, 0x21, 0x44, 0x51, 0xc6, 0x7d, 0x39,
+        0x83, 0xdc, 0xaa, 0x7c, 0x77, 0x56, 0x05, 0x1b, 0xa4, 0x15, 0x34, 0x1e, 0x1c, 0xf8, 0x52,
+        0x20, 0x14, 0xe9, 0xbd, 0xdd, 0xe4, 0xa1, 0xe0, 0x8a, 0xf1, 0xd6, 0x7a, 0xbb, 0xe3, 0x40,
+        0x4f,
+    ],
+    // SBOX4
+    [
+        0x70, 0x2c, 0xb3, 0xc0, 0xe4, 0x57, 0xea, 0xae, 0x23, 0x6b, 0x45, 0xa5, 0xed, 0x4f, 0x1d,
+        0x92, 0x86, 0xaf, 0x7c, 0x1f, 0x3e, 0xdc, 0x5e, 0x0b, 0xa6, 0x39, 0xd5, 0x5d, 0xd9, 0x5a,
+        0x51, 0x6c, 0x8b, 0x9a, 0xfb, 0xb0, 0x74, 0x2b, 0xf0, 0x84, 0xdf, 0xcb, 0x34, 0x76, 0x6d,
+        0xa9, 0xd1, 0x04, 0x14, 0x3a, 0xde, 0x11, 0x32, 0x9c, 0x53, 0xf2, 0xfe, 0xcf, 0xc3, 0x7a,
+        0x24, 0xe8, 0x60, 0x69, 0xaa, 0xa0, 0xa1, 0x62, 0x54, 0x1e, 0xe0, 0x64, 0x10, 0x00, 0xa3,
+        0x75, 0x8a, 0xe6, 0x09, 0xdd, 0x87, 0x83, 0xcd, 0x90, 0x73, 0xf6, 0x9d, 0xbf, 0x52, 0xd8,
+        0xc8, 0xc6, 0x81, 0x6f, 0x13, 0x63, 0xe9, 0xa7, 0x9f, 0xbc, 0x29, 0xf9, 0x2f, 0xb4, 0x78,
+        0x06, 0xe7, 0x71, 0xd4, 0xab, 0x88, 0x8d, 0x72, 0xb9, 0xf8, 0xac, 0x36, 0x2a, 0x3c, 0xf1,
+        0x40, 0xd3, 0xbb, 0x43, 0x15, 0xad, 0x77, 0x80, 0x82, 0xec, 0x27, 0xe5, 0x85, 0x35, 0x0c,
+        0x41, 0xef, 0x93, 0x19, 0x21, 0x0e, 0x4e, 0x65, 0xbd, 0xb8, 0x8f, 0xeb, 0xce, 0x30, 0x5f,
+        0xc5, 0x1a, 0xe1, 0xca, 0x47, 0x3d, 0x01, 0xd6, 0x56, 0x4d, 0x0d, 0x66, 0xcc, 0x2d, 0x12,
+        0x20, 0xb1, 0x99, 0x4c, 0xc2, 0x7e, 0x05, 0xb7, 0x31, 0x17, 0xd7, 0x58, 0x61, 0x1b, 0x1c,
+        0x0f, 0x16, 0x18, 0x22, 0x44, 0xb2, 0xb5, 0x91, 0x08, 0xa8, 0xfc, 0x50, 0xd0, 0x7d, 0x89,
+        0x97, 0x5b, 0x95, 0xff, 0xd2, 0xc4, 0x48, 0xf7, 0xdb, 0x03, 0xda, 0x3f, 0x94, 0x5c, 0x02,
+        0x4a, 0x33, 0x67, 0xf3, 0x7f, 0xe2, 0x9b, 0x26, 0x37, 0x3b, 0x96, 0x4b, 0xbe, 0x2e, 0x79,
+        0x8c, 0x6e, 0x8e, 0xf5, 0xb6, 0xfd, 0x59, 0x98, 0x6a, 0x46, 0xba, 0x25, 0x42, 0xa2, 0xfa,
+        0x07, 0x55, 0xee, 0x0a, 0x49, 0x68, 0x38, 0xa4, 0x28, 0x7b, 0xc9, 0xc1, 0xe3, 0xf4, 0xc7,
+        0x9e,
+    ],
+];
diff --git a/camellia/src/lib.rs b/camellia/src/lib.rs
new file mode 100644
index 00000000..06eaeef3
--- /dev/null
+++ b/camellia/src/lib.rs
@@ -0,0 +1,51 @@
+//! Pure Rust implementation of the [Camellia][1] block cipher.
+//!
+//! # ⚠️ Security Warning: Hazmat!
+//!
+//! This crate implements only the low-level block cipher function, and is intended
+//! for use for implementing higher-level constructions *only*. It is NOT
+//! intended for direct use in applications.
+//!
+//! USE AT YOUR OWN RISK!
+//!
+//! # Examples
+//! ```
+//! use camellia::cipher::generic_array::GenericArray;
+//! use camellia::cipher::{BlockDecrypt, BlockEncrypt, KeyInit};
+//! use camellia::Camellia128;
+//!
+//! let key = GenericArray::from([0_u8; 16]);
+//! let mut block = GenericArray::from([0_u8; 16]);
+//!
+//! // Initialize cipher
+//! let cipher = Camellia128::new(&key);
+//!
+//! let block_copy = block;
+//!
+//! // Encrypt block in-place
+//! cipher.encrypt_block(&mut block);
+//!
+//! // And decrypt it back
+//! cipher.decrypt_block(&mut block);
+//!
+//! assert_eq!(block, block_copy);
+//! ```
+//!
+//! [1]: https://en.wikipedia.org/wiki/Camellia_(cipher)
+
+#![no_std]
+#![doc(
+    html_logo_url = "https://raw.githubusercontent.com/RustCrypto/media/26acc39f/logo.svg",
+    html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/media/26acc39f/logo.svg",
+    html_root_url = "https://docs.rs/camellia/0.1.0"
+)]
+#![deny(unsafe_code)]
+#![cfg_attr(docsrs, feature(doc_cfg))]
+#![warn(missing_docs, rust_2018_idioms)]
+
+pub use cipher;
+
+mod camellia;
+mod consts;
+
+pub use crate::camellia::{Camellia128, Camellia192, Camellia256};
diff --git a/camellia/tests/data/camellia128.blb b/camellia/tests/data/camellia128.blb
new file mode 100644
index 0000000000000000000000000000000000000000..a8e86e590548579632784094dba390ad1ee4ee97
GIT binary patch
diff --git a/camellia/tests/data/camellia192.blb b/camellia/tests/data/camellia192.blb
new file mode 100644
index 0000000000000000000000000000000000000000..bc105c97722d8e506f5ea76699320fc17daad3f0
GIT binary patch
diff --git a/camellia/tests/data/camellia256.blb b/camellia/tests/data/camellia256.blb
new file mode 100644
index 0000000000000000000000000000000000000000..f93354424ba555d003a425c967155d5d0b263674
GIT binary patch
diff --git a/camellia/tests/mod.rs b/camellia/tests/mod.rs
new file mode 100644
index 00000000..00ff3d76
--- /dev/null
+++ b/camellia/tests/mod.rs
@@ -0,0 +1,6 @@
+//! Test vectors are from NESSIE:
+//! <https://www.cosic.esat.kuleuven.be/nessie/testvectors/>
+
+cipher::block_cipher_test!(camellia128_test, "camellia128", camellia::Camellia128);
+cipher::block_cipher_test!(camellia192_test, "camellia192", camellia::Camellia192);
+cipher::block_cipher_test!(camellia256_test, "camellia256", camellia::Camellia256);
