mirror of
https://github.com/logos-blockchain/sponges.git
synced 2026-07-30 10:33:21 +00:00
ascon: use aead crate for AEAD API; MSRV 1.60 (#44)
Impls the standard AEAD API from the `aead` crate. Eventually we can split this API out into a separate crate, e.g. `ascon-aead`, but for now this just gets things working initially. Uses weak/namespaced features which requires MSRV 1.60.
This commit is contained in:
parent
11cb7366da
commit
c8b07a46c8
4
.github/workflows/ascon.yml
vendored
4
.github/workflows/ascon.yml
vendored
@ -21,7 +21,7 @@ jobs:
|
||||
set-msrv:
|
||||
uses: RustCrypto/actions/.github/workflows/set-msrv.yml@master
|
||||
with:
|
||||
msrv: 1.59.0
|
||||
msrv: 1.60.0
|
||||
|
||||
benches:
|
||||
runs-on: ubuntu-latest
|
||||
@ -56,6 +56,7 @@ jobs:
|
||||
target: ${{ matrix.target }}
|
||||
override: true
|
||||
- run: cargo build --no-default-features --target ${{ matrix.target }}
|
||||
- run: cargo build --no-default-features --target ${{ matrix.target }} --features aead
|
||||
|
||||
minimal-versions:
|
||||
uses: RustCrypto/actions/.github/workflows/minimal-versions.yml@master
|
||||
@ -80,3 +81,4 @@ jobs:
|
||||
override: true
|
||||
- run: cargo test --no-default-features
|
||||
- run: cargo test
|
||||
- run: cargo test --all-features
|
||||
|
||||
59
Cargo.lock
generated
59
Cargo.lock
generated
@ -2,6 +2,65 @@
|
||||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "aead"
|
||||
version = "0.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5c192eb8f11fc081b0fe4259ba5af04217d4e0faddd02417310a927911abd7c8"
|
||||
dependencies = [
|
||||
"crypto-common",
|
||||
"generic-array",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ascon"
|
||||
version = "0.2.0-pre"
|
||||
dependencies = [
|
||||
"aead",
|
||||
"hex-literal",
|
||||
"subtle",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crypto-common"
|
||||
version = "0.1.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3"
|
||||
dependencies = [
|
||||
"generic-array",
|
||||
"typenum",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "generic-array"
|
||||
version = "0.14.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bff49e947297f3312447abdca79f45f4738097cc82b06e72054d2223f601f1b9"
|
||||
dependencies = [
|
||||
"typenum",
|
||||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hex-literal"
|
||||
version = "0.3.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7ebdb29d2ea9ed0083cd8cece49bbd968021bd99b0849edb4a9a7ee0fdf6a4e0"
|
||||
|
||||
[[package]]
|
||||
name = "subtle"
|
||||
version = "2.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601"
|
||||
|
||||
[[package]]
|
||||
name = "typenum"
|
||||
version = "1.16.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba"
|
||||
|
||||
[[package]]
|
||||
name = "version_check"
|
||||
version = "0.9.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
|
||||
|
||||
@ -13,11 +13,21 @@ keywords = ["crypto", "sponge"]
|
||||
categories = ["cryptography", "no-std"]
|
||||
readme = "README.md"
|
||||
edition = "2021"
|
||||
rust-version = "1.59"
|
||||
rust-version = "1.60"
|
||||
|
||||
[dependencies]
|
||||
aead = { version = "0.5", optional = true, default-features = false }
|
||||
subtle = { version = "2", optional = true, default-features = false }
|
||||
|
||||
[dev-dependencies]
|
||||
hex-literal = "0.3"
|
||||
|
||||
[features]
|
||||
default = ["alloc"]
|
||||
alloc = []
|
||||
default = ["aead"]
|
||||
alloc = ["aead?/alloc"]
|
||||
std = ["aead?/std"]
|
||||
|
||||
aead = ["dep:aead", "alloc", "subtle"] # TODO(tarcieri): remove alloc dependency
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
all-features = true
|
||||
|
||||
@ -186,7 +186,7 @@ APPENDIX: How to apply the Apache License to your work.
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright (c) 2016-2023 quininer kel, RustCrypto Developers
|
||||
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.
|
||||
|
||||
@ -28,7 +28,7 @@ portfolio of the [CAESAR competition].
|
||||
|
||||
## Minimum Supported Rust Version
|
||||
|
||||
This crate requires **Rust 1.59** at a minimum.
|
||||
This crate requires **Rust 1.60** at a minimum.
|
||||
|
||||
We may change the MSRV in the future, but it will be accompanied by a minor
|
||||
version bump.
|
||||
@ -57,7 +57,7 @@ dual licensed as above, without any additional terms or conditions.
|
||||
[build-image]: https://github.com/RustCrypto/sponges/actions/workflows/ascon.yml/badge.svg
|
||||
[build-link]: https://github.com/RustCrypto/sponges/actions/workflows/ascon.yml
|
||||
[license-image]: https://img.shields.io/badge/license-Apache2.0/MIT-blue.svg
|
||||
[rustc-image]: https://img.shields.io/badge/rustc-1.59+-blue.svg
|
||||
[rustc-image]: https://img.shields.io/badge/rustc-1.60+-blue.svg
|
||||
[chat-image]: https://img.shields.io/badge/zulip-join_chat-blue.svg
|
||||
[chat-link]: https://rustcrypto.zulipchat.com/#narrow/stream/369879-sponges
|
||||
|
||||
|
||||
@ -2,28 +2,35 @@
|
||||
|
||||
extern crate test;
|
||||
|
||||
use ascon::aead;
|
||||
use ascon::aead::{AeadInPlace, AsconAead, KeyInit};
|
||||
use hex_literal::hex;
|
||||
use test::Bencher;
|
||||
|
||||
#[bench]
|
||||
fn ascon_encrypt_bench(b: &mut Bencher) {
|
||||
let key = [4; 16];
|
||||
let iv = [8; 16];
|
||||
let aad = [3; 16];
|
||||
let message = [99; 1025];
|
||||
|
||||
b.bytes = message.len() as u64;
|
||||
b.iter(|| aead::encrypt(&key, &iv, &message, &aad));
|
||||
}
|
||||
const KEY: [u8; 16] = [4; 16];
|
||||
const NONCE: [u8; 16] = [8; 16];
|
||||
const AAD: [u8; 16] = [3; 16];
|
||||
const PLAINTEXT: [u8; 1025] = [99; 1025];
|
||||
const CIPHERTEXT: [u8; 1025] = hex!("d5cfb4650e0a82b9e86455de588cfd48c4bf240301efbf1981a57f00c5ec31eb9127d5da85fab0bf3c927b9d875cd1f71e0945f0281a0774e890bae1f98d488580c63e19972d73b6df19773503b0d8f0317727b8ab7681e15237eec369e8ea2915695d6f03f44541ea28f737574d5c7277361636a0a246fbc8c4b6764ef642b9a15211e11f5059fd08d173e4a9fff4cc55389d04a392f0a12dbccce67439e967bb8f39887b078cd68eaa8fd5a3c3b7299536c50a35b7871ab612417fdd1313527cbc82591d20417f2ef3dc37dc1298b32677daac9e79cf28307ceb886aea42694322ac5e978405fff9df6b9da86c83661fa165c957b830dc85350bb41ae6a6f9ee7c713d47b6277b54c64d0ceefd41945f23cfe4f0ba0ea39ba7c829c308ab53591817adeda57c4d3858fff07f57ec4100905e8568e855f61d558f7cffc3dc47b4e2ab9b90053caef52bede5871c5839b33f48e8822dbca59e96532ded31e809d901de72d65d5112ac067f7135670445bdec7e9f41287190dd091f906d6d98b6d15aa3fa475a2b4f99bc0e12e9c057140308a73572dcabad2e2140103028c075e9da74d92177aaea9d1899dace0ee8f4a9edfa9c4abc39a4b6239a2ea3841af1f90af884d10ef43b48924cba8474cb0162c8204acab4647cb680e9b64fb77e4d2195f63dd45e6c21b637db5c15101a72259e5af940ce9e5c0fe0b4affefef059e2982c32dfe50c0aefee368f15867ab2ff205fa855a895a0379b5678f432e25fd884771873acf6ee72fe4cf02c13843239b3114ff9e9bfebc44618bffc731b272cf08e627e47d759f1ae63191892d493a19fb54b96dd2132e416612d4e4a3bb536d0470c151c998a9ce5a44883ac395efa23e201734ef6a9e7ac1dade6a48fff8445e39a38157b5263cf9e52abf8cb604be9f1ed7ebe85e10933ab1f3e0546c17bbf7561233d7f95b32f8086fdbb06948af5a0ffd06dd47e89c3f4a419cc5b34300a76a542aeeae716563204f68f880cac077855297150fd217d6185116d542b64ce1319712760bf61fa1b6b52c8e9feb609bf6caa07b41ed80c7423cbe5390ec9851a2629d9d307971515c0a1696b0d4d52deabab089b945326b1e62a6ec5eb2cf2c58a5af0404962923a0c8605b6d55fd899765b193db8f5a849ecab478e187476779cf5f08d38a812b14ddff6143870ce5d9afc3e2eda91624067654940856421f5a8e0f6e3eefe888bd11c9364a29e2821374a1550e888359230ba863424746c793708e0ba23be967fa527ee5989eaf48541928e594ea846d67d5a6a56aa886be7b693d662cd675c786687c0d870bf19ab7564fb0b87bc6bba157ae04f482fca52858f8ff600141efa24f2f29cb0b8e222d88d9bfd9e60818474e55cc2b11e70125a956934c75cad4207f83b372c501ca7864bf8d387d0f81ec1cc872ff180");
|
||||
const TAG: [u8; 16] = hex!("17d7dca595adcaaddf537a1e9fd02854");
|
||||
|
||||
#[bench]
|
||||
fn ascon_decrypt_bench(b: &mut Bencher) {
|
||||
let key = [4; 16];
|
||||
let iv = [8; 16];
|
||||
let aad = [3; 16];
|
||||
let message = [99; 1025];
|
||||
let (ciphertext, tag) = aead::encrypt(&key, &iv, &message, &aad);
|
||||
|
||||
b.bytes = message.len() as u64;
|
||||
b.iter(|| aead::decrypt(&key, &iv, &ciphertext, &aad, &tag));
|
||||
let aead = AsconAead::<12, 8>::new(&KEY.into());
|
||||
b.bytes = CIPHERTEXT.len() as u64;
|
||||
b.iter(|| {
|
||||
let mut buffer = CIPHERTEXT;
|
||||
aead.decrypt_in_place_detached(&NONCE.into(), &AAD, &mut buffer, &TAG.into())
|
||||
.unwrap();
|
||||
});
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn ascon_encrypt_bench(b: &mut Bencher) {
|
||||
let aead = AsconAead::<12, 8>::new(&KEY.into());
|
||||
b.bytes = PLAINTEXT.len() as u64;
|
||||
b.iter(|| {
|
||||
let mut buffer = PLAINTEXT;
|
||||
aead.encrypt_in_place_detached(&NONCE.into(), &AAD, &mut buffer)
|
||||
.unwrap();
|
||||
});
|
||||
}
|
||||
|
||||
@ -1,156 +1,164 @@
|
||||
//! Authenticated Encryption with Associated Data.
|
||||
|
||||
use crate::{Ascon, Key, Nonce, KEY_SIZE, RATE, S_SIZE};
|
||||
use alloc::{vec, vec::Vec};
|
||||
pub use ::aead::{self, AeadCore, AeadInPlace, Error, KeyInit, KeySizeUser};
|
||||
|
||||
/// Ascon(a,b) `b`-parameter.
|
||||
const B: usize = 8;
|
||||
use crate::{Ascon, KEY_SIZE, RATE, S_SIZE};
|
||||
use ::aead::consts::{U0, U16};
|
||||
|
||||
/// Tag length.
|
||||
const TAG_LEN: usize = 16;
|
||||
// TODO(tarcieri): remove hard dependency on alloc
|
||||
use alloc::vec;
|
||||
|
||||
/// Authentication tag.
|
||||
type Tag = [u8; TAG_LEN];
|
||||
/// Ascon AEAD key.
|
||||
pub type Key = ::aead::generic_array::GenericArray<u8, U16>;
|
||||
|
||||
/// Decryption errors.
|
||||
#[derive(Debug)]
|
||||
pub enum DecryptFail {
|
||||
/// Invalid tag length.
|
||||
TagLengthError,
|
||||
/// Ascon AEAD nonce.
|
||||
pub type Nonce = ::aead::generic_array::GenericArray<u8, U16>;
|
||||
|
||||
/// Authentication failure (invalid tag).
|
||||
AuthenticationFail,
|
||||
/// Ascon AEAD authentication tag.
|
||||
pub type Tag = ::aead::generic_array::GenericArray<u8, U16>;
|
||||
|
||||
/// Ascon AEAD encryption.
|
||||
#[derive(Clone)]
|
||||
pub struct AsconAead<const A: usize = 12, const B: usize = 8> {
|
||||
key: Key,
|
||||
}
|
||||
|
||||
/// AEAD encryption.
|
||||
pub fn encrypt(key: &Key, nonce: &Nonce, message: &[u8], aad: &[u8]) -> (Vec<u8>, Tag) {
|
||||
let s = aad.len() / RATE + 1;
|
||||
let t = message.len() / RATE + 1;
|
||||
let l = message.len() % RATE;
|
||||
impl<const A: usize, const B: usize> KeySizeUser for AsconAead<A, B> {
|
||||
type KeySize = U16;
|
||||
}
|
||||
|
||||
let mut aa = vec![0; s * RATE];
|
||||
let mut mm = vec![0; t * RATE];
|
||||
|
||||
let mut output = vec![0; message.len()];
|
||||
|
||||
// pad aad
|
||||
aa[..aad.len()].copy_from_slice(aad);
|
||||
aa[aad.len()] = 0x80;
|
||||
|
||||
// pad message
|
||||
mm[..message.len()].copy_from_slice(message);
|
||||
mm[message.len()] = 0x80;
|
||||
|
||||
// init
|
||||
let mut ss = Ascon::new(key, nonce);
|
||||
|
||||
// aad
|
||||
if !aad.is_empty() {
|
||||
process_aad(&mut ss, &aa, s);
|
||||
impl<const A: usize, const B: usize> KeyInit for AsconAead<A, B> {
|
||||
fn new(key_bytes: &Key) -> Self {
|
||||
Self { key: *key_bytes }
|
||||
}
|
||||
}
|
||||
|
||||
ss.state[S_SIZE - 1] ^= 1;
|
||||
impl<const A: usize, const B: usize> AeadCore for AsconAead<A, B> {
|
||||
type NonceSize = U16;
|
||||
type TagSize = U16;
|
||||
type CiphertextOverhead = U0;
|
||||
}
|
||||
|
||||
// plaintext
|
||||
for i in 0..(t - 1) {
|
||||
for j in 0..RATE {
|
||||
ss.state[j] ^= mm[i * RATE + j];
|
||||
impl<const A: usize, const B: usize> AeadInPlace for AsconAead<A, B> {
|
||||
fn encrypt_in_place_detached(
|
||||
&self,
|
||||
nonce: &Nonce,
|
||||
aad: &[u8],
|
||||
buffer: &mut [u8],
|
||||
) -> Result<Tag, Error> {
|
||||
let s = aad.len() / RATE + 1;
|
||||
let t = buffer.len() / RATE + 1;
|
||||
let l = buffer.len() % RATE;
|
||||
|
||||
let mut aa = vec![0; s * RATE];
|
||||
let mut mm = vec![0; t * RATE];
|
||||
|
||||
// pad aad
|
||||
aa[..aad.len()].copy_from_slice(aad);
|
||||
aa[aad.len()] = 0x80;
|
||||
|
||||
// pad message
|
||||
mm[..buffer.len()].copy_from_slice(buffer);
|
||||
mm[buffer.len()] = 0x80;
|
||||
|
||||
// init
|
||||
let mut ss = Ascon::<A, B>::new(self.key.as_ref(), nonce.as_ref());
|
||||
|
||||
// aad
|
||||
if !aad.is_empty() {
|
||||
process_aad(&mut ss, &aa, s);
|
||||
}
|
||||
output[(i * RATE)..(i * RATE + RATE)].copy_from_slice(&ss.state[..RATE]);
|
||||
ss.permutation(12 - B, B);
|
||||
}
|
||||
|
||||
for j in 0..RATE {
|
||||
ss.state[j] ^= mm[(t - 1) * RATE + j];
|
||||
}
|
||||
ss.state[S_SIZE - 1] ^= 1;
|
||||
|
||||
for j in 0..l {
|
||||
output[(t - 1) * RATE + j] = ss.state[j];
|
||||
}
|
||||
|
||||
// tag
|
||||
let mut tag = Tag::default();
|
||||
tag.copy_from_slice(&ss.finalize()[S_SIZE - KEY_SIZE..]);
|
||||
|
||||
(output, tag)
|
||||
}
|
||||
|
||||
/// AEAD decryption.
|
||||
pub fn decrypt(
|
||||
key: &Key,
|
||||
nonce: &Nonce,
|
||||
ciphertext: &[u8],
|
||||
aad: &[u8],
|
||||
tag: &[u8],
|
||||
) -> Result<Vec<u8>, DecryptFail> {
|
||||
if tag.len() != KEY_SIZE {
|
||||
Err(DecryptFail::TagLengthError)?
|
||||
};
|
||||
|
||||
let s = aad.len() / RATE + 1;
|
||||
let t = ciphertext.len() / RATE + 1;
|
||||
let l = ciphertext.len() % RATE;
|
||||
|
||||
let mut aa = vec![0; s * RATE];
|
||||
let mut mm = vec![0; t * RATE];
|
||||
|
||||
// pad aad
|
||||
aa[..aad.len()].copy_from_slice(aad);
|
||||
aa[aad.len()] = 0x80;
|
||||
|
||||
// init
|
||||
let mut ss = Ascon::new(key, nonce);
|
||||
|
||||
// aad
|
||||
if !aad.is_empty() {
|
||||
process_aad(&mut ss, &aa, s);
|
||||
}
|
||||
|
||||
ss.state[S_SIZE - 1] ^= 1;
|
||||
|
||||
// ciphertext
|
||||
for i in 0..(t - 1) {
|
||||
for j in 0..RATE {
|
||||
mm[i * RATE + j] = ss.state[j] ^ ciphertext[i * RATE + j];
|
||||
// plaintext
|
||||
for i in 0..(t - 1) {
|
||||
for j in 0..RATE {
|
||||
ss.state[j] ^= mm[i * RATE + j];
|
||||
}
|
||||
buffer[(i * RATE)..(i * RATE + RATE)].copy_from_slice(&ss.state[..RATE]);
|
||||
ss.permutation(12 - B, B);
|
||||
}
|
||||
ss.state[..RATE].copy_from_slice(&ciphertext[(i * RATE)..(i * RATE + RATE)]);
|
||||
ss.permutation(12 - B, B);
|
||||
|
||||
for j in 0..RATE {
|
||||
ss.state[j] ^= mm[(t - 1) * RATE + j];
|
||||
}
|
||||
|
||||
for j in 0..l {
|
||||
buffer[(t - 1) * RATE + j] = ss.state[j];
|
||||
}
|
||||
|
||||
// tag
|
||||
let mut tag = Tag::default();
|
||||
tag.copy_from_slice(&ss.finalize()[S_SIZE - KEY_SIZE..]);
|
||||
|
||||
Ok(tag)
|
||||
}
|
||||
|
||||
for j in 0..l {
|
||||
mm[(t - 1) * RATE + j] = ss.state[j] ^ ciphertext[(t - 1) * RATE + j];
|
||||
}
|
||||
fn decrypt_in_place_detached(
|
||||
&self,
|
||||
nonce: &Nonce,
|
||||
aad: &[u8],
|
||||
buffer: &mut [u8],
|
||||
tag: &Tag,
|
||||
) -> Result<(), Error> {
|
||||
let s = aad.len() / RATE + 1;
|
||||
let t = buffer.len() / RATE + 1;
|
||||
let l = buffer.len() % RATE;
|
||||
|
||||
for j in 0..l {
|
||||
ss.state[j] = ciphertext[(t - 1) * RATE + j];
|
||||
}
|
||||
let mut aa = vec![0; s * RATE];
|
||||
let mut mm = vec![0; t * RATE];
|
||||
|
||||
ss.state[l] ^= 0x80;
|
||||
// pad aad
|
||||
aa[..aad.len()].copy_from_slice(aad);
|
||||
aa[aad.len()] = 0x80;
|
||||
|
||||
// finalization
|
||||
let expected_tag = ss.finalize();
|
||||
// init
|
||||
let mut ss = Ascon::<A, B>::new(self.key.as_ref(), nonce.as_ref());
|
||||
|
||||
if ct_eq(&expected_tag[S_SIZE - KEY_SIZE..], tag) {
|
||||
Ok(mm[..ciphertext.len()].into())
|
||||
} else {
|
||||
Err(DecryptFail::AuthenticationFail)
|
||||
// aad
|
||||
if !aad.is_empty() {
|
||||
process_aad(&mut ss, &aa, s);
|
||||
}
|
||||
|
||||
ss.state[S_SIZE - 1] ^= 1;
|
||||
|
||||
// ciphertext
|
||||
for i in 0..(t - 1) {
|
||||
for j in 0..RATE {
|
||||
mm[i * RATE + j] = ss.state[j] ^ buffer[i * RATE + j];
|
||||
}
|
||||
ss.state[..RATE].copy_from_slice(&buffer[(i * RATE)..(i * RATE + RATE)]);
|
||||
ss.permutation(12 - B, B);
|
||||
}
|
||||
|
||||
for j in 0..l {
|
||||
mm[(t - 1) * RATE + j] = ss.state[j] ^ buffer[(t - 1) * RATE + j];
|
||||
}
|
||||
|
||||
for j in 0..l {
|
||||
ss.state[j] = buffer[(t - 1) * RATE + j];
|
||||
}
|
||||
|
||||
ss.state[l] ^= 0x80;
|
||||
|
||||
// finalization
|
||||
let expected_tag = ss.finalize();
|
||||
|
||||
use subtle::ConstantTimeEq;
|
||||
if expected_tag[S_SIZE - KEY_SIZE..]
|
||||
.ct_eq(tag.as_slice())
|
||||
.into()
|
||||
{
|
||||
buffer.copy_from_slice(&mm[..buffer.len()]);
|
||||
Ok(())
|
||||
} else {
|
||||
Err(Error)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO(tarcieri): use `subtle`
|
||||
fn ct_eq(a: &[u8], b: &[u8]) -> bool {
|
||||
if a.len() != b.len() {
|
||||
false
|
||||
} else {
|
||||
a.iter()
|
||||
.zip(b)
|
||||
.map(|(x, y)| x ^ y)
|
||||
.fold(0, |sum, next| sum | next)
|
||||
.eq(&0)
|
||||
}
|
||||
}
|
||||
|
||||
fn process_aad(ss: &mut Ascon, aa: &[u8], s: usize) {
|
||||
fn process_aad<const A: usize, const B: usize>(ss: &mut Ascon<A, B>, aa: &[u8], s: usize) {
|
||||
for i in 0..s {
|
||||
for j in 0..RATE {
|
||||
ss.state[j] ^= aa[i * RATE + j];
|
||||
@ -162,38 +170,50 @@ fn process_aad(ss: &mut Ascon, aa: &[u8], s: usize) {
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::{decrypt, encrypt};
|
||||
use super::{AeadInPlace, AsconAead, KeyInit};
|
||||
use hex_literal::hex;
|
||||
|
||||
#[test]
|
||||
fn round_trip() {
|
||||
let key = [0; 16];
|
||||
let iv = [0; 16];
|
||||
let nonce = [0; 16];
|
||||
let aad = [0; 16];
|
||||
let message = [0; 64];
|
||||
|
||||
let (ciphertext, tag) = encrypt(&key, &iv, &message, &aad);
|
||||
let plaintext = decrypt(&key, &iv, &ciphertext, &aad, &tag).unwrap();
|
||||
assert_eq!(plaintext, &message[..]);
|
||||
let aead = AsconAead::<12, 8>::new(&key.into());
|
||||
let mut buffer = message;
|
||||
|
||||
let tag = aead
|
||||
.encrypt_in_place_detached(&nonce.into(), &aad, &mut buffer)
|
||||
.unwrap();
|
||||
aead.decrypt_in_place_detached(&nonce.into(), &aad, &mut buffer, &tag)
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(message, buffer);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_vectors() {
|
||||
let key = [0; 16];
|
||||
let iv = [0; 16];
|
||||
let aad = b"ASCON";
|
||||
let message = b"ascon";
|
||||
const KEY: [u8; 16] = [0; 16];
|
||||
const NONCE: [u8; 16] = [0; 16];
|
||||
const AAD: &[u8; 5] = b"ASCON";
|
||||
const PLAINTEXT: &[u8; 5] = b"ascon";
|
||||
const CIPHERTEXT: &[u8; 5] = &hex!("4c8c428949");
|
||||
const TAG: &[u8; 16] = &hex!("65fd17b6d30cd876a05a8efcecad993a");
|
||||
|
||||
let (ciphertext, tag) = encrypt(&key, &iv, message, aad);
|
||||
assert_eq!(ciphertext, [0x4c, 0x8c, 0x42, 0x89, 0x49]);
|
||||
assert_eq!(
|
||||
tag,
|
||||
[
|
||||
0x65, 0xfd, 0x17, 0xb6, 0xd3, 0x0c, 0xd8, 0x76, 0xa0, 0x5a, 0x8e, 0xfc, 0xec, 0xad,
|
||||
0x99, 0x3a
|
||||
]
|
||||
);
|
||||
let aead = AsconAead::<12, 8>::new(&KEY.into());
|
||||
let mut buffer = *PLAINTEXT;
|
||||
|
||||
let plaintext = decrypt(&key, &iv, &ciphertext, aad, &tag).unwrap();
|
||||
assert_eq!(plaintext, message);
|
||||
let tag = aead
|
||||
.encrypt_in_place_detached(&NONCE.into(), AAD, &mut buffer)
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(CIPHERTEXT, &buffer);
|
||||
assert_eq!(TAG, tag.as_slice());
|
||||
|
||||
aead.decrypt_in_place_detached(&NONCE.into(), AAD, &mut buffer, &tag)
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(PLAINTEXT, &buffer);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
#![no_std]
|
||||
#![cfg_attr(docsrs, feature(doc_auto_cfg))]
|
||||
#![doc = include_str!("../README.md")]
|
||||
#![doc(
|
||||
html_logo_url = "https://raw.githubusercontent.com/RustCrypto/meta/master/logo.svg",
|
||||
@ -17,9 +18,12 @@
|
||||
#[cfg(feature = "alloc")]
|
||||
extern crate alloc;
|
||||
|
||||
#[cfg(feature = "alloc")]
|
||||
#[cfg(feature = "aead")]
|
||||
pub mod aead;
|
||||
|
||||
#[cfg(feature = "aead")]
|
||||
pub use crate::aead::AsconAead;
|
||||
|
||||
use core::convert::TryInto;
|
||||
|
||||
/// Size of an Ascon key in bytes.
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user